text:
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.editor.impl.view;

import com.intellij.lang.CodeDocumentationAwareCommenter;
import com.intellij.lang.Commenter;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageCommenters;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.bidi.BidiRegionsSeparator;
import com.intellij.openapi.editor.bidi.LanguageBidiRegionsSeparator;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.editor.impl.FontFallbackIterator;
import com.intellij.openapi.editor.impl.FontInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.StringEscapesTokenTypes;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.BitUtil;
import com.intellij.util.DocumentUtil;
import com.intellij.util.text.CharArrayUtil;
import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.text.Bidi;
import java.util.*;
import java.util.List;
import java.util.stream.Stream;

/**
 * Layout of a single line of document text. Consists of a series of BidiRuns, which, in turn, consist of TextFragments.
 * TextFragments within BidiRun are grouped into Chunks for performance reasons, glyph layout is performed per-Chunk, and only
 * for required Chunks.
 */
abstract class LineLayout {
  private static final Logger LOG = Logger.getInstance(LineLayout.class);

  private LineLayout() {}

  /**
   * Creates a layout for a fragment of text from editor.
   */
  @NotNull
  static LineLayout create(@NotNull EditorView view, int line, boolean skipBidiLayout) {
    List<BidiRun> runs = createFragments(view, line, skipBidiLayout);
    return createLayout(view, runs, null, line);
  }

  /**
   * Creates a layout for an arbitrary piece of text (using a common font style).
   */
  @NotNull
  static LineLayout create(@NotNull EditorView view, @NotNull CharSequence text, @JdkConstants.FontStyle int fontStyle) {
    List<BidiRun> runs = createFragments(view, text, fontStyle);
    LineLayout delegate = createLayout(view, runs, text, 0);
    return new WithSize(delegate);
  }

  private static LineLayout createLayout(@NotNull EditorView view, @NotNull List<BidiRun> runs, @Nullable CharSequence text, int line) {
    if (runs.isEmpty()) return new SingleChunk(null);
    if (runs.size() == 1) {
      BidiRun run = runs.get(0);
      if (run.level == 0 && run.getChunkCount() == 1) {
        Chunk chunk = run.chunks == null ? new Chunk(0, run.endOffset) : run.chunks[0];
        return new SingleChunk(chunk);
      }
    }
    BidiRun[] runArray = new BidiRun[runs.size()];
    int prevColumn = 0;
    for (int i = 0; i < runs.size(); i++) {
      BidiRun run = runs.get(i);
      assert i == 0 || run.startOffset == runs.get(i - 1).endOffset;
      int startColumn = prevColumn;
      int endColumn = text == null
                      ? view.getLogicalPositionCache().offsetToLogicalColumn(line, run.endOffset)
                      : LogicalPositionCache.calcColumn(text, run.startOffset, prevColumn, run.endOffset, view.getTabSize());
      run.visualStartLogicalColumn = run.isRtl() ? endColumn : startColumn;
      prevColumn = endColumn;
      runArray[i] = run;
    }
    return new MultiChunk(runArray);
  }

  // runs are supposed to be in logical order initially
  private static void reorderRunsVisually(BidiRun[] bidiRuns) {
    byte[] levels = new byte[bidiRuns.length];
    for (int i = 0; i < bidiRuns.length; i++) {
      levels[i] = bidiRuns[i].level;
    }
    Bidi.reorderVisually(levels, 0, bidiRuns, 0, levels.length);
  }

  static boolean isBidiLayoutRequired(@NotNull CharSequence text) {
    char[] chars = CharArrayUtil.fromSequence(text);
    return Bidi.requiresBidi(chars, 0, chars.length);
  }

  private static List<BidiRun> createFragments(@NotNull EditorView view, int line, boolean skipBidiLayout) {
    Document document = view.getEditor().getDocument();
    int lineStartOffset = document.getLineStartOffset(line);
    int lineEndOffset = document.getLineEndOffset(line);
    if (lineEndOffset <= lineStartOffset) return Collections.emptyList();
    if (skipBidiLayout) return Collections.singletonList(new BidiRun(lineEndOffset - lineStartOffset));
    CharSequence text = document.getImmutableCharSequence().subSequence(lineStartOffset, lineEndOffset);
    char[] chars = CharArrayUtil.fromSequence(text);
    return createRuns(view, chars, lineStartOffset);
  }

  private static List<BidiRun> createFragments(@NotNull EditorView view, @NotNull CharSequence text,
                                                @JdkConstants.FontStyle int fontStyle) {
    if (text.length() == 0) return Collections.emptyList();

    FontFallbackIterator ffi = new FontFallbackIterator()
      .setPreferredFonts(view.getEditor().getColorsScheme().getFontPreferences())
      .setFontStyle(fontStyle)
      .setFontRenderContext(view.getFontRenderContext());

    char[] chars = CharArrayUtil.fromSequence(text);
    List<BidiRun> runs = createRuns(view, chars, -1);
    for (BidiRun run : runs) {
      for (Chunk chunk : run.getChunks(text, 0)) {
        chunk.fragments = new ArrayList<>();
        addFragments(run, chunk, chars, chunk.startOffset, chunk.endOffset, null, ffi);
      }
    }
    return runs;
  }

  private static List<BidiRun> createRuns(EditorView view, char[] text, int startOffsetInEditor) {
    int textLength = text.length;
    if (view.getEditor().myDisableRtl || !Bidi.requiresBidi(text, 0, textLength)) {
      return Collections.singletonList(new BidiRun(textLength));
    }
    List<BidiRun> runs = new ArrayList<>();
    int flags = view.getBidiFlags();
    if (startOffsetInEditor >= 0) {
      // skipping indent
      int relLastOffset = 0;
      while (relLastOffset < text.length && text[relLastOffset] == ' ' || text[relLastOffset] == '\t') relLastOffset++;
      addRuns(runs, text, 0, relLastOffset, flags);
      // running bidi algorithm separately for text fragments corresponding to different lexer tokens
      IElementType lastToken = null;
      HighlighterIterator iterator = view.getEditor().getHighlighter().createIterator(startOffsetInEditor + relLastOffset);
      while (!iterator.atEnd() && iterator.getStart() - startOffsetInEditor < textLength) {
        int iteratorRelStart = alignToCodePointBoundary(text, iterator.getStart() - startOffsetInEditor);
        int iteratorRelEnd = alignToCodePointBoundary(text, iterator.getEnd() - startOffsetInEditor);
        IElementType currentToken = iterator.getTokenType();
        int relStartOffset = Math.max(relLastOffset, iteratorRelStart);
        String lcPrefix = getLineCommentPrefix(currentToken);
        // for line comments we process prefix and following text separately
        if (!StringUtil.isEmpty(lcPrefix) && lcPrefix.length() <= iteratorRelEnd - iteratorRelStart &&
            CharArrayUtil.regionMatches(text, relStartOffset, relStartOffset + lcPrefix.length(), lcPrefix) &&
            !isInsideSurrogatePair(text, relStartOffset + lcPrefix.length())) {
          addRuns(runs, text, relLastOffset, relStartOffset, flags);
          int textStartOffset = Math.min(textLength, Math.min(iteratorRelEnd,
                                                              CharArrayUtil.shiftForward(text, relStartOffset + lcPrefix.length(), " \t")));
          relLastOffset = Math.min(iteratorRelEnd, textLength);
          lastToken = null;
          addRuns(runs, text, relStartOffset, textStartOffset, flags);
          addRuns(runs, text, textStartOffset, relLastOffset, flags);
        }
        else if (distinctTokens(lastToken, currentToken)) {
          addRuns(runs, text, relLastOffset, relStartOffset, flags);
          lastToken = currentToken;
          relLastOffset = relStartOffset;
        }
        iterator.advance();
      }
      addRuns(runs, text, relLastOffset, textLength, flags);
    }
    else {
      addRuns(runs, text, 0, textLength, flags);
    }
    for (BidiRun run : runs) {
      assert !isInsideSurrogatePair(text, run.startOffset);
      assert !isInsideSurrogatePair(text, run.endOffset);
    }
    return runs;
  }

  private static boolean isInsideSurrogatePair(char[] text, int offset) {
    return offset > 0 && offset < text.length && Character.isHighSurrogate(text[offset - 1]) && Character.isLowSurrogate(text[offset]);
  }

  private static int alignToCodePointBoundary(char[] text, int offset) {
    return isInsideSurrogatePair(text, offset) ? offset - 1 : offset;
  }

  private static int alignToCodePointBoundary(CharSequence text, int offset) {
    return offset > 0 && offset < text.length() &&
           Character.isHighSurrogate(text.charAt(offset - 1)) && Character.isLowSurrogate(text.charAt(offset)) ? offset - 1 : offset;
  }

  private static String getLineCommentPrefix(IElementType token) {
    if (token == null) return null;
    Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(token.getLanguage());
    return commenter instanceof CodeDocumentationAwareCommenter &&
           token.equals(((CodeDocumentationAwareCommenter)commenter).getLineCommentTokenType()) ?
           commenter.getLineCommentPrefix() : null;
  }

  private static boolean distinctTokens(@Nullable IElementType token1, @Nullable IElementType token2) {
    if (token1 == token2) return false;
    if (token1 == null || token2 == null) return true;
    if (StringEscapesTokenTypes.STRING_LITERAL_ESCAPES.contains(token1) ||
        StringEscapesTokenTypes.STRING_LITERAL_ESCAPES.contains(token2)) return false;
    if (token1 != TokenType.WHITE_SPACE && token2 != TokenType.WHITE_SPACE && !token1.getLanguage().is(token2.getLanguage())) return true;
    Language language = token1.getLanguage();
    if (language == Language.ANY) language = token2.getLanguage();
    BidiRegionsSeparator separator = LanguageBidiRegionsSeparator.INSTANCE.forLanguage(language);
    return separator.createBorderBetweenTokens(token1, token2);
  }

  private static void addRuns(List<BidiRun> runs, char[] text, int start, int end, int flags) {
    if (start < end && !Bidi.requiresBidi(text, start, end)) {
      addOrMergeRun(runs, new BidiRun((byte)0, start, end));
      return;
    }
    int afterLastTabPosition = start;
    for (int i = start; i < end; i++) {
      if (text[i] == '\t') {
        addRunsNoTabs(runs, text, afterLastTabPosition, i, flags);
        afterLastTabPosition = i + 1;
        addOrMergeRun(runs, new BidiRun((byte)0, i, i + 1));
      }
    }
    addRunsNoTabs(runs, text, afterLastTabPosition, end, flags);
  }

  private static void addRunsNoTabs(List<BidiRun> runs, char[] text, int start, int end, int flags) {
    if (start >= end) return;
    Bidi bidi = new Bidi(text, start, null, 0, end - start, flags);
    int runCount = bidi.getRunCount();
    for (int i = 0; i < runCount; i++) {
      addOrMergeRun(runs, new BidiRun((byte)bidi.getRunLevel(i), start + bidi.getRunStart(i), start + bidi.getRunLimit(i)));
    }
  }

  private static void addOrMergeRun(List<BidiRun> runs, BidiRun run) {
    int size = runs.size();
    if (size > 0 && runs.get(size - 1).level == 0 && run.level == 0) {
      BidiRun lastRun = runs.remove(size - 1);
      assert lastRun.endOffset == run.startOffset;
      runs.add(new BidiRun((byte)0, lastRun.startOffset, run.endOffset));
    }
    else {
      runs.add(run);
    }
  }

  @SuppressWarnings("AssignmentToForLoopParameter")
  private static void addFragments(BidiRun run, Chunk chunk, char[] text, int start, int end, @Nullable TabFragment tabFragment,
                                   FontFallbackIterator it) {
    assert start < end;
    if (tabFragment == null) {
      addFragmentsNoTabs(run, chunk, text, start, end, it);
    }
    else {
      int last = start;
      for (int i = start; i < end; i++) {
        if (text[i] == '\t') {
          assert run.level == 0;
          addFragmentsNoTabs(run, chunk, text, last, i, it);
          chunk.fragments.add(tabFragment);
          last = i + 1;
        }
      }
      addFragmentsNoTabs(run, chunk, text, last, end, it);
    }
    assert !chunk.fragments.isEmpty();
  }

  private static void addFragmentsNoTabs(BidiRun run, Chunk chunk, char[] text, int start, int end, FontFallbackIterator it) {
    if (start < end) {
      it.start(text, start, end);
      while (!it.atEnd()) {
        addTextFragmentIfNeeded(chunk, text, it.getStart(), it.getEnd(), it.getFontInfo(), run.isRtl());
        it.advance();
      }
    }
  }

  private static void addTextFragmentIfNeeded(Chunk chunk, char[] chars, int from, int to, FontInfo fontInfo, boolean isRtl) {
    if (to > from) {
      assert fontInfo != null;
      chunk.fragments.add(TextFragmentFactory.createTextFragment(chars, from, to, isRtl, fontInfo));
    }
  }

  Iterable<VisualFragment> getFragmentsInVisualOrder(final float startX) {
    return () -> new VisualOrderIterator(null, 0, startX, 0, 0, getRunsInVisualOrder());
  }

  /**
   * If {@code quickEvaluationListener} is provided, quick approximate iteration becomes enabled, listener will be invoked
   * if approximation will in fact be used during width calculation.
   */
  Iterator<VisualFragment> getFragmentsInVisualOrder(@NotNull final EditorView view,
                                                     final int line,
                                                     final float startX,
                                                     final int startVisualColumn,
                                                     final int startOffset,
                                                     int endOffset,
                                                     @Nullable Runnable quickEvaluationListener) {
    assert startOffset <= endOffset;
    Document document = view.getEditor().getDocument();
    int lineStartOffset = document.getLineStartOffset(line);
    assert !DocumentUtil.isInsideSurrogatePair(document, lineStartOffset + startOffset);
    assert !DocumentUtil.isInsideSurrogatePair(document, lineStartOffset + endOffset);

    final BidiRun[] runs;
    if (startOffset == endOffset) {
      runs = BidiRun.EMPTY_ARRAY;
    }
    else {
      List<BidiRun> runList = new ArrayList<>();
      for (BidiRun run : getRunsInLogicalOrder()) {
        if (run.endOffset <= startOffset) continue;
        if (run.startOffset >= endOffset) break;
        runList.add(run.subRun(view, line, startOffset, endOffset, quickEvaluationListener));
      }
      runs = runList.toArray(new BidiRun[runList.size()]);
      if (runs.length > 1) {
        reorderRunsVisually(runs);
      }
    }
    return new VisualOrderIterator(view, line, startX, startVisualColumn, startOffset, runs);
  }

  abstract Stream<Chunk> getChunksInLogicalOrder();

  float getWidth() {
    throw new RuntimeException("This LineLayout instance doesn't have precalculated width");
  }

  abstract boolean isLtr();

  abstract boolean isRtlLocation(int offset, boolean leanForward);

  abstract int findNearestDirectionBoundary(int offset, boolean lookForward);

  abstract BidiRun[] getRunsInLogicalOrder();

  abstract BidiRun[] getRunsInVisualOrder();

  private static class SingleChunk extends LineLayout {
    private final Chunk myChunk;

    private SingleChunk(Chunk chunk) {
      myChunk = chunk;
    }

    @Override
    Stream<Chunk> getChunksInLogicalOrder() {
      return myChunk == null ? Stream.empty() : Stream.of(myChunk);
    }

    @Override
    boolean isLtr() {
      return true;
    }

    @Override
    boolean isRtlLocation(int offset, boolean leanForward) {
      return false;
    }

    @Override
    int findNearestDirectionBoundary(int offset, boolean lookForward) {
      return -1;
    }

    @Override
    BidiRun[] getRunsInLogicalOrder() {
      return createRuns();
    }

    @Override
    BidiRun[] getRunsInVisualOrder() {
      return createRuns();
    }

    private BidiRun[] createRuns() {
      if (myChunk == null) return BidiRun.EMPTY_ARRAY;
      BidiRun run = new BidiRun(myChunk.endOffset);
      run.chunks = new Chunk[] {myChunk};
      return new BidiRun[] {run};
    }
  }

  private static class MultiChunk extends LineLayout {
    private final BidiRun[] myBidiRunsInLogicalOrder;
    private final BidiRun[] myBidiRunsInVisualOrder;

    private MultiChunk(BidiRun[] bidiRunsInLogicalOrder) {
      myBidiRunsInLogicalOrder = bidiRunsInLogicalOrder;
      if (bidiRunsInLogicalOrder.length > 1) {
        myBidiRunsInVisualOrder = myBidiRunsInLogicalOrder.clone();
        reorderRunsVisually(myBidiRunsInVisualOrder);
      }
      else {
        myBidiRunsInVisualOrder = bidiRunsInLogicalOrder;
      }
    }

    @Override
    Stream<Chunk> getChunksInLogicalOrder() {
      return Stream.of(myBidiRunsInLogicalOrder).flatMap((BidiRun r) -> r.chunks == null ? Stream.empty() : Stream.of(r.chunks));
    }

    @Override
    boolean isLtr() {
      return myBidiRunsInLogicalOrder.length == 0 || myBidiRunsInLogicalOrder.length == 1 && !myBidiRunsInLogicalOrder[0].isRtl();
    }

    @Override
    boolean isRtlLocation(int offset, boolean leanForward) {
      if (offset == 0 && !leanForward) return false;
      for (BidiRun run : myBidiRunsInLogicalOrder) {
        if (offset < run.endOffset || offset == run.endOffset && !leanForward) return run.isRtl();
      }
      return false;
    }

    @Override
    int findNearestDirectionBoundary(int offset, boolean lookForward) {
      if (lookForward) {
        byte originLevel = -1;
        for (BidiRun run : myBidiRunsInLogicalOrder) {
          if (originLevel >= 0) {
            if (run.level != originLevel) return run.startOffset;
          }
          else if (run.endOffset > offset) {
            originLevel = run.level;
          }
        }
        return originLevel > 0 ? myBidiRunsInLogicalOrder[myBidiRunsInLogicalOrder.length - 1].endOffset : -1;
      }
      else {
        byte originLevel = -1;
        for (int i = myBidiRunsInLogicalOrder.length - 1; i >= 0; i--) {
          BidiRun run = myBidiRunsInLogicalOrder[i];
          if (originLevel >= 0) {
            if (run.level != originLevel) return run.endOffset;
          }
          else if (run.startOffset < offset) {
            originLevel = run.level;

          }
        }
        return originLevel > 0 ? 0 : -1;
      }
    }

    @Override
    BidiRun[] getRunsInLogicalOrder() {
      return myBidiRunsInLogicalOrder;
    }

    @Override
    BidiRun[] getRunsInVisualOrder() {
      return myBidiRunsInVisualOrder;
    }
  }

  private static class WithSize extends LineLayout {
    private final LineLayout myDelegate;
    private final float myWidth;

    private WithSize(@NotNull LineLayout delegate) {
      myDelegate = delegate;
      myWidth = calculateWidth();
    }

    private float calculateWidth() {
      float x = 0;
      for (VisualFragment fragment : getFragmentsInVisualOrder(x)) {
        x = fragment.getEndX();
      }
      return x;
    }

    @Override
    Stream<Chunk> getChunksInLogicalOrder() {
      return myDelegate.getChunksInLogicalOrder();
    }

    @Override
    float getWidth() {
      return myWidth;
    }

    @Override
    boolean isLtr() {
      return myDelegate.isLtr();
    }

    @Override
    boolean isRtlLocation(int offset, boolean leanForward) {
      return myDelegate.isRtlLocation(offset, leanForward);
    }

    @Override
    int findNearestDirectionBoundary(int offset, boolean lookForward) {
      return myDelegate.findNearestDirectionBoundary(offset, lookForward);
    }

    @Override
    BidiRun[] getRunsInLogicalOrder() {
      return myDelegate.getRunsInLogicalOrder();
    }

    @Override
    BidiRun[] getRunsInVisualOrder() {
      return myDelegate.getRunsInVisualOrder();
    }
  }

  private static class BidiRun {
    public static final BidiRun[] EMPTY_ARRAY = new BidiRun[0];
    private static final int CHUNK_CHARACTERS = 1024;

    private final byte level;
    private final int startOffset;
    private final int endOffset;
    private int visualStartLogicalColumn;
    private Chunk[] chunks; // in logical order

    private BidiRun(int length) {
      this((byte)0, 0, length);
    }

    private BidiRun(byte level, int startOffset, int endOffset) {
      this.level = level;
      this.startOffset = startOffset;
      this.endOffset = endOffset;
    }

    private boolean isRtl() {
      return BitUtil.isSet(level, 1);
    }

    private Chunk[] getChunks(CharSequence text, int startOffsetInText) {
      if (chunks == null) {
        int chunkCount = getChunkCount();
        chunks = new Chunk[chunkCount];
        for (int i = 0; i < chunkCount; i++) {
          int from = startOffset + i * CHUNK_CHARACTERS;
          int to = i == chunkCount - 1 ? endOffset : from + CHUNK_CHARACTERS;
          Chunk chunk = new Chunk(alignToCodePointBoundary(text, from + startOffsetInText) - startOffsetInText,
                                  alignToCodePointBoundary(text, to + startOffsetInText) - startOffsetInText);
          chunks[i] = chunk;
        }
      }
      return chunks;
    }

    private int getChunkCount() {
      return (endOffset - startOffset + CHUNK_CHARACTERS - 1) / CHUNK_CHARACTERS;
    }

    private BidiRun subRun(@NotNull EditorView view, int line, int targetStartOffset, int targetEndOffset,
                           @Nullable Runnable quickEvaluationListener) {
      assert targetStartOffset < endOffset;
      assert targetEndOffset > startOffset;
      int start = Math.max(startOffset, targetStartOffset);
      int end = Math.min(endOffset, targetEndOffset);
      BidiRun subRun = new BidiRun(level, start, end);
      List<Chunk> subChunks = new ArrayList<>();
      Document document = view.getEditor().getDocument();
      for (Chunk chunk : getChunks(document.getImmutableCharSequence(), document.getLineStartOffset(line))) {
        if (chunk.endOffset <= start) continue;
        if (chunk.startOffset >= end) break;
        subChunks.add(chunk.subChunk(view, this, line, start, end, quickEvaluationListener));
      }
      subRun.chunks = subChunks.toArray(new Chunk[subChunks.size()]);
      subRun.visualStartLogicalColumn = (subRun.isRtl() ? end == endOffset : start == startOffset) ? visualStartLogicalColumn :
                                        view.getLogicalPositionCache().offsetToLogicalColumn(line, subRun.isRtl() ? end : start);
      return subRun;
    }
  }

  static class Chunk {
    List<LineFragment> fragments; // in logical order
    private final int startOffset;
    private final int endOffset;

    private Chunk(int startOffset, int endOffset) {
      this.startOffset = startOffset;
      this.endOffset = endOffset;
    }

    private void ensureLayout(@NotNull EditorView view, BidiRun run, int line) {
      if (isReal()) {
        view.getTextLayoutCache().onChunkAccess(this);
      }
      if (fragments != null) return;
      assert isReal();
      fragments = new ArrayList<>();
      int lineStartOffset = view.getEditor().getDocument().getLineStartOffset(line);
      int start = lineStartOffset + startOffset;
      int end = lineStartOffset + endOffset;
      if (LOG.isDebugEnabled()) LOG.debug("Text layout for " + view.getEditor().getVirtualFile() + " (" + start + "-" + end + ")");
      IterationState it = new IterationState(view.getEditor(), start, end, null, false, true, false, false);

      FontFallbackIterator ffi = new FontFallbackIterator()
        .setPreferredFonts(view.getEditor().getColorsScheme().getFontPreferences())
        .setFontRenderContext(view.getFontRenderContext());

      char[] chars = CharArrayUtil.fromSequence(view.getEditor().getDocument().getImmutableCharSequence(), start, end);
      int currentFontType = 0;
      Color currentColor = null;
      int currentStart = start;
      while (!it.atEnd()) {
        int fontType = it.getMergedAttributes().getFontType();
        Color color = it.getMergedAttributes().getForegroundColor();
        if (fontType != currentFontType || !color.equals(currentColor)) {
          int tokenStart = it.getStartOffset();
          if (tokenStart > currentStart) {
            addFragments(run, this, chars, currentStart - start, tokenStart - start, view.getTabFragment(), ffi);
          }
          currentStart = tokenStart;
          currentColor = color;
          ffi.setFontStyle(currentFontType = fontType);
        }
        it.advance();
      }
      if (end > currentStart) {
        addFragments(run, this, chars, currentStart - start, end - start, view.getTabFragment(), ffi);
      }
      view.getSizeManager().textLayoutPerformed(start, end);
      assert !fragments.isEmpty();
    }

    private Chunk subChunk(EditorView view, BidiRun run, int line, int targetStartOffset, int targetEndOffset,
                           @Nullable Runnable quickEvaluationListener) {
      assert isReal();
      assert targetStartOffset < endOffset;
      assert targetEndOffset > startOffset;
      int start = Math.max(startOffset, targetStartOffset);
      int end = Math.min(endOffset, targetEndOffset);
      if (quickEvaluationListener != null && fragments == null) {
        quickEvaluationListener.run();
        Chunk chunk = new SyntheticChunk(start, end);
        int startColumn = view.getLogicalPositionCache().offsetToLogicalColumn(line, start);
        int endColumn = view.getLogicalPositionCache().offsetToLogicalColumn(line, end);
        chunk.fragments = Collections.singletonList(new ApproximationFragment(end - start, endColumn - startColumn,
                                                                              view.getMaxCharWidth()));
        return chunk;
      }
      if (start == startOffset && end == endOffset) {
        return this;
      }
      ensureLayout(view, run, line);
      Chunk chunk = new SyntheticChunk(start, end);
      chunk.fragments = new ArrayList<>();
      int offset = startOffset;
      for (LineFragment fragment : fragments) {
        if (end <= offset) break;
        int endOffset = offset + fragment.getLength();
        if (start < endOffset) {
          chunk.fragments.add(fragment.subFragment(Math.max(start, offset) - offset, Math.min(end, endOffset) - offset));
        }
        offset = endOffset;
      }
      return chunk;
    }

    boolean isReal() {
      return true;
    }

    void clearCache() {
      fragments = null;
    }
  }

  private static class SyntheticChunk extends Chunk {
    private SyntheticChunk(int startOffset, int endOffset) {
      super(startOffset, endOffset);
    }

    @Override
    boolean isReal() {
      return false;
    }
  }

  private static class VisualOrderIterator implements Iterator<VisualFragment> {
    private final EditorView myView;
    private final CharSequence myText;
    private final int myLine;
    private final int myLineStartOffset;
    private final BidiRun[] myRuns;
    private int myRunIndex;
    private int myChunkIndex;
    private int myFragmentIndex;
    private int myOffsetInsideRun;
    private final VisualFragment myFragment = new VisualFragment();

    private VisualOrderIterator(EditorView view, int line,
                                float startX, int startVisualColumn, int startOffset, BidiRun[] runsInVisualOrder) {
      myView = view;
      myText = view == null ? null : view.getEditor().getDocument().getImmutableCharSequence();
      myLine = line;
      myLineStartOffset = view == null ? 0 : view.getEditor().getDocument().getLineStartOffset(line);
      myRuns = runsInVisualOrder;
      myFragment.startX = startX;
      myFragment.startVisualColumn = startVisualColumn;
      myFragment.startOffset = startOffset;
    }

    @Override
    public boolean hasNext() {
      if (myRunIndex >= myRuns.length) return false;
      BidiRun run = myRuns[myRunIndex];
      Chunk[] chunks = run.getChunks(myText, myLineStartOffset);
      if (myChunkIndex >= chunks.length) return false;
      Chunk chunk = chunks[run.isRtl() ? chunks.length - 1 - myChunkIndex : myChunkIndex];
      if (myView != null) {
        chunk.ensureLayout(myView, run, myLine);
      }
      return myFragmentIndex < chunk.fragments.size();
    }

    @Override
    public VisualFragment next() {
      if (!hasNext()) {
        throw new NoSuchElementException();
      }
      BidiRun run = myRuns[myRunIndex];

      if (myRunIndex == 0 && myChunkIndex == 0 && myFragmentIndex == 0) {
        myFragment.startLogicalColumn = run.visualStartLogicalColumn;
      }
      else {
        myFragment.startLogicalColumn = myChunkIndex == 0 && myFragmentIndex == 0 ?
                                        run.visualStartLogicalColumn :
                                        myFragment.getEndLogicalColumn();
        myFragment.startVisualColumn = myFragment.getEndVisualColumn();
        myFragment.startX = myFragment.getEndX();
      }

      myFragment.isRtl = run.isRtl();
      Chunk[] chunks = run.getChunks(myText, myLineStartOffset);
      Chunk chunk = chunks[run.isRtl() ? chunks.length - 1 - myChunkIndex : myChunkIndex];
      myFragment.delegate = chunk.fragments.get(run.isRtl() ? chunk.fragments.size() - 1 - myFragmentIndex : myFragmentIndex);
      myFragment.startOffset = run.isRtl() ? run.endOffset - myOffsetInsideRun : run.startOffset + myOffsetInsideRun;

      myOffsetInsideRun += myFragment.getLength();
      myFragmentIndex++;
      if (myFragmentIndex >= chunk.fragments.size()) {
        myFragmentIndex = 0;
        myChunkIndex++;
          if (myChunkIndex >= chunks.length) {
            myChunkIndex = 0;
            myOffsetInsideRun = 0;
            myRunIndex++;
          }
      }

      return myFragment;
    }

    @Override
    public void remove() {
      throw new UnsupportedOperationException();
    }
  }

  static class VisualFragment {
    private LineFragment delegate;
    private int startOffset;
    private int startLogicalColumn;
    private int startVisualColumn;
    private float startX;
    private boolean isRtl;

    boolean isRtl() {
      return isRtl;
    }

    int getMinOffset() {
      return isRtl ? startOffset - getLength() : startOffset;
    }

    int getMaxOffset() {
      return isRtl ? startOffset : startOffset + getLength();
    }

    int getStartOffset() {
      return startOffset;
    }

    int getEndOffset() {
      return isRtl ? startOffset - getLength() : startOffset + getLength();
    }

    int getLength() {
      return delegate.getLength();
    }

    int getStartLogicalColumn() {
      return startLogicalColumn;
    }

    int getEndLogicalColumn() {
      return isRtl ? startLogicalColumn - getLogicalColumnCount() : startLogicalColumn + getLogicalColumnCount();
    }

    int getMinLogicalColumn() {
      return isRtl ? startLogicalColumn - getLogicalColumnCount() : startLogicalColumn;
    }

    int getMaxLogicalColumn() {
      return isRtl ? startLogicalColumn : startLogicalColumn + getLogicalColumnCount();
    }

    int getStartVisualColumn() {
      return startVisualColumn;
    }

    int getEndVisualColumn() {
      return startVisualColumn + getVisualColumnCount();
    }

    int getLogicalColumnCount() {
      // there's no need to calculate start column for RTL case - it makes sense only for TabFragment, which cannot be part of RTL  run
      return delegate.getLogicalColumnCount(isRtl ? 0 : getMinLogicalColumn());
    }

    int getVisualColumnCount() {
      return delegate.getVisualColumnCount(startX);
    }

    float getStartX() {
      return startX;
    }

    float getEndX() {
      return delegate.offsetToX(startX, 0, getLength());
    }

    float getWidth() {
      return getEndX() - getStartX();
    }

    // column is expected to be between minLogicalColumn and maxLogicalColumn for this fragment
    int logicalToVisualColumn(int column) {
      return startVisualColumn + delegate.logicalToVisualColumn(startX, getMinLogicalColumn(),
                                                                isRtl ? startLogicalColumn - column : column - startLogicalColumn);
    }

    // column is expected to be between startVisualColumn and endVisualColumn for this fragment
    int visualToLogicalColumn(int column) {
      int relativeLogicalColumn = delegate.visualToLogicalColumn(startX, getMinLogicalColumn(), column - startVisualColumn);
      return isRtl ? startLogicalColumn - relativeLogicalColumn : startLogicalColumn + relativeLogicalColumn;
    }

    // returned offset is visual and relative (counted from fragment's start)
    int visualColumnToOffset(int relativeVisualColumn) {
      return delegate.visualColumnToOffset(startX, relativeVisualColumn);
    }

    // offset is expected to be between minOffset and maxOffset for this fragment
    float offsetToX(int offset) {
      return delegate.offsetToX(startX, 0, getRelativeOffset(offset));
    }

    // both startOffset and offset are expected to be between minOffset and maxOffset for this fragment
    float offsetToX(float startX, int startOffset, int offset) {
      return delegate.offsetToX(startX, getRelativeOffset(startOffset), getRelativeOffset(offset));
    }

    // x is expected to be between startX and endX for this fragment
    // returns array of two elements
    // - first one is visual column,
    // - second one is 1 if target location is closer to larger columns and 0 otherwise
    int[] xToVisualColumn(float x) {
      int[] column = delegate.xToVisualColumn(startX, x);
      column[0] += startVisualColumn;
      return column;
    }

    // column is expected to be between startVisualColumn and endVisualColumn for this fragment
    float visualColumnToX(int column) {
      return delegate.visualColumnToX(startX, column - startVisualColumn);
    }

    void draw(Graphics2D g, float x, float y) {
      delegate.draw(g, x, y, 0, getLength());
    }

    // offsets are visual (relative to fragment's start)
    void draw(Graphics2D g, float x, float y, int startRelativeOffset, int endRelativeOffset) {
      delegate.draw(g, x, y, startRelativeOffset, endRelativeOffset);
    }

    private int getRelativeOffset(int offset) {
      return isRtl ? startOffset - offset : offset - startOffset;
    }
  }
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <!-- Local Wildfly10 and local MySQL-Datasource MysqlXADS -->
    <persistence-unit name="iWorld" transaction-type="JTA">
        <jta-data-source>java:/MysqlXADS</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <!-- Auswahl des DB-Dialektes -->
            <property name="eclipselink.target-database" value="Auto" />
            <property name="eclipselink.jdbc.native-sql" value="true" />

            <!-- Schemagenerierung -->
            <!--
                  <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
                  <property name="javax.persistence.schema-generation.drop-script-source" value="META-INF/drop.sql" />
                  <property name="javax.persistence.schema-generation.drop-source" value="script-then-metadata" />
                  <property name="javax.persistence.schema-generation.create-script-source" value="META-INF/create.sql" />
                  <property name="javax.persistence.schema-generation.create-source" value="metadata-then-script" />
                  <property name="javax.persistence.sql-load-script-source" value="META-INF/sqlLoad.sql" />
             -->
            <!--property name="eclipselink.ddl-generation" value="create-or-extend-tables" /-->
            <property name="eclipselink.ddl-generation.output-mode" value="database" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />

            <!-- Logging level -->
            <!-- EclipseLink: FINE logs SQL commands -->
            <property name="eclipselink.logging.level" value="FINE" />
            <property name="eclipselink.logging.connection" value="false" />
            <property name="eclipselink.logging.parameters" value="true" />
            <property name="eclipselink.logging.session" value="false" />
            <property name="eclipselink.logging.thread" value="false" />
            <property name="eclipselink.logging.timestamp" value="true" />

            <property name="openjpa.Log" value="log4j" />
            <property name="openjpa.ConnectionFactoryProperties" value="PrintParameters=true, PrettyPrint=true, PrettyPrintLineLength=72" />

            <!-- Hibernate: Use new id generator -->
            <property name="hibernate.id.new_generator_mappings" value="true" />

            <!-- Hibernate: For SQL logging set the log categories org.hibernate.SQL und org.hibernate.type.descriptor.sql.BasicBinder to TRACE -->
            <property name="org.hibernate.SQL" value="TRACE" />
            <property name="org.hibernate.type.descriptor.sql.BasicBinder" value="TRACE" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.use_sql_comments" value="true" />

        </properties>
    </persistence-unit>
</persistence>

redpajama_set_name: RedPajamaGithub


text:
from django.conf.urls import url, patterns
from rest_framework import routers
from rest_framework.response import Response
from rest_framework.reverse import reverse
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework.views import APIView

from onadata.apps.api.viewsets.data_viewset import DataViewSet
from onadata.apps.api.viewsets.organization_profile_viewset import\
    OrganizationProfileViewSet
from onadata.apps.api.viewsets.note_viewset import NoteViewSet
from onadata.apps.api.viewsets.project_viewset import ProjectViewSet
from onadata.apps.api.viewsets.stats_viewset import StatsViewSet
from onadata.apps.api.viewsets.team_viewset import TeamViewSet
from onadata.apps.api.viewsets.xform_viewset import XFormViewSet
from onadata.apps.api.viewsets.user_profile_viewset import UserProfileViewSet
from onadata.apps.api.viewsets.user_viewset import UserViewSet
from onadata.apps.api.viewsets.submissionstats_viewset import\
    SubmissionStatsViewSet
from onadata.apps.api.views import chart_views

class MultiLookupRouter(routers.DefaultRouter):
    def __init__(self, *args, **kwargs):
        super(MultiLookupRouter, self).__init__(*args, **kwargs)
        self.lookups_routes = []
        self.lookups_routes.append(routers.Route(
            url=r'^{prefix}/{lookups}{trailing_slash}$',
            mapping={
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            },
            name='{basename}-detail',
            initkwargs={'suffix': 'Instance'}
        )
        )
        self.lookups_routes.append(routers.Route(
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'list',
                'post': 'create'
            },
            name='{basename}-list',
            initkwargs={'suffix': 'List'}
        ))
        self.lookups_routes.append(routers.Route(
            url=r'^{prefix}/{lookups}{trailing_slash}$',
            mapping={
                'get': 'list',
                'post': 'create'
            },
            name='{basename}-list',
            initkwargs={'suffix': 'List'}
        ))
        # Dynamically generated routes.
        # Generated using @action or @link decorators on methods of the viewset
        self.lookups_routes.append(routers.Route(
            url=[
                r'^{prefix}/{lookups}/{methodname}{trailing_slash}$',
                r'^{prefix}/{lookups}/{methodname}/{extra}{trailing_slash}$'],
            mapping={
                '{httpmethod}': '{methodname}',
            },
            name='{basename}-{methodnamehyphen}',
            initkwargs={}
        ))

    def get_extra_lookup_regexes(self, route):
        ret = []
        base_regex = '(?P<{lookup_field}>[^/]+)'
        if 'extra_lookup_fields' in route.initkwargs:
            for lookup_field in route.initkwargs['extra_lookup_fields']:
                ret.append(base_regex.format(lookup_field=lookup_field))
        return '/'.join(ret)

    def get_lookup_regexes(self, viewset):
        ret = []
        lookup_fields = getattr(viewset, 'lookup_fields', None)
        if lookup_fields:
            for i in range(1, len(lookup_fields)):
                tmp = []
                for lookup_field in lookup_fields[:i + 1]:
                    if lookup_field == lookup_fields[i]:
                        base_regex = '(?P<{lookup_field}>[^/.]+)'
                    else:
                        base_regex = '(?P<{lookup_field}>[^/]+)'
                    tmp.append(base_regex.format(lookup_field=lookup_field))
                ret.append(tmp)
        return ret

    def get_lookup_routes(self, viewset):
        ret = [self.routes[0]]
        # Determine any `@action` or `@link` decorated methods on the viewset
        dynamic_routes = []
        for methodname in dir(viewset):
            attr = getattr(viewset, methodname)
            httpmethods = getattr(attr, 'bind_to_methods', None)
            if httpmethods:
                httpmethods = [method.lower() for method in httpmethods]
                dynamic_routes.append((httpmethods, methodname))

        for route in self.lookups_routes:
            if route.mapping == {'{httpmethod}': '{methodname}'}:
                # Dynamic routes (@link or @action decorator)
                for httpmethods, methodname in dynamic_routes:
                    initkwargs = route.initkwargs.copy()
                    initkwargs.update(getattr(viewset, methodname).kwargs)
                    mapping = dict(
                        (httpmethod, methodname) for httpmethod in httpmethods)
                    name = routers.replace_methodname(route.name, methodname)
                    if 'extra_lookup_fields' in initkwargs:
                        uri = route.url[1]
                        uri = routers.replace_methodname(uri, methodname)
                        ret.append(routers.Route(
                            url=uri, mapping=mapping, name='%s-extra' % name,
                            initkwargs=initkwargs,
                        ))
                    uri = routers.replace_methodname(route.url[0], methodname)
                    ret.append(routers.Route(
                        url=uri, mapping=mapping, name=name,
                        initkwargs=initkwargs,
                    ))
            else:
                # Standard route
                ret.append(route)
        return ret

    def get_routes(self, viewset):
        ret = []
        lookup_fields = getattr(viewset, 'lookup_fields', None)
        if lookup_fields:
            ret = self.get_lookup_routes(viewset)
        else:
            ret = super(MultiLookupRouter, self).get_routes(viewset)
        return ret

    def get_api_root_view(self):
        """
        Return a view to use as the API root.
        """
        api_root_dict = {}
        list_name = self.routes[0].name
        for prefix, viewset, basename in self.registry:
            api_root_dict[prefix] = list_name.format(basename=basename)

        class OnaDataApi(APIView):
            """
## JSON Rest API

OnaData provides the following JSON api endpoints:

* [/api/v1/users](/api/v1/users) - List, Retrieve username, first
and last name
* [/api/v1/profiles](/api/v1/profiles) - List, Create,
Update, user information
* [/api/v1/orgs](/api/v1/orgs) - List, Retrieve, Create,
Update organization and organization info
* [/api/v1/projects](/api/v1/projects) - List, Retrieve, Create,
 Update organization projects, forms
* [/api/v1/teams](/api/v1/teams) - List, Retrieve, Create,
Update teams
* [/api/v1/forms](/api/v1/forms) - List, Retrieve
xlsforms information
* [/api/v1/data](/api/v1/data) - List, Retrieve submission data

## Status Codes

* **200** - Successful [`GET`, `PATCH`, `PUT`]
* **201** - Resource successfully created [`POST`]
* **204** - Resouce successfully deleted [`DELETE`]
* **403** - Permission denied to resource
* **404** - Resource was not found

## Authentication

OnaData JSON API enpoints support both Basic authentication
and API Token Authentication through the `Authorization` header.

### Basic Authentication

Example using curl:

    curl -X GET https://formhub.org/api/v1 -u username:password

### Token Authentication

Example using curl:

    curl -X GET https://formhub.org/api/v1 -H "Authorization: Token TOKEN_KEY"

### OnaData Tagging API

* [Filter form list by
* tags.](/api/v1/forms#get-list-of-forms-with-specific-tags)
* [List Tags for a specific form.](
   /api/v1/forms#get-list-of-tags-for-a-specific-form)
* [Tag Forms.](/api/v1/forms#tag-forms)
* [Delete a specific tag.](/api/v1/forms#delete-a-specific-tag)
* [List form data by tag.](
   /api/v1/data#query-submitted-data-of-a-specific-form-using-tags)
* [Tag a specific submission](/api/v1/data#tag-a-submission-data-point)

## Using Oauth2 with formhub API

You can learn more about oauth2 from [http://tools.ietf.org/html/rfc6749](
http://tools.ietf.org/html/rfc6749).

### 1. Register your client application with formhub - [register](
/o/applications/register/)

- `name` - name of your application
- `client_type` - Client Type: select confidential
- `authorization_grant_type` - Authorization grant type: Authorization code
- `redirect_uri` - Redirect urls: redirection endpoint

Keep note of the `client_id` and the `client_secret`, it is required when
 requesting for an `access_token`.

### 2. Authorize client application.

The authorization url is of the form:

   `GET`  /o/authorize?client_id=XXXXXX&response_type=code&state=abc

example:

    http://localhost:8000/o/authorize?client_id=e8&response_type=code&state=xyz

Note: Providing the url to any user will prompt for a password and
request for read and write permission for the application whose `client_id` is
specified.

Where:

- `client_id` - is the client application id - ensure its urlencoded
- `response_type` - should be code
- `state` - a random state string that you client application will get when
   redirection happens

What happens:

1. a login page is presented, the username used to login determines the account
   that provides access.
2. redirection to the client application occurs, the url is of the form:

    REDIRECT_URI/?state=abc&code=YYYYYYYYY

example redirect uri

    http://localhost:30000/?state=xyz&code=SWWk2PN6NdCwfpqiDiPRcLmvkw2uWd

- `code` - is the code to use to request for `access_token`
- `state` - same state string used during authorization request

Your client application should use the `code` to request for an access_token.

### 3. Request for access token.

Request:

    `POST` /o/token

Payload:

    grant_type=authorization_code&code=YYYYYYYYY&client_id=XXXXXX&
    redirect_uri=http://redirect/uri/path

curl example:

    curl -X POST -d "grant_type=authorization_code&
    code=PSwrMilnJESZVFfFsyEmEukNv0sGZ8&
    client_id=e8x4zzJJIyOikDqjPcsCJrmnU22QbpfHQo4HhRnv&
    redirect_uri=http://localhost:30000" "http://localhost:8000/o/token/"
    --user "e8:xo7i4LNpMj"

Response:

    {
        "access_token": "Q6dJBs9Vkf7a2lVI7NKLT8F7c6DfLD",
        "token_type": "Bearer", "expires_in": 36000,
        "refresh_token": "53yF3uz79K1fif2TPtNBUFJSFhgnpE",
        "scope": "read write groups"
    }

Where:

- `access_token` - access token - expires
- `refresh_token` - token to use to request a new `access_token` in case it has
   expored.

Now that you have an `access_token` you can make API calls.

### 4. Accessing the OnaData API using the `access_token`.

Example using curl:

    curl -X GET https://formhub.org/api/v1
    -H "Authorization: Bearer ACCESS_TOKEN"
"""
            _ignore_model_permissions = True

            def get(self, request, format=None):
                ret = {}
                for key, url_name in api_root_dict.items():
                    ret[key] = reverse(
                        url_name, request=request, format=format)
                return Response(ret)

        return OnaDataApi.as_view()

    def get_urls(self):
        ret = []

        if self.include_root_view:
            root_url = url(r'^$', self.get_api_root_view(),
                           name=self.root_view_name)
            ret.append(root_url)
        for prefix, viewset, basename in self.registry:
            lookup = self.get_lookup_regex(viewset)
            lookup_list = self.get_lookup_regexes(viewset)
            if lookup_list:
                # lookup = lookups[0]
                lookup_list = [u'/'.join(k) for k in lookup_list]
            else:
                lookup_list = [u'']
            routes = self.get_routes(viewset)
            for route in routes:
                mapping = self.get_method_map(viewset, route.mapping)
                if not mapping:
                    continue
                for lookups in lookup_list:
                    regex = route.url.format(
                        prefix=prefix,
                        lookup=lookup,
                        lookups=lookups,
                        trailing_slash=self.trailing_slash,
                        extra=self.get_extra_lookup_regexes(route)
                    )
                    view = viewset.as_view(mapping, **route.initkwargs)
                    name = route.name.format(basename=basename)
                    ret.append(url(regex, view, name=name))
        if self.include_format_suffixes:
            ret = format_suffix_patterns(ret)
        return ret

router = MultiLookupRouter(trailing_slash=False)
router.register(r'users', UserViewSet)
router.register(r'profiles', UserProfileViewSet)
router.register(r'orgs', OrganizationProfileViewSet)
router.register(r'forms', XFormViewSet)
router.register(r'projects', ProjectViewSet)
router.register(r'teams', TeamViewSet)
router.register(r'notes', NoteViewSet)
router.register(r'data', DataViewSet, base_name='data')
router.register(r'stats', StatsViewSet, base_name='stats')
router.register(r'stats/submissions', SubmissionStatsViewSet,
                base_name='submissionstats')
urlpatterns = router.urls
urlpatterns += patterns('', url(
    r'^charts/(?P<formid>[^/]+)/(?P<field_name>[^/]+)$',
    chart_views.ChartDetail.as_view()))


text:
import uuid, json

from flask import Blueprint, request, url_for, flash, redirect, make_response
from flask import render_template, abort
from flask.ext.login import login_user, logout_user, current_user
from flask.ext.wtf import TextField, TextAreaField, SelectField, HiddenField
from flask.ext.wtf import Form, PasswordField, validators, ValidationError

from portality.core import app
import portality.models as models
import portality.util as util

blueprint = Blueprint('account', __name__)

if len(app.config.get('SUPER_USER',[])) > 0:
    firstsu = app.config['SUPER_USER'][0]
    if models.Account.pull(firstsu) is None:
        su = models.Account(id=firstsu)
        su.set_password(firstsu)
        su.save()
        print 'superuser account named - ' + firstsu + ' created.'
        print 'default password matches username. Change it.'

@blueprint.route('/')
def index():
    if current_user.is_anonymous():
        abort(401)
    users = models.Account.query() #{"sort":{'id':{'order':'asc'}}},size=1000000
    if users['hits']['total'] != 0:
        accs = [models.Account.pull(i['_source']['id']) for i in users['hits']['hits']]
        # explicitly mapped to ensure no leakage of sensitive data. augment as necessary
        users = []
        for acc in accs:
            user = {'id':acc.id}
            if 'created_date' in acc.data:
                user['created_date'] = acc.data['created_date']
            users.append(user)
    if util.request_wants_json():
        resp = make_response( json.dumps(users, sort_keys=True, indent=4) )
        resp.mimetype = "application/json"
        return resp
    else:
        return render_template('account/users.html', users=users)

@blueprint.route('/<username>', methods=['GET','POST', 'DELETE'])
def username(username):
    acc = models.Account.pull(username)

    if acc is None:
        abort(404)
    elif ( request.method == 'DELETE' or
            ( request.method == 'POST' and
            request.values.get('submit',False) == 'Delete' ) ):
        if current_user.id != acc.id and not current_user.is_super:
            abort(401)
        else:
            acc.delete()
            flash('Account ' + acc.id + ' deleted')
            return redirect(url_for('.index'))
    elif request.method == 'POST':
        if current_user.id != acc.id and not current_user.is_super:
            abort(401)
        newdata = request.json if request.json else request.values
        if newdata.get('id',False):
            if newdata['id'] != username:
                acc = models.Account.pull(newdata['id'])
            else:
                newdata['api_key'] = acc.data['api_key']
        for k, v in newdata.items():
            if k not in ['submit','password']:
                acc.data[k] = v
        if 'password' in newdata and not newdata['password'].startswith('sha1'):
            acc.set_password(newdata['password'])
        acc.save()
        flash("Record updated")
        return render_template('account/view.html', account=acc)
    else:
        if util.request_wants_json():
            resp = make_response(
                json.dumps(acc.data, sort_keys=True, indent=4) )
            resp.mimetype = "application/json"
            return resp
        else:
            return render_template('account/view.html', account=acc)

def get_redirect_target():
    for target in request.args.get('next'), request.referrer:
        if not target:
            continue
        if target == util.is_safe_url(target):
            return target

class RedirectForm(Form):
    next = HiddenField()

    def __init__(self, *args, **kwargs):
        Form.__init__(self, *args, **kwargs)
        if not self.next.data:
            self.next.data = get_redirect_target() or ''

    def redirect(self, endpoint='index', **values):
        if self.next.data == util.is_safe_url(self.next.data):
            return redirect(self.next.data)
        target = get_redirect_target()
        return redirect(target or url_for(endpoint, **values))

class LoginForm(RedirectForm):
    username = TextField('Username', [validators.Required()])
    password = PasswordField('Password', [validators.Required()])

@blueprint.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm(request.form, csrf_enabled=False)
    if request.method == 'POST' and form.validate():
        password = form.password.data
        username = form.username.data
        user = models.Account.pull(username)
        if user is None:
            user = models.Account.pull_by_email(username)
        if user is not None and user.check_password(password):
            login_user(user, remember=True)
            flash('Welcome back.', 'success')
            return form.redirect('index')
        else:
            flash('Incorrect username/password', 'error')
    if request.method == 'POST' and not form.validate():
        flash('Invalid form', 'error')
    return render_template('account/login.html', form=form)

@blueprint.route('/forgot', methods=['GET', 'POST'])
def forgot():
    if request.method == 'POST':
        un = request.form.get('un',"")
        account = models.Account.pull(un)
        if account is None: account = models.Account.pull_by_email(un)
        if account is None:
            flash('Sorry, your account username / email address is not recognised. Please contact us.')
        else:
            newpass = util.generate_password()
            account.set_password(newpass)
            account.save()

            to = [account.data['email'],app.config['ADMIN_EMAIL']]
            fro = app.config['ADMIN_EMAIL']
            subject = app.config.get("SERVICE_NAME","") + "password reset"
            text = "A password reset request for account " + account.id + " has been received and processed.\n\n"
            text += "The new password for this account is " + newpass + ".\n\n"
            text += "If you are the user " + account.id + " and you requested this change, please login now and change the password again to something of your preference.\n\n"

            text += "If you are the user " + account.id + " and you did NOT request this change, please contact us immediately.\n\n"
            try:
                util.send_mail(to=to, fro=fro, subject=subject, text=text)
                flash('Your password has been reset. Please check your emails.')
                if app.config.get('DEBUG',False):
                    flash('Debug mode - new password was set to ' + newpass)
            except:
                flash('Email failed.')
                if app.config.get('DEBUG',False):
                    flash('Debug mode - new password was set to ' + newpass)

    return render_template('account/forgot.html')

@blueprint.route('/logout')
def logout():
    logout_user()
    flash('You are now logged out', 'success')
    return redirect('/')

def existscheck(form, field):
    test = models.Account.pull(form.w.data)
    if test:
        raise ValidationError('Taken! Please try another.')

class RegisterForm(Form):
    w = TextField('Username', [validators.Length(min=3, max=25),existscheck])
    n = TextField('Email Address', [
        validators.Length(min=3, max=35),
        validators.Email(message='Must be a valid email address')
    ])
    s = PasswordField('Password', [
        validators.Required(),
        validators.EqualTo('c', message='Passwords must match')
    ])
    c = PasswordField('Repeat Password')

@blueprint.route('/register', methods=['GET', 'POST'])
def register():
    if not app.config.get('PUBLIC_REGISTER',False) and not current_user.is_super:
        abort(401)
    form = RegisterForm(request.form, csrf_enabled=False)
    if request.method == 'POST' and form.validate():
        api_key = str(uuid.uuid4())
        account = models.Account(
            id=form.w.data,
            email=form.n.data,
            api_key=api_key
        )
        account.set_password(form.s.data)
        account.save()
        flash('Account created for ' + account.id + '. If not listed below, refresh the page to catch up.', 'success')
        return redirect('/account')
    if request.method == 'POST' and not form.validate():
        flash('Please correct the errors', 'error')
    return render_template('account/register.html', form=form)


text:
package tests

import (
	"os"
	"testing"

	"github.com/hyperledger/fabric/common/flogging"
)

func TestMain(m *testing.M) {
	flogging.ActivateSpec("lockbasedtxmgr,statevalidator,statebasedval,statecouchdb,valimpl,pvtstatepurgemgmt,confighistory,kvledger=debug")
	os.Exit(m.Run())
}

func TestLedgerAPIs(t *testing.T) {
	env := newEnv(defaultConfig, t)
	defer env.cleanup()

	// create two ledgers
	h1 := newTestHelperCreateLgr("ledger1", t)
	h2 := newTestHelperCreateLgr("ledger2", t)

	// populate ledgers with sample data
	dataHelper := newSampleDataHelper(t)
	dataHelper.populateLedger(h1)
	dataHelper.populateLedger(h2)

	// verify contents in both the ledgers
	dataHelper.verifyLedgerContent(h1)
	dataHelper.verifyLedgerContent(h2)
}


text:
"""Seed Helpers copied from OpenAI Gym.

https://github.com/openai/gym/blob/master/gym/utils/seeding.py
"""

import hashlib
import os
import struct
import numpy as np
from six import integer_types

def np_random(seed=None):
  if seed is not None and not (isinstance(seed, integer_types) and 0 <= seed):
    raise ValueError(
        'Seed must be a non-negative integer or omitted, not {}'.format(seed))

  seed = create_seed(seed)

  rng = np.random.RandomState()
  rng.seed(_int_list_from_bigint(hash_seed(seed)))
  return rng, seed

def hash_seed(seed=None, max_bytes=8):
  # pylint: disable=g-doc-return-or-yield
  """Function for hashing the seed.

    Any given evaluation is likely to have many PRNG's active at
    once. (Most commonly, because the environment is running in
    multiple processes.) There's literature indicating that having
    linear correlations between seeds of multiple PRNG's can correlate
    the outputs:

    http://blogs.unity3d.com/2015/01/07/a-primer-on-repeatable-random-numbers/
    http://stackoverflow.com/questions/1554958/how-different-do-random-seeds-need-to-be
    http://dl.acm.org/citation.cfm?id=1276928

    Thus, for sanity we hash the seeds before using them. (This scheme
    is likely not crypto-strength, but it should be good enough to get
    rid of simple correlations.)

  Args:
    seed (Optional[int]): None seeds from an operating system specific
      randomness source.
    max_bytes: Maximum number of bytes to use in the hashed seed.
  """
  # pylint: enable=g-doc-return-or-yield
  if seed is None:
    seed = create_seed(max_bytes=max_bytes)
  hash_value = hashlib.sha512(str(seed).encode('utf8')).digest()
  return _bigint_from_bytes(hash_value[:max_bytes])

def create_seed(a=None, max_bytes=8):
  # pylint: disable=g-doc-return-or-yield
  """Create a strong random seed.

  Otherwise, Python 2 would seed using
    the system time, which might be non-robust especially in the
    presence of concurrency.

  Args:
    a (Optional[int, str]): None seeds from an operating system specific
      randomness source.
    max_bytes: Maximum number of bytes to use in the seed.
  """
  # pylint: enable=g-doc-return-or-yield
  # Adapted from https://svn.python.org/projects/python/tags/r32/Lib/random.py
  if a is None:
    a = _bigint_from_bytes(os.urandom(max_bytes))
  elif isinstance(a, str):
    a = a.encode('utf8')
    a += hashlib.sha512(a).digest()
    a = _bigint_from_bytes(a[:max_bytes])
  elif isinstance(a, integer_types):
    a = a % 2**(8 * max_bytes)
  else:
    raise ValueError('Invalid type for seed: {} ({})'.format(type(a), a))

  return a

# pylint: disable=redefined-builtin
def _bigint_from_bytes(bytes):
  sizeof_int = 4
  padding = sizeof_int - len(bytes) % sizeof_int
  bytes += b'\0' * padding
  int_count = int(len(bytes) / sizeof_int)
  unpacked = struct.unpack('{}I'.format(int_count), bytes)
  accum = 0
  for i, val in enumerate(unpacked):
    accum += 2**(sizeof_int * 8 * i) * val
  return accum

# pylint: enable=redefined-builtin

# pylint: disable=missing-docstring
def _int_list_from_bigint(bigint):
  if bigint < 0:  # Special case 0
    raise ValueError('Seed must be non-negative, not {}'.format(bigint))
  elif bigint == 0:
    return [0]

  ints = []
  while bigint > 0:
    bigint, mod = divmod(bigint, 2**32)
    ints.append(mod)
  return ints

# pylint: enable=missing-docstring


text:
class NetworkOverlay
{

protected:
	virtual std::string getIdentifier(void) = 0;
	virtual ITransport * getTransport(void) = 0;
	virtual Node * getThisNode(void) = 0;
  // Get and put a key/value pair
	virtual void put(std::string key_i, std::string value_i) = 0;
	virtual std::string get(std::string key_i) = 0;
};

#endif


text:
get_ipython().magic(u'matplotlib inline')

# In[2]:

import numpy as np
import matplotlib.tri as tri
import matplotlib.pyplot as plt
import datetime as dt
import netCDF4

# In[3]:

import cartopy.crs as ccrs
from cartopy.io.img_tiles import MapQuestOpenAerial, MapQuestOSM, OSM

# In[4]:

import iris
import pyugrid

# In[5]:

iris.FUTURE.netcdf_promote = True

# In[6]:

#ADCIRC
#url =  'http://comt.sura.org/thredds/dodsC/data/comt_1_archive/inundation_tropical/UND_ADCIRC/Hurricane_Ike_3D_final_run_with_waves'
#FVCOM
#url = 'http://www.smast.umassd.edu:8080/thredds/dodsC/FVCOM/NECOFS/Forecasts/NECOFS_GOM3_FORECAST.nc'
#SELFE
#url = 'http://comt.sura.org/thredds/dodsC/data/comt_1_archive/inundation_tropical/VIMS_SELFE/Hurricane_Ike_2D_final_run_with_waves'

# In[7]:

# UMASSD/SMAST Water Quality FVCOM Simulation for MWRA
url = 'http://www.smast.umassd.edu:8080/thredds/dodsC/fvcom/mwra/wq'
var = 'Dissolved oxygen'  # use long_name because DO has no standard_name in this dataset
levs = np.arange(5.,15.,.25)   # contour levels for plotting
klev = 0   # level 0 is top in FVCOM

# In[8]:

# UMASSD/SMAST FVCOM Simulations in support of Water Quality for MWRA
url = 'http://www.smast.umassd.edu:8080/thredds/dodsC/fvcom/mwra/fvcom'
var = 'sea_water_salinity'    # use standard_name if it exists
levs = np.arange(28.,33.5,.1)   # contour levels for plotting
klev = 0   # level 0 is top in FVCOM

# In[9]:

# Desired time for snapshot
# ....right now (or some number of hours from now) ...
start = dt.datetime.utcnow() + dt.timedelta(hours=6)
# ... or specific time (UTC)
start = dt.datetime(1998,3,2,15,0,0)

# In[10]:

nc = netCDF4.Dataset(url)
#print nc.variables.keys()  # list variables
#nc.variables['DO']  # show variable with attributes

# In[11]:

cube = iris.load_cube(url,var)    # Iris uses the standard_name or long_name to access variables

# In[12]:

# Get desired time step
time_var = nc['time']
itime = netCDF4.date2index(start,time_var,select='nearest')

# In[13]:

ug = pyugrid.UGrid.from_ncfile(url)

print "There are %i nodes"%ug.nodes.shape[0]
print "There are %i faces"%ug.faces.shape[0]

# In[14]:

print cube

# In[15]:

cube.mesh = ug
cube.mesh_dimension = 1  # (0:time,1:node)

# In[16]:

lon = cube.mesh.nodes[:,0]
lat = cube.mesh.nodes[:,1]
nv = cube.mesh.faces

# In[17]:

triang = tri.Triangulation(lon,lat,triangles=nv)

# In[18]:

zcube = cube[itime, klev, :]

# In[19]:

print zcube.data.min()
print zcube.data.max()

# ## Try a simple Cartopy plot

# In[20]:

fig = plt.figure(figsize=(10,10))
ax = plt.axes(projection=ccrs.PlateCarree())
#ax.set_extent([-90, -60, 5, 50])
#ax.coastlines('10m')
plt.tricontourf(triang, zcube.data, levels=levs)
plt.colorbar(fraction=0.035, pad=0.04)
plt.tricontour(triang, zcube.data, colors='k',levels=levs)
tvar = cube.coord('time')
tstr = tvar.units.num2date(tvar.points[itime])
gl = ax.gridlines(draw_labels=True)
gl.xlabels_top = False
gl.ylabels_right = False
plt.title('%s: Elevation (m): %s' % (zcube.attributes['title'],tstr));

# ## Try to plot using tiled background

# In[21]:

projection = ccrs.PlateCarree()

fig = plt.figure(figsize=(10,10))
tiler = MapQuestOpenAerial()
ax = plt.axes(projection=projection)

ax.set_extent([-71.5, -70, 41.5, 43], projection)
ax.add_image(tiler, 8, zorder=0)

cs = ax.tricontourf(triang, zcube.data, levels=levs, zorder=1)
ax.tricontour(triang, zcube.data, colors='k', levels=levs, zorder=2)
fig.colorbar(cs,fraction=0.035, pad=0.04)

tvar = cube.coord('time')
tstr = tvar.units.num2date(tvar.points[itime])
gl = ax.gridlines(draw_labels=True)
gl.xlabels_top = False
gl.ylabels_right = False
ax.set_title('%s: %s %s' % (zcube.attributes['title'],var,tstr));

# In[ ]:


text:
<?php

namespace Order\Domain\UseCase;

use Order\Domain\Model\Order;

final class EnterOrder
{
    public function execute(Order $order, array $data): void
    {
        $articles = $order->articles()->toArray();

        foreach ($data as $datum) {
            foreach ($articles as $article) {
                if ($article->label() === $datum['label']) {
                    $article->updateOrderedQuantity($datum['quantityToOrder']);
                }
            }
        }
    }
}


text:
PATH=%PATH%;C:\Program Files\WampServer\bin\php\php5.4.12
PATH=%PATH%;C:\wamp\bin\php\php5.4.12

REM environnement de debug (app_dev.php)
php app/console --env=dev doctrine:cache:clear-metadata
php app/console --env=dev doctrine:cache:clear-query
php app/console --env=dev doctrine:cache:clear-result

php app/console --env=dev cache:clear
php app/console --env=dev assets:install web


text:
'use strict';

const fastGlob = require('fast-glob');
const fs = require('fs');
const json5 = require('json5');
const {cyan, green, red} = require('kleur/colors');
const {default: addFormats} = require('ajv-formats');
const {default: Ajv} = require('ajv');
const {log} = require('../common/logging');

/**
 * Fetches the content of a JSON/JSONC/JSON5 file.
 *
 * @param {string} file repo root relative.
 * @return {any}
 */
function getJsonContents(file) {
  return json5.parse(fs.readFileSync(file, 'utf8'));
}

/**
 * Checks JSON files against their JSON Schemas.
 */
function checkJsonSchemas() {
  log('Validating JSON files');
  const ajv = new Ajv({allErrors: true});
  addFormats(ajv);

  const vscodeSettings = getJsonContents('.vscode/settings.json');
  const schemas = vscodeSettings['json.schemas'];

  for (const {fileMatch, url: schemaFile} of schemas.values()) {
    log('Using schema', `${cyan(schemaFile)}:`);
    const schemaJson = getJsonContents(schemaFile);
    const validate = ajv.compile(schemaJson);

    const jsonFiles = fastGlob.sync(fileMatch, {
      dot: true,
      ignore: ['**/node_modules'],
    });

    for (const jsonFile of jsonFiles) {
      try {
        const jsonData = getJsonContents(jsonFile);
        if (validate(jsonData)) {
          log('⤷', cyan(jsonFile), '-', green('valid'));
        } else {
          process.exitCode = 1;
          log('⤷', cyan(jsonFile), '-', red('invalid'));
          for (const error of validate.errors || []) {
            log('  ⤷', cyan(error.instancePath), red(error.message || ''));
          }
        }
      } catch (error) {
        process.exitCode = 1;
        if (error instanceof SyntaxError) {
          log('⤷', cyan(jsonFile), '-', red('unable to parse as a JSON file'));
        } else {
          throw error;
        }
      }
    }
  }
}

module.exports = {
  checkJsonSchemas,
};

checkJsonSchemas.description =
  'Checks JSON files against their required schemas';


text:
<?php namespace Cms\Controllers;

use Url;
use Lang;
use Flash;
use Config;
use Request;
use Response;
use Exception;
use BackendMenu;
use Cms\Widgets\AssetList;
use Cms\Widgets\TemplateList;
use Cms\Widgets\ComponentList;
use Cms\Classes\Page;
use Cms\Classes\Theme;
use Cms\Classes\Router;
use Cms\Classes\Layout;
use Cms\Classes\Partial;
use Cms\Classes\Content;
use Cms\Classes\CmsCompoundObject;
use Cms\Classes\ComponentManager;
use Cms\Classes\ComponentPartial;
use Backend\Classes\Controller;
use Backend\Classes\WidgetManager;
use October\Rain\Router\Router as RainRouter;
use ApplicationException;

/**
 * CMS index
 *
 * @package october\cms
 * @author Alexey Bobkov, Samuel Georges
 */
class Index extends Controller
{
    use \Backend\Traits\InspectableContainer;

    protected $theme;

    public $requiredPermissions = [
        'cms.manage_content',
        'cms.manage_assets',
        'cms.manage_pages',
        'cms.manage_layouts',
        'cms.manage_partials'
    ];

    /**
     * Constructor.
     */
    public function __construct()
    {
        parent::__construct();

        BackendMenu::setContext('October.Cms', 'cms', true);

        try {
            if (!($theme = Theme::getEditTheme())) {
                throw new ApplicationException(Lang::get('cms::lang.theme.edit.not_found'));
            }

            $this->theme = $theme;

            new TemplateList($this, 'pageList', function () use ($theme) {
                return Page::listInTheme($theme, true);
            });

            new TemplateList($this, 'partialList', function () use ($theme) {
                return Partial::listInTheme($theme, true);
            });

            new TemplateList($this, 'layoutList', function () use ($theme) {
                return Layout::listInTheme($theme, true);
            });

            new TemplateList($this, 'contentList', function () use ($theme) {
                return Content::listInTheme($theme, true);
            });

            new ComponentList($this, 'componentList');

            new AssetList($this, 'assetList');
        }
        catch (Exception $ex) {
            $this->handleError($ex);
        }
    }

    //
    // Pages
    //

    public function index()
    {
        $this->addJs('/modules/cms/assets/js/october.cmspage.js', 'core');
        $this->addJs('/modules/cms/assets/js/october.dragcomponents.js', 'core');
        $this->addJs('/modules/cms/assets/js/october.tokenexpander.js', 'core');
        $this->addCss('/modules/cms/assets/css/october.components.css', 'core');

        // Preload the code editor class as it could be needed
        // before it loads dynamically.
        $this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core');

        $this->bodyClass = 'compact-container';
        $this->pageTitle = 'cms::lang.cms.menu_label';
        $this->pageTitleTemplate = '%s '.trans($this->pageTitle);

        if (Request::ajax() && Request::input('formWidgetAlias')) {
            $this->bindFormWidgetToController();
        }
    }

    public function index_onOpenTemplate()
    {
        $this->validateRequestTheme();

        $type = Request::input('type');
        $template = $this->loadTemplate($type, Request::input('path'));
        $widget = $this->makeTemplateFormWidget($type, $template);

        $this->vars['templatePath'] = Request::input('path');

        if ($type == 'page') {
            $router = new RainRouter;
            $this->vars['pageUrl'] = $router->urlFromPattern($template->url);
        }

        return [
            'tabTitle' => $this->getTabTitle($type, $template),
            'tab'      => $this->makePartial('form_page', [
                'form'          => $widget,
                'templateType'  => $type,
                'templateTheme' => $this->theme->getDirName(),
                'templateMtime' => $template->mtime
            ])
        ];
    }

    public function onSave()
    {
        $this->validateRequestTheme();
        $type = Request::input('templateType');
        $templatePath = trim(Request::input('templatePath'));
        $template = $templatePath ? $this->loadTemplate($type, $templatePath) : $this->createTemplate($type);
        $formWidget = $this->makeTemplateFormWidget($type, $template);

        $saveData = $formWidget->getSaveData();
        $postData = post();
        $templateData = [];

        $settings = array_get($saveData, 'settings', []) + Request::input('settings', []);
        $settings = $this->upgradeSettings($settings);

        if ($settings) {
            $templateData['settings'] = $settings;
        }

        $fields = ['markup', 'code', 'fileName', 'content'];

        foreach ($fields as $field) {
            if (array_key_exists($field, $saveData)) {
                $templateData[$field] = $saveData[$field];
            }
            elseif (array_key_exists($field, $postData)) {
                $templateData[$field] = $postData[$field];
            }
        }

        if (!empty($templateData['markup']) && Config::get('cms.convertLineEndings', false) === true) {
            $templateData['markup'] = $this->convertLineEndings($templateData['markup']);
        }

        if (!empty($templateData['code']) && Config::get('cms.convertLineEndings', false) === true) {
            $templateData['code'] = $this->convertLineEndings($templateData['code']);
        }

        if (!Request::input('templateForceSave') && $template->mtime) {
            if (Request::input('templateMtime') != $template->mtime) {
                throw new ApplicationException('mtime-mismatch');
            }
        }

        $template->attributes = [];
        $template->fill($templateData);
        $template->save();

        /*
         * Extensibility
         */
        $this->fireSystemEvent('cms.template.save', [$template, $type]);

        Flash::success(Lang::get('cms::lang.template.saved'));

        $result = [
            'templatePath'  => $template->fileName,
            'templateMtime' => $template->mtime,
            'tabTitle'      => $this->getTabTitle($type, $template)
        ];

        if ($type == 'page') {
            $result['pageUrl'] = Url::to($template->url);
            $router = new Router($this->theme);
            $router->clearCache();
            CmsCompoundObject::clearCache($this->theme);
        }

        return $result;
    }

    public function onOpenConcurrencyResolveForm()
    {
        return $this->makePartial('concurrency_resolve_form');
    }

    public function onCreateTemplate()
    {
        $type = Request::input('type');
        $template = $this->createTemplate($type);

        if ($type == 'asset') {
            $template->fileName = $this->widget->assetList->getCurrentRelativePath();
        }

        $widget = $this->makeTemplateFormWidget($type, $template);

        $this->vars['templatePath'] = '';

        return [
            'tabTitle' => $this->getTabTitle($type, $template),
            'tab'      => $this->makePartial('form_page', [
                'form'          => $widget,
                'templateType'  => $type,
                'templateTheme' => $this->theme->getDirName(),
                'templateMtime' => null
            ])
        ];
    }

    public function onDeleteTemplates()
    {
        $this->validateRequestTheme();

        $type = Request::input('type');
        $templates = Request::input('template');
        $error = null;
        $deleted = [];

        try {
            foreach ($templates as $path => $selected) {
                if ($selected) {
                    $this->loadTemplate($type, $path)->delete();
                    $deleted[] = $path;
                }
            }
        }
        catch (Exception $ex) {
            $error = $ex->getMessage();
        }

        /*
         * Extensibility
         */
        $this->fireSystemEvent('cms.template.delete', [$type]);

        return [
            'deleted' => $deleted,
            'error'   => $error,
            'theme'   => Request::input('theme')
        ];
    }

    public function onDelete()
    {
        $this->validateRequestTheme();

        $type = Request::input('templateType');

        $this->loadTemplate($type, trim(Request::input('templatePath')))->delete();

        /*
         * Extensibility
         */
        $this->fireSystemEvent('cms.template.delete', [$type]);
    }

    public function onGetTemplateList()
    {
        $this->validateRequestTheme();

        $page = Page::inTheme($this->theme);
        return [
            'layouts' => $page->getLayoutOptions()
        ];
    }

    public function onExpandMarkupToken()
    {
        if (!$alias = post('tokenName')) {
            throw new ApplicationException(trans('cms::lang.component.no_records'));
        }

        // Can only expand components at this stage
        if ((!$type = post('tokenType')) && $type != 'component') {
            return;
        }

        if (!($names = (array) post('component_names')) || !($aliases = (array) post('component_aliases'))) {
            throw new ApplicationException(trans('cms::lang.component.not_found', ['name' => $alias]));
        }

        if (($index = array_get(array_flip($aliases), $alias, false)) === false) {
            throw new ApplicationException(trans('cms::lang.component.not_found', ['name' => $alias]));
        }

        if (!$componentName = array_get($names, $index)) {
            throw new ApplicationException(trans('cms::lang.component.not_found', ['name' => $alias]));
        }

        $manager = ComponentManager::instance();
        $componentObj = $manager->makeComponent($componentName);
        $partial = ComponentPartial::load($componentObj, 'default');
        $content = $partial->getContent();
        $content = str_replace('__SELF__', $alias, $content);

        return $content;
    }

    //
    // Methods for the internal use
    //

    protected function validateRequestTheme()
    {
        if ($this->theme->getDirName() != Request::input('theme')) {
            throw new ApplicationException(trans('cms::lang.theme.edit.not_match'));
        }
    }

    protected function resolveTypeClassName($type)
    {
        $types = [
            'page'    => '\Cms\Classes\Page',
            'partial' => '\Cms\Classes\Partial',
            'layout'  => '\Cms\Classes\Layout',
            'content' => '\Cms\Classes\Content',
            'asset'   => '\Cms\Classes\Asset'
        ];

        if (!array_key_exists($type, $types)) {
            throw new ApplicationException(trans('cms::lang.template.invalid_type'));
        }

        return $types[$type];
    }

    protected function loadTemplate($type, $path)
    {
        $class = $this->resolveTypeClassName($type);

        if (!($template = call_user_func([$class, 'load'], $this->theme, $path))) {
            throw new ApplicationException(trans('cms::lang.template.not_found'));
        }

        /*
         * Extensibility
         */
        $this->fireSystemEvent('cms.template.processSettingsAfterLoad', [$template]);

        return $template;
    }

    protected function createTemplate($type)
    {
        $class = $this->resolveTypeClassName($type);

        if (!($template = $class::inTheme($this->theme))) {
            throw new ApplicationException(trans('cms::lang.template.not_found'));
        }

        return $template;
    }

    protected function getTabTitle($type, $template)
    {
        if ($type == 'page') {
            $result = $template->title ?: $template->getFileName();
            if (!$result) {
                $result = trans('cms::lang.page.new');
            }

            return $result;
        }

        if ($type == 'partial' || $type == 'layout' || $type == 'content' || $type == 'asset') {
            $result = in_array($type, ['asset', 'content']) ? $template->getFileName() : $template->getBaseFileName();
            if (!$result) {
                $result = trans('cms::lang.'.$type.'.new');
            }

            return $result;
        }

        return $template->getFileName();
    }

    protected function makeTemplateFormWidget($type, $template, $alias = null)
    {
        $formConfigs = [
            'page'    => '~/modules/cms/classes/page/fields.yaml',
            'partial' => '~/modules/cms/classes/partial/fields.yaml',
            'layout'  => '~/modules/cms/classes/layout/fields.yaml',
            'content' => '~/modules/cms/classes/content/fields.yaml',
            'asset'   => '~/modules/cms/classes/asset/fields.yaml'
        ];

        if (!array_key_exists($type, $formConfigs)) {
            throw new ApplicationException(trans('cms::lang.template.not_found'));
        }

        $widgetConfig = $this->makeConfig($formConfigs[$type]);
        $widgetConfig->model = $template;
        $widgetConfig->alias = $alias ?: 'form'.studly_case($type).md5($template->getFileName()).uniqid();

        $widget = $this->makeWidget('Backend\Widgets\Form', $widgetConfig);

        return $widget;
    }

    protected function upgradeSettings($settings)
    {
        /*
         * Handle component usage
         */
        $componentProperties = post('component_properties');
        $componentNames = post('component_names');
        $componentAliases = post('component_aliases');

        if ($componentProperties !== null) {
            if ($componentNames === null || $componentAliases === null) {
                throw new ApplicationException(trans('cms::lang.component.invalid_request'));
            }

            $count = count($componentProperties);
            if (count($componentNames) != $count || count($componentAliases) != $count) {
                throw new ApplicationException(trans('cms::lang.component.invalid_request'));
            }

            for ($index = 0; $index < $count; $index++) {
                $componentName = $componentNames[$index];
                $componentAlias = $componentAliases[$index];

                $section = $componentName;
                if ($componentAlias != $componentName) {
                    $section .= ' '.$componentAlias;
                }

                $properties = json_decode($componentProperties[$index], true);
                unset($properties['oc.alias']);
                unset($properties['inspectorProperty']);
                unset($properties['inspectorClassName']);
                $settings[$section] = $properties;
            }
        }

        /*
         * Handle view bag
         */
        $viewBag = post('viewBag');
        if ($viewBag !== null) {
            $settings['viewBag'] = $viewBag;
        }

        /*
         * Extensibility
         */
        $dataHolder = (object) ['settings' => $settings];

        $this->fireSystemEvent('cms.template.processSettingsBeforeSave', [$dataHolder]);

        return $dataHolder->settings;
    }

    protected function bindFormWidgetToController()
    {
        $alias = Request::input('formWidgetAlias');
        $type = Request::input('templateType');
        $object = $this->loadTemplate($type, Request::input('templatePath'));

        $widget = $this->makeTemplateFormWidget($type, $object, $alias);
        $widget->bindToController();
    }

    /**
     * Replaces Windows style (/r/n) line endings with unix style (/n)
     * line endings.
     * @param string $markup The markup to convert to unix style endings
     * @return string
     */
    protected function convertLineEndings($markup)
    {
        $markup = str_replace("\r\n", "\n", $markup);
        $markup = str_replace("\r", "\n", $markup);

        return $markup;
    }
}


text:
<accordion
    timing="200"
    handle="myaccordion"
    close-others="false"
    toggle-icon="chevron">
    <toggle ng-repeat="c in content" content="c.value"></toggle>
</accordion>


text:
<?php
  require_once("config.php");
  require_once("functions.php");

  session_start();

  $username = addslashes($_POST['username']);
  $password = addslashes($_POST['password']);

  $mysqli = new mysqli(SERVERNAME, USERNAME, PASSWORD, DATABASE);
  if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
  }
  if ( $loginQuery = $mysqli->prepare("SELECT * FROM users WHERE username = ?")) {
    /* bind parameters for markers */
    $loginQuery->bind_param("s", $username);

    if ($loginQuery->execute()){
      $result = $loginQuery->get_result();
      $array  = $result->fetch_array(MYSQLI_ASSOC); // this does work :)
    } else{
      error_log ("Didn't work");
    }

    $loginQuery->close();
  }
  /* close connection */
  $mysqli->close();

  if (password_verify($password, $array['password'])) {
  	if ( $array['isActive'] ) {

      $mysqli = new mysqli(SERVERNAME, USERNAME, PASSWORD, DATABASE);
      if (mysqli_connect_errno()) {
        printf("Connect failed: %s\n", mysqli_connect_error());
        exit();
      }
      if ( $loginQuery = $mysqli->prepare("UPDATE users SET last_login = now() WHERE username = ?") ) {
        /* bind parameters for markers */
        $loginQuery->bind_param("s", $username);
        /* execute query */
        $loginQuery->execute();
        /* close statement */
        $loginQuery->close();
      }
      /* close connection */
      $mysqli->close();
      unset($array['password'], $array['last_login'], $array['isActive'], $array['account_date']);
  		$_SESSION['user'] = $array;
      $_SESSION['viewing_user_id'] = $_SESSION['user']['id'];
  		header('Location: ../../budget.php');
  		die;
  	}
    unset($_SESSION['user']);
  	$_SESSION['feedback'] = [
  		'color' => 'red',
  		'message' =>'It seems that organization is no longer active. Contact the finance chair to update this.'
  	];
  	header('Location: ../../index.php');
  	die;
  }
  else {
    unset($_SESSION['user']);
  	$_SESSION['feedback'] = [
  		'color' => 'red',
  		'message' =>'Wrong Password!'
  	];
  	header('Location: ../../index.php');
  	die;
  }
?>