text:
namespace mozc {
namespace session {

namespace {
const size_t kDefaultMaxHistorySize = 3;
}

SessionConverter::SessionConverter(const ConverterInterface *converter)
    : SessionConverterInterface(),
      state_(COMPOSITION),
      converter_(converter),
      segments_(new Segments),
      segment_index_(0),
      candidate_list_(new CandidateList(true)),
      candidate_list_visible_(false) {
  conversion_preferences_.use_history = true;
  conversion_preferences_.max_history_size = kDefaultMaxHistorySize;
  operation_preferences_.use_cascading_window = true;
  operation_preferences_.candidate_shortcuts.clear();
}

SessionConverter::~SessionConverter() {}

void SessionConverter::SetOperationPreferences(
    const OperationPreferences &preferences) {
  operation_preferences_.use_cascading_window =
      preferences.use_cascading_window;
  operation_preferences_.candidate_shortcuts =
      preferences.candidate_shortcuts;
}

bool SessionConverter::CheckState(
    SessionConverterInterface::States states) const {
  return ((state_ & states) != NO_STATE);
}

bool SessionConverter::IsActive() const {
  return CheckState(SUGGESTION | PREDICTION | CONVERSION);
}

const ConversionPreferences &SessionConverter::conversion_preferences() const {
  return conversion_preferences_;
}

bool SessionConverter::Convert(const composer::Composer &composer) {
  return ConvertWithPreferences(composer, conversion_preferences_);
}

bool SessionConverter::ConvertWithPreferences(
    const composer::Composer &composer,
    const ConversionPreferences &preferences) {
  DCHECK(CheckState(COMPOSITION | SUGGESTION | CONVERSION));

  segments_->set_request_type(Segments::CONVERSION);
  SetConversionPreferences(preferences, segments_.get());

  if (!converter_->StartConversionWithComposer(segments_.get(), &composer)) {
    LOG(WARNING) << "StartConversionWithComposer() failed";
    return false;
  }

  segment_index_ = 0;
  state_ = CONVERSION;
  candidate_list_visible_ = false;
  UpdateCandidateList();
  return true;
}

bool SessionConverter::GetReadingText(const string &source_text,
                                      string *reading) {
  DCHECK(reading);
  reading->clear();
  Segments reverse_segments;
  if (!converter_->StartReverseConversion(&reverse_segments, source_text)) {
    return false;
  }
  if (reverse_segments.segments_size() == 0) {
    LOG(WARNING) << "no segments from reverse conversion";
    return false;
  }
  for (int i = 0; i < reverse_segments.segments_size(); ++i) {
    const mozc::Segment &segment = reverse_segments.segment(i);
    if (segment.candidates_size() == 0) {
      LOG(WARNING) << "got an empty segment from reverse conversion";
      return false;
    }
    reading->append(segment.candidate(0).value);
  }
  return true;
}

namespace {
Attributes GetT13nAttributes(const transliteration::TransliterationType type) {
  Attributes attributes = NO_ATTRIBUTES;
  switch (type) {
    case transliteration::HIRAGANA:  // "ひらがな"
      attributes = HIRAGANA;
      break;
    case transliteration::FULL_KATAKANA:  // "カタカナ"
      attributes = (FULL_WIDTH | KATAKANA);
      break;
    case transliteration::HALF_ASCII:  // "ascII"
      attributes = (HALF_WIDTH | ASCII);
      break;
    case transliteration::HALF_ASCII_UPPER:  // "ASCII"
      attributes = (HALF_WIDTH | ASCII | UPPER);
      break;
    case transliteration::HALF_ASCII_LOWER:  // "ascii"
      attributes = (HALF_WIDTH | ASCII | LOWER);
      break;
    case transliteration::HALF_ASCII_CAPITALIZED:  // "Ascii"
      attributes = (HALF_WIDTH | ASCII | CAPITALIZED);
      break;
    case transliteration::FULL_ASCII:  // "ascII"
      attributes = (FULL_WIDTH | ASCII);
      break;
    case transliteration::FULL_ASCII_UPPER:  // "ASCII"
      attributes = (FULL_WIDTH | ASCII | UPPER);
      break;
    case transliteration::FULL_ASCII_LOWER:  // "ascii"
      attributes = (FULL_WIDTH | ASCII | LOWER);
      break;
    case transliteration::FULL_ASCII_CAPITALIZED:  // "Ascii"
      attributes = (FULL_WIDTH | ASCII | CAPITALIZED);
      break;
    case transliteration::HALF_KATAKANA:  // "カタカナ"
      attributes = (HALF_WIDTH | KATAKANA);
      break;
    default:
      LOG(ERROR) << "Unknown type: " << type;
      break;
  }
  return attributes;
}
}  // namespace

bool SessionConverter::ConvertToTransliteration(
    const composer::Composer &composer,
    const transliteration::TransliterationType type) {
  DCHECK(CheckState(COMPOSITION | SUGGESTION | PREDICTION | CONVERSION));
  if (CheckState(PREDICTION)) {
    // TODO(komatsu): A better way is to transliterate the key of the
    // focused candidate.  However it takes a long time.
    Cancel();
    DCHECK(CheckState(COMPOSITION));
  }

  Attributes query_attr =
      (GetT13nAttributes(type) &
       (HALF_WIDTH | FULL_WIDTH | ASCII | HIRAGANA | KATAKANA));

  if (CheckState(COMPOSITION | SUGGESTION)) {
    if (!Convert(composer)) {
      LOG(ERROR) << "Conversion failed";
      return false;
    }

    // TODO(komatsu): This is a workaround to transliterate the whole
    // preedit as a single segment.  We should modify
    // converter/converter.cc to enable to accept mozc::Segment::FIXED
    // from the session layer.
    if (segments_->conversion_segments_size() != 1) {
      string composition;
      GetPreedit(0, segments_->conversion_segments_size(), &composition);
      converter_->ResizeSegment(segments_.get(), 0,
                                Util::CharsLen(composition));
      UpdateCandidateList();
    }

    DCHECK(CheckState(CONVERSION));
    candidate_list_->MoveToAttributes(query_attr);
  } else {
    DCHECK(CheckState(CONVERSION));
    const Attributes current_attr =
        candidate_list_->GetDeepestFocusedCandidate().attributes();

    if ((query_attr & current_attr & ASCII) &&
        ((((query_attr & HALF_WIDTH) && (current_attr & FULL_WIDTH))) ||
         (((query_attr & FULL_WIDTH) && (current_attr & HALF_WIDTH))))) {
      query_attr |= (current_attr & (UPPER | LOWER | CAPITALIZED));
    }

    candidate_list_->MoveNextAttributes(query_attr);
  }
  candidate_list_visible_ = false;
  SegmentFocus();
  return true;
}

bool SessionConverter::ConvertToHalfWidth(const composer::Composer &composer) {
  DCHECK(CheckState(COMPOSITION | SUGGESTION | PREDICTION | CONVERSION));
  if (CheckState(PREDICTION)) {
    // TODO(komatsu): A better way is to transliterate the key of the
    // focused candidate.  However it takes a long time.
    Cancel();
    DCHECK(CheckState(COMPOSITION));
  }

  string composition;
  if (CheckState(COMPOSITION | SUGGESTION)) {
    if (!Convert(composer)) {
      LOG(ERROR) << "Conversion failed";
      return false;
    }
    GetPreedit(0, segments_->conversion_segments_size(), &composition);
    // TODO(komatsu): This is a workaround to transliterate the whole
    // preedit as a single segment.  We should modify
    // converter/converter.cc to enable to accept mozc::Segment::FIXED
    // from the session layer.
    if (segments_->conversion_segments_size() != 1) {
      converter_->ResizeSegment(segments_.get(), 0,
                                Util::CharsLen(composition));
      UpdateCandidateList();
    }
  } else {
    composition = GetSelectedCandidate(segment_index_).value;
  }

  DCHECK(CheckState(CONVERSION));
  Attributes attributes = HALF_WIDTH;
  // TODO(komatsu): make a function to return a logical sum of ScriptType.
  // If composition_ is "あbc", it should be treated as Katakana.
  if (Util::ContainsScriptType(composition, Util::KATAKANA) ||
      Util::ContainsScriptType(composition, Util::HIRAGANA) ||
      Util::ContainsScriptType(composition, Util::KANJI) ||
      Util::IsKanaSymbolContained(composition)
  ) {
    attributes |= KATAKANA;
  } else {
    attributes |= ASCII;
    attributes |= (candidate_list_->GetDeepestFocusedCandidate().attributes() &
                   (UPPER | LOWER | CAPITALIZED));
  }
  candidate_list_->MoveNextAttributes(attributes);
  candidate_list_visible_ = false;
  SegmentFocus();
  return true;
}

bool SessionConverter::SwitchKanaType(const composer::Composer &composer) {
  DCHECK(CheckState(COMPOSITION | SUGGESTION | PREDICTION | CONVERSION));
  if (CheckState(PREDICTION)) {
    // TODO(komatsu): A better way is to transliterate the key of the
    // focused candidate.  However it takes a long time.
    Cancel();
    DCHECK(CheckState(COMPOSITION));
  }

  Attributes attributes = NO_ATTRIBUTES;
  if (CheckState(COMPOSITION | SUGGESTION)) {
    if (!Convert(composer)) {
      LOG(ERROR) << "Conversion failed";
      return false;
    }

    // TODO(komatsu): This is a workaround to transliterate the whole
    // preedit as a single segment.  We should modify
    // converter/converter.cc to enable to accept mozc::Segment::FIXED
    // from the session layer.
    if (segments_->conversion_segments_size() != 1) {
      string composition;
      GetPreedit(0, segments_->conversion_segments_size(), &composition);
      converter_->ResizeSegment(segments_.get(), 0,
                                Util::CharsLen(composition));
      UpdateCandidateList();
    }

    attributes = (FULL_WIDTH | KATAKANA);
  } else {
    const Attributes current_attributes =
        candidate_list_->GetDeepestFocusedCandidate().attributes();
    // "漢字" -> "かんじ" -> "カンジ" -> "カンジ" -> "かんじ" -> ...
    if (current_attributes & HIRAGANA) {
      attributes = (FULL_WIDTH | KATAKANA);
    } else if ((current_attributes & KATAKANA) &&
               (current_attributes & FULL_WIDTH)) {
      attributes = (HALF_WIDTH | KATAKANA);
    } else {
      attributes = HIRAGANA;
    }
  }

  DCHECK(CheckState(CONVERSION));
  candidate_list_->MoveNextAttributes(attributes);
  candidate_list_visible_ = false;
  SegmentFocus();
  return true;
}

namespace {

// Prepend the candidates to the first conversion segment.
void PrependCandidates(const Segment &previous_segment,
                       const string &preedit,
                       Segments *segments) {
  DCHECK(segments);

  // TODO(taku) want to have a method in converter to make an empty segment
  if (segments->conversion_segments_size() == 0) {
    segments->clear_conversion_segments();
    Segment *segment = segments->add_segment();
    segment->Clear();
    segment->set_key(preedit);
  }

  DCHECK_EQ(1, segments->conversion_segments_size());
  Segment *segment = segments->mutable_conversion_segment(0);
  DCHECK(segment);

  const size_t cands_size = previous_segment.candidates_size();
  for (size_t i = 0; i < cands_size; ++i) {
    Segment::Candidate *candidate = segment->push_front_candidate();
    *candidate = previous_segment.candidate(cands_size - i - 1);  // copy
  }
  *(segment->mutable_meta_candidates()) = previous_segment.meta_candidates();
}
}  // namespace

bool SessionConverter::Suggest(const composer::Composer &composer) {
  return SuggestWithPreferences(composer, conversion_preferences_);
}

bool SessionConverter::SuggestWithPreferences(
    const composer::Composer &composer,
    const ConversionPreferences &preferences) {
  DCHECK(CheckState(COMPOSITION | SUGGESTION));
  bool use_partial_suggestion = false;
  candidate_list_visible_ = false;

  // Normalize the current state by resetting the previous state.
  ResetState();

  // If we are on a password field, suppress suggestion.
  if (composer.GetInputFieldType() == commands::SessionCommand::PASSWORD) {
    return false;
  }

  // Initialize the segments for suggestion.
  SetConversionPreferences(preferences, segments_.get());

  const size_t cursor = composer.GetCursor();
  if (cursor == composer.GetLength() || cursor == 0 ||
      !use_partial_suggestion) {
    if (!converter_->StartSuggestionWithComposer(segments_.get(), &composer)) {
      // TODO(komatsu): Because suggestion is a prefix search, once
      // StartSuggestion returns false, this GetSuggestion always
      // returns false.  Refactor it.
      VLOG(1) << "StartSuggestion() returns no suggestions.";

      // Clear segments and keep the context
      converter_->CancelConversion(segments_.get());
      return false;
    }
  } else {
    string preedit;
    composer.GetQueryForPrediction(&preedit);
    string query;
    Util::SubString(preedit, 0, cursor, &query);
    if (!converter_->StartPartialSuggestion(segments_.get(), query)) {
      VLOG(1) << "StartPartialSuggestion() returns no suggestions.";
      // Clear segments and keep the context
      converter_->CancelConversion(segments_.get());
      return false;
    }
  }
  DCHECK_EQ(1, segments_->conversion_segments_size());

  // Copy current suggestions so that we can merge
  // prediction/suggestions later
  previous_suggestions_.CopyFrom(segments_->conversion_segment(0));

  // TODO(komatsu): the next line can be deleted.
  segment_index_ = 0;
  state_ = SUGGESTION;
  UpdateCandidateList();
  candidate_list_visible_ = true;
  return true;
}

bool SessionConverter::Predict(const composer::Composer &composer) {
  return PredictWithPreferences(composer, conversion_preferences_);
}

bool SessionConverter::IsEmptySegment(const Segment &segment) const {
  return ((segment.candidates_size() == 0) &&
          (segment.meta_candidates_size() == 0));
}

bool SessionConverter::PredictWithPreferences(
    const composer::Composer &composer,
    const ConversionPreferences &preferences) {
  // TODO(komatsu): DCHECK should be
  // DCHECK(CheckState(COMPOSITION | SUGGESTION | PREDICTION));
  DCHECK(CheckState(COMPOSITION | SUGGESTION | CONVERSION | PREDICTION));
  ResetResult();

  // Initialize the segments for prediction
  segments_->set_request_type(Segments::PREDICTION);
  SetConversionPreferences(preferences, segments_.get());

  const bool predict_first =
      !CheckState(PREDICTION) && IsEmptySegment(previous_suggestions_);

  const bool predict_expand =
      (CheckState(PREDICTION) &&
       !IsEmptySegment(previous_suggestions_) &&
       candidate_list_->size() > 0 &&
       candidate_list_->focused() &&
       candidate_list_->focused_index() == candidate_list_->last_index());

  segments_->clear_conversion_segments();

  if (predict_expand || predict_first) {
    if (!converter_->StartPredictionWithComposer(segments_.get(), &composer)) {
      LOG(WARNING) << "StartPredictionWithComposer() failed";

      // TODO(komatsu): Perform refactoring after checking the stability test.
      //
      // If predict_expand is true, it means we have prevous_suggestions_.
      // So we can use it as the result of this prediction.
      if (predict_first) {
        ResetState();
        return false;
      }
    }
  }

  // Merge suggestions and prediction
  string preedit;
  composer.GetQueryForPrediction(&preedit);
  PrependCandidates(previous_suggestions_, preedit, segments_.get());

  segment_index_ = 0;
  state_ = PREDICTION;
  UpdateCandidateList();
  candidate_list_visible_ = true;

  return true;
}

bool SessionConverter::ExpandSuggestion(const composer::Composer &composer) {
  return ExpandSuggestionWithPreferences(composer, conversion_preferences_);
}

bool SessionConverter::ExpandSuggestionWithPreferences(
    const composer::Composer &composer,
    const ConversionPreferences &preferences) {
  DCHECK(CheckState(COMPOSITION | SUGGESTION | PREDICTION));
  if (CheckState(COMPOSITION)) {
    // Client can send EXPAND_SUGGESTION command when on composition mode.
    // In such case we do nothing.
    VLOG(1) << "ExpandSuggestion does nothing on composition mode.";
    return false;
  }

  ResetResult();

  // Expand suggestion.
  // Current implementation is hacky.
  // We want prediction candidates,
  // but want to set candidates' category SUGGESTION.
  // TODO(matsuzakit or yamaguchi): Refactor following lines,
  //     after implemention of partial conversion.

  // Initialize the segments for prediction.
  SetConversionPreferences(preferences, segments_.get());

  string preedit;
  composer.GetQueryForPrediction(&preedit);

  // We do not need "segments_->clear_conversion_segments()".
  // Without this statement we can add additional candidates into
  // existing segments.

  bool use_partial_suggestion = false;
  const size_t cursor = composer.GetCursor();
  if (cursor == composer.GetLength() || cursor == 0 ||
      !use_partial_suggestion) {
    // This is abuse of StartPrediction().
    // TODO(matsuzakit or yamaguchi): Add ExpandSuggestion method
    //    to Converter class.
    if (!converter_->StartPredictionWithComposer(segments_.get(), &composer)) {
      LOG(WARNING) << "StartPrediction() failed";
    }
  } else {
    string query;
    Util::SubString(preedit, 0, cursor, &query);
    if (!converter_->StartPartialPrediction(segments_.get(), query)) {
      VLOG(1) << "StartPartialPrediction() returns no suggestions.";
      // Clear segments and keep the context
      converter_->CancelConversion(segments_.get());
      return false;
    }
  }
  // Overwrite the request type to SUGGESTION.
  // Without this logic, a candidate gets focused that is unexpected behavior.
  segments_->set_request_type(Segments::SUGGESTION);

  // Merge suggestions and predictions.
  PrependCandidates(previous_suggestions_, preedit, segments_.get());

  segment_index_ = 0;
  // Call AppendCandidateList instead of UpdateCandidateList because
  // we want to keep existing candidates.
  // As a result, ExpandSuggestionWithPreferences adds expanded suggestion
  // candidates at the tail of existing candidates.
  AppendCandidateList();
  candidate_list_visible_ = true;
  return true;
}

void SessionConverter::MaybeExpandPrediction(
    const composer::Composer &composer) {
  DCHECK(CheckState(PREDICTION | CONVERSION));

  // Expand the current suggestions and fill with Prediction results.
  if (!CheckState(PREDICTION) ||
      IsEmptySegment(previous_suggestions_) ||
      !candidate_list_->focused() ||
      candidate_list_->focused_index() != candidate_list_->last_index()) {
    return;
  }

  DCHECK(CheckState(PREDICTION));
  ResetResult();

  const int previous_index = static_cast<int>(candidate_list_->focused_index());
  PredictWithPreferences(composer, conversion_preferences_);

  // Move to the last suggestion if expand mode
  if (previous_index >= 0) {
    candidate_list_->MoveToId(candidate_list_->candidate(previous_index).id());
  }
}

void SessionConverter::Cancel() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  ResetResult();

  // Clear segments and keep the context
  converter_->CancelConversion(segments_.get());
  ResetState();
}

void SessionConverter::Reset() {
  DCHECK(CheckState(COMPOSITION | SUGGESTION | PREDICTION | CONVERSION));

  // Even if composition mode, call ResetConversion
  // in order to clear history segments.
  converter_->ResetConversion(segments_.get());

  if (CheckState(COMPOSITION)) {
    return;
  }

  ResetResult();
  // Reset segments and context
  ResetState();
}

void SessionConverter::Commit() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  ResetResult();

  if (!UpdateResult(0, segments_->conversion_segments_size())) {
    Cancel();
    ResetState();
    return;
  }

  for (size_t i = 0; i < segments_->conversion_segments_size(); ++i) {
    converter_->CommitSegmentValue(segments_.get(),
                                   i,
                                   GetCandidateIndexForConverter(i));
  }
  converter_->FinishConversion(segments_.get());
  ResetState();
}

bool SessionConverter::CommitSuggestionInternal(
    const composer::Composer &composer,
    size_t *committed_length) {
  DCHECK(CheckState(SUGGESTION));
  ResetResult();
  string preedit;
  composer.GetStringForPreedit(&preedit);

  if (!UpdateResult(0, segments_->conversion_segments_size())) {
    // Do not need to call Cancel like Commit because the current
    // state is SUGGESTION.
    ResetState();
    return false;
  }

  const size_t result_length = Util::CharsLen(result_.key());
  const size_t preedit_length = Util::CharsLen(preedit);
  if (result_length < preedit_length) {
    // A candidate was chosen from partial suggestion.
    converter_->CommitPartialSuggestionSegmentValue(
        segments_.get(),
        0,
        GetCandidateIndexForConverter(0),
        Util::SubString(preedit, 0, result_length),
        Util::SubString(preedit,
                        result_length,
                        preedit_length - result_length));
    // One or more segments must exist because new segment is inserted
    // just after the commited segment.
    DCHECK_GT(segments_->conversion_segments_size(), 0);
  } else {
    // Not partial suggestion so let's reset the state.
    converter_->CommitSegmentValue(segments_.get(),
                                   0,
                                   GetCandidateIndexForConverter(0));
    converter_->FinishConversion(segments_.get());
    DCHECK_EQ(0, segments_->conversion_segments_size());
    ResetState();
  }
  *committed_length = result_length;
  return true;
}

bool SessionConverter::CommitSuggestionByIndex(
    const size_t index,
    const composer::Composer &composer,
    size_t *committed_key_size) {
  DCHECK(CheckState(SUGGESTION));
  if (index >= candidate_list_->size()) {
    LOG(ERROR) << "index is out of the range: " << index;
    return false;
  }
  candidate_list_->MoveToPageIndex(index);
  return CommitSuggestionInternal(composer, committed_key_size);
}

bool SessionConverter::CommitSuggestionById(
    const int id,
    const composer::Composer &composer,
    size_t *committed_key_size) {
  DCHECK(CheckState(SUGGESTION));
  if (!candidate_list_->MoveToId(id)) {
    // Don't use CandidateMoveToId() method, which overwrites candidates.
    // This is harmful for EXPAND_SUGGESTION session command.
    LOG(ERROR) << "No id found";
    return false;
  }
  return CommitSuggestionInternal(composer, committed_key_size);
}

void SessionConverter::CommitFirstSegment(size_t *committed_key_size) {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  ResetResult();
  candidate_list_visible_ = false;
  *committed_key_size = 0;

  // If the number of segments is one, just call Commit.
  if (segments_->conversion_segments_size() == 1) {
    Commit();
    return;
  }

  // Store the first conversion segment to the result.
  if (!UpdateResult(0, 1)) {
    // If the selected candidate of the first segment has the command
    // attribute, Cancel is performed instead of Commit.
    Cancel();
    ResetState();
    return;
  }

  // Get the first conversion segment and the selected candidate.
  Segment *first_segment = segments_->mutable_conversion_segment(0);
  if (first_segment == NULL) {
    LOG(ERROR) << "There is no segment.";
    return;
  }

  // Set the size of 1st segment's key.
  // The caller will remove corresponding characters from the composer.
  *committed_key_size = Util::CharsLen(first_segment->key());

  // Adjust the segment_index, since the first segment disappeared.
  if (segment_index_ > 0) {
    --segment_index_;
  }

  // Commit the first conversion segment only.
  converter_->SubmitFirstSegment(segments_.get(),
                                 candidate_list_->focused_id());
  UpdateCandidateList();
}

void SessionConverter::CommitPreedit(const composer::Composer &composer) {
  string key, preedit, normalized_preedit;
  composer.GetQueryForConversion(&key);
  composer.GetStringForSubmission(&preedit);
  TextNormalizer::NormalizePreeditText(preedit, &normalized_preedit);
  SessionOutput::FillPreeditResult(preedit, &result_);

  ConverterUtil::InitSegmentsFromString(key, normalized_preedit,
                                        segments_.get());

  converter_->FinishConversion(segments_.get());
  ResetState();
}

void SessionConverter::CommitHead(
    size_t count, const composer::Composer &composer, size_t *committed_size) {
  string preedit;
  composer.GetStringForSubmission(&preedit);
  if (count > preedit.length()) {
    *committed_size = preedit.length();
  } else {
    *committed_size = count;
  }
  preedit = Util::SubString(preedit, 0, *committed_size);
  string composition;
  TextNormalizer::NormalizePreeditText(preedit, &composition);
  SessionOutput::FillPreeditResult(composition, &result_);
}

void SessionConverter::Revert() {
  converter_->RevertConversion(segments_.get());
}

void SessionConverter::SegmentFocusRight() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  candidate_list_visible_ = false;
  if (CheckState(PREDICTION)) {
    return;  // Do nothing.
  }
  ResetResult();
  SegmentFix();

  if (segment_index_ + 1 >= segments_->conversion_segments_size()) {
    // If |segment_index_| is at the tail of the segments,
    // focus on the head.
    segment_index_ = 0;
  } else {
    ++segment_index_;
  }
  UpdateCandidateList();
}

void SessionConverter::SegmentFocusLast() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  candidate_list_visible_ = false;
  if (CheckState(PREDICTION)) {
    return;  // Do nothing.
  }
  ResetResult();

  const size_t r_edge = segments_->conversion_segments_size() - 1;
  if (segment_index_ >= r_edge) {
    return;
  }

  SegmentFix();
  segment_index_ = r_edge;
  UpdateCandidateList();
}

void SessionConverter::SegmentFocusLeft() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  candidate_list_visible_ = false;
  if (CheckState(PREDICTION)) {
    return;  // Do nothing.
  }
  ResetResult();
  SegmentFix();

  if (segment_index_ <= 0) {
    // If |segment_index_| is at the head of the segments,
    // focus on the tail.
    segment_index_ = segments_->conversion_segments_size() - 1;
  } else {
    --segment_index_;
  }

  UpdateCandidateList();
}

void SessionConverter::SegmentFocusLeftEdge() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  candidate_list_visible_ = false;
  if (CheckState(PREDICTION)) {
    return;  // Do nothing.
  }
  ResetResult();

  if (segment_index_ <= 0) {
    return;
  }

  SegmentFix();
  segment_index_ = 0;
  UpdateCandidateList();
}

void SessionConverter::SegmentWidthExpand() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  candidate_list_visible_ = false;
  if (CheckState(PREDICTION)) {
    return;  // Do nothing.
  }
  ResetResult();

  if (!converter_->ResizeSegment(segments_.get(), segment_index_, 1)) {
    return;
  }

  UpdateCandidateList();
}

void SessionConverter::SegmentWidthShrink() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  candidate_list_visible_ = false;
  if (CheckState(PREDICTION)) {
    return;  // Do nothing.
  }
  ResetResult();

  if (!converter_->ResizeSegment(segments_.get(), segment_index_, -1)) {
    return;
  }

  UpdateCandidateList();
}

void SessionConverter::CandidateNext(const composer::Composer &composer) {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  ResetResult();

  MaybeExpandPrediction(composer);
  candidate_list_->MoveNext();
  candidate_list_visible_ = true;
  SegmentFocus();
}

void SessionConverter::CandidateNextPage() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  ResetResult();

  candidate_list_->MoveNextPage();
  candidate_list_visible_ = true;
  SegmentFocus();
}

void SessionConverter::CandidatePrev() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  ResetResult();

  candidate_list_->MovePrev();
  candidate_list_visible_ = true;
  SegmentFocus();
}

void SessionConverter::CandidatePrevPage() {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  ResetResult();

  candidate_list_->MovePrevPage();
  candidate_list_visible_ = true;
  SegmentFocus();
}

void SessionConverter::CandidateMoveToId(
    const int id, const composer::Composer &composer) {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  ResetResult();

  if (CheckState(SUGGESTION)) {
    // This method makes a candidate focused but SUGGESTION state cannot
    // have focused candidate.
    // To solve this conflict we call Predict() method to transit to
    // PREDICTION state, on which existence of focused candidate is acceptable.
    Predict(composer);
  }
  DCHECK(CheckState(PREDICTION | CONVERSION));

  candidate_list_->MoveToId(id);
  candidate_list_visible_ = false;
  SegmentFocus();
}

void SessionConverter::CandidateMoveToPageIndex(const size_t index) {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  ResetResult();

  candidate_list_->MoveToPageIndex(index);
  candidate_list_visible_ = false;
  SegmentFocus();
}

bool SessionConverter::CandidateMoveToShortcut(const char shortcut) {
  DCHECK(CheckState(PREDICTION | CONVERSION));

  if (!candidate_list_visible_) {
    VLOG(1) << "Candidate list is not displayed.";
    return false;
  }

  const string &shortcuts = operation_preferences_.candidate_shortcuts;
  if (shortcuts.empty()) {
    VLOG(1) << "No shortcuts";
    return false;
  }

  // Check if the input character is in the shortcut.
  // TODO(komatsu): Support non ASCII characters such as Unicode and
  // special keys.
  const string::size_type index = shortcuts.find(shortcut);
  if (index == string::npos) {
    VLOG(1) << "shortcut is not a member of shortcuts.";
    return false;
  }

  if (!candidate_list_->MoveToPageIndex(index)) {
    VLOG(1) << "shortcut is out of the range.";
    return false;
  }
  ResetResult();
  SegmentFocus();
  return true;
}

bool SessionConverter::IsCandidateListVisible() const {
  return candidate_list_visible_;
}

void SessionConverter::SetCandidateListVisible(bool visible) {
  candidate_list_visible_ = visible;
}

void SessionConverter::PopOutput(
    const composer::Composer &composer, commands::Output *output) {
  FillOutput(composer, output);
  ResetResult();
}

void SessionConverter::FillOutput(
    const composer::Composer &composer, commands::Output *output) const {
  if (output == NULL) {
    LOG(ERROR) << "output is NULL.";
    return;
  }
  if (result_.has_value()) {
    FillResult(output->mutable_result());
  }
  if (CheckState(COMPOSITION)) {
    if (!composer.Empty()) {
      session::SessionOutput::FillPreedit(composer,
                                          output->mutable_preedit());
    }
  }
  if (!IsActive()) {
    return;
  }

  // Composition on Suggestion
  if (CheckState(SUGGESTION)) {
    // When the suggestion comes from zero query suggestion, the
    // composer is empty.  In that case, preedit is not rendered.
    if (!composer.Empty()) {
      session::SessionOutput::FillPreedit(composer,
                                          output->mutable_preedit());
    }
  } else if (CheckState(PREDICTION | CONVERSION)) {
    // Conversion on Prediction or Conversion
    FillConversion(output->mutable_preedit());
  }
  // Candidate list
  if (CheckState(SUGGESTION | PREDICTION | CONVERSION) &&
      candidate_list_visible_) {
    FillCandidates(output->mutable_candidates());
  }
  // All candidate words
  if (CheckState(SUGGESTION | PREDICTION | CONVERSION)) {
    FillAllCandidateWords(output->mutable_all_candidate_words());
  }
}

void SessionConverter::FillContext(commands::Context *context) const {
  if (context->has_preceding_text()) {
    // Client has set the information of surrounding text, so do nothing.
    return;
  }
  if (segments_->history_segments_size() == 0) {
    return;
  }

  // Set preceding text using history segments.
  string *preceding_text = context->mutable_preceding_text();
  for (size_t i = 0; i < segments_->history_segments_size(); ++i) {
    *preceding_text += segments_->history_segment(i).candidate(0).value;
  }
}

void SessionConverter::GetSegments(Segments *dest) const {
  DCHECK(dest);
  dest->Clear();
  dest->CopyFrom(*segments_.get());
}

void SessionConverter::SetSegments(const Segments &src) {
  segments_->Clear();
  segments_->CopyFrom(src);
}

void SessionConverter::RemoveTailOfHistorySegments(size_t num_of_characters) {
  segments_->RemoveTailOfHistorySegments(num_of_characters);
}

const commands::Result &SessionConverter::GetResult() const {
  return result_;
}

const CandidateList &SessionConverter::GetCandidateList() const {
  return *candidate_list_;
}

const OperationPreferences &SessionConverter::GetOperationPreferences() const {
  return operation_preferences_;
}

SessionConverterInterface::State SessionConverter::GetState() const {
  return state_;
}

size_t SessionConverter::GetSegmentIndex() const {
  return segment_index_;
}

const Segment &SessionConverter::GetPreviousSuggestions()
    const {
  return previous_suggestions_;
}

// static
void SessionConverter::SetConversionPreferences(
    const ConversionPreferences &preferences,
    Segments *segments) {
  segments->set_user_history_enabled(preferences.use_history);
  segments->set_max_history_segments_size(preferences.max_history_size);
}

void SessionConverter::CopyFrom(const SessionConverterInterface &src) {
  Reset();

  Segments segments;
  src.GetSegments(&segments);
  SetSegments(segments);

  state_ = src.GetState();
  segment_index_ = src.GetSegmentIndex();
  conversion_preferences_ = src.conversion_preferences();
  operation_preferences_ = src.GetOperationPreferences();
  result_.CopyFrom(src.GetResult());

  const Segment &previous_suggestions =
      src.GetPreviousSuggestions();
  previous_suggestions_.CopyFrom(previous_suggestions);

  if (CheckState(SUGGESTION | PREDICTION | CONVERSION)) {
    UpdateCandidateList();
    candidate_list_->MoveToId(src.GetCandidateList().focused_id());
    SetCandidateListVisible(src.IsCandidateListVisible());
  }
}

void SessionConverter::ResetResult() {
  result_.Clear();
}

void SessionConverter::ResetState() {
  state_ = COMPOSITION;
  segment_index_ = 0;
  previous_suggestions_.clear();
  candidate_list_visible_ = false;
  candidate_list_->Clear();
}

void SessionConverter::SegmentFocus() {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  converter_->FocusSegmentValue(segments_.get(),
                                segment_index_,
                                GetCandidateIndexForConverter(segment_index_));
}

void SessionConverter::SegmentFix() {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  converter_->CommitSegmentValue(segments_.get(),
                                 segment_index_,
                                 GetCandidateIndexForConverter(segment_index_));
}

void SessionConverter::GetPreedit(const size_t index,
                                  const size_t size,
                                  string *preedit) const {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  DCHECK(index + size <= segments_->conversion_segments_size());
  DCHECK(preedit);

  preedit->clear();
  for (size_t i = index; i < size; ++i) {
    if (CheckState(CONVERSION)) {
      // In conversion mode, all the key of candidates is same.
      preedit->append(segments_->conversion_segment(i).key());
    } else {
      DCHECK(CheckState(SUGGESTION | PREDICTION));
      // In suggestion or prediction modes, each key may have
      // different keys, so content_key is used although it is
      // possibly droped the conjugational word (ex. the content_key
      // of "はしる" is "はし").
      preedit->append(GetSelectedCandidate(i).content_key);
    }
  }
}

void SessionConverter::GetConversion(const size_t index,
                                     const size_t size,
                                     string *conversion) const {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  DCHECK(index + size <= segments_->conversion_segments_size());
  DCHECK(conversion);

  conversion->clear();
  for (size_t i = index; i < size; ++i) {
    conversion->append(GetSelectedCandidateValue(i));
  }
}

bool SessionConverter::MaybePerformCommandCandidate(
    const size_t index,
    const size_t size) const {
  // If a candidate has the command attribute, Cancel is performed
  // instead of Commit.
  for (size_t i = index; i < size; ++i) {
    const int id = GetCandidateIndexForConverter(i);
    const Segment::Candidate &candidate =
        segments_->conversion_segment(i).candidate(id);
    if (candidate.attributes & Segment::Candidate::COMMAND_CANDIDATE) {
      // TODO(komatsu): Move the logic for command_candidate here from
      // the rewriter.
      return true;
    }
  }
  return false;
}

bool SessionConverter::UpdateResult(const size_t index, const size_t size) {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));

  // If command candidate is performed, result is not updated and
  // returns false.
  if (MaybePerformCommandCandidate(index, size)) {
    return false;
  }

  string preedit, conversion;
  GetPreedit(index, size, &preedit);
  GetConversion(index, size, &conversion);
  SessionOutput::FillConversionResult(preedit, conversion, &result_);
  return true;
}

namespace {
// Convert transliteration::TransliterationType to id used in the
// converter.  The id number are negative values, and 0 of
// transliteration::TransliterationType is bound for -1 of the id.
int GetT13nId(const transliteration::TransliterationType type) {
  return -(type + 1);
}
}  // namespace

void SessionConverter::AppendCandidateList() {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));

  // Meta candidates are added iff |candidate_list_| is empty.
  // This is because if |candidate_list_| is not empty we cannot decide
  // where to add meta candidates, especially use_cascading_window flag
  // is true (If there are two or more sub candidate lists, and existent
  // meta candidates are not located in the same list (distributed over
  // some lists), the most appropriate location to be added new meta candidates
  // cannot be decided).
  const bool add_meta_candidates = (candidate_list_->size() == 0);

  const Segment &segment = segments_->conversion_segment(segment_index_);
  for (size_t i = candidate_list_->next_available_id();
       i < segment.candidates_size();
       ++i) {
    candidate_list_->AddCandidate(i, segment.candidate(i).value);
    // if candidate has spelling correction attribute,
    // always display the candidate to let user know the
    // miss spelled candidate.
    if (i < 10 &&
        (segment.candidate(i).attributes &
         Segment::Candidate::SPELLING_CORRECTION)) {
      candidate_list_visible_ = true;
    }
  }

  const bool focused = (segments_->request_type() != Segments::SUGGESTION);
  candidate_list_->set_focused(focused);

  if (segment.meta_candidates_size() == 0) {
    LOG(WARNING) << "T13N is not initialized: " << segment.key();
    return;
  }

  if (!add_meta_candidates) {
    return;
  }

  // Set transliteration candidates
  CandidateList *transliterations;
  if (operation_preferences_.use_cascading_window) {
    const bool kNoRotate = false;
    transliterations = candidate_list_->AllocateSubCandidateList(kNoRotate);
    transliterations->set_focused(true);

    const char kT13nLabel[] =
      // "そのほかの文字種";
      "\xe3\x81\x9d\xe3\x81\xae\xe3\x81\xbb\xe3\x81\x8b\xe3\x81\xae"
      "\xe6\x96\x87\xe5\xad\x97\xe7\xa8\xae";
    transliterations->set_name(kT13nLabel);
  } else {
    transliterations = candidate_list_.get();
  }

  // Add transliterations.
  for (size_t i = 0; i < transliteration::NUM_T13N_TYPES; ++i) {
    const transliteration::TransliterationType type =
      transliteration::TransliterationTypeArray[i];
    transliterations->AddCandidateWithAttributes(
        GetT13nId(type),
        segment.meta_candidate(i).value,
        GetT13nAttributes(type));
  }
}

void SessionConverter::UpdateCandidateList() {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  candidate_list_->Clear();
  AppendCandidateList();
}

int SessionConverter::GetCandidateIndexForConverter(
    const size_t segment_index) const {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  // If segment_index does not point to the focused segment, the value
  // should be always zero.
  if (segment_index != segment_index_) {
    return 0;
  }
  return candidate_list_->focused_id();
}

string SessionConverter::GetSelectedCandidateValue(
    const size_t segment_index) const {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  const int id = GetCandidateIndexForConverter(segment_index);
  const Segment::Candidate &candidate =
      segments_->conversion_segment(segment_index).candidate(id);
  if (candidate.attributes & Segment::Candidate::COMMAND_CANDIDATE) {
    // Return an empty string, however this path should not be reached.
    return "";
  }
  return candidate.value;
}

const Segment::Candidate &SessionConverter::GetSelectedCandidate(
    const size_t segment_index) const {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  const int id = GetCandidateIndexForConverter(segment_index);
  return segments_->conversion_segment(segment_index).candidate(id);
}

void SessionConverter::FillConversion(commands::Preedit *preedit) const {
  DCHECK(CheckState(PREDICTION | CONVERSION));
  SessionOutput::FillConversion(*segments_,
                                segment_index_,
                                candidate_list_->focused_id(),
                                preedit);
}

void SessionConverter::FillResult(commands::Result *result) const {
  result->CopyFrom(result_);
}

void SessionConverter::FillCandidates(commands::Candidates *candidates) const {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  if (!candidate_list_visible_) {
    return;
  }

  // The position to display the candidate window.
  size_t position = 0;
  string conversion;
  for (size_t i = 0; i < segment_index_; ++i) {
    position += Util::CharsLen(GetSelectedCandidate(i).value);
  }

  const Segment &segment = segments_->conversion_segment(segment_index_);
  SessionOutput::FillCandidates(
      segment, *candidate_list_, position, candidates);

  // Shortcut keys
  if (CheckState(PREDICTION | CONVERSION)) {
    SessionOutput::FillShortcuts(operation_preferences_.candidate_shortcuts,
                                 candidates);
  }

  // Store category
  switch (segments_->request_type()) {
    case Segments::CONVERSION:
      candidates->set_category(commands::CONVERSION);
      break;
    case Segments::PREDICTION:
      candidates->set_category(commands::PREDICTION);
      break;
    case Segments::SUGGESTION:
      candidates->set_category(commands::SUGGESTION);
      break;
    case Segments::PARTIAL_PREDICTION:
      // Not PREDICTION because we do not want to get focused candidate.
      candidates->set_category(commands::SUGGESTION);
      break;
    case Segments::PARTIAL_SUGGESTION:
      candidates->set_category(commands::SUGGESTION);
      break;
    default:
      LOG(WARNING) << "Unknown request type: " << segments_->request_type();
      candidates->set_category(commands::CONVERSION);
      break;
  }

  if (candidates->has_usages()) {
    candidates->mutable_usages()->set_category(commands::USAGE);
  }
  if (candidates->has_subcandidates()) {
    // TODO(komatsu): Subcandidate is not always for transliterations.
    // The category of the subcandidates should be checked.
    candidates->mutable_subcandidates()->set_category(
        commands::TRANSLITERATION);
  }

  // Store display type
  candidates->set_display_type(commands::MAIN);
  if (candidates->has_usages()) {
    candidates->mutable_usages()->set_display_type(commands::CASCADE);
  }
  if (candidates->has_subcandidates()) {
    // TODO(komatsu): Subcandidate is not always for transliterations.
    // The category of the subcandidates should be checked.
    candidates->mutable_subcandidates()->set_display_type(commands::CASCADE);
  }

  // Store footer.
  SessionOutput::FillFooter(candidates->category(), candidates);
}

void SessionConverter::FillAllCandidateWords(
    commands::CandidateList *candidates) const {
  DCHECK(CheckState(SUGGESTION | PREDICTION | CONVERSION));
  commands::Category category;
  switch (segments_->request_type()) {
    case Segments::CONVERSION:
      category = commands::CONVERSION;
      break;
    case Segments::PREDICTION:
      category = commands::PREDICTION;
      break;
    case Segments::SUGGESTION:
      category = commands::SUGGESTION;
      break;
    case Segments::PARTIAL_PREDICTION:
      // Not PREDICTION because we do not want to get focused candidate.
      category = commands::SUGGESTION;
      break;
    case Segments::PARTIAL_SUGGESTION:
      category = commands::SUGGESTION;
      break;
    default:
      LOG(WARNING) << "Unkown request type: " << segments_->request_type();
      category = commands::CONVERSION;
      break;
  }

  const Segment &segment = segments_->conversion_segment(segment_index_);
  SessionOutput::FillAllCandidateWords(
      segment, *candidate_list_, category, candidates);
}

}  // namespace session
}  // namespace mozc


text:
import ko from "knockout";

import router from "modules/router";

export function Component(options: { selector: string, template: string }) {
	return (target) => {
		ko.components.register(options.selector, {
			template: {
				require: options.template
			},
			viewModel: new target({})
		});
	};
}

export function Route(route) {

}

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace Surfnet\StepupRa\RaBundle\Security\Authentication\Handler;

use Psr\Log\LoggerInterface;
use Surfnet\StepupRa\RaBundle\Security\Authentication\AuthenticatedSessionStateHandler;
use Surfnet\StepupRa\RaBundle\Security\Authentication\Session\SessionLifetimeGuard;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Http\Logout\CookieClearingLogoutHandler;
use Symfony\Component\Security\Http\Logout\SessionLogoutHandler;

/**
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class ExplicitSessionTimeoutHandler implements AuthenticationHandler
{
    /**
     * @var AuthenticationHandler|null
     */
    private $nextHandler;

    /**
     * @var TokenStorageInterface
     */
    private $tokenStorage;

    /**
     * @var SessionLifetimeGuard
     */
    private $sessionLifetimeGuard;

    /**
     * @var AuthenticatedSessionStateHandler
     */
    private $authenticatedSession;

    /**
     * @var SessionLogoutHandler
     */
    private $sessionLogoutHandler;

    /**
     * @var CookieClearingLogoutHandler
     */
    private $cookieClearingLogoutHandler;

    /**
     * @var RouterInterface
     */
    private $router;
    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(
        TokenStorageInterface $tokenStorageInterface,
        AuthenticatedSessionStateHandler $authenticatedSessionStateHandler,
        SessionLifetimeGuard $sessionLifetimeGuard,
        SessionLogoutHandler $sessionLogoutHandler,
        CookieClearingLogoutHandler $cookieClearingLogoutHandler,
        RouterInterface $router,
        LoggerInterface $logger
    ) {
        $this->tokenStorage                = $tokenStorageInterface;
        $this->authenticatedSession        = $authenticatedSessionStateHandler;
        $this->sessionLifetimeGuard        = $sessionLifetimeGuard;
        $this->sessionLogoutHandler        = $sessionLogoutHandler;
        $this->cookieClearingLogoutHandler = $cookieClearingLogoutHandler;
        $this->router                      = $router;
        $this->logger                      = $logger;
    }

    public function process(GetResponseEvent $event)
    {
        if ($this->tokenStorage->getToken() !== null
            && !$this->sessionLifetimeGuard->sessionLifetimeWithinLimits($this->authenticatedSession)
        ) {
            $invalidatedBy = [];
            if (!$this->sessionLifetimeGuard->sessionLifetimeWithinAbsoluteLimit($this->authenticatedSession)) {
                $invalidatedBy[] = 'absolute';
            }

            if (!$this->sessionLifetimeGuard->sessionLifetimeWithinRelativeLimit($this->authenticatedSession)) {
                $invalidatedBy[] = 'relative';
            }

            $this->logger->notice(sprintf(
                'Authenticated user found, but session was determined to be outside of the "%s" time limit. User will '
                . 'be logged out and redirected to session-expired page to attempt new login.',
                implode(' and ', $invalidatedBy)
            ));

            $token   = $this->tokenStorage->getToken();
            $request = $event->getRequest();

            // if the current request was not a GET request we cannot safely redirect to that page after login as it
            // may require a form resubmit for instance. Therefor, we redirect to the last GET request (either current
            // or previous).
            $afterLoginRedirectTo = $this->authenticatedSession->getCurrentRequestUri();
            if ($event->getRequest()->getMethod() === 'GET') {
                $afterLoginRedirectTo = $event->getRequest()->getRequestUri();
            }

            // log the user out using Symfony methodology, see the LogoutListener
            $event->setResponse(new RedirectResponse($this->router->generate('ra_security_session_expired')));

            $this->sessionLogoutHandler->logout($request, $event->getResponse(), $token);
            $this->cookieClearingLogoutHandler->logout($request, $event->getResponse(), $token);
            $this->tokenStorage->setToken(null);

            // the session is restarted after invalidation during the logout, so we can (re)store the last GET request
            $this->authenticatedSession->setCurrentRequestUri($afterLoginRedirectTo);

            return;
        }

        if ($this->nextHandler !== null) {
            $this->nextHandler->process($event);
        }
    }

    public function setNext(AuthenticationHandler $handler)
    {
        $this->nextHandler = $handler;
    }
}


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<TITLE>
ConfusionMatrix (ANJI API)
</TITLE>

<META NAME="keywords" CONTENT="com.anji.fingerprint.ConfusionMatrix class">

<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">

      Overview
      Package
    Class
      Use
      Tree
      Deprecated
      Index
      Help

 PREV CLASS
 NEXT CLASS

  FRAMES
 NO FRAMES

  All Classes

  SUMMARY: NESTED | FIELD | CONSTR | METHOD

DETAIL: FIELD | CONSTR | METHOD

com.anji.fingerprint

Class ConfusionMatrix

java.lang.Object
  com.anji.fingerprint.ConfusionMatrix

public class ConfusionMatrix
extends java.lang.Object

ConfusionMatrix

Constructor Summary

ConfusionMatrix()

Method Summary

 int
getCount(Classification actual,
         Classification machine)

          get cell in confusion matrix

 int[][]
getValues()

 void
increment(Classification actual,
          Classification machine)

          increment cell in confusion matrix

 void
setCount(Classification actual,
         Classification machine,
         int count)

          set cell in confusion matrix

 java.lang.String
toString()

 java.lang.String
toString(java.lang.String sep)

          record separator is "\n"

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Constructor Detail

ConfusionMatrix

public ConfusionMatrix()

Method Detail

setCount

public void setCount(Classification actual,
                     Classification machine,
                     int count)

set cell in confusion matrix

Parameters:
actual -
machine -
count -

getCount

public int getCount(Classification actual,
                    Classification machine)

get cell in confusion matrix

Parameters:
actual -
machine -

Returns:
count

increment

public void increment(Classification actual,
                      Classification machine)

increment cell in confusion matrix

Parameters:
actual -
machine -

getValues

public int[][] getValues()

Returns:
values

toString

public java.lang.String toString()

See Also:
Object.toString()

toString

public java.lang.String toString(java.lang.String sep)

record separator is "\n"

Parameters:
sep - field separator

Returns:
tabular representation of confusion matrix

      Overview
      Package
    Class
      Use
      Tree
      Deprecated
      Index
      Help

 PREV CLASS
 NEXT CLASS

  FRAMES
 NO FRAMES

  All Classes

  SUMMARY: NESTED | FIELD | CONSTR | METHOD

DETAIL: FIELD | CONSTR | METHOD


text:
using System.Collections.Generic;
using System.Linq;
using YouTown.GameAction;

namespace YouTown
{
    public interface IGamePhase : IGameItem
    {
        bool IsSetup { get; }
        bool IsDetermineFirstPlayer { get; }
        bool IsInitialPlacement { get; }
        bool IsTurns { get; }
        bool IsEnd { get; }

        void Start(IGame game);
        void End(IGame game);

        Production RollDice(IGame game, DiceRoll diceRoll, IPlayer player);
        void BuildTown(IGame game, IPlayer player, Town town);
        void BuildRoad(IGame game, IPlayer player, Road road);
    }

    public abstract class GamePhaseBase
    {
        protected GamePhaseBase(int id)
        {
            Id = id;
        }

        public int Id { get; }
        public virtual bool IsSetup => false;
        public virtual bool IsDetermineFirstPlayer => false;
        public virtual bool IsInitialPlacement => false;
        public virtual bool IsTurns => false;
        public virtual bool IsEnd => false;

        public virtual void BuildTown(IGame game, IPlayer player, Town town) { }
        public virtual void BuildRoad(IGame game, IPlayer player, Road road) { }
        public virtual Production RollDice(IGame game, DiceRoll diceRoll, IPlayer player)
        {
            return null;
        }
    }

    /// <summary>
    /// A mechanism must determine the first player and the order of players.
    /// </summary>
    /// Many mechanisms are used to do this:
    /// - let the server randomly decide
    /// - have players roll a dice until a highroller turns up
    /// - setting in the game: first come, first serve (gives host deterministic
    ///   first spot)
    /// For initial simplicity sake of implementation, we let the server decide for now
    /// as default implementation.
    public class DetermineFirstPlayer : GamePhaseBase, IGamePhase
    {
        public DetermineFirstPlayer(int id) : base(id) { }
        public override bool IsDetermineFirstPlayer => true;

        public void Start(IGame game)
        {
        }

        public void End(IGame game)
        {
        }
    }

    /// <summary>
    /// Housekeeping phase for animation purposes
    /// </summary>
    /// Imagine a start state where the board is not setup and players
    /// do not yet have any pieces. It would be nice for players to
    /// see the board transform from a design state to a playable state.
    /// Further, having the pieces appear animated at each player and the
    /// bank clarify what's in the game.
    public class SetupGamePhase : GamePhaseBase, IGamePhase
    {
        public SetupGamePhase(int id) : base(id) { }
        public override bool IsSetup => true;
        public void Start(IGame game)
        {
        }

        public void End(IGame game)
        {
        }
    }

    /// <summary>
    /// Player place each 2 towns and 2 roads to start with
    /// </summary>
    /// There is an alternative setup where player get one town, one city and three
    /// roads. The order then is town+road, (other players), city+road+road.
    public class PlaceInitialPieces : GamePhaseBase, IGamePhase
    {
        public PlaceInitialPieces(int id) : base(id) { }
        public PlaceInitialPieces(PlaceInitialPiecesData data, IRepository repo) : base(data.Id)
        {
            Turns = data.Turns.Select(td => new PlaceTurn(td, repo)).ToList();
            repo.AddAll(Turns);

            RoadsBuilt = data.RoadsBuiltCount;
            PlayerOnTurn = repo.GetOrNull<IPlayer>(data.PlayerOnTurnId);
        }

        public List<PlaceTurn> Turns { get; } = new List<PlaceTurn>();
        public int RoadsBuilt { get; private set; }
        public IPlayer PlayerOnTurn { get; private set; }

        public override bool IsInitialPlacement => true;

        public PlaceInitialPiecesData ToData() =>
            new PlaceInitialPiecesData
            {
                Turns = Turns.Select(t => t.ToData()).ToList(),
                RoadsBuiltCount = RoadsBuilt,
                PlayerOnTurnId = PlayerOnTurn?.Id,
            };

        public void Start(IGame game)
        {
            PlayerOnTurn = game.Players.First();
            PlayerOnTurn.IsOnTurn = true;
        }

        public void End(IGame game)
        {
        }

        public override void BuildRoad(IGame game, IPlayer player, Road road)
        {
            RoadsBuilt++;
            bool to = RoadsBuilt < game.Players.Count;
            bool halfway = RoadsBuilt == game.Players.Count;
            bool back = RoadsBuilt > game.Players.Count;
            PlayerOnTurn.IsOnTurn = false;
            if (to)
            {
                var index = game.Players.IndexOf(PlayerOnTurn) + 1;
                PlayerOnTurn = game.Players[index];
            } else if (halfway)
            {
                // nothing, player stays "on turn"
            } else if (back && PlayerOnTurn.Equals(game.Players.First()))
            {
                // nothing, player stays "on turn"
            }
            else
            {
                var index = game.Players.IndexOf(PlayerOnTurn) - 1;
                PlayerOnTurn = game.Players[index];
            }
            PlayerOnTurn.IsOnTurn = true;
            int expectedAmountRoadsBuilt = game.Players.Count * 2;
            if (RoadsBuilt == expectedAmountRoadsBuilt)
            {
                game.MoveToNextPhase();
            }
        }

        public override void BuildTown(IGame game, IPlayer player, Town town)
        {
            if (player.Towns.Count != 1)
            {
                return;
            }
            var resourcesGained = new List<IResource>();
            foreach (Location location in town.Vertex.Locations)
            {
                IHex hex = game.Board.HexesByLocation[location];
                IResource resource = hex.Produce();
                if (resource != null)
                {
                    resourcesGained.Add(resource);
                }
            }
            player.GainResourcesFrom(game.Bank.Resources, new ResourceList(resourcesGained), null);
            // TODO: indicate to all players what resources this player gained
        }
    }

    /// <summary>
    /// Longest phase of all in the game where players switch turns
    /// </summary>
    public class PlayTurns : GamePhaseBase, IGamePhase
    {
        private readonly BeforeDiceRoll _beforeDiceRoll;
        private readonly RollDicePhase _diceRoll;
        private readonly Trading _trading;
        private readonly Building _building;

        public PlayTurns(int id, IRepository repo, IIdentifier identifier) : base(id)
        {
            Turns = new List<IPlayTurnsTurn>();
            TurnPhase = _beforeDiceRoll;
            _beforeDiceRoll = new BeforeDiceRoll(identifier.NewId());
            _diceRoll = new RollDicePhase(identifier.NewId());
            _trading = new Trading(identifier.NewId());
            _building = new Building(identifier.NewId());
            repo.AddAll(_beforeDiceRoll, _diceRoll, _trading, _building);
        }

        public PlayTurns(PlayTurnsData data, IRepository repo) : base(data.Id)
        {
            _beforeDiceRoll = new BeforeDiceRoll(data.BeforeDiceRoll.Id);
            _diceRoll = new RollDicePhase(data.DiceRoll.Id);
            _trading = new Trading(data.Trading.Id);
            _building = new Building(data.Trading.Id);
            repo.AddAll(_beforeDiceRoll, _diceRoll, _trading, _building);

            Turns = data.Turns.Select(td => td.FromData(repo)).Cast<IPlayTurnsTurn>().ToList();
            repo.AddAll(Turns);

            Turn = repo.GetOrNull<IPlayTurnsTurn>(data.TurnId);
            TurnPhase = repo.GetOrNull<ITurnPhase>(data.TurnPhaseId);
        }

        public override bool IsTurns => true;
        public IList<IPlayTurnsTurn> Turns { get; }
        public IPlayTurnsTurn Turn { get; private set; }
        public ITurnPhase TurnPhase { get; private set; }

        public PlayTurnsData ToData() =>
            new PlayTurnsData
            {
                BeforeDiceRoll = new BeforeDiceRollData
                {
                    Id = _beforeDiceRoll.Id,
                    TurnPhaseType = TurnPhaseTypeData.BeforeDiceRoll
                },
                DiceRoll = new DiceRollTurnPhaseData
                {
                    Id = _diceRoll.Id,
                    TurnPhaseType = TurnPhaseTypeData.RollDice
                },
                Trading = new TradingData
                {
                    Id = _trading.Id,
                    TurnPhaseType = TurnPhaseTypeData.Trading
                },
                Building = new BuildingData
                {
                    Id = _building.Id,
                    TurnPhaseType = TurnPhaseTypeData.Building
                },
                Turns = Turns.Select(t => t.ToData()).ToList(),
                TurnId = Turn?.Id,
                TurnPhaseId = TurnPhase?.Id
            };

        public void Start(IGame game)
        {
        }

        public void End(IGame game)
        {
        }

        public void SetToBeforeDiceRoll()
        {
            if (TurnPhase != _beforeDiceRoll)
            {
                TurnPhase = _beforeDiceRoll;
            }
        }

        public void SetToDiceRoll()
        {
            if (TurnPhase != _diceRoll)
            {
                TurnPhase = _diceRoll;
            }
        }

        public void SetToTrading()
        {
            if (TurnPhase != _trading)
            {
                TurnPhase = _trading;
            }
        }

        public void SetToBuilding()
        {
            if (TurnPhase != _building)
            {
                TurnPhase = _building;
            }
        }

        public void MoveToNextTurn(IPlayTurnsTurn nextTurn)
        {
            Turns.Add(nextTurn);
            Turn = nextTurn;
        }

        public override Production RollDice(IGame game, DiceRoll diceRoll, IPlayer player)
        {
            SetToDiceRoll();
            int roll = diceRoll.Sum;
            if (roll == 7)
            {
                var looseCards = game.Players
                    .Where(p => p.Hand.Count > 7)
                    .Select(p => new LooseCards(p));
                game.Queue.EnqueueUnordered(looseCards);
                game.Queue.EnqueueSingle(new MoveRobber(player), optional: false);
                game.Queue.EnqueueSingle(new RobPlayer(player), optional: true);
                return null;
            }
            // Produce resources:
            // 1. determine productions
            // 2. determine production per player
            // 3. determine shortages
            // 4. determine resources to distribute
            // 5. distribute resources
            var hexes = game.Board.HexesByLocation.Values
                .Where(h => h.Chit != null)
                .Where(h => h.Chit.Number == roll)
                .Where(h => !h.Location.Equals(game.Board.Robber.Location));

            var productions = new List<Produce>();
            foreach (var hex in hexes)
            {
                var produced = game.Board.Producers
                    .Where(p => p.IsAt(hex.Location))
                    .Select(p => new Produce(p, hex, p.Produce(hex)));
                productions.AddRange(produced);
            }
            var producedResources = new ResourceList(productions.SelectMany(p => p.Resources));
            var resourcesByPlayer = new Dictionary<IPlayer, IResourceList>();
            var players = productions.Select(p => p.Producer.Player).Distinct();
            foreach (var player1 in players)
            {
                var resources = productions
                    .Where(p => p.Producer.Player.Equals(player1))
                    .SelectMany(p => p.Resources);
                var resourceList = new ResourceList(resources);
                resourcesByPlayer[player1] = resourceList;
            }
            var toDistribute = new Dictionary<IPlayer, IResourceList>(resourcesByPlayer);
            var shortages = new List<ProductionShortage>();
            if (game.Bank.Resources.HasAtLeast(producedResources))
            {
                return new Production(toDistribute, productions, shortages);
            }

            // divide shortage among players
            // players are assigned shortages starting at the player last on turn.
            // example: p0, p1, p2, [p3], p4 (p3 is on turn)
            // p2 gets first shortage, then p1, p0, p4, p3.
            // note: alternative ways of dealing with this situation exist:
            // - don't contrain bank on resources (there's always enough)
            // - randomly assign shortage (but balanced)
            // - start by player having most victory points (incentivizes playing VictoryPoint devcards)
            var bank = game.Bank.Resources;
            foreach (var resourceType in producedResources.ResourceTypes)
            {
                var resourceOfType = producedResources.OfType(resourceType);
                var bankCount = bank.OfType(resourceType).Count;
                if (bankCount == resourceOfType.Count)
                {
                    continue;
                }
                var players1 = productions
                    .Where(p => p.Resources.HasType(resourceType))
                    .Select(p => p.Producer.Player)
                    .Distinct()
                    .ToList();
                var shortage = resourceOfType.Count - bankCount;
                var shortagePerPlayer = shortage/players1.Count;
                var shortageRemainder = shortage%players1.Count;
                var shortageByPlayer = new Dictionary<IPlayer, int>();
                int indexOfCurrentPlayer = game.Players.IndexOf(player);
                while (shortageRemainder > 0)
                {
                    int index = indexOfCurrentPlayer == 0 ? game.Players.Count - 1 : indexOfCurrentPlayer - 1;
                    var player1 = game.Players[index];
                    if (players1.Contains(player1))
                    {
                        shortageByPlayer[player1] = shortagePerPlayer + 1;
                        shortageRemainder--;
                    }
                }
                foreach (var pair in shortageByPlayer)
                {
                    var player1 = pair.Key;
                    var amountShort = pair.Value;
                    shortages.Add(new ProductionShortage(player1, resourceType, amountShort));
                }
            }
            foreach (var shortage in shortages)
            {
                var resources = toDistribute[shortage.Player];
                var removed = resources.ToList();
                for (int i = 0; i < shortage.AmountShort; i++)
                {
                    var toRemove = removed.Last();
                    removed.Remove(toRemove);
                }
                toDistribute[shortage.Player] = new ResourceList(removed);
            }

            // Actually distribute the resources
            foreach (KeyValuePair<IPlayer, IResourceList> pair in toDistribute)
            {
                var player1 = pair.Key;
                var resourcesToGain = pair.Value;
                player1.GainResourcesFrom(game.Bank.Resources, resourcesToGain, null);
            }

            return new Production(toDistribute, productions, shortages);
        }
    }

    public class EndOfGame : GamePhaseBase, IGamePhase
    {
        public EndOfGame(int id) : base(id) { }
        public override bool IsEnd => true;

        public void Start(IGame game)
        {
        }

        public void End(IGame game)
        {
        }
    }
}


text:
using System;
using System.Xml.Serialization;
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json;
using JdSdk.Request;
using JdSdk.Response.Supplier;

namespace JdSdk.Request.Supplier
{
    public class ProcurementOrderConfirmRequest : JdRequestBase<ProcurementOrderConfirmResponse>
    {
        public Nullable<Int64> OrderId
        {
            get;
            set;
        }

        public Nullable<DateTime> DeliveryTime
        {
            get;
            set;
        }

        public String WareId
        {
            get;
            set;
        }

        public String DeliverCenterId
        {
            get;
            set;
        }

        public String BackExplanationType
        {
            get;
            set;
        }

        public String ConfirmNum
        {
            get;
            set;
        }

        public override String ApiName
        {
            get{ return "jingdong.procurement.order.confirm"; }
        }

        protected override void PrepareParam(IDictionary<String, Object> paramters)
        {
            paramters.Add("orderId" ,this.OrderId);
            paramters.Add("deliveryTime" ,this.DeliveryTime);
            paramters.Add("wareId" ,this.WareId);
            paramters.Add("deliverCenterId" ,this.DeliverCenterId);
            paramters.Add("backExplanationType" ,this.BackExplanationType);
            paramters.Add("confirmNum" ,this.ConfirmNum);
        }

    }

}


text:
package tbsc.server.db.service;

import tbsc.server.db.DB;
import tbsc.server.security.PasswordHasher;
import tbsc.server.security.RandomStringGenerator;
import tbsc.shared.model.User;

public class UserService {

	public static User createUser(String username, String password) {

		String md = new PasswordHasher().hash(password);

		User user = new User();
		user.username = username;
		user.password = md;
		user.email = "";
		user.session = new RandomStringGenerator().generate();

		try {
			DB.datastore.save(user);
		} catch (Exception e){
			return null;
		}

		return user;

	}

	public static boolean exists(String username) {

		return DB.datastore.createQuery(User.class)
			.field("username").equal(username)
			.countAll() > 0;

	}

	public static User getUserByName(String username) {

		return DB.datastore.createQuery(User.class)
			.field("username").equal(username).get();

	}

}


text:
body {
  background-color: #fefefe;
  line-height: 20vh;
}

.svg {
  display: inline-block;
  height: 200px;
  width: 200px;
  line-height: 200px;
  text-align: center;
  background-color: #FFF;
  border-radius: 50%;
  vertical-align: middle;
}

#svg {
  display: inline-block;
  vertical-align: middle;
  fill: #0057B8;
}
#svg path:nth-child(1) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.1s;
          animation-delay: 0.1s;
}
#svg path:nth-child(1):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(2) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.2s;
          animation-delay: 0.2s;
}
#svg path:nth-child(2):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(3) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.3s;
          animation-delay: 0.3s;
}
#svg path:nth-child(3):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(4) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.4s;
          animation-delay: 0.4s;
}
#svg path:nth-child(4):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(5) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.5s;
          animation-delay: 0.5s;
}
#svg path:nth-child(5):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(6) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.6s;
          animation-delay: 0.6s;
}
#svg path:nth-child(6):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(7) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.7s;
          animation-delay: 0.7s;
}
#svg path:nth-child(7):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(8) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.8s;
          animation-delay: 0.8s;
}
#svg path:nth-child(8):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(9) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 0.9s;
          animation-delay: 0.9s;
}
#svg path:nth-child(9):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(10) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1s;
          animation-delay: 1s;
}
#svg path:nth-child(10):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(11) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1.1s;
          animation-delay: 1.1s;
}
#svg path:nth-child(11):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(12) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1.2s;
          animation-delay: 1.2s;
}
#svg path:nth-child(12):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(13) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1.3s;
          animation-delay: 1.3s;
}
#svg path:nth-child(13):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(14) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1.4s;
          animation-delay: 1.4s;
}
#svg path:nth-child(14):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(15) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1.5s;
          animation-delay: 1.5s;
}
#svg path:nth-child(15):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(16) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1.6s;
          animation-delay: 1.6s;
}
#svg path:nth-child(16):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(17) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1.7s;
          animation-delay: 1.7s;
}
#svg path:nth-child(17):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}
#svg path:nth-child(18) {
  -webkit-animation: pweek 1.8s linear infinite;
          animation: pweek 1.8s linear infinite;
  -webkit-animation-delay: 1.8s;
          animation-delay: 1.8s;
}
#svg path:nth-child(18):hover {
  -webkit-animation-play-state: paused;
          animation-play-state: paused;
}

@-webkit-keyframes pweek {
  0% {
    fill: #0057B8;
  }
  20% {
    fill: #F11E4A;
  }
  40% {
    fill: #F8A527;
  }
  60% {
    fill: #266D7F;
  }
  80% {
    fill: #82A;
  }
  100% {
    fill: #0057B8;
  }
}

@keyframes pweek {
  0% {
    fill: #0057B8;
  }
  20% {
    fill: #F11E4A;
  }
  40% {
    fill: #F8A527;
  }
  60% {
    fill: #266D7F;
  }
  80% {
    fill: #82A;
  }
  100% {
    fill: #0057B8;
  }
}


text:
TRANSACTION

<a href="<?=base_url('stock_opname')?>">STOCK OPNAME

STOCK OPNAME ADD

    <form method="post" ng-app="myApp" ng-controller="myCtrl">

				STOCK OPNAME ADD

					Waarehouse

						<select class="form-control warehouseplace" ng-model="warehouseplace" name="warehouseplace" ng-change="changewarehouse()" onchange="excecuteSearch()">
							<option value="">Choose Warehouse Location</option>
							<option ng-repeat="da in data" value="{{da.warehouse_name}}~{{da.warehouse_id}}">{{da.warehouse_location}}</option>
						</select>

					Warehouse
					{{warehousename}}

					Date
					<?=date("d/m/Y")?>

			<input type="radio"  name="tab" value="asset" checked="checked"/>Asset  <input type="radio" value="inventory" name="tab"/>Inventory

						SEARCH BY :

							<select name="forecast_param" class="form-control filter1">
								<option value="asset_code">ASSET CODE</option>
								<option value="asset_name">ASSET NAME</option>
								<option value="asset_serial_number">ASSET SERIAL NUMBER</option>
								<option value="asset_serial_number">ASSET SERIAL NUMBER</option>
							</select>
							<input type="text" class="form-control value1" name="value" placeholder="value">
							<button type="button" class="btn btn-default" onclick="excecuteSearch()"></button>

								Asset Code
								Asset Name
								Serial Number
								Certificate

						SEARCH BY :

							<select name="forecast_param" class="form-control filter2">
								<option value="inventory_code">INVENTORY CODE</option>
								<option value="inventory_name">INVENTORY NAME</option>
								<option value="inventory_part_number">INVENTORY SERIAL NUMBER</option>
							</select>
							<input type="text" class="form-control value2" name="value" placeholder="value">
							<button type="button" class="btn btn-default" onclick="excecuteSearch()"></button>

								Inventory Code
								Inventory Name
								Part Number

								Asset Code
								Asset Name
								Serial Number
								Department

								Inventory Code
								Inventory Name
								Part Number
								Department

				<button type="submit" class="btn btn-success" onclick="do_insert(0)">Save As Draft</button>
				<button type="button" class="btn btn-primary" onclick="do_insert(1)">Submit</button>
				<button type="submit" class="btn btn-warning" id="opname_cancel">Cancel</button>

    </form>

TOP


text:
using System;
using System.Collections.Generic;
using System.Linq;
using Coevery.Environment.Descriptor;
using Coevery.Environment.Descriptor.Models;
using Coevery.Environment.Extensions;
using Coevery.Environment.Extensions.Models;
using Coevery.Localization;
using Coevery.Logging;

namespace Coevery.Environment.Features {
    public class FeatureManager : IFeatureManager {
        private readonly IExtensionManager _extensionManager;
        private readonly IShellDescriptorManager _shellDescriptorManager;

        /// <summary>
        /// Delegate to notify about feature dependencies.
        /// </summary>
        public FeatureDependencyNotificationHandler FeatureDependencyNotification { get; set; }

        public FeatureManager(
            IExtensionManager extensionManager,
            IShellDescriptorManager shellDescriptorManager) {
            _extensionManager = extensionManager;
            _shellDescriptorManager = shellDescriptorManager;

            T = NullLocalizer.Instance;
            Logger = NullLogger.Instance;
        }

        public Localizer T { get; set; }
        public ILogger Logger { get; set; }

        /// <summary>
        /// Retrieves the available features.
        /// </summary>
        /// <returns>An enumeration of feature descriptors for the available features.</returns>
        public IEnumerable<FeatureDescriptor> GetAvailableFeatures() {
            return _extensionManager.AvailableFeatures();
        }

        /// <summary>
        /// Retrieves the enabled features.
        /// </summary>
        /// <returns>An enumeration of feature descriptors for the enabled features.</returns>
        public IEnumerable<FeatureDescriptor> GetEnabledFeatures() {
            var currentShellDescriptor = _shellDescriptorManager.GetShellDescriptor();
            return _extensionManager.EnabledFeatures(currentShellDescriptor);
        }

        /// <summary>
        /// Enables a list of features.
        /// </summary>
        /// <param name="featureIds">The IDs for the features to be enabled.</param>
        public IEnumerable<string> EnableFeatures(IEnumerable<string> featureIds) {
            return EnableFeatures(featureIds, false);
        }

        /// <summary>
        /// Enables a list of features.
        /// </summary>
        /// <param name="featureIds">The IDs for the features to be enabled.</param>
        /// <param name="force">Boolean parameter indicating if the feature should enable it's dependencies if required or fail otherwise.</param>
        public IEnumerable<string> EnableFeatures(IEnumerable<string> featureIds, bool force) {
            ShellDescriptor shellDescriptor = _shellDescriptorManager.GetShellDescriptor();
            List<ShellFeature> enabledFeatures = shellDescriptor.Features.ToList();

            IDictionary<FeatureDescriptor, bool> availableFeatures = GetAvailableFeatures()
                .ToDictionary(featureDescriptor => featureDescriptor,
                                featureDescriptor => enabledFeatures.FirstOrDefault(shellFeature => shellFeature.Name == featureDescriptor.Id) != null);

            IEnumerable<string> featuresToEnable = featureIds
                .Select(featureId => EnableFeature(featureId, availableFeatures, force)).ToList()
                .SelectMany(ies => ies.Select(s => s));

            if (featuresToEnable.Count() > 0) {
                foreach (string featureId in featuresToEnable) {
                    string id = featureId;

                    enabledFeatures.Add(new ShellFeature { Name = id });
                    Logger.Information("{0} was enabled", featureId);
                }

                _shellDescriptorManager.UpdateShellDescriptor(shellDescriptor.SerialNumber, enabledFeatures,
                                                              shellDescriptor.Parameters);
            }

            return featuresToEnable;
        }

        /// <summary>
        /// Disables a list of features.
        /// </summary>
        /// <param name="featureIds">The IDs for the features to be disabled.</param>
        /// <returns>An enumeration with the disabled feature IDs.</returns>
        public IEnumerable<string> DisableFeatures(IEnumerable<string> featureIds) {
            return DisableFeatures(featureIds, false);
        }

        /// <summary>
        /// Disables a list of features.
        /// </summary>
        /// <param name="featureIds">The IDs for the features to be disabled.</param>
        /// <param name="force">Boolean parameter indicating if the feature should disable the features which depend on it if required or fail otherwise.</param>
        /// <returns>An enumeration with the disabled feature IDs.</returns>
        public IEnumerable<string> DisableFeatures(IEnumerable<string> featureIds, bool force) {
            ShellDescriptor shellDescriptor = _shellDescriptorManager.GetShellDescriptor();
            List<ShellFeature> enabledFeatures = shellDescriptor.Features.ToList();

            IEnumerable<string> featuresToDisable = featureIds
                .Select(featureId => DisableFeature(featureId, force)).ToList()
                .SelectMany(ies => ies.Select(s => s));

            if (featuresToDisable.Any()) {
                foreach (string featureId in featuresToDisable) {
                    string id = featureId;

                    enabledFeatures.RemoveAll(shellFeature => shellFeature.Name == id);
                    Logger.Information("{0} was disabled", featureId);
                }

                _shellDescriptorManager.UpdateShellDescriptor(shellDescriptor.SerialNumber, enabledFeatures,
                                                              shellDescriptor.Parameters);
            }

            return featuresToDisable;
        }

        /// <summary>
        /// Lists all enabled features that depend on a given feature.
        /// </summary>
        /// <param name="featureId">ID of the feature to check.</param>
        /// <returns>An enumeration with dependent feature IDs.</returns>
        public IEnumerable<string> GetDependentFeatures(string featureId) {
            var getEnabledDependants =
                new Func<string, IDictionary<FeatureDescriptor, bool>, IDictionary<FeatureDescriptor, bool>>(
                    (currentFeatureId, fs) => fs
                        .Where(f => f.Value && f.Key.Dependencies != null && f.Key.Dependencies
                            .Select(s => s.ToLowerInvariant())
                            .Contains(currentFeatureId.ToLowerInvariant()))
                        .ToDictionary(f => f.Key, f => f.Value));

            ShellDescriptor shellDescriptor = _shellDescriptorManager.GetShellDescriptor();
            List<ShellFeature> enabledFeatures = shellDescriptor.Features.ToList();

            IDictionary<FeatureDescriptor, bool> availableFeatures = GetAvailableFeatures()
                .ToDictionary(featureDescriptor => featureDescriptor,
                              featureDescriptor => enabledFeatures.FirstOrDefault(shellFeature => shellFeature.Name.Equals(featureDescriptor.Id)) != null);

            return GetAffectedFeatures(featureId, availableFeatures, getEnabledDependants);
        }

        /// <summary>
        /// Enables a feature.
        /// </summary>
        /// <param name="featureId">The ID of the feature to be enabled.</param>
        /// <param name="availableFeatures">A dictionary of the available feature descriptors and their current state (enabled / disabled).</param>
        /// <param name="force">Boolean parameter indicating if the feature should enable it's dependencies if required or fail otherwise.</param>
        /// <returns>An enumeration of the enabled features.</returns>
        private IEnumerable<string> EnableFeature(string featureId, IDictionary<FeatureDescriptor, bool> availableFeatures, bool force) {
	        var getDisabledDependencies =
		        new Func<string, IDictionary<FeatureDescriptor, bool>, IDictionary<FeatureDescriptor, bool>>(
			        (currentFeatureId, featuresState) => {
				        KeyValuePair<FeatureDescriptor, bool> feature = featuresState.Single(featureState => featureState.Key.Id.Equals(currentFeatureId, StringComparison.OrdinalIgnoreCase));

				        // Retrieve disabled dependencies for the current feature
				        return feature.Key.Dependencies
				                      .Select(fId => {
					                      var states = featuresState.Where(featureState => featureState.Key.Id.Equals(fId, StringComparison.OrdinalIgnoreCase)).ToList();

					                      if (states.Count == 0) {
											  throw new CoeveryException(T("Failed to get state for feature {0}", fId));
					                      }

					                      if (states.Count > 1) {
											  throw new CoeveryException(T("Found {0} states for feature {1}", states.Count, fId));
					                      }

					                      return states[0];
				                      })
				                      .Where(featureState => !featureState.Value)
				                      .ToDictionary(f => f.Key, f => f.Value);
			        });

            IEnumerable<string> featuresToEnable = GetAffectedFeatures(featureId, availableFeatures, getDisabledDependencies);
            if (featuresToEnable.Count() > 1 && !force) {
                Logger.Warning("Additional features need to be enabled.");
                if (FeatureDependencyNotification != null) {
                    FeatureDependencyNotification("If {0} is enabled, then you'll also need to enable {1}.", featureId, featuresToEnable.Where(fId => fId != featureId));
                }

                return Enumerable.Empty<string>();
            }

            return featuresToEnable;
        }

        /// <summary>
        /// Disables a feature.
        /// </summary>
        /// <param name="featureId">The ID of the feature to be enabled.</param>
        /// <param name="force">Boolean parameter indicating if the feature should enable it's dependencies if required or fail otherwise.</param>
        /// <returns>An enumeration of the disabled features.</returns>
        private IEnumerable<string> DisableFeature(string featureId, bool force) {
            IEnumerable<string> featuresToDisable = GetDependentFeatures(featureId);

            if (featuresToDisable.Count() > 1 && !force) {
                Logger.Warning("Additional features need to be disabled.");
                if (FeatureDependencyNotification != null) {
                    FeatureDependencyNotification("If {0} is disabled, then you'll also need to disable {1}.", featureId, featuresToDisable.Where(fId => fId != featureId));
                }

                return Enumerable.Empty<string>();
            }

            return featuresToDisable;
        }

        private static IEnumerable<string> GetAffectedFeatures(
            string featureId, IDictionary<FeatureDescriptor, bool> features,
            Func<string, IDictionary<FeatureDescriptor, bool>, IDictionary<FeatureDescriptor, bool>> getAffectedDependencies) {

            var dependencies = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { featureId };
            var stack = new Stack<IDictionary<FeatureDescriptor, bool>>();

            stack.Push(getAffectedDependencies(featureId, features));

            while (stack.Any()) {
                var next = stack.Pop();
                foreach (var dependency in next.Where(dependency => !dependencies.Contains(dependency.Key.Id))) {
                    dependencies.Add(dependency.Key.Id);
                    stack.Push(getAffectedDependencies(dependency.Key.Id, features));
                }
            }

            return dependencies;
        }
    }
}


text:
<?php

// direct access protection
if(!defined('KIRBY')) die('Direct access is not allowed');

// default param separator
if(!c::get('uri.param.separator')) {
  // check for linux or windows
  c::set('uri.param.separator', (DIRECTORY_SEPARATOR == '/') ? ':' : ';');
}

class uri {

  function __construct($uri=false) {

    // set the defaults
    $this->path      = new uriPath();
    $this->params    = new uriParams();
    $this->query     = new uriQuery(str::parse(server::get('query_string'), 'query'));
    $this->extension = false;
    $this->original  = $_SERVER['REQUEST_URI'];
    $this->raw       = $this->raw($uri);
    $this->url       = url(ltrim($this->raw, '/'));

    // crawl the uri and get all elements
    $this->crawl();

  }

  function __toString() {
    return $this->toString();
  }

  static function raw($uri=false) {
    $raw = ($uri) ? $uri : ltrim($_SERVER['REQUEST_URI'], '/');
    $raw = ltrim(str_replace('index.php', '', $raw), '/');

    // strip subfolders from uri
    if(c::get('subfolder'))    $raw = ltrim(preg_replace('!^' . preg_quote(c::get('subfolder')) . '(\/|)!i', '/', $raw), '/');
    if(c::get('lang.support')) $raw = ltrim(preg_replace('!^' . preg_quote(c::get('lang.current')) . '(\/|)!i', '/', $raw), '/');

    return $raw;
  }

  function crawl() {

    $path = url::strip_query($this->raw);
    $path = (array)str::split($path, '/');
    if(a::first($path) == 'index.php') array_shift($path);

    // parse params
    foreach($path AS $p) {
      if(str::contains($p, c::get('uri.param.separator'))) {
        $parts = explode(c::get('uri.param.separator'), $p);
        if(count($parts) < 2) continue;
        $this->params->$parts[0] = $parts[1];
      } else {
        $this->path->_[] = $p;
      }
    }

    // get the extension from the last part of the path
    $this->extension = f::extension($this->path->last());

    if($this->extension != false) {
      // remove the last part of the path
      $last = array_pop($this->path->_);
      $this->path->_[] = f::name($last);
    }

    return $this->path;

  }

  function path($key=false, $default=false) {
    if(!$key) return $this->path;
    return $this->path->find($key, $default);
  }

  function param($key=false, $default=false) {
    if(!$key) return $this->params;
    return $this->params->find($key, $default);
  }

  function params($key=false, $default=false) {
    return $this->param($key, $default);
  }

  function query($key=false, $default=false) {
    if(!$key) return $this->query;
    return $this->query->find($key, $default);
  }

  function toString($includeQuery=true) {

    $parts  = array();
    $path   = $this->path();
    $params = $this->params();
    $query  = $this->query();

    if(!empty($path->_))   $parts[] = (string)$path;
    if(!empty($params->_)) $parts[] = (string)$params;

    if($includeQuery && !empty($query->_)) $parts[] = '?' . $query;

    return implode('/', $parts);

  }

  function toUrl($includeQuery=true) {
    return url($this->toString($includeQuery));
  }

  function toCacheID() {
    $url = $this->toURL();
    return md5($url);
  }

  function stripPath() {
    $this->path = new uriPath();
    return $this;
  }

  function replaceParam($key, $value) {
    $this->params->{$key} = $value;
    return $this;
  }

  function removeParam($key) {
    unset($this->params->_[$key]);
    return $this;
  }

  function stripParams() {
    $this->params = new uriParams();
    return $this;
  }

  function urlWithoutParam($param) {
    $this->removeParam($param);
    return $this->toUrl();
  }

  function replaceQueryKey($key, $value) {
    $this->query->{$key} = $value;
    return $this;
  }

  function removeQueryKey($key) {
    unset($this->query->_[$key]);
    return $this;
  }

  function urlWithoutQueryKey($key) {
    $this->removeQueryKey($key);
    return $this->toUrl();
  }

  function stripQuery() {
    $this->query = new uriQuery();
    return $this;
  }

}

class uriPath extends obj {

  function __toString() {
    return $this->toString();
  }

  function toString() {
    return implode('/', $this->_);
  }

  function find($key=false, $default=false) {
    if($key===false) return $this->_;
    $key--;
    return a::get($this->_, $key, $default);
  }

}

class uriParams extends obj {

  function __toString() {
    return $this->toString();
  }

  function toString() {
    $output = array();
    foreach($this->_ as $key => $value) {
      $output[] = $key . c::get('uri.param.separator') . $value;
    }
    return implode('/', $output);
  }

}

class uriQuery extends obj {

  function __toString() {
    return $this->toString();
  }

  function toString() {
    return http_build_query($this->_);
  }

}