text:
/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 *    KDTree.java
 *    Copyright (C) 2000-2012 University of Waikato
 *
 */

package weka.core.neighboursearch;

import java.util.Collections;
import java.util.Enumeration;
import java.util.Vector;

import weka.core.DistanceFunction;
import weka.core.EuclideanDistance;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.Option;
import weka.core.RevisionUtils;
import weka.core.TechnicalInformation;
import weka.core.TechnicalInformation.Field;
import weka.core.TechnicalInformation.Type;
import weka.core.TechnicalInformationHandler;
import weka.core.Utils;
import weka.core.neighboursearch.kdtrees.KDTreeNode;
import weka.core.neighboursearch.kdtrees.KDTreeNodeSplitter;
import weka.core.neighboursearch.kdtrees.SlidingMidPointOfWidestSide;

/**

 * Class implementing the KDTree search algorithm for nearest neighbour search.

 * The connection to dataset is only a reference. For the tree structure the indexes are stored in an array.

 * Building the tree:

 * If a node has <maximal-inst-number> (option -L) instances no further splitting is done. Also if the split would leave one side empty, the branch is not split any further even if the instances in the resulting node are more than <maximal-inst-number> instances.

 * **PLEASE NOTE:** The algorithm can not handle missing values, so it is advisable to run ReplaceMissingValues filter if there are any missing values in the dataset.

 *

 * For more information see:

 *

 * Jerome H. Friedman, Jon Luis Bentley, Raphael Ari Finkel (1977). An Algorithm for Finding Best Matches in Logarithmic Expected Time. ACM Transactions on Mathematics Software. 3(3):209-226.

 *

 * Andrew Moore (1991). A tutorial on kd-trees.
 *

 *

 * BibTeX:
 *

 * @article{Friedman1977,
 *    author = {Jerome H. Friedman and Jon Luis Bentley and Raphael Ari Finkel},
 *    journal = {ACM Transactions on Mathematics Software},
 *    month = {September},
 *    number = {3},
 *    pages = {209-226},
 *    title = {An Algorithm for Finding Best Matches in Logarithmic Expected Time},
 *    volume = {3},
 *    year = {1977}
 * }
 *
 * @techreport{Moore1991,
 *    author = {Andrew Moore},
 *    booktitle = {University of Cambridge Computer Laboratory Technical Report No. 209},
 *    howpublished = {Extract from PhD Thesis},
 *    title = {A tutorial on kd-trees},
 *    year = {1991},
 *    HTTP = {Available from http://www.autonlab.org/autonweb/14665.html}
 * }
 *

 *

 *

 * Valid options are:

 *
 *
 -S <classname and options>
 *  Node splitting method to use.
 *  (default: weka.core.neighboursearch.kdtrees.SlidingMidPointOfWidestSide)

 *
 *
 -W <value>
 *  Set minimal width of a box
 *  (default: 1.0E-2).

 *
 *
 -L
 *  Maximal number of instances in a leaf
 *  (default: 40).

 *
 *
 -N
 *  Normalizing will be done
 *  (Select dimension for split, with normalising to universe).

 *

 *
 * @author Gabi Schmidberger (gabi[at-the-rate]cs[dot]waikato[dot]ac[dot]nz)
 * @author Malcolm Ware (mfw4[at-the-rate]cs[dot]waikato[dot]ac[dot]nz)
 * @author Ashraf M. Kibriya (amk14[at-the-rate]cs[dot]waikato[dot]ac[dot]nz)
 * @version $Revision: 10141 $
 */
public class KDTree
  extends NearestNeighbourSearch
  implements TechnicalInformationHandler {

  /** For serialization. */
  private static final long serialVersionUID = 1505717283763272533L;

  /**
   * Array holding the distances of the nearest neighbours. It is filled up both
   * by nearestNeighbour() and kNearestNeighbours().
   */
  protected double[] m_DistanceList;

  /**
   * Indexlist of the instances of this kdtree. Instances get sorted according
   * to the splits. the nodes of the KDTree just hold their start and end
   * indices
   */
  protected int[] m_InstList;

  /** The root node of the tree. */
  protected KDTreeNode m_Root;

  /** The node splitter. */
  protected KDTreeNodeSplitter m_Splitter = new SlidingMidPointOfWidestSide();

  /** Tree stats. */
  protected int m_NumNodes, m_NumLeaves, m_MaxDepth;

  /** Tree Stats variables. */
  protected TreePerformanceStats m_TreeStats = null;

  // Constants
  /** The index of MIN value in attributes' range array. */
  public static final int MIN = EuclideanDistance.R_MIN;

  /** The index of MAX value in attributes' range array. */
  public static final int MAX = EuclideanDistance.R_MAX;

  /** The index of WIDTH (MAX-MIN) value in attributes' range array. */
  public static final int WIDTH = EuclideanDistance.R_WIDTH;

  /**
   * Returns an instance of a TechnicalInformation object, containing detailed
   * information about the technical background of this class, e.g., paper
   * reference or book this class is based on.
   *
   * @return		the technical information about this class
   */
  public TechnicalInformation getTechnicalInformation() {
    TechnicalInformation result;
    TechnicalInformation additional;

    result = new TechnicalInformation(Type.ARTICLE);
    result.setValue(Field.AUTHOR, "Jerome H. Friedman and Jon Luis Bentley and Raphael Ari Finkel");
    result.setValue(Field.YEAR, "1977");
    result.setValue(Field.TITLE, "An Algorithm for Finding Best Matches in Logarithmic Expected Time");
    result.setValue(Field.JOURNAL, "ACM Transactions on Mathematics Software");
    result.setValue(Field.PAGES, "209-226");
    result.setValue(Field.MONTH, "September");
    result.setValue(Field.VOLUME, "3");
    result.setValue(Field.NUMBER, "3");

    additional = result.add(Type.TECHREPORT);
    additional.setValue(Field.AUTHOR, "Andrew Moore");
    additional.setValue(Field.YEAR, "1991");
    additional.setValue(Field.TITLE, "A tutorial on kd-trees");
    additional.setValue(Field.HOWPUBLISHED, "Extract from PhD Thesis");
    additional.setValue(Field.BOOKTITLE, "University of Cambridge Computer Laboratory Technical Report No. 209");
    additional.setValue(Field.HTTP, "Available from http://www.autonlab.org/autonweb/14665.html");

    return result;
  }

  /**
   * Creates a new instance of KDTree.
   */
  public KDTree() {
    super();
    if (getMeasurePerformance())
      m_Stats = m_TreeStats = new TreePerformanceStats();
  }

  /**
   * Creates a new instance of KDTree.
   * It also builds the tree on supplied set of Instances.
   * @param insts The instances/points on which the BallTree
   * should be built on.
   */
  public KDTree(Instances insts) {
    super(insts);
    if (getMeasurePerformance())
      m_Stats = m_TreeStats = new TreePerformanceStats();
  }

  /**
   * Builds the KDTree on the supplied set of instances/points. It
   * is adviseable to run the replace missing attributes filter
   * on the passed instances first.
   * NOTE: This method should not be called from outside this
   * class. Outside classes should call setInstances(Instances)
   * instead.
   *
   * @param instances	The instances to build the tree on
   * @throws Exception	if something goes wrong
   */
  protected void buildKDTree(Instances instances) throws Exception {

    checkMissing(instances);
    if (m_EuclideanDistance == null)
      m_DistanceFunction = m_EuclideanDistance = new EuclideanDistance(
          instances);
    else
      m_EuclideanDistance.setInstances(instances);

    m_Instances = instances;
    int numInst = m_Instances.numInstances();

    // Make the global index list
    m_InstList = new int[numInst];

    for (int i = 0; i < numInst; i++) {
      m_InstList[i] = i;
    }

    double[][] universe = m_EuclideanDistance.getRanges();

    // initializing internal fields of KDTreeSplitter
    m_Splitter.setInstances(m_Instances);
    m_Splitter.setInstanceList(m_InstList);
    m_Splitter.setEuclideanDistanceFunction(m_EuclideanDistance);
    m_Splitter.setNodeWidthNormalization(m_NormalizeNodeWidth);

    // building tree
    m_NumNodes = m_NumLeaves = 1;
    m_MaxDepth = 0;
    m_Root = new KDTreeNode(m_NumNodes, 0, m_Instances.numInstances() - 1,
        universe);

    splitNodes(m_Root, universe, m_MaxDepth + 1);
  }

  /**
   * Recursively splits nodes of a tree starting from the supplied node.
   * The splitting stops for any node for which the number of instances/points
   * falls below a given threshold (given by m_MaxInstInLeaf), or if the
   * maximum relative width/range of the instances/points
   * (i.e. max_i(max(att_i) - min(att_i)) ) falls below a given threshold
   * (given by m_MinBoxRelWidth).
   *
   * @param node The node to start splitting from.
   * @param universe The attribute ranges of the whole dataset.
   * @param depth The depth of the supplied node.
   * @throws Exception If there is some problem
   * splitting.
   */
  protected void splitNodes(KDTreeNode node, double[][] universe,
      int depth) throws Exception {
    double[][] nodeRanges = m_EuclideanDistance.initializeRanges(m_InstList,
                                                 node.m_Start, node.m_End);
    if (node.numInstances() <= m_MaxInstInLeaf
        || getMaxRelativeNodeWidth(nodeRanges, universe) <= m_MinBoxRelWidth)
      return;

    // splitting a node so it is no longer a leaf
    m_NumLeaves--;

    if (depth > m_MaxDepth)
      m_MaxDepth = depth;

    m_Splitter.splitNode(node, m_NumNodes, nodeRanges, universe);
    m_NumNodes += 2;
    m_NumLeaves += 2;

    splitNodes(node.m_Left, universe, depth + 1);
    splitNodes(node.m_Right, universe, depth + 1);
  }

  /**
   * Returns (in the supplied heap object) the k nearest
   * neighbours of the given instance starting from the give
   * tree node. >k neighbours are returned if there are more than
   * one neighbours at the kth boundary. NOTE: This method should
   * not be used from outside this class. Outside classes should
   * call kNearestNeighbours(Instance, int).
   *
   * @param target  The instance to find the nearest neighbours for.
   * @param node The KDTreeNode to start the search from.
   * @param k    The number of neighbours to find.
   * @param heap The MyHeap object to store/update the kNNs found
   * during the search.
   * @param distanceToParents The distance of the supplied target
   * to the parents of the supplied tree node.
   * @throws Exception  if the nearest neighbour could not be found.
   */
  protected void findNearestNeighbours(Instance target, KDTreeNode node, int k,
      MyHeap heap, double distanceToParents) throws Exception {
    if (node.isALeaf()) {
      if (m_TreeStats != null) {
        m_TreeStats.updatePointCount(node.numInstances());
        m_TreeStats.incrLeafCount();
      }
      double distance;
      // look at all the instances in this leaf
      for (int idx = node.m_Start; idx <= node.m_End; idx++) {
        if (target == m_Instances.instance(m_InstList[idx])) // for
                                                              // hold-one-out
                                                              // cross-validation
          continue;
        if (heap.size() < k) {
          distance = m_EuclideanDistance.distance(target, m_Instances
              .instance(m_InstList[idx]), Double.POSITIVE_INFINITY, m_Stats);
          heap.put(m_InstList[idx], distance);
        } else {
          MyHeapElement temp = heap.peek();
          distance = m_EuclideanDistance.distance(target, m_Instances
              .instance(m_InstList[idx]), temp.distance, m_Stats);
          if (distance < temp.distance) {
            heap.putBySubstitute(m_InstList[idx], distance);
          } else if (distance == temp.distance) {
            heap.putKthNearest(m_InstList[idx], distance);
          }
        }// end else heap.size==k
      }// end for

    } else {
      if (m_TreeStats != null) {
        m_TreeStats.incrIntNodeCount();
      }
      KDTreeNode nearer, further;
      boolean targetInLeft = m_EuclideanDistance.valueIsSmallerEqual(target,
          node.m_SplitDim, node.m_SplitValue);

      if (targetInLeft) {
        nearer = node.m_Left;
        further = node.m_Right;
      } else {
        nearer = node.m_Right;
        further = node.m_Left;
      }
      findNearestNeighbours(target, nearer, k, heap, distanceToParents);

      // ... now look in further half if maxDist reaches into it
      if (heap.size() < k) { // if haven't found the first k
        double distanceToSplitPlane = distanceToParents
            + m_EuclideanDistance.sqDifference(node.m_SplitDim, target
                .value(node.m_SplitDim), node.m_SplitValue);
        findNearestNeighbours(target, further, k, heap, distanceToSplitPlane);
        return;
      } else { // else see if ball centered at query intersects with the other
                // side.
        double distanceToSplitPlane = distanceToParents
            + m_EuclideanDistance.sqDifference(node.m_SplitDim, target
                .value(node.m_SplitDim), node.m_SplitValue);
        if (heap.peek().distance >= distanceToSplitPlane) {
          findNearestNeighbours(target, further, k, heap, distanceToSplitPlane);
        }
      }// end else
    }// end else_if an internal node
  }

  /**
   * Returns the k nearest neighbours of the supplied instance.
   * >k neighbours are returned if there are more than one
   * neighbours at the kth boundary.
   *
   * @param target	The instance to find the nearest neighbours for.
   * @param k 		The number of neighbours to find.
   * @return The k nearest neighbours (or >k if more there are than
   * one neighbours at the kth boundary).
   * @throws Exception 	if the nearest neighbour could not be found.
   */
  public Instances kNearestNeighbours(Instance target, int k) throws Exception {
    checkMissing(target);

    if (m_Stats != null)
      m_Stats.searchStart();

    MyHeap heap = new MyHeap(k);
    findNearestNeighbours(target, m_Root, k, heap, 0.0);

    if (m_Stats != null)
      m_Stats.searchFinish();

    Instances neighbours = new Instances(m_Instances, (heap.size() + heap
        .noOfKthNearest()));
    m_DistanceList = new double[heap.size() + heap.noOfKthNearest()];
    int[] indices = new int[heap.size() + heap.noOfKthNearest()];
    int i = indices.length - 1;
    MyHeapElement h;
    while (heap.noOfKthNearest() > 0) {
      h = heap.getKthNearest();
      indices[i] = h.index;
      m_DistanceList[i] = h.distance;
      i--;
    }
    while (heap.size() > 0) {
      h = heap.get();
      indices[i] = h.index;
      m_DistanceList[i] = h.distance;
      i--;
    }
    m_DistanceFunction.postProcessDistances(m_DistanceList);

    for (int idx = 0; idx < indices.length; idx++) {
      neighbours.add(m_Instances.instance(indices[idx]));
    }

    return neighbours;
  }

  /**
   * Returns the nearest neighbour of the supplied target
   * instance.
   *
   * @param target	The instance to find the nearest neighbour for.
   * @return The nearest neighbour from among the previously
   * supplied training instances.
   * @throws Exception 	if the neighbours could not be found.
   */
  public Instance nearestNeighbour(Instance target) throws Exception {
    return (kNearestNeighbours(target, 1)).instance(0);
  }

  /**
   * Returns the distances to the kNearest or 1 nearest neighbour currently
   * found with either the kNearestNeighbours or the nearestNeighbour method.
   *
   * @return array containing the distances of the
   *         nearestNeighbours. The length and ordering of the array
   *         is the same as that of the instances returned by
   *         nearestNeighbour functions.
   * @throws Exception 	if called before calling kNearestNeighbours or
   * 			nearestNeighbours.
   */
  public double[] getDistances() throws Exception {
    if (m_Instances == null || m_DistanceList == null)
      throw new Exception("The tree has not been supplied with a set of "
          + "instances or getDistances() has been called "
          + "before calling kNearestNeighbours().");
    return m_DistanceList;
  }

  /**
   * Builds the KDTree on the given set of instances.
   * @param instances The insts on which the KDTree is to be
   * built.
   * @throws Exception If some error occurs while
   * building the KDTree
   */
  public void setInstances(Instances instances) throws Exception {
    super.setInstances(instances);
    buildKDTree(instances);
  }

  /**
   * Adds one instance to the KDTree. This updates the KDTree structure to take
   * into account the newly added training instance.
   *
   * @param instance 	the instance to be added. Usually the newly added instance in the
   *          		training set.
   * @throws Exception If the instance cannot be added.
   */
  public void update(Instance instance) throws Exception { // better to change
                                                            // to addInstance
    if (m_Instances == null)
      throw new Exception("No instances supplied yet. Have to call "
          + "setInstances(instances) with a set of Instances " + "first.");

    addInstanceInfo(instance);
    addInstanceToTree(instance, m_Root);
  }

  /**
   * Recursively adds an instance to the tree starting from
   * the supplied KDTreeNode.
   * NOTE: This should not be called by outside classes,
   * outside classes should instead call update(Instance)
   * method.
   *
   * @param inst The instance to add to the tree
   * @param node The node to start the recursive search
   * from, for the leaf node where the supplied instance
   * would go.
   * @throws Exception If some error occurs while adding
   * the instance.
   */
  protected void addInstanceToTree(Instance inst, KDTreeNode node)
      throws Exception {
    if (node.isALeaf()) {
      int instList[] = new int[m_Instances.numInstances()];
      try {
        System.arraycopy(m_InstList, 0, instList, 0, node.m_End + 1); // m_InstList.squeezeIn(m_End,
                                                                      // index);
        if (node.m_End < m_InstList.length - 1)
          System.arraycopy(m_InstList, node.m_End + 1, instList,
              node.m_End + 2, m_InstList.length - node.m_End - 1);
        instList[node.m_End + 1] = m_Instances.numInstances() - 1;
      } catch (ArrayIndexOutOfBoundsException ex) {
        System.err.println("m_InstList.length: " + m_InstList.length
            + " instList.length: " + instList.length + "node.m_End+1: "
            + (node.m_End + 1) + "m_InstList.length-node.m_End+1: "
            + (m_InstList.length - node.m_End - 1));
        throw ex;
      }
      m_InstList = instList;

      node.m_End++;
      node.m_NodeRanges = m_EuclideanDistance.updateRanges(inst,
          node.m_NodeRanges);

      m_Splitter.setInstanceList(m_InstList);

      // split this leaf node if necessary
      double[][] universe = m_EuclideanDistance.getRanges();
      if (node.numInstances() > m_MaxInstInLeaf
          && getMaxRelativeNodeWidth(node.m_NodeRanges, universe) > m_MinBoxRelWidth) {
        m_Splitter.splitNode(node, m_NumNodes, node.m_NodeRanges, universe);
        m_NumNodes += 2;
      }
    }// end if node is a leaf
    else {
      if (m_EuclideanDistance.valueIsSmallerEqual(inst, node.m_SplitDim,
          node.m_SplitValue)) {
        addInstanceToTree(inst, node.m_Left);
        afterAddInstance(node.m_Right);
      } else
        addInstanceToTree(inst, node.m_Right);

      node.m_End++;
      node.m_NodeRanges = m_EuclideanDistance.updateRanges(inst,
          node.m_NodeRanges);
    }
  }

  /**
   * Corrects the start and end indices of a
   * KDTreeNode after an instance is added to
   * the tree. The start and end indices for
   * the master index array (m_InstList)
   * stored in the nodes need to be updated
   * for all nodes in the subtree on the
   * right of a node where the instance
   * was added.
   * NOTE: No outside class should call this
   * method.
   *
   * @param node KDTreeNode whose start and end indices
   * need to be updated.
   */
  protected void afterAddInstance(KDTreeNode node) {
    node.m_Start++;
    node.m_End++;
    if (!node.isALeaf()) {
      afterAddInstance(node.m_Left);
      afterAddInstance(node.m_Right);
    }
  }

  /**
   * Adds one instance to KDTree loosly. It only changes the ranges in
   * EuclideanDistance, and does not affect the structure of the KDTree.
   *
   * @param instance	the new instance. Usually this is the test instance
   * 			supplied to update the range of attributes in the distance function.
   */
  public void addInstanceInfo(Instance instance) {
    m_EuclideanDistance.updateRanges(instance);
  }

  /**
   * Checks if there is any instance with missing values. Throws an exception if
   * there is, as KDTree does not handle missing values.
   *
   * @param instances	the instances to check
   * @throws Exception	if missing values are encountered
   */
  protected void checkMissing(Instances instances) throws Exception {
    for (int i = 0; i < instances.numInstances(); i++) {
      Instance ins = instances.instance(i);
      for (int j = 0; j < ins.numValues(); j++) {
        if (ins.index(j) != ins.classIndex())
          if (ins.isMissingSparse(j)) {
            throw new Exception("ERROR: KDTree can not deal with missing "
                + "values. Please run ReplaceMissingValues filter "
                + "on the dataset before passing it on to the KDTree.");
          }
      }
    }
  }

  /**
   * Checks if there is any missing value in the given
   * instance.
   * @param ins The instance to check missing values in.
   * @throws Exception If there is a missing value in the
   * instance.
   */
  protected void checkMissing(Instance ins) throws Exception {
    for (int j = 0; j < ins.numValues(); j++) {
      if (ins.index(j) != ins.classIndex())
        if (ins.isMissingSparse(j)) {
          throw new Exception("ERROR: KDTree can not deal with missing "
              + "values. Please run ReplaceMissingValues filter "
              + "on the dataset before passing it on to the KDTree.");
        }
    }
  }

  /**
   * Returns the maximum attribute width of instances/points
   * in a KDTreeNode relative to the whole dataset.
   *
   * @param nodeRanges The attribute ranges of the
   * KDTreeNode whose maximum relative width is to be
   * determined.
   * @param universe The attribute ranges of the whole
   * dataset (training instances + test instances so
   * far encountered).
   * @return The maximum relative width
   */
  protected double getMaxRelativeNodeWidth(double[][] nodeRanges,
      double[][] universe) {
    int widest = widestDim(nodeRanges, universe);
    if(widest < 0)
    	return 0.0;
    else
    	return nodeRanges[widest][WIDTH] / universe[widest][WIDTH];
  }

  /**
   * Returns the widest dimension/attribute in a
   * KDTreeNode (widest after normalizing).
   * @param nodeRanges The attribute ranges of
   * the KDTreeNode.
   * @param universe The attribute ranges of the
   * whole dataset (training instances + test
   * instances so far encountered).
   * @return The index of the widest
   * dimension/attribute.
   */
  protected int widestDim(double[][] nodeRanges, double[][] universe) {
    final int classIdx = m_Instances.classIndex();
    double widest = 0.0;
    int w = -1;
    if (m_NormalizeNodeWidth) {
      for (int i = 0; i < nodeRanges.length; i++) {
        double newWidest = nodeRanges[i][WIDTH] / universe[i][WIDTH];
        if (newWidest > widest) {
          if (i == classIdx)
            continue;
          widest = newWidest;
          w = i;
        }
      }
    } else {
      for (int i = 0; i < nodeRanges.length; i++) {
        if (nodeRanges[i][WIDTH] > widest) {
          if (i == classIdx)
            continue;
          widest = nodeRanges[i][WIDTH];
          w = i;
        }
      }
    }
    return w;
  }

  /**
   * Returns the size of the tree.
   *
   * @return 		the size of the tree
   */
  public double measureTreeSize() {
    return m_NumNodes;
  }

  /**
   * Returns the number of leaves.
   *
   * @return 		the number of leaves
   */
  public double measureNumLeaves() {
    return m_NumLeaves;
  }

  /**
   * Returns the depth of the tree.
   *
   * @return The depth of the tree
   */
  public double measureMaxDepth() {
    return m_MaxDepth;
  }

  /**
   * Returns an enumeration of the additional measure names.
   *
   * @return 		an enumeration of the measure names
   */
  public Enumeration<String> enumerateMeasures() {
    Vector<String> newVector = new Vector<String>();
    newVector.addElement("measureTreeSize");
    newVector.addElement("measureNumLeaves");
    newVector.addElement("measureMaxDepth");
    if (m_Stats != null) {
      newVector.addAll(Collections.list(m_Stats.enumerateMeasures()));
    }
    return newVector.elements();
  }

  /**
   * Returns the value of the named measure.
   *
   * @param additionalMeasureName	the name of
   * the measure to query for its value.
   * @return The value of the named measure
   * @throws IllegalArgumentException	If the named measure
   * is not supported.
   */
  public double getMeasure(String additionalMeasureName) {
    if (additionalMeasureName.compareToIgnoreCase("measureMaxDepth") == 0) {
      return measureMaxDepth();
    } else if (additionalMeasureName.compareToIgnoreCase("measureTreeSize") == 0) {
      return measureTreeSize();
    } else if (additionalMeasureName.compareToIgnoreCase("measureNumLeaves") == 0) {
      return measureNumLeaves();
    } else if (m_Stats != null) {
      return m_Stats.getMeasure(additionalMeasureName);
    } else {
      throw new IllegalArgumentException(additionalMeasureName
          + " not supported (KDTree)");
    }
  }

  /**
   * Sets whether to calculate the performance statistics or not.
   * @param measurePerformance Should be true if performance
   * statistics are to be measured.
   */
  public void setMeasurePerformance(boolean measurePerformance) {
    m_MeasurePerformance = measurePerformance;
    if (m_MeasurePerformance) {
      if (m_Stats == null)
        m_Stats = m_TreeStats = new TreePerformanceStats();
    } else
      m_Stats = m_TreeStats = null;
  }

  /**
   * Assigns instances to centers using KDTree.
   *
   * @param centers	the current centers
   * @param assignments	the centerindex for each instance
   * @param pc		the threshold value for pruning.
   * @throws Exception If there is some problem
   * assigning instances to centers.
   */
  public void centerInstances(Instances centers, int[] assignments, double pc)
      throws Exception {

    int[] centList = new int[centers.numInstances()];
    for (int i = 0; i < centers.numInstances(); i++)
      centList[i] = i;

    determineAssignments(m_Root, centers, centList, assignments, pc);
  }

  /**
   * Assigns instances to the current centers called candidates.
   *
   * @param node The node to start assigning the instances from.
   * @param centers	all the current centers.
   * @param candidates	the current centers the method works on.
   * @param assignments	the center index for each instance.
   * @param pc the threshold value for pruning.
   * @throws Exception If there is some problem assigning
   * instances to centers.
   */
  protected void determineAssignments(KDTreeNode node, Instances centers,
      int[] candidates, int[] assignments, double pc) throws Exception {

    // reduce number of owners for current hyper rectangle
    int[] owners = refineOwners(node, centers, candidates);

    // only one owner
    if (owners.length == 1) {
      // all instances of this node are owned by one center
      for (int i = node.m_Start; i <= node.m_End; i++) {
        assignments[m_InstList[i]] // the assignment of this instance
        = owners[0]; // is the current owner
      }
    } else if (!node.isALeaf()) {
      // more than one owner and it is not a leaf
      determineAssignments(node.m_Left, centers, owners, assignments, pc);
      determineAssignments(node.m_Right, centers, owners, assignments, pc);
    } else {
      // this is a leaf and there are more than 1 owner
      // XMeans.
      assignSubToCenters(node, centers, owners, assignments);
    }
  }

  /**
   * Refines the ownerlist.
   *
   * @param node The current tree node.
   * @param centers	all centers
   * @param candidates	the indexes of those centers that are candidates.
   * @return list of owners
   * @throws Exception If some problem occurs in refining.
   */
  protected int[] refineOwners(KDTreeNode node, Instances centers,
      int[] candidates) throws Exception {

    int[] owners = new int[candidates.length];
    double minDistance = Double.POSITIVE_INFINITY;
    int ownerIndex = -1;
    Instance owner;
    int numCand = candidates.length;
    double[] distance = new double[numCand];
    boolean[] inside = new boolean[numCand];
    for (int i = 0; i < numCand; i++) {
      distance[i] = distanceToHrect(node, centers.instance(candidates[i]));
      inside[i] = (distance[i] == 0.0);
      if (distance[i] < minDistance) {
        minDistance = distance[i];
        ownerIndex = i;
      }
    }
    owner = (Instance)centers.instance(candidates[ownerIndex]).copy();

    // are there other owners
    // loop also goes over already found owner, keeps order
    // in owner list
    int index = 0;
    for (int i = 0; i < numCand; i++) {
      // 1. all centers that are points within rectangle are owners
      if ((inside[i])

      // 2. take all points with same distance to the rect. as the owner
          || (distance[i] == distance[ownerIndex])) {

        // add competitor to owners list
        owners[index++] = candidates[i];
      } else {

        Instance competitor = (Instance)centers.instance(candidates[i]).copy();
        if

        // 3. point has larger distance to rectangle but still can compete
        // with owner for some points in the rectangle
        (!candidateIsFullOwner(node, owner, competitor))

        {
          // also add competitor to owners list
          owners[index++] = candidates[i];
        }
      }
    }
    int[] result = new int[index];
    for (int i = 0; i < index; i++)
      result[i] = owners[i];
    return result;
  }

  /**
   * Returns the distance between a point and an hyperrectangle.
   *
   * @param node The current node from whose hyperrectangle
   * the distance is to be measured.
   * @param x		the point
   * @return 		the distance
   * @throws Exception If some problem occurs in determining
   * the distance to the hyperrectangle.
   */
  protected double distanceToHrect(KDTreeNode node, Instance x) throws Exception {
    double distance = 0.0;

    Instance closestPoint = (Instance)x.copy();
    boolean inside;
    inside = clipToInsideHrect(node, closestPoint);
    if (!inside)
      distance = m_EuclideanDistance.distance(closestPoint, x);
    return distance;
  }

  /**
   * Finds the closest point in the hyper rectangle to a given point. Change the
   * given point to this closest point by clipping of at all the dimensions to
   * be clipped of. If the point is inside the rectangle it stays unchanged. The
   * return value is true if the point was not changed, so the the return value
   * is true if the point was inside the rectangle.
   *
   * @param node The current KDTreeNode in whose hyperrectangle the closest
   * point is to be found.
   * @param x		a point
   * @return 		true if the input point stayed unchanged.
   */
  protected boolean clipToInsideHrect(KDTreeNode node, Instance x) {
    boolean inside = true;
    for (int i = 0; i < m_Instances.numAttributes(); i++) {
      // TODO treat nominals differently!??

      if (x.value(i) < node.m_NodeRanges[i][MIN]) {
        x.setValue(i, node.m_NodeRanges[i][MIN]);
        inside = false;
      } else if (x.value(i) > node.m_NodeRanges[i][MAX]) {
        x.setValue(i, node.m_NodeRanges[i][MAX]);
        inside = false;
      }
    }
    return inside;
  }

  /**
   * Returns true if candidate is a full owner in respect to a competitor.
   *

   *
   * The candidate has been the closer point to the current rectangle or even
   * has been a point within the rectangle. The competitor is competing with the
   * candidate for a few points out of the rectangle although it is a point
   * further away from the rectangle then the candidate. The extrem point is the
   * corner of the rectangle that is furthest away from the candidate towards
   * the direction of the competitor.
   *
   * If the distance candidate to this extreme point is smaller then the
   * distance competitor to this extreme point, then it is proven that none of
   * the points in the rectangle can be owned be the competitor and the
   * candidate is full owner of the rectangle in respect to this competitor. See
   * also D. Pelleg and A. Moore's paper 'Accelerating exact k-means Algorithms
   * with Geometric Reasoning'.
   *

   *
   * @param node The current KDTreeNode / hyperrectangle.
   * @param candidate	instance that is candidate to be owner
   * @param competitor	instance that competes against the candidate
   * @return 		true if candidate is full owner
   * @throws Exception If some problem occurs.
   */
  protected boolean candidateIsFullOwner(KDTreeNode node, Instance candidate,
      Instance competitor) throws Exception {
    // get extreme point
    Instance extreme = (Instance)candidate.copy();
    for (int i = 0; i < m_Instances.numAttributes(); i++) {
      if ((competitor.value(i) - candidate.value(i)) > 0) {
        extreme.setValue(i, node.m_NodeRanges[i][MAX]);
      } else {
        extreme.setValue(i, node.m_NodeRanges[i][MIN]);
      }
    }
    boolean isFullOwner = m_EuclideanDistance.distance(extreme, candidate) < m_EuclideanDistance
        .distance(extreme, competitor);

    return isFullOwner;
  }

  /**
   * Assigns instances of this node to center. Center to be assign to is decided
   * by the distance function.
   *
   * @param node The KDTreeNode whose instances are to be assigned.
   * @param centers	all the input centers
   * @param centList	the list of centers to work with
   * @param assignments	index list of last assignments
   * @throws Exception If there is error assigning the instances.
   */
  public void assignSubToCenters(KDTreeNode node, Instances centers,
      int[] centList, int[] assignments) throws Exception {
    // todo: undecided situations

    // WARNING: assignments is "input/output-parameter"
    // should not be null and the following should not happen
    if (assignments == null) {
      assignments = new int[m_Instances.numInstances()];
      for (int i = 0; i < assignments.length; i++) {
        assignments[i] = -1;
      }
    }

    // set assignments for all instances of this node
    for (int i = node.m_Start; i <= node.m_End; i++) {
      int instIndex = m_InstList[i];
      Instance inst = m_Instances.instance(instIndex);
      // if (instList[i] == 664) System.out.println("664***");
      int newC = m_EuclideanDistance.closestPoint(inst, centers, centList);
      // int newC = clusterProcessedInstance(inst, centers);
      assignments[instIndex] = newC;
    }
  }

  /**
   * Properties' variables =====================================================
   */

  /** flag for normalizing. */
  boolean m_NormalizeNodeWidth = true;

  /** The euclidean distance function to use. */
  protected EuclideanDistance m_EuclideanDistance;
  { // to make sure we have only one object of EuclideanDistance
    if (m_DistanceFunction instanceof EuclideanDistance)
      m_EuclideanDistance = (EuclideanDistance) m_DistanceFunction;
    else
      m_DistanceFunction = m_EuclideanDistance = new EuclideanDistance();
  }

  /** minimal relative width of a KDTree rectangle. */
  protected double m_MinBoxRelWidth = 1.0E-2;

  /** maximal number of instances in a leaf. */
  protected int m_MaxInstInLeaf = 40;

  /**
   * the GET and SET - functions ===============================================
   */

  /**
   * Tip text for this property.
   *
   * @return 		the tip text for this property
   */
  public String minBoxRelWidthTipText() {
    return "The minimum relative width of the box. A node is only made a leaf "
        + "if the width of the split dimension of the instances in a node "
        + "normalized over the width of the split dimension of all the "
        + "instances is less than or equal to this minimum relative width.";
  }

  /**
   * Sets the minimum relative box width.
   *
   * @param i		the minimum relative box width
   */
  public void setMinBoxRelWidth(double i) {
    m_MinBoxRelWidth = i;
  }

  /**
   * Gets the minimum relative box width.
   *
   * @return 		the minimum relative box width
   */
  public double getMinBoxRelWidth() {
    return m_MinBoxRelWidth;
  }

  /**
   * Tip text for this property.
   *
   * @return 		the tip text for this property
   */
  public String maxInstInLeafTipText() {
    return "The max number of instances in a leaf.";
  }

  /**
   * Sets the maximum number of instances in a leaf.
   *
   * @param i		the maximum number of instances in a leaf
   */
  public void setMaxInstInLeaf(int i) {
    m_MaxInstInLeaf = i;
  }

  /**
   * Get the maximum number of instances in a leaf.
   *
   * @return 		the maximum number of instances in a leaf
   */
  public int getMaxInstInLeaf() {
    return m_MaxInstInLeaf;
  }

  /**
   * Tip text for this property.
   *
   * @return 		the tip text for this property
   */
  public String normalizeNodeWidthTipText() {
    return "Whether if the widths of the KDTree node should be normalized "
        + "by the width of the universe or not. "
        + "Where, width of the node is the range of the split attribute "
        + "based on the instances in that node, and width of the "
        + "universe is the range of the split attribute based on all the "
        + "instances (default: false).";
  }

  /**
   * Sets the flag for normalizing the widths of a KDTree Node by the width of
   * the dimension in the universe.
   *
   * @param n		true to use normalizing.
   */
  public void setNormalizeNodeWidth(boolean n) {
    m_NormalizeNodeWidth = n;
  }

  /**
   * Gets the normalize flag.
   *
   * @return 		True if normalizing
   */
  public boolean getNormalizeNodeWidth() {
    return m_NormalizeNodeWidth;
  }

  /**
   * returns the distance function currently in use.
   *
   * @return 		the distance function
   */
  public DistanceFunction getDistanceFunction() {
    return (DistanceFunction) m_EuclideanDistance;
  }

  /**
   * sets the distance function to use for nearest neighbour search.
   *
   * @param df		the distance function to use
   * @throws Exception	if not EuclideanDistance
   */
  public void setDistanceFunction(DistanceFunction df) throws Exception {
    if (!(df instanceof EuclideanDistance))
      throw new Exception("KDTree currently only works with "
          + "EuclideanDistanceFunction.");
    m_DistanceFunction = m_EuclideanDistance = (EuclideanDistance) df;
  }

  /**
   * Returns the tip text for this property.
   *
   * @return 		tip text for this property suitable for
   * 			displaying in the explorer/experimenter gui
   */
  public String nodeSplitterTipText() {
    return "The the splitting method to split the nodes of the KDTree.";
  }

  /**
   * Returns the splitting method currently in use to split the nodes of the
   * KDTree.
   *
   * @return The KDTreeNodeSplitter currently in use.
   */
  public KDTreeNodeSplitter getNodeSplitter() {
    return m_Splitter;
  }

  /**
   * Sets the splitting method to use to split the nodes of the KDTree.
   *
   * @param splitter The KDTreeNodeSplitter to use.
   */
  public void setNodeSplitter(KDTreeNodeSplitter splitter) {
    m_Splitter = splitter;
  }

  /**
   * Returns a string describing this nearest neighbour search algorithm.
   *
   * @return 		a description of the algorithm for displaying in the
   *         		explorer/experimenter gui
   */
  public String globalInfo() {
    return
        "Class implementing the KDTree search algorithm for nearest "
      + "neighbour search.\n"
      + "The connection to dataset is only a reference. For the tree "
      + "structure the indexes are stored in an array. \n"
      + "Building the tree:\n"
      + "If a node has <maximal-inst-number> (option -L) instances no "
      + "further splitting is done. Also if the split would leave one "
      + "side empty, the branch is not split any further even if the "
      + "instances in the resulting node are more than "
      + "<maximal-inst-number> instances.\n"
      + "**PLEASE NOTE:** The algorithm can not handle missing values, so it "
      + "is advisable to run ReplaceMissingValues filter if there are any "
      + "missing values in the dataset.\n\n"
      + "For more information see:\n\n"
      + getTechnicalInformation().toString();
  }

  /**
   * Returns an enumeration describing the available options.
   *
   * @return an enumeration of all the available options.
   */
  public Enumeration<Option> listOptions() {
    Vector<Option> newVector = new Vector<Option>();

    newVector.add(new Option(
	"\tNode splitting method to use.\n"
	+ "\t(default: weka.core.neighboursearch.kdtrees.SlidingMidPointOfWidestSide)",
	"S", 1, "-S <classname and options>"));

    newVector.addElement(new Option(
	"\tSet minimal width of a box\n"
        + "\t(default: 1.0E-2).",
        "W", 0, "-W <value>"));

    newVector.addElement(new Option(
	"\tMaximal number of instances in a leaf\n"
        + "\t(default: 40).",
        "L", 0, "-L"));

    newVector.addElement(new Option(
	"\tNormalizing will be done\n"
        + "\t(Select dimension for split, with normalising to universe).",
        "N", 0, "-N"));

    newVector.addAll(Collections.list(super.listOptions()));

    return newVector.elements();
  }

  /**
   * Parses a given list of options.

   *

   * Valid options are:

   *
   *
 -S <classname and options>
   *  Node splitting method to use.
   *  (default: weka.core.neighboursearch.kdtrees.SlidingMidPointOfWidestSide)

   *
   *
 -W <value>
   *  Set minimal width of a box
   *  (default: 1.0E-2).

   *
   *
 -L
   *  Maximal number of instances in a leaf
   *  (default: 40).

   *
   *
 -N
   *  Normalizing will be done
   *  (Select dimension for split, with normalising to universe).

   *

   *
   * @param options	the list of options as an array of strings
   * @throws Exception	if an option is not supported
   */
  public void setOptions(String[] options) throws Exception {
    super.setOptions(options);

    String optionString = Utils.getOption('S', options);
    if (optionString.length() != 0) {
      String splitMethodSpec[] = Utils.splitOptions(optionString);
      if (splitMethodSpec.length == 0) {
        throw new Exception("Invalid DistanceFunction specification string.");
      }
      String className = splitMethodSpec[0];
      splitMethodSpec[0] = "";

      setNodeSplitter((KDTreeNodeSplitter) Utils.forName(
          KDTreeNodeSplitter.class, className, splitMethodSpec));
    }
    else {
      setNodeSplitter(new SlidingMidPointOfWidestSide());
    }

    optionString = Utils.getOption('W', options);
    if (optionString.length() != 0)
      setMinBoxRelWidth(Double.parseDouble(optionString));
    else
      setMinBoxRelWidth(1.0E-2);

    optionString = Utils.getOption('L', options);
    if (optionString.length() != 0)
      setMaxInstInLeaf(Integer.parseInt(optionString));
    else
      setMaxInstInLeaf(40);

    setNormalizeNodeWidth(Utils.getFlag('N', options));

    Utils.checkForRemainingOptions(options);
  }

  /**
   * Gets the current settings of KDtree.
   *
   * @return 		an array of strings suitable for passing to setOptions
   */
  public String[] getOptions() {
    Vector<String>	result;
    String[]		options;
    int			i;

    result = new Vector<String>();

    options = super.getOptions();
    for (i = 0; i < options.length; i++)
      result.add(options[i]);

    result.add("-S");
    result.add(
	(m_Splitter.getClass().getName() + " " +
	 Utils.joinOptions(m_Splitter.getOptions())).trim());

    result.add("-W");
    result.add("" + getMinBoxRelWidth());

    result.add("-L");
    result.add("" + getMaxInstInLeaf());

    if (getNormalizeNodeWidth())
      result.add("-N");

    return result.toArray(new String[result.size()]);
  }

  /**
   * Returns the revision string.
   *
   * @return		the revision
   */
  public String getRevision() {
    return RevisionUtils.extract("$Revision: 10141 $");
  }
}


text:
===================
CAPseq Pipeline
===================

Contents:

.. toctree::
   :maxdepth: 2

   pipeline/Methods.rst
   pipeline/genome_composition.rst
   pipeline/predicted_cgis.rst
   pipeline/Mapping.rst
   pipeline/macs.rst
   pipeline/macs_replicated_intervals.rst
   pipeline/macs_replicated_intervals_per_contig.rst
   pipeline/macs_replicated_interval_genomic_features.rst
   pipeline/macs_replicated_interval_noncoding.rst
   pipeline/macs_replicated_genes_with_nmi.rst
   pipeline/macs_replicated_interval_tss_distance.rst
   pipeline/macs_replicated_interval_rnaseq_tss.rst
   pipeline/peakshape.rst
   pipeline/macs_replicated_unique_interval_chromatin_profile.rst
   pipeline/macs_replicated_interval_comparison.rst
   pipeline/macs_replicated_tissue_specific_intervals.rst
   pipeline/macs_replicated_unique_intervals.rst
   pipeline/macs_replicated_shared_intervals.rst
   pipeline/macs_tss_intervals.rst
   pipeline/macs_cgi_intervals.rst
   pipeline/macs_long_intervals.rst
   pipeline/macs_low_cpg_intervals.rst
   pipeline/macs_genomic_features.rst
   pipeline/macs_tss_distance.rst
   pipeline/macs_intervals.rst
   pipeline/macs_interval_comparison.rst
   pipeline/macs_unique_intervals.rst
   pipeline/macs_shared_intervals.rst
   pipeline/macs_parameter_correlation.rst
.. errorlist::

redpajama_set_name: RedPajamaGithub


text:
namespace mclib::abl {

//***************************************************************************

extern TokenCodeType curToken;
extern wchar_t wordString[];
extern Literal curLiteral;

extern const std::unique_ptr<SymTableNode>& SymTableDisplay[];
extern int32_t level;

extern const std::unique_ptr<Type>& IntegerTypePtr;
extern const std::unique_ptr<Type>& CharTypePtr;
extern const std::unique_ptr<Type>& RealTypePtr;
extern const std::unique_ptr<Type>& BooleanTypePtr;

extern TokenCodeType declarationStartList[];
extern TokenCodeType statementStartList[];

extern int32_t eternalOffset;
extern int32_t NumStaticVariables;
extern int32_t MaxStaticVariables;
extern int32_t* StaticVariablesSizes;
extern int32_t* EternalVariablesSizes;
extern const std::unique_ptr<ABLModule>& CurLibrary;

//***************************************************************************

TokenCodeType followRoutineList[] = {TKN_SEMICOLON, TKN_EOF, TKN_NONE};

TokenCodeType followDeclarationList[] = {TKN_SEMICOLON, TKN_IDENTIFIER, TKN_EOF, TKN_NONE};

TokenCodeType followVariablesList[] = {TKN_SEMICOLON, TKN_IDENTIFIER, TKN_EOF, TKN_NONE};

TokenCodeType followVarBlockList[] = {
	TKN_FUNCTION, TKN_ORDER, TKN_STATE, TKN_CODE, TKN_EOF, TKN_NONE};

TokenCodeType followDimensionList[] = {TKN_COMMA, TKN_RBRACKET, TKN_EOF, TKN_NONE};

TokenCodeType indexTypeStartList[] = {TKN_IDENTIFIER, TKN_NUMBER, TKN_NONE};

TokenCodeType followIndexesList[] = {TKN_OF, TKN_IDENTIFIER, TKN_LPAREN, TKN_PLUS, TKN_MINUS,
	TKN_NUMBER, TKN_SEMICOLON, TKN_EOF, TKN_NONE};

//***************************************************************************
// MISC. routines
//***************************************************************************

void
ifTokenGet(TokenCodeType tokenCode)
{
	if (curToken == tokenCode)
		getToken();
}

//***************************************************************************

void
ifTokenGetElseError(TokenCodeType tokenCode, SyntaxErrorType errorCode)
{
	if (curToken == tokenCode)
		getToken();
	else
		syntaxError(errorCode);
}

//***************************************************************************
// DECLARATIONS routines
//***************************************************************************

void
declarations(const std::unique_ptr<SymTableNode>& routineIdPtr, bool allowFunctions)
{
	if (curToken == TKN_CONST)
	{
		getToken();
		constDefinitions();
	}
	if (curToken == TKN_TYPE)
	{
		getToken();
		typeDefinitions();
	}
	if (curToken == TKN_VAR)
	{
		getToken();
		varDeclarations(routineIdPtr);
	}
	//---------------------------------------------------
	// Loop to process all of the function definitions...
	if (allowFunctions)
		while ((curToken == TKN_FUNCTION) || (curToken == TKN_ORDER) || (curToken == TKN_STATE))
		{
			routine();
			//---------------------
			// Error synchronize...
			synchronize(followRoutineList, declarationStartList, statementStartList);
			if (curToken == TKN_SEMICOLON)
				getToken();
			else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
				syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
		}
	else if ((curToken == TKN_FUNCTION) || (curToken == TKN_ORDER) || (curToken == TKN_STATE))
		syntaxError(ABL_ERR_SYNTAX_NO_FUNCTION_NESTING);
}

//***************************************************************************
// CONST routines
//***************************************************************************

void
constDefinitions(void)
{
	//-------------------------------------------------------
	// Loop to process definitions separated by semicolons...
	while (curToken == TKN_IDENTIFIER)
	{
		const std::unique_ptr<SymTableNode>& constantIdPtr;
		searchAndEnterLocalSymTable(constantIdPtr);
		constantIdPtr->defn.key = DFN_CONST;
		constantIdPtr->library = CurLibrary;
		getToken();
		ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL);
		doConst(constantIdPtr);
		analyzeConstDefn(constantIdPtr);
		//---------------------------------
		// Error synchronize: should be a ;
		synchronize(followDeclarationList, declarationStartList, statementStartList);
		if (curToken == TKN_SEMICOLON)
			getToken();
		else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
			syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
	}
}

//***************************************************************************

const std::unique_ptr<Type>&
makeStringType(int32_t length)
{
	const std::unique_ptr<Type>& stringTypePtr = createType();
	if (!stringTypePtr)
		ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc stringType ");
	stringTypePtr->form = FRM_ARRAY;
	stringTypePtr->size = length;
	stringTypePtr->typeIdPtr = nullptr;
	stringTypePtr->info.array.indexTypePtr = IntegerTypePtr;
	stringTypePtr->info.array.elementTypePtr = CharTypePtr;
	stringTypePtr->info.array.elementCount = length + 1;
	return (stringTypePtr);
}

//***************************************************************************

void
doConst(const std::unique_ptr<SymTableNode>& constantIdPtr)
{
	TokenCodeType sign = TKN_PLUS;
	bool sawSign = false;
	if ((curToken == TKN_PLUS) || (curToken == TKN_MINUS))
	{
		sign = curToken;
		sawSign = true;
		getToken();
	}
	//----------------------------------
	// Numeric constant: real or integer
	if (curToken == TKN_NUMBER)
	{
		if (curLiteral.type == LIT_INTEGER)
		{
			if (sign == TKN_PLUS)
				constantIdPtr->defn.info.constant.value.integer = curLiteral.value.integer;
			else
				constantIdPtr->defn.info.constant.value.integer = -(curLiteral.value.integer);
			constantIdPtr->ptype = setType(IntegerTypePtr);
		}
		else
		{
			if (sign == TKN_PLUS)
				constantIdPtr->defn.info.constant.value.real = curLiteral.value.real;
			else
				constantIdPtr->defn.info.constant.value.real = -(curLiteral.value.real);
			constantIdPtr->ptype = setType(RealTypePtr);
		}
	}
	else if (curToken == TKN_IDENTIFIER)
	{
		const std::unique_ptr<SymTableNode>& idPtr = nullptr;
		searchAllSymTables(idPtr);
		if (!idPtr)
			syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
		else if (idPtr->defn.key != DFN_CONST)
			syntaxError(ABL_ERR_SYNTAX_NOT_A_CONSTANT_IDENTIFIER);
		else if (idPtr->ptype == IntegerTypePtr)
		{
			if (sign == TKN_PLUS)
				constantIdPtr->defn.info.constant.value.integer =
					idPtr->defn.info.constant.value.integer;
			else
				constantIdPtr->defn.info.constant.value.integer =
					-(idPtr->defn.info.constant.value.integer);
			constantIdPtr->ptype = setType(IntegerTypePtr);
		}
		else if (idPtr->ptype == CharTypePtr)
		{
			if (sawSign)
				syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
			constantIdPtr->defn.info.constant.value.character =
				idPtr->defn.info.constant.value.character;
			constantIdPtr->ptype = setType(CharTypePtr);
		}
		else if (idPtr->ptype == RealTypePtr)
		{
			if (sign == TKN_PLUS)
				constantIdPtr->defn.info.constant.value.real = idPtr->defn.info.constant.value.real;
			else
				constantIdPtr->defn.info.constant.value.real =
					-(idPtr->defn.info.constant.value.real);
			constantIdPtr->ptype = setType(RealTypePtr);
		}
		else if (((Type*)(idPtr->ptype))->form == FRM_ENUM)
		{
			if (sawSign)
				syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
			constantIdPtr->defn.info.constant.value.integer =
				idPtr->defn.info.constant.value.integer;
			constantIdPtr->ptype = setType(idPtr->ptype);
		}
		else if (((const std::unique_ptr<Type>&)(idPtr->ptype))->form == FRM_ARRAY)
		{
			if (sawSign)
				syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
			constantIdPtr->defn.info.constant.value.stringPtr =
				idPtr->defn.info.constant.value.stringPtr;
			constantIdPtr->ptype = setType(idPtr->ptype);
		}
	}
	else if (curToken == TKN_STRING)
	{
		if (sawSign)
			syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
		if (strlen(curLiteral.value.string) == 1)
		{
			constantIdPtr->defn.info.constant.value.character = curLiteral.value.string[0];
			constantIdPtr->ptype = setType(CharTypePtr);
		}
		else
		{
			int32_t length = strlen(curLiteral.value.string);
			constantIdPtr->defn.info.constant.value.stringPtr =
				(const std::wstring_view&)ABLSymbolMallocCallback(length + 1);
			if (!constantIdPtr->defn.info.constant.value.stringPtr)
				ABL_Fatal(0,
					" ABL: Unable to AblSymbolHeap->malloc array "
					"string constant ");
			strcpy(constantIdPtr->defn.info.constant.value.stringPtr, curLiteral.value.string);
			constantIdPtr->ptype = makeStringType(length);
		}
	}
	else
	{
		constantIdPtr->ptype = nullptr;
		syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
	}
	getToken();
}

//***************************************************************************
// TYPE routines
//***************************************************************************

//---------------------------------------------------------------------------
// Need to implement type routines if we allow user-defined types, and/or the
// PASCAL style array types (otherwise, arrays should be implemented in the
// var routines...

void
typeDefinitions(void)
{
	while (curToken == TKN_IDENTIFIER)
	{
		const std::unique_ptr<SymTableNode>& typeIdPtr;
		searchAndEnterLocalSymTable(typeIdPtr);
		typeIdPtr->defn.key = DFN_TYPE;
		typeIdPtr->library = CurLibrary;
		getToken();
		ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL);
		//----------------------------------
		// Process the type specification...
		typeIdPtr->ptype = doType();
		if (typeIdPtr->ptype->typeIdPtr == nullptr)
			typeIdPtr->ptype->typeIdPtr = typeIdPtr;
		analyzeTypeDefn(typeIdPtr);
		//---------------
		// Error synch...
		synchronize(followDeclarationList, declarationStartList, statementStartList);
		if (curToken == TKN_SEMICOLON)
			getToken();
		else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
			syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
	}
}

//***************************************************************************

const std::unique_ptr<Type>&
doType(void)
{
	switch (curToken)
	{
	case TKN_IDENTIFIER:
	{
		const std::unique_ptr<SymTableNode>& idPtr;
		searchAllSymTables(idPtr);
		if (!idPtr)
		{
			syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
			return (nullptr);
		}
		else if (idPtr->defn.key == DFN_TYPE)
		{
			//----------------------------------------------------------
			// NOTE: Array types should be parsed in this case if a left
			// bracket follows the type identifier.
			const std::unique_ptr<Type>& elementType = setType(identifierType(idPtr));
			if (curToken == TKN_LBRACKET)
			{
				//--------------
				// Array type...
				const std::unique_ptr<Type>& ptype = createType();
				if (!ptype)
					ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc array type ");
				const std::unique_ptr<Type>& elementTypePtr = ptype;
				do
				{
					getToken();
					if (tokenIn(indexTypeStartList))
					{
						elementTypePtr->form = FRM_ARRAY;
						elementTypePtr->size = 0;
						elementTypePtr->typeIdPtr = nullptr;
						//----------------------------------------------
						// All array indices must be integer, for now...
						elementTypePtr->info.array.indexTypePtr = setType(IntegerTypePtr);
						//------------------------
						// Read the index count...
						switch (curToken)
						{
						case TKN_NUMBER:
							if (curLiteral.type == LIT_INTEGER)
								elementTypePtr->info.array.elementCount = curLiteral.value.integer;
							else
							{
								elementTypePtr->form = FRM_NONE;
								elementTypePtr->size = 0;
								elementTypePtr->typeIdPtr = nullptr;
								elementTypePtr->info.array.indexTypePtr = nullptr;
								syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
							}
							getToken();
							break;
						case TKN_IDENTIFIER:
						{
							const std::unique_ptr<SymTableNode>& idPtr;
							searchAllSymTables(idPtr);
							if (idPtr == nullptr)
								syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
							else if (idPtr->defn.key == DFN_CONST)
							{
								if (idPtr->ptype == IntegerTypePtr)
									elementTypePtr->info.array.elementCount =
										idPtr->defn.info.constant.value.integer;
								else
								{
									elementTypePtr->form = FRM_NONE;
									elementTypePtr->size = 0;
									elementTypePtr->typeIdPtr = nullptr;
									elementTypePtr->info.array.indexTypePtr = nullptr;
									syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
								}
							}
							else
							{
								elementTypePtr->form = FRM_NONE;
								elementTypePtr->size = 0;
								elementTypePtr->typeIdPtr = nullptr;
								elementTypePtr->info.array.indexTypePtr = nullptr;
								syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
							}
							getToken();
						}
						break;
						default:
							elementTypePtr->form = FRM_NONE;
							elementTypePtr->size = 0;
							elementTypePtr->typeIdPtr = nullptr;
							elementTypePtr->info.array.indexTypePtr = nullptr;
							syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
							getToken();
						}
					}
					else
					{
						elementTypePtr->form = FRM_NONE;
						elementTypePtr->size = 0;
						elementTypePtr->typeIdPtr = nullptr;
						elementTypePtr->info.array.indexTypePtr = nullptr;
						syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE);
						getToken();
					}
					synchronize(followDimensionList, nullptr, nullptr);
					//--------------------------------
					// Create an array element type...
					if (curToken == TKN_COMMA)
					{
						elementTypePtr = elementTypePtr->info.array.elementTypePtr = createType();
						if (!elementTypePtr)
							ABL_Fatal(0,
								" ABL: Unable to AblStackHeap->malloc "
								"array element Type ");
					}
				} while (curToken == TKN_COMMA);
				ifTokenGetElseError(TKN_RBRACKET, ABL_ERR_SYNTAX_MISSING_RBRACKET);
				elementTypePtr->info.array.elementTypePtr = elementType;
				ptype->size = arraySize(ptype);
				elementType = ptype;
			}
			return (elementType);
		}
		else
		{
			syntaxError(ABL_ERR_SYNTAX_NOT_A_TYPE_IDENTIFIER);
			return (nullptr);
		}
	}
	break;
	case TKN_LPAREN:
		return (enumerationType());
	default:
		syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE);
		return (nullptr);
	}
}

//***************************************************************************

const std::unique_ptr<Type>&
identifierType(const std::unique_ptr<SymTableNode>& idPtr)
{
	const std::unique_ptr<Type>& ptype = (const std::unique_ptr<Type>&)idPtr->ptype;
	getToken();
	return (ptype);
}

//***************************************************************************

const std::unique_ptr<Type>&
enumerationType(void)
{
	const std::unique_ptr<SymTableNode>& constantIdPtr = nullptr;
	const std::unique_ptr<SymTableNode>& lastIdPtr = nullptr;
	const std::unique_ptr<Type>& ptype = createType();
	if (!ptype)
		ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc enumeration type ");
	int32_t constantValue = -1;
	ptype->form = FRM_ENUM;
	ptype->size = sizeof(int32_t);
	ptype->typeIdPtr = nullptr;
	getToken();
	//------------------------------------------------------------
	// Process list of identifiers in this new enumeration type...
	while (curToken == TKN_IDENTIFIER)
	{
		searchAndEnterLocalSymTable(constantIdPtr);
		constantIdPtr->defn.key = DFN_CONST;
		constantIdPtr->defn.info.constant.value.integer = ++constantValue;
		constantIdPtr->ptype = ptype;
		constantIdPtr->library = CurLibrary;
		if (lastIdPtr == nullptr)
			ptype->info.enumeration.constIdPtr = lastIdPtr = constantIdPtr;
		else
		{
			lastIdPtr->next = constantIdPtr;
			lastIdPtr = constantIdPtr;
		}
		getToken();
		ifTokenGet(TKN_COMMA);
	}
	ifTokenGetElseError(TKN_RPAREN, ABL_ERR_SYNTAX_MISSING_RPAREN);
	ptype->info.enumeration.max = constantValue;
	return (ptype);
}

//***************************************************************************

int32_t
arraySize(const std::unique_ptr<Type>& ptype)
{
	if (ptype->info.array.elementTypePtr->size == 0)
		ptype->info.array.elementTypePtr->size = arraySize(ptype->info.array.elementTypePtr);
	if (ptype->info.array.elementCount == -1)
	{
		//--------------------------------------------------------------
		// Open array, so just return the size of its element. Remember,
		// open arrays must be open at the end...
		ptype->size = ptype->info.array.elementTypePtr->size;
	}
	else
		ptype->size = ptype->info.array.elementCount * ptype->info.array.elementTypePtr->size;
	return (ptype->size);
}

//***************************************************************************
// VAR routines
//***************************************************************************

void
varDeclarations(const std::unique_ptr<SymTableNode>& routineIdPtr)
{
	varOrFieldDeclarations(
		routineIdPtr, STACK_FRAME_HEADER_SIZE + routineIdPtr->defn.info.routine.paramCount);
}

//***************************************************************************

void
varOrFieldDeclarations(const std::unique_ptr<SymTableNode>& routineIdPtr, int32_t offset)
{
	bool varFlag = (routineIdPtr != nullptr);
	const std::unique_ptr<SymTableNode>& idPtr = nullptr;
	const std::unique_ptr<SymTableNode>& firstIdPtr = nullptr;
	const std::unique_ptr<SymTableNode>& lastIdPtr = nullptr;
	const std::unique_ptr<SymTableNode>& prevLastIdPtr = nullptr;
	int32_t totalSize = 0;
	while ((curToken == TKN_IDENTIFIER) || (curToken == TKN_ETERNAL) || (curToken == TKN_STATIC))
	{
		VariableType varType = VAR_TYPE_NORMAL;
		if ((curToken == TKN_ETERNAL) || (curToken == TKN_STATIC))
		{
			if (curToken == TKN_ETERNAL)
				varType = VAR_TYPE_ETERNAL;
			else
				varType = VAR_TYPE_STATIC;
			getToken();
			if (curToken != TKN_IDENTIFIER)
				syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
		}
		firstIdPtr = nullptr;
		//------------------------------
		// Process the variable type...
		const std::unique_ptr<Type>& ptype = doType();
		//------------------------------------------------------------------
		// Since we haven't really assigned it here, decrement its
		// numInstances. Every variable in this list will set it properly...
		ptype->numInstances--;
		int32_t size = ptype->size;
		//-------------------------------------------------------
		// Now that we've read the type, read in the variable (or
		// possibly list of variables) declared of this type.
		// Loop to process every variable (and field, if records
		// are being implemented:) in sublist...
		while (curToken == TKN_IDENTIFIER)
		{
			if (varFlag)
			{
				//---------------------------------------------
				// We're working with a variable declaration...
				if (varType == VAR_TYPE_ETERNAL)
				{
					int32_t curLevel = level;
					level = 0;
					searchAndEnterThisTable(idPtr, SymTableDisplay[0]);
					level = curLevel;
				}
				else
					searchAndEnterLocalSymTable(idPtr);
				idPtr->library = CurLibrary;
				idPtr->defn.key = DFN_VAR;
			}
			else
				syntaxError(ABL_ERR_SYNTAX_NO_RECORD_TYPES);
			idPtr->labelIndex = 0;
			//------------------------------------------
			// Now, link Id's together into a sublist...
			if (!firstIdPtr)
			{
				firstIdPtr = lastIdPtr = idPtr;
				if (varFlag && (varType != VAR_TYPE_ETERNAL) && (routineIdPtr->defn.info.routine.locals == nullptr))
					routineIdPtr->defn.info.routine.locals = idPtr;
			}
			else
			{
				lastIdPtr->next = idPtr;
				lastIdPtr = idPtr;
			}
			getToken();
			ifTokenGet(TKN_COMMA);
		}
		//--------------------------------------------------------------------------
		// Assign the offset and the type to all variable or field Ids in
		// sublist...
		for (idPtr = firstIdPtr; idPtr != nullptr; idPtr = idPtr->next)
		{
			idPtr->ptype = setType(ptype);
			if (varFlag)
			{
				idPtr->defn.info.data.varType = varType;
				switch (varType)
				{
				case VAR_TYPE_NORMAL:
					totalSize += size;
					idPtr->defn.info.data.offset = offset++;
					break;
				case VAR_TYPE_ETERNAL:
				{
					idPtr->defn.info.data.offset = eternalOffset;
					//-----------------------------------
					// Initialize the variable to zero...
					const std::unique_ptr<StackItem>& dataPtr = (const std::unique_ptr<StackItem>&)stack + eternalOffset;
					if (ptype->form == FRM_ARRAY)
					{
						dataPtr->address = (Address)ABLStackMallocCallback((size_t)size);
						if (!dataPtr->address)
							ABL_Fatal(0,
								" ABL: Unable to AblStackHeap->malloc "
								"eternal array ");
						memset(dataPtr->address, 0, size);
						EternalVariablesSizes[eternalOffset] = size;
					}
					else
					{
						dataPtr->integer = 0;
						EternalVariablesSizes[eternalOffset] = 0;
					}
					eternalOffset++;
				}
				break;
				case VAR_TYPE_STATIC:
				{
					if (NumStaticVariables == MaxStaticVariables)
						syntaxError(ABL_ERR_SYNTAX_TOO_MANY_STATIC_VARS);
					idPtr->defn.info.data.offset = NumStaticVariables;
					if (ptype->form == FRM_ARRAY)
						StaticVariablesSizes[NumStaticVariables] = size;
					else
						StaticVariablesSizes[NumStaticVariables] = 0;
					NumStaticVariables++;
				}
				break;
				}
				analyzeVarDecl(idPtr);
			}
			else
			{
				//----------------
				// record field...
				idPtr->defn.info.data.varType = VAR_TYPE_NORMAL;
				idPtr->defn.info.data.offset = offset;
				offset += size;
			}
		}
		//--------------------------------------------------
		// Now, link this sublist to the previous sublist...
		if (varType != VAR_TYPE_ETERNAL)
		{
			if (prevLastIdPtr != nullptr)
				prevLastIdPtr->next = firstIdPtr;
			prevLastIdPtr = lastIdPtr;
		}
		//---------------------
		// Error synchronize...
		if (varFlag)
			synchronize(followVariablesList, declarationStartList, statementStartList);
		if (curToken == TKN_SEMICOLON)
			getToken();
		else if (varFlag && (tokenIn(declarationStartList) || tokenIn(statementStartList)))
			syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
	}
	synchronize(followVarBlockList, nullptr, nullptr);
	if (varFlag)
	{
		//----------------------------------------------------------------
		// If the following error occurs too frequently, simply make the
		// totalLocalSize field an uint32_t instead, and dramatically
		// increase the totalSize limit here...
		if (totalSize > 32000)
			syntaxError(ABL_ERR_SYNTAX_TOO_MANY_LOCAL_VARIABLES);
		routineIdPtr->defn.info.routine.totalLocalSize = (uint16_t)totalSize;
	}
}

//***************************************************************************

} // namespace mclib::abl


text:
/**
 * Detailed explanation of the code can be found here: http://javascript.boxsheep.com/polyfills/Array-prototype-forEach/
 *
 * NOTE: This is not one big polyfill but several ways to write the same polyfill.
 */

/*
 * By Bjorn A. Johansen @ javascript.boxsheep.com
 * Array.prototype.forEach using for-loop
 */
if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fn, arg) {
        "use strict";
        var arr = this,
            len = arr.length,
            thisArg = arg ? arg : undefined,
            i;
        for (i = 0; i < len; i += 1) {
            if (arr.hasOwnProperty(i)) {
                fn.call(thisArg, arr[i], i, arr);
            }
        }
        return undefined;
    };
}

/*
 * By Bjorn A. Johansen @ javascript.boxsheep.com
 * Array.prototype.forEach using recursion
 */
if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (fn, arg) {
        var arr = this,
            len = arr.length,
            thisArg = arg ? arg : undefined;
        return (function each(i) {
            return (i < len) ? (function () {
                fn.call(thisArg, arr[i], i, arr);
                each(i + 1);
            }()) : undefined;
        }(0));
    };
}

/*
 * By Bjorn A. Johansen @ javascript.boxsheep.com
 * ECMAScript 5.1 compliant version (check the step by step guide at http://javascript.boxsheep.com/polyfills/Array-prototype-forEach/)
 */
if (!Array.prototype.forEach) {
    Array.prototype.forEach = function (callbackfn, thisArg) {
        "use strict";
        var O = Object(this),
            lenValue = O.length,
            len = lenValue >>> 0,
            T,
            k,
            Pk,
            kPresent,
            kValue;

        if (typeof callbackfn !== 'function') {
            throw new TypeError();
        }

        T = thisArg ? thisArg : undefined;

        k = 0;
        while (k < len) {
            Pk = k.toString();
            kPresent = O.hasOwnProperty(Pk);
            if (kPresent) {
                kValue = O[Pk];
                callbackfn.call(T, kValue, k, O);
            }
            k += 1;
        }
        return undefined;
    };
}


text:
Kayvee translates an dictionary into a human and machine parseable string, with a "json" format.

## Usage

The Kayvee formatter can be used directly or through the `kayvee.logger`

### kayvee formatter

```python
import kayvee as kv

print(kv.format(source="logger-test",
                level=kv.INFO,
                title="informational-log-title",
                dict(id=name_id, context=context_str))
```

### kayvee.logger

```python
import kayvee.logger as logger

log = logger.Logger("logger-test")
log.info("information-log-title", dict(id=name_id, context=context_str))

# Pass global variables:
log = logger.Logger("logger-test", default_fields=dict("query"=query))
log.info("msg-title")
```

Other functions supported for structured logging:

* `Logger.debug`
* `Logger.info`
* `Logger.warn`
* `Logger.error`
* `Logger.critical`

Supported metrics:

* `Logger.counter`
* `Logger.gauge`

## Releasing a new version

When you merge changes for a new version:

- bump the `VERSION`
- update `CHANGELOG.md` explaining the changes
- after merging, run `publish.sh`
    - requires you to install twine and wheel via `pip install <package>`
    - creates a git tag associating the version with the commit
    - publishes the versioned package to pypi (Python package store)

If you have any issues, please work with `#oncall-infra`.


text:
<mat-toolbar color="primary">
  <mat-toolbar-row>
    <button class="toggle-menu" mat-raised-button (click)="drawer.toggle()" *ngIf="mobile">
      <mat-icon>menu</mat-icon>
    </button>

    ng2-pdf-viewer

    Angular 5+ Component to render PDF

    Get Started
  </mat-toolbar-row>
</mat-toolbar>

<mat-drawer-container class="example-container">
  <mat-drawer [mode]="mobile ? 'push' : 'side'" #drawer [opened]="!mobile">
    <mat-form-field class="mb">
      <input matInput type="text" placeholder="Set URL of the PDF file" [(ngModel)]="pdfSrc">
    </mat-form-field>

        Or render preview by just selecting PDF file (no upload required)

      <input (change)="onFileSelected()" type="file" id="file">

      {{ error.message | json }}

      <mat-slide-toggle [(ngModel)]="originalSize">
        Original size
      </mat-slide-toggle>

      <mat-slide-toggle [(ngModel)]="fitToPage">
        Fit to page
      </mat-slide-toggle>

      <mat-slide-toggle [(ngModel)]="renderText">
        Render text layer
      </mat-slide-toggle>

      <mat-slide-toggle [(ngModel)]="autoresize">
        Auto resize
      </mat-slide-toggle>

      <mat-slide-toggle [(ngModel)]="showAll">
        Show all pages
      </mat-slide-toggle>

    <mat-form-field *ngIf="!originalSize">
      <mat-label>Select an option</mat-label>
      <mat-select [(value)]="zoomScale">
        <mat-option value="page-width">Page Width</mat-option>
        <mat-option value="page-height">Page Height</mat-option>
        <mat-option value="page-fit">Page Fit</mat-option>
      </mat-select>
    </mat-form-field>

      <button (click)="incrementZoom(-0.1)" mat-button type="button">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <circle cx="11" cy="11" r="8"></circle>
          <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
          <line x1="8" y1="11" x2="14" y2="11"></line>
        </svg>
      </button>

      <mat-form-field class="page-number">
        <input matInput type="number" placeholder="Zoom" [(ngModel)]="zoom" pattern="-?[0-9]*(\.[0-9]+)?">
        <mat-error>Input is not a number!</mat-error>
      </mat-form-field>

      <button (click)="incrementZoom(0.1)" mat-button type="button">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <circle cx="11" cy="11" r="8"></circle>
          <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
          <line x1="11" y1="8" x2="11" y2="14"></line>
          <line x1="8" y1="11" x2="14" y2="11"></line>
        </svg>
      </button>

      <mat-slide-toggle [(ngModel)]="stickToPage">
        Stick to page
      </mat-slide-toggle>

      <button (click)="incrementPage(-1)" mat-button type="button">
        Previous
      </button>

      <mat-form-field class="page-number">
        <input matInput type="number" placeholder="Page" [(ngModel)]="page" pattern="-?[0-9]*(\.[0-9]+)?">
        <mat-error>Input is not a number!</mat-error>
      </mat-form-field>

      of {{ pdf.numPages }}
      <button (click)="incrementPage(1)" mat-button type="button">
        Next
      </button>

      <button (click)="rotate(-90)" mat-button type="button" matTooltip="Rotate left" [matTooltipPosition]="'above'">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" transform="scale(-1,1)">
          <polyline points="23 4 23 10 17 10"></polyline>
          <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
        </svg>
      </button>

      <mat-form-field class="page-number">
        <input matInput type="number" placeholder="Rotation" [ngModel]="rotation" disabled>
        <mat-error>Input is not a number!</mat-error>
      </mat-form-field>

      <button (click)="rotate(90)" mat-button type="button" matTooltip="Rotate right" [matTooltipPosition]="'above'">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
          stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <polyline points="23 4 23 10 17 10"></polyline>
          <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
        </svg>
      </button>

      <mat-slide-toggle [(ngModel)]="isOutlineShown">
        Show outline
      </mat-slide-toggle>

            {{ item.title }}

                {{ child.title }}

      <mat-form-field>
        <input #queryInp matInput id="pdfQueryInput" type="text" placeholder="Search..." [value]="pdfQuery"
          (input)="searchQueryChanged($event.target.value)" (keyup.enter)="searchQueryChanged(queryInp.value)">
        <mat-hint>Search in entire pdf</mat-hint>
      </mat-form-field>

      {{ getInt(progressData.loaded / progressData.total * 100) }}%

  </mat-drawer>

  <mat-drawer-content>
    <pdf-viewer [src]="pdfSrc"
                [(page)]="page"
                [rotation]="rotation"
                [original-size]="originalSize"
                [show-all]="showAll"
                [fit-to-page]="fitToPage"
                (after-load-complete)="afterLoadComplete($event)"
                [zoom]="zoom"
                [zoom-scale]="zoomScale"
                [stick-to-page]="stickToPage"
                [render-text]="renderText"
                [external-link-target]="'blank'"
                [autoresize]="autoresize"
                (error)="onError($event)"
                (on-progress)="onProgress($event)"
                (page-rendered)="pageRendered($event)"
                (pages-initialized)="pageInitialized($event)"
                (pageChange)="pageChange($event)"
                [show-borders]="false"
    ></pdf-viewer>
  </mat-drawer-content>
</mat-drawer-container>


text:
/* tslint:disable */
import { Injectable, Inject, Optional } from '@angular/core';
import { Http, Headers, Request } from '@angular/http';
import { NgModule, ModuleWithProviders } from '@angular/core';
import { JSONSearchParams } from './search.params';
import { ErrorHandler } from './error.service';
import { LoopBackAuth } from './auth.service';
import { LoopBackConfig } from '../../lb.config';
import { AccessToken } from '../../models/index';
import { Observable } from 'rxjs/Observable';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
/**
* @module BaseLoopBackApi
* @author Nikolay Matiushenkov <https://github.com/mnvx>
* @contributor Jonathan Casarrubias <@johncasarrubias> <github:jonathan-casarrubias>
* @license MTI
* @description
* Abstract class that will be implemented in every custom service automatically built
* by the sdk builder.
* It provides the core functionallity for every API call, either by HTTP Calls or by
* WebSockets.
**/
@Injectable()
export abstract class BaseLoopBackApi {

  protected path: string;

  constructor(
    @Inject(Http) protected http: Http,
    @Inject(LoopBackAuth) protected auth: LoopBackAuth,
    @Inject(JSONSearchParams) protected searchParams: JSONSearchParams,
    @Optional() @Inject(ErrorHandler) protected errorHandler: ErrorHandler
  ) {}

  /**
   * Process request
   * @param string  method      Request method (GET, POST, PUT)
   * @param string  url         Request url (my-host/my-url/:id)
   * @param any     routeParams Values of url parameters
   * @param any     urlParams   Parameters for building url (filter and other)
   * @param any     postBody    Request postBody
   * @param boolean isio        Request socket connection (When IO is enabled)
   */
  public request(
    method      : string,
    url         : string,
    routeParams : any = {},
    urlParams   : any = {},
    postBody    : any = null,
    isio        : boolean = false
  ): Observable<any> {

    let headers = new Headers();
    headers.append('Content-Type', 'application/json');

    if (this.auth.getAccessTokenId()) {
      headers.append(
        'Authorization',
        LoopBackConfig.getAuthPrefix() + this.auth.getAccessTokenId()
      );
    }

    let requestUrl = url;
    let key: string;
    for (key in routeParams) {
      requestUrl = requestUrl.replace(
        new RegExp(":" + key + "(\/|$)", "g"),
        routeParams[key] + "$1"
      );
    }

    // Body fix for built in remote methods using "data", "options" or "credentials
    // that are the actual body, Custom remote method properties are different and need
    // to be wrapped into a body object
    let body: any;
    let postBodyKeys = typeof postBody === 'object' ? Object.keys(postBody) : []
    if (postBodyKeys.length === 1) {
      body = postBody[postBodyKeys[0]]
    } else {
      body = postBody;
    }
    this.searchParams.setJSON(urlParams);
    let request: Request = new Request({
      headers : headers,
      method  : method,
      url     : urlParams.filter ? `${requestUrl}?filter=${ encodeURI(JSON.stringify(urlParams.filter))}`
              : requestUrl,
      search  : !urlParams.filter && Object.keys(urlParams).length > 0
              ? this.searchParams.getURLSearchParams() : null,
      body    : body ? JSON.stringify(body) : undefined
    });
    return this.http.request(request)
      .map((res: any) => (res.text() != "" ? res.json() : {}))
      .catch(this.errorHandler.handleError);
  }
}


text:
package org.openmhealth.dsu.repository;

import org.openmhealth.dsu.domain.SimpleClientDetails;
import org.springframework.data.repository.Repository;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;

import java.util.Optional;

/**
 * A repository of OAuth 2.0 client details. This infrastructure code is similar to {@link JdbcClientDetailsService},
 * but allows persistence to be backed by any Spring Data compatible data source, notably MongoDB.
 *
 * @author Emerson Farrugia
 */
public interface ClientDetailsRepository extends Repository<SimpleClientDetails, String> {

    /**
     * @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable)
     */
    Optional<SimpleClientDetails> findOne(String clientId);

    /**
     * @see org.springframework.data.repository.CrudRepository#findAll()
     */
    Iterable<SimpleClientDetails> findAll();

    /**
     * @see org.springframework.data.repository.CrudRepository#save(Object)
     */
    SimpleClientDetails save(SimpleClientDetails clientDetails);

    /**
     * @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable)
     */
    void delete(String clientId);
}


text:
/**
 *
OData JPA Processor API Library - Java Persistence Access

 * The library provides a set of APIs to access Java Persistence Models and Data.
 *
 *
 */
package org.apache.olingo.odata2.jpa.processor.api.access;


text:
from flask import Blueprint

blueprint = Blueprint('api_1_0', __name__)

from . import authentication


text:
package org.apache.harmony.test.func.api.java.security.F_AccessControlContextTest_01;

import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.DomainCombiner;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.security.SecureClassLoader;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Enumeration;
import org.apache.harmony.test.func.share.ScenarioTest;

/**
 * Created on 06.12.2004
 */
public class F_AccessControlContextTest_01 extends ScenarioTest
{

    private Policy policy = Policy.getPolicy();
    //ProtectionDomain[] dummyCurrentDomains = null;
    //ProtectionDomain[] dummyAssignedDomains = null;
    //static int index = 0;

    public int test()
    {
        if ("false".equalsIgnoreCase(Security.getProperty("policy.allowSystemProperty"))) {
            return error("Extra policy feature is disabled.");
        }

//        for (Enumeration en = Policy.getPolicy().getPermissions(this.getClass().getProtectionDomain()).elements(); en.hasMoreElements();) {
//            System.out.println(en.nextElement());
//        }
        //dummyCurrentDomains = new ProtectionDomain[2][1];
        //dummyAssignedDomains = new ProtectionDomain[2][1];

        System.setSecurityManager(new SecurityManager());

        Policy.getPolicy().refresh();

        AccessControlContext currContext = AccessController.getContext();
        try {
            currContext.checkPermission(new RuntimePermission("getProtectionDomain"));
            return fail("The current access control context mustn't have a permission to get a protection domain though it has one. Test failed.");
        } catch (AccessControlException e) {
        }

        Policy.getPolicy().refresh();

        //log.info("\tProtection domain of the main execution thread after a \"getProtectionDomain\" permission has been added:\n" + this.getClass().getProtectionDomain());

        PermissionCollection permissions = new Permissions();
        permissions.add(new RuntimePermission("createClassLoader"));
        if (!permissions.implies(new RuntimePermission("createClassLoader"))) {
            return fail("An operation of adding new permission into PermissionCollection failed. Test failed.");
        }

        ProtectionDomain pd = null;
        try {
            String user_dir = System.getProperty("qe.suite");
            pd = new ProtectionDomain(new CodeSource(new URL("file:/" + user_dir + "/-"), new Certificate[] {}), permissions, ClassLoader.getSystemClassLoader(), null);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return error("Couldn't create URL.");
        }

        log.info("\tA protection domain for the context being constructed:\n" + pd);

        ProtectionDomain[] pds = {pd};
        AccessControlContext intermediateContext = new AccessControlContext(pds);

        if (intermediateContext.equals(currContext))
        {
            return fail("Contexts are equal while they mustn't be. Test failed.");
        }

        DomainCombiner dc = new MyDomainCombiner2();
        AccessControlContext finalContext = new AccessControlContext(intermediateContext, dc);

        /*log.info("\tDummy current domains before:");
        for (int i = 0; i < dummyCurrentDomains.length; i++) {
            for (int j = 0; j < dummyCurrentDomains[i].length; j++) {
                log.info("dummyCurrentDomains[" + i + "][" + j + "]: " + dummyCurrentDomains[i][j]);
            }
        }

        log.info("\tDummy assigned domains before:");
        for (int i = 0; i < dummyAssignedDomains.length; i++) {
            for (int j = 0; j < dummyAssignedDomains[i].length; j++) {
                log.info("dummyAssignedDomains[" + i + "][" + j + "]: " + dummyAssignedDomains[i][j]);
            }
        }*/

        MySecureClassLoader scl;
        try {
            scl = (MySecureClassLoader)AccessController.doPrivileged(new PrivilegedAction() {
                public Object run()
                {
                    return new MySecureClassLoader(ClassLoader.getSystemClassLoader());
                }
            }, finalContext);
        } catch (AccessControlException e) {
            e.printStackTrace();
            return fail("Test failed.");
        }

        /*log.info("\tDummy current domains after:");
        for (int i = 0; i < dummyCurrentDomains.length; i++) {
            for (int j = 0; j < dummyCurrentDomains[i].length; j++) {
                log.info("dummyCurrentDomains[" + i + "][" + j + "]: " + dummyCurrentDomains[i][j]);
            }
        }

        log.info("\tDummy assigned domains after:");
        for (int i = 0; i < dummyAssignedDomains.length; i++) {
            for (int j = 0; j < dummyAssignedDomains[i].length; j++) {
                log.info("dummyAssignedDomains[" + i + "][" + j + "]: " + dummyAssignedDomains[i][j]);
            }
        }*/

        if (finalContext.hashCode() == currContext.hashCode())
        {
            return fail("Hash codes are equal. Test failed.");
        }

        if (finalContext.hashCode() != intermediateContext.hashCode())
        {
            return fail("Hash codes aren't equal. Test failed.");
        }

        return pass("Test passed.");
    }

//    private void UpdatePolicyFile(final String content) throws IOException
//    {
//        FileOutputStream out = null;
//        try {
//            out = new FileOutputStream(testArgs[0]);
//            out.write(content.getBytes());
//        } finally {
//            if (out != null)
//            {
//                out.close();
//            }
//        }
//    }

    public static void main(String[] args)
    {
        System.exit(new F_AccessControlContextTest_01().test(args));
    }

    class MySecureClassLoader extends SecureClassLoader
    {
        public MySecureClassLoader(ClassLoader parent)
        {
            super(parent);
            log.info("\tMySecureClassLoader ctor has been called.");
        }
    }

    public class MyDomainCombiner2 implements DomainCombiner
    {
        public ProtectionDomain[] combine(ProtectionDomain[] currentDomains, ProtectionDomain[] assignedDomains)
        {
            ProtectionDomain[] resultPDs = new ProtectionDomain[2];
            resultPDs[0] = assignedDomains[0];

            PermissionCollection newPerms = new Permissions();
            for (int i = 0; i < currentDomains.length; i++) {
                PermissionCollection origPerms = currentDomains[0].getPermissions();
                for (Enumeration en = origPerms.elements(); en.hasMoreElements();) {
                    Permission p = (Permission)en.nextElement();
                    if (!newPerms.implies(p)) {
                        newPerms.add(p);
                    }
                }
            }

            for (int i = 0; i < assignedDomains.length; i++) {
                PermissionCollection origPerms = assignedDomains[0].getPermissions();
                for (Enumeration en = origPerms.elements(); en.hasMoreElements();) {
                    Permission p = (Permission)en.nextElement();
                    if (!newPerms.implies(p)) {
                        newPerms.add(p);
                    }
                }
            }

            ProtectionDomain pd = new ProtectionDomain(currentDomains[0].getCodeSource(), newPerms, currentDomains[0].getClassLoader(), null);
            resultPDs[1] = pd;

            return resultPDs;
        }
    }
}