text:
<?php

include __DIR__ . '/src/WebinoCanonicalRedirect/Module.php';

redpajama_set_name: RedPajamaGithub


text:
@echo off
setlocal enableextensions

set base=%~dp0

for %%i in (node.bat node.exe) do if not "%%~$PATH:i"=="" set node=%%~$PATH:i
if "%node%"=="" echo error: node.js is not on the system path && exit /b 1

"%node%" "%base%jsc.js" %*


text:
package org.apache.pdfbox.pdmodel.graphics.color;

import java.awt.Point;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNull;
import org.apache.pdfbox.pdmodel.common.function.PDFunction;

/**
 * A Separation color space used to specify either additional colorants or for isolating the
 * control of individual colour components of a device colour space for a subtractive device.
 * When such a space is the current colour space, the current colour shall be a single-component
 * value, called a tint, that controls the given colorant or colour components only.
 *
 * @author Ben Litchfield
 * @author John Hewson
 */
public class PDSeparation extends PDSpecialColorSpace
{
    private final PDColor initialColor = new PDColor(new float[] { 1 }, this);

    // array indexes
    private static final int COLORANT_NAMES = 1;
    private static final int ALTERNATE_CS = 2;
    private static final int TINT_TRANSFORM = 3;

    // fields
    private PDColorSpace alternateColorSpace = null;
    private PDFunction tintTransform = null;

    /**
     * Map used to speed up {@link #toRGB(float[])}. Note that this class contains three maps (this
     * and the two in {@link #toRGBImage(java.awt.image.WritableRaster) } and {@link #toRGBImage2(java.awt.image.WritableRaster)
     * }. The maps use different key intervals. This map here is needed for shading, which produce
     * more than 256 different float values, which we cast to int so that the map can work.
     */
    private Map<Integer, float[]> toRGBMap = null;

    /**
     * Creates a new Separation color space.
     */
    public PDSeparation()
    {
        array = new COSArray();
        array.add(COSName.SEPARATION);
        array.add(COSName.getPDFName(""));
        // add some placeholder
        array.add(COSNull.NULL);
        array.add(COSNull.NULL);
    }

    /**
     * Creates a new Separation color space from a PDF color space array.
     * @param separation an array containing all separation information.
     * @throws IOException if the color space or the function could not be created.
     */
    public PDSeparation(COSArray separation) throws IOException
    {
        array = separation;
        alternateColorSpace = PDColorSpace.create(array.getObject(ALTERNATE_CS));
        tintTransform = PDFunction.create(array.getObject(TINT_TRANSFORM));
    }

    @Override
    public String getName()
    {
        return COSName.SEPARATION.getName();
    }

    @Override
    public int getNumberOfComponents()
    {
        return 1;
    }

    @Override
    public float[] getDefaultDecode(int bitsPerComponent)
    {
        return new float[] { 0, 1 };
    }

    @Override
    public PDColor getInitialColor()
    {
        return initialColor;
    }

    @Override
    public float[] toRGB(float[] value) throws IOException
    {
        if (toRGBMap == null)
        {
            toRGBMap = new HashMap<>();
        }
        int key = (int) (value[0] * 255);
        float[] retval = toRGBMap.get(key);
        if (retval != null)
        {
            return retval;
        }
        float[] altColor = tintTransform.eval(value);
        retval = alternateColorSpace.toRGB(altColor);
        toRGBMap.put(key, retval);
        return retval;
    }

    //
    // WARNING: this method is performance sensitive, modify with care!
    //
    @Override
    public BufferedImage toRGBImage(WritableRaster raster) throws IOException
    {
        if (alternateColorSpace instanceof PDLab)
        {
            // PDFBOX-3622 - regular converter fails for Lab colorspaces
            return toRGBImage2(raster);
        }

        // use the tint transform to convert the sample into
        // the alternate color space (this is usually 1:many)
        WritableRaster altRaster = Raster.createBandedRaster(DataBuffer.TYPE_BYTE,
                raster.getWidth(), raster.getHeight(),
                alternateColorSpace.getNumberOfComponents(),
                new Point(0, 0));

        int numAltComponents = alternateColorSpace.getNumberOfComponents();
        int width = raster.getWidth();
        int height = raster.getHeight();
        float[] samples = new float[1];

        Map<Integer, int[]> calculatedValues = new HashMap<>();
        Integer hash;
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                raster.getPixel(x, y, samples);
                hash = Float.floatToIntBits(samples[0]);
                int[] alt = calculatedValues.get(hash);
                if (alt == null)
                {
                    alt = new int[numAltComponents];
                    tintTransform(samples, alt);
                    calculatedValues.put(hash, alt);
                }
                altRaster.setPixel(x, y, alt);
            }
        }

        // convert the alternate color space to RGB
        return alternateColorSpace.toRGBImage(altRaster);
    }

    // converter that works without using super implementation of toRGBImage()
    private BufferedImage toRGBImage2(WritableRaster raster) throws IOException
    {
        int width = raster.getWidth();
        int height = raster.getHeight();
        BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        WritableRaster rgbRaster = rgbImage.getRaster();
        float[] samples = new float[1];

        Map<Integer, int[]> calculatedValues = new HashMap<>();
        Integer hash;
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                raster.getPixel(x, y, samples);
                hash = Float.floatToIntBits(samples[0]);
                int[] rgb = calculatedValues.get(hash);
                if (rgb == null)
                {
                    samples[0] /= 255;
                    float[] altColor = tintTransform.eval(samples);
                    float[] fltab = alternateColorSpace.toRGB(altColor);
                    rgb = new int[3];
                    rgb[0] = (int) (fltab[0] * 255);
                    rgb[1] = (int) (fltab[1] * 255);
                    rgb[2] = (int) (fltab[2] * 255);
                    calculatedValues.put(hash, rgb);
                }
                rgbRaster.setPixel(x, y, rgb);
            }
        }
        return rgbImage;
    }

    protected void tintTransform(float[] samples, int[] alt) throws IOException
    {
        samples[0] /= 255; // 0..1
        float[] result = tintTransform.eval(samples);
        for (int s = 0; s < alt.length; s++)
        {
            // scale to 0..255
            alt[s] = (int) (result[s] * 255);
        }
    }

    @Override
    public BufferedImage toRawImage(WritableRaster raster)
    {
        return toRawImage(raster, ColorSpace.getInstance(ColorSpace.CS_GRAY));
    }

    /**
     * Returns the colorant name.
     * @return the name of the colorant
     */
    public PDColorSpace getAlternateColorSpace()
    {
       return alternateColorSpace;
    }

    /**
     * Returns the colorant name.
     * @return the name of the colorant
     */
    public String getColorantName()
    {
        COSName name = (COSName)array.getObject(COLORANT_NAMES);
        return name.getName();
    }

    /**
     * Sets the colorant name.
     * @param name the name of the colorant
     */
    public void setColorantName(String name)
    {
        array.set(1, COSName.getPDFName(name));
    }

    /**
     * Sets the alternate color space.
     * @param colorSpace The alternate color space.
     */
    public void setAlternateColorSpace(PDColorSpace colorSpace)
    {
        alternateColorSpace = colorSpace;
        COSBase space = null;
        if (colorSpace != null)
        {
            space = colorSpace.getCOSObject();
        }
        array.set(ALTERNATE_CS, space);
    }

    /**
     * Sets the tint transform function.
     * @param tint the tint transform function
     */
    public void setTintTransform(PDFunction tint)
    {
        tintTransform = tint;
        array.set(TINT_TRANSFORM, tint);
    }

    @Override
    public String toString()
    {
        return getName() + "{" +
                "\"" + getColorantName() + "\"" + " " +
                alternateColorSpace.getName() + " " +
                tintTransform + "}";
    }
}


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Agron. lusit. 15(3): 185 (1953)

#### Original name
Entyloma chaenorrhini Sousa da Câmara & A.T. Vasconc.

### Remarks
null


text:
package me.doshou.admin.sys.permission.task;

import me.doshou.common.repository.RepositoryHelper;
import me.doshou.common.utils.LogUtils;
import me.doshou.admin.sys.permission.entity.Role;
import me.doshou.admin.sys.permission.entity.RoleResourcePermission;
import me.doshou.admin.sys.permission.service.PermissionService;
import me.doshou.admin.sys.permission.service.RoleService;
import me.doshou.admin.sys.resource.service.ResourceService;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Iterator;
/**
 * 清理无关联的Role-Resource/Permission关系
 * 1、Role-Resource
 * 2、Role-Permission
 * @author YorkChow<york.chow@actionsky.com>
 * @since 2014/12/21
 * Time: 20:05
 */
@Service
public class RoleClearRelationTask {

    @Autowired
    private RoleService roleService;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private PermissionService permissionService;

    /**
     * 清除删除的角色对应的关系
     */
    public void clearDeletedRoleRelation() {

        final int PAGE_SIZE = 100;
        int pn = 0;

        Page<Role> rolePage = null;
        do {
            Pageable pageable = new PageRequest(pn++, PAGE_SIZE);
            rolePage = roleService.findAll(pageable);
            //开启新事物清除
            try {
                RoleClearRelationTask roleClearRelationTask = (RoleClearRelationTask) AopContext.currentProxy();
                roleClearRelationTask.doClear(rolePage.getContent());
            } catch (Exception e) {
                //出异常也无所谓
                LogUtils.logError("clear role relation error", e);

            }
            //清空会话
            RepositoryHelper.clear();
        } while (rolePage.hasNextPage());
    }

    public void doClear(Collection<Role> roleColl) {

        for (Role role : roleColl) {

            boolean needUpdate = false;
            Iterator<RoleResourcePermission> iter = role.getResourcePermissions().iterator();

            while (iter.hasNext()) {
                RoleResourcePermission roleResourcePermission = iter.next();

                //如果资源不存在了 就删除
                Long resourceId = roleResourcePermission.getResourceId();
                if (!resourceService.exists(resourceId)) {
                    iter.remove();
                    needUpdate = true;
                }

                Iterator<Long> permissionIdIter = roleResourcePermission.getPermissionIds().iterator();
                while (permissionIdIter.hasNext()) {
                    Long permissionId = permissionIdIter.next();

                    if (!permissionService.exists(permissionId)) {
                        permissionIdIter.remove();
                        needUpdate = true;
                    }
                }

            }

            if (needUpdate) {
                roleService.update(role);
            }

        }

    }
}


text:
#include <algorithm>
#include <vector>

#include "mlir/IR/Builders.h"  // from @llvm-project
#include "mlir/IR/Module.h"  // from @llvm-project
#include "mlir/IR/UseDefLists.h"  // from @llvm-project
#include "mlir/Pass/Pass.h"  // from @llvm-project
#include "mlir/Support/LLVM.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_saved_model.h"

namespace mlir {
namespace tf_saved_model {
namespace {

// This pass will replace a func's bound inputs which are bound to
// tf.ReadVariable ops global tensors with tf.Const ops inside the func's body.
// If this pass runs successfully, the resultant IR will be guaranteed to:
//
// 1. Not contain any tf_saved_model.global_tensor ops
// 2. Not contain any  tf_saved_model.bound_input arg attrs on tf_saved_model
// exported functions
// Else, the pass fails.
//
// The reason this pass has this contract is so that once this succeeds, we know
// the IR is in correct form for inference backends (like lite) that do not
// support resources/variables . Further, this contract also ensures that this
// pass lowers from saved model to pure TF. Hence it fails, if it cannot lower.
struct FreezeGlobalTensorsPass
    : public PassWrapper<FreezeGlobalTensorsPass, OperationPass<ModuleOp>> {
  void runOnOperation() override;
};

void FreezeGlobalTensorsPass::runOnOperation() {
  auto module = getOperation();
  if (!tf_saved_model::HasTfSavedModelSemantics(module)) {
    return;
  }
  SymbolTable symbol_table(module);
  DenseSet<Operation*> frozen_global_tensors;

  for (auto func : module.getOps<FuncOp>()) {
    SmallVector<unsigned, 4> args_to_erase;
    OpBuilder builder(func.getBody());

    for (int i = 0, e = func.getNumArguments(); i < e; ++i) {
      SmallVector<TF::ReadVariableOp, 4> read_variable_ops_to_erase;
      auto global_tensor =
          LookupBoundInputOfType<GlobalTensorOp>(func, i, symbol_table);

      if (!global_tensor) continue;
      frozen_global_tensors.insert(global_tensor);

      // This pass assumes that all global tensors as immutable (e.g. by a
      // previous optimize global tensors pass). If not, this pass has to fail
      // since it cannot perform one of its goals.
      if (global_tensor.is_mutable()) {
        global_tensor.emitError() << "is not immutable, try running "
                                     "tf-saved-model-optimize-global-tensors "
                                     "to prove tensors are immutable";
        return signalPassFailure();
      }

      auto arg = func.getArgument(i);
      for (auto user : arg.getUsers()) {
        if (auto read_op = llvm::dyn_cast<TF::ReadVariableOp>(user)) {
          // Collect all read variable ops so that all its uses can be replaced
          // with the tf.constant corresponding to the global tensor op.
          read_variable_ops_to_erase.push_back(read_op);
        } else {
          // Current assumption is all users are tf.ReadVariableOp. Need to
          // expand this to handle control flow and call ops.
          user->emitError() << "could not rewrite use of immutable bound input";
          return signalPassFailure();
        }
      }

      // Replace the arg with a tf.Const op in the function body.
      builder.setInsertionPointToStart(&func.getBody().front());
      auto const_op = builder.create<TF::ConstOp>(global_tensor.getLoc(),
                                                  global_tensor.value());
      args_to_erase.push_back(i);
      for (auto read_op : read_variable_ops_to_erase) {
        read_op.getResult().replaceAllUsesWith(const_op.getResult());
        read_op.erase();
      }
    }
    func.eraseArguments(args_to_erase);
  }
  // Erase all global tensors that were frozen.
  for (auto global_tensor : frozen_global_tensors) {
    global_tensor->erase();
  }

  if (!module.getOps<GlobalTensorOp>().empty()) {
    module.emitError() << "could not freeze all global tensors in the module";
    return signalPassFailure();
  }
}

}  // namespace

// For "opt" to pick up this pass.
static PassRegistration<FreezeGlobalTensorsPass> pass(
    "tf-saved-model-freeze-global-tensors",
    "Freeze tf_saved_model.global_tensor's in func bodies.");

std::unique_ptr<OperationPass<ModuleOp>> CreateFreezeGlobalTensorsPass() {
  return std::make_unique<FreezeGlobalTensorsPass>();
}

}  // namespace tf_saved_model
}  // namespace mlir


text:
<?php
namespace App\Http\Controllers;

use Serverfireteam\Panel\CrudController;
use App\Storehouse;
use App\MyFnc\Permission;

class StorehouseController extends CrudController {

    public function all($entity) {
        parent::all($entity);
        if(!parent::all($entity)) return view('panelViews::hasNoAuthority');
        $this->filter = \DataFilter::source(new Storehouse());
        $this->filter->add('id', trans('panel::fields.siid'), 'text');
        $this->filter->add('storehouse', trans('panel::fields.storehouse'), 'text');
        $this->filter->add('storeAddr', trans('panel::fields.storeAddr'), 'text');
        $this->filter->submit(trans('panel::fields.search'));
        $this->filter->reset(trans('panel::fields.reset'));
        $this->filter->build();

        $this->grid = \DataGrid::source($this->filter);
        $this->grid->add('id', trans('panel::fields.siid'), true)->style("width:140px");
        $this->addGrid('storehouse');
        $this->addGrid('storeAddr');
        $this->addGrid('telephone');
        $this->grid->link('panel/'.$this->entity.'/edit', trans('panel::fields.add'), "TR", ['class'=>'btn btn-primary']);
        $this->grid->edit('edit', trans('panel::fields.edit'), 'modify');
        return view('panelViews::all', array(
        		'grid' 	      => $this->grid,
        		'filter' 	      => $this->filter,
        		'title'          => $this->entity ,
        		'current_entity' => $this->entity,
        		'method' => $this->routeMethod,
        		'import_message' => (\Session::has('import_message')) ? \Session::get('import_message') : '',
        ));
    }

    public function edit($entity) {
    	$this->edit = \DataEdit::source(new Storehouse());
        if(!parent::edit($entity)) return view('panelViews::hasNoAuthority');

        $this->initEntity(trans('panel::fields.storehouse'));

        $this->edit->add('id', trans('panel::fields.shNum'), 'text')->rule('unique:storehouse_info,id|required');
        $this->addEdit('storehouse')->rule('required');
        $this->addEdit('storeAddr')->rule('required');
        $this->addEdit('telephone')->rule('required');

        return $this->returnEditView();
    }
}


text:
package com.ptrprograms.navigationdrawer.adapters;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.ptrprograms.navigationdrawer.R;
import com.ptrprograms.navigationdrawer.models.DrawerItem;

/**
 * Created by PaulTR on 5/12/14.
 */
public class DrawerAdapter extends ArrayAdapter<DrawerItem> {

	public DrawerAdapter( Context context ) {
		this( context, 0 );
	}

	public DrawerAdapter(Context context, int resource) {
		super(context, resource);

	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder;
		if( convertView == null ) {
			holder = new ViewHolder();
			convertView = LayoutInflater.from( getContext() ).inflate( R.layout.view_drawer_item, parent, false );
			holder.drawerItemLabel = (TextView) convertView.findViewById( R.id.drawer_text );
			holder.drawerItemIcon = (ImageView) convertView.findViewById( R.id.drawer_icon );
			convertView.setTag( holder );
		} else {
			holder = (ViewHolder) convertView.getTag();
		}

		holder.drawerItemLabel.setText( getItem( position ).getDrawerText() );
		holder.drawerItemIcon.setImageResource( getItem( position ).getDrawerIcon() );

		return convertView;
	}

	public class ViewHolder {
		public TextView drawerItemLabel;
		public ImageView drawerItemIcon;
	}
}


text:
var fs = require('fs');
var cheerio = require('cheerio');
var afterAll = require('after-all');
var path = require('path');

validateDirectory(path.join(__dirname, '..'))

function validateDirectory(dirname, cb) {
  fs.readdir(dirname, function (err, files) {
    if (err) cb(err);
    var result = []
    var next = afterAll(function (err) {
      if (err) cb(err);
      if (result.length === 0) {
        console.log('everything seems nice')
      } else {
        console.log('While inspecting files: ' + files + ', we have found issues')
        console.log(result.join('\n'))
      }
    });
    files.filter(RegExp.prototype.test.bind(/\.html$/)).forEach(function (filename) {
      validateFile(result, filename, next());
    });
  });
}

function validateFile(result, filename, callback) {
  fs.readFile(filename, function (err, data) {
    var seenOnThisPage = {};
    if (err) return callback(err);
    var $ = cheerio.load(data);
    $('[data-i18n]').each(function () {
      var text = ($(this).html() || $(this).text()).trim();
      var key = $(this).attr('data-i18n');
      if ((key in seenOnThisPage) && seenOnThisPage[key] !== text) {
        var errMsg = filename + ': ' + key + ' is associated both with \n' + seenOnThisPage[key] + '\n -- AND -- \n' + text
        result.push(errMsg)
      }
      seenOnThisPage[key] = text
    });
    callback();
  });
};


text:
/* Author: Ioan Sucan */

#ifndef OMPL_DATASTRUCTURES_GRID_B_
#define OMPL_DATASTRUCTURES_GRID_B_

#include "ompl/datastructures/GridN.h"
#include "ompl/datastructures/BinaryHeap.h"

namespace ompl
{
    /** \brief This class defines a grid that keeps track of its boundary:
     * it distinguishes between interior and exterior cells.  */
    template <typename _T, class LessThanExternal = std::less<_T>, class LessThanInternal = LessThanExternal>
    class GridB : public GridN<_T>
    {
    public:
        /// Definition of a cell in this grid
        using Cell = typename GridN<_T>::Cell;

        /// The datatype for arrays of cells
        using CellArray = typename GridN<_T>::CellArray;

        /// Datatype for cell coordinates
        using Coord = typename GridN<_T>::Coord;

    protected:
        /// \cond IGNORE
        // the type of cell here needs an extra pointer to allow the updatable heap to work fast
        // however, this stays hidden from the user
        struct CellX : public Cell
        {
            CellX() : Cell()
            {
            }

            ~CellX() override = default;

            void *heapElement;
        };

        /// \endcond

    public:
        /// Event to be called when a cell's priority is to be updated
        using EventCellUpdate = void (*)(Cell *, void *);

        /// Constructor
        explicit GridB(unsigned int dimension) : GridN<_T>(dimension)
        {
            setupHeaps();
        }

        ~GridB() override
        {
            clearHeaps();
        }

        /// Set the function callback and to be called when a cell's
        /// priority is updated
        void onCellUpdate(EventCellUpdate event, void *arg)
        {
            eventCellUpdate_ = event;
            eventCellUpdateData_ = arg;
        }

        /// Return the cell that is at the top of the heap maintaining internal cells
        Cell *topInternal() const
        {
            auto *top = static_cast<Cell *>(internal_.top()->data);
            return top ? top : topExternal();
        }

        /// Return the cell that is at the top of the heap maintaining external cells
        Cell *topExternal() const
        {
            auto *top = static_cast<Cell *>(external_.top()->data);
            return top ? top : topInternal();
        }

        /// Return the number of internal cells
        unsigned int countInternal() const
        {
            return internal_.size();
        }

        /// Return the number of external cells
        unsigned int countExternal() const
        {
            return external_.size();
        }

        /// Return the fraction of external cells
        double fracExternal() const
        {
            return external_.empty() ? 0.0 : (double)(external_.size()) / (double)(external_.size() + internal_.size());
        }

        /// Return the fraction of internal cells
        double fracInternal() const
        {
            return 1.0 - fracExternal();
        }

        /// Update the position in the heaps for a particular cell.
        void update(Cell *cell)
        {
            eventCellUpdate_(cell, eventCellUpdateData_);
            if (cell->border)
                external_.update(
                    reinterpret_cast<typename externalBHeap::Element *>(static_cast<CellX *>(cell)->heapElement));
            else
                internal_.update(
                    reinterpret_cast<typename internalBHeap::Element *>(static_cast<CellX *>(cell)->heapElement));
        }

        /// Update all cells and reconstruct the heaps
        void updateAll()
        {
            std::vector<Cell *> cells;
            this->getCells(cells);
            for (int i = cells.size() - 1; i >= 0; --i)
                eventCellUpdate_(cells[i], eventCellUpdateData_);
            external_.rebuild();
            internal_.rebuild();
        }

        /// Create a cell but do not add it to the grid; update neighboring cells however
        virtual Cell *createCell(const Coord &coord, CellArray *nbh = nullptr)
        {
            auto *cell = new CellX();
            cell->coord = coord;

            CellArray *list = nbh ? nbh : new CellArray();
            this->neighbors(cell->coord, *list);

            for (auto cl = list->begin(); cl != list->end(); ++cl)
            {
                auto *c = static_cast<CellX *>(*cl);
                bool wasBorder = c->border;
                c->neighbors++;
                if (c->border && c->neighbors >= GridN<_T>::interiorCellNeighborsLimit_)
                    c->border = false;

                eventCellUpdate_(c, eventCellUpdateData_);

                if (c->border)
                    external_.update(reinterpret_cast<typename externalBHeap::Element *>(c->heapElement));
                else
                {
                    if (wasBorder)
                    {
                        external_.remove(reinterpret_cast<typename externalBHeap::Element *>(c->heapElement));
                        internal_.insert(c);
                    }
                    else
                        internal_.update(reinterpret_cast<typename internalBHeap::Element *>(c->heapElement));
                }
            }

            cell->neighbors = GridN<_T>::numberOfBoundaryDimensions(cell->coord) + list->size();
            if (cell->border && cell->neighbors >= GridN<_T>::interiorCellNeighborsLimit_)
                cell->border = false;

            if (!nbh)
                delete list;

            return static_cast<Cell *>(cell);
        }

        /// Add the cell to the grid
        virtual void add(Cell *cell)
        {
            auto *ccell = static_cast<CellX *>(cell);
            eventCellUpdate_(ccell, eventCellUpdateData_);

            GridN<_T>::add(cell);

            if (cell->border)
                external_.insert(ccell);
            else
                internal_.insert(ccell);
        }

        /// Remove a cell from the grid
        virtual bool remove(Cell *cell)
        {
            if (cell)
            {
                auto *list = new CellArray();
                this->neighbors(cell->coord, *list);

                for (auto cl = list->begin(); cl != list->end(); ++cl)
                {
                    auto *c = static_cast<CellX *>(*cl);
                    bool wasBorder = c->border;
                    c->neighbors--;
                    if (!c->border && c->neighbors < GridN<_T>::interiorCellNeighborsLimit_)
                        c->border = true;

                    eventCellUpdate_(c, eventCellUpdateData_);

                    if (c->border)
                    {
                        if (wasBorder)
                            external_.update(reinterpret_cast<typename externalBHeap::Element *>(c->heapElement));
                        else
                        {
                            internal_.remove(reinterpret_cast<typename internalBHeap::Element *>(c->heapElement));
                            external_.insert(c);
                        }
                    }
                    else
                        internal_.update(reinterpret_cast<typename internalBHeap::Element *>(c->heapElement));
                }

                delete list;

                auto pos = GridN<_T>::hash_.find(&cell->coord);
                if (pos != GridN<_T>::hash_.end())
                {
                    GridN<_T>::hash_.erase(pos);
                    auto *cx = static_cast<CellX *>(cell);
                    if (cx->border)
                        external_.remove(reinterpret_cast<typename externalBHeap::Element *>(cx->heapElement));
                    else
                        internal_.remove(reinterpret_cast<typename internalBHeap::Element *>(cx->heapElement));
                    return true;
                }
            }
            return false;
        }

        void clear() override
        {
            GridN<_T>::clear();
            clearHeaps();
        }

        void status(std::ostream &out = std::cout) const override
        {
            GridN<_T>::status(out);
            out << countInternal() << " internal cells" << std::endl;
            out << countExternal() << " external cells" << std::endl;
        }

    protected:
        /// Pointer to function to be called when a cell needs to be updated
        EventCellUpdate eventCellUpdate_;

        /// Data to be passed to function pointer above
        void *eventCellUpdateData_;

        /// Default no-op update routine for a cell
        static void noCellUpdate(Cell * /*unused*/, void * /*unused*/)
        {
        }

        /// Set the update procedure for the heaps of internal and external cells
        void setupHeaps()
        {
            eventCellUpdate_ = &noCellUpdate;
            eventCellUpdateData_ = nullptr;
            internal_.onAfterInsert(&setHeapElementI, nullptr);
            external_.onAfterInsert(&setHeapElementE, nullptr);
        }

        /// Clear the data from both heaps
        void clearHeaps()
        {
            internal_.clear();
            external_.clear();
        }

        /// Define order for internal cells
        struct LessThanInternalCell
        {
            bool operator()(const CellX *const a, const CellX *const b) const
            {
                return lt_(a->data, b->data);
            }

        private:
            LessThanInternal lt_;
        };

        /// Define order for external cells
        struct LessThanExternalCell
        {
            bool operator()(const CellX *const a, const CellX *const b) const
            {
                return lt_(a->data, b->data);
            }

        private:
            LessThanExternal lt_;
        };

        /// Datatype for a heap of cells containing interior cells
        using internalBHeap = BinaryHeap<CellX *, LessThanInternalCell>;

        /// Datatype for a heap of cells containing exterior cells
        using externalBHeap = BinaryHeap<CellX *, LessThanExternalCell>;

        /// Routine used internally for keeping track of binary heap elements for internal cells
        static void setHeapElementI(typename internalBHeap::Element *element, void * /*unused*/)
        {
            element->data->heapElement = reinterpret_cast<void *>(element);
        }

        /// Routine used internally for keeping track of binary heap elements for external cells
        static void setHeapElementE(typename externalBHeap::Element *element, void * /*unused*/)
        {
            element->data->heapElement = reinterpret_cast<void *>(element);
        }

        /// The heap of interior cells
        internalBHeap internal_;

        /// The heap of external cells
        externalBHeap external_;
    };
}

#endif


text:
---
layout: doc-page
title: Debugging Techniques
---

# Debugging Techniques
- [Setting up the playground](#setting-up-the-playground)
- [Show for human readable output](#show-for-human-readable-output)
- [How to disable color](#how-to-disable-color)
- [Reporting as a non-intrusive println](#reporting-as-a-non-intrusive-println)
- [Printing out trees after phases](#printing-out-trees-after-phases)
- [Printing out stack traces of compile time errors](#printing-out-stack-traces-of-compile-time-errors)
- [Configuring the printer output](#configuring-the-printer-output)
- [Figuring out an object creation site](#figuring-out-an-object-creation-site)
  * [Via ID](#via-id)
  * [Via tracer](#via-tracer)
- [Built-in Logging Architecture](#built-in-logging-architecture)
  * [Printers](#printers)
  * [Tracing](#tracing)
  * [Reporter](#reporter)

Table of contents generated with markdown-toc

## Setting up the playground
Consider the `../issues/Playground.scala` (relative to the Dotty directory) file is:

```scala
object Playground {
  def main(args: Array[String]) = {
    println("Hello World")
  }
}
```

Then, you can debug Dotty by compiling this file via `scalac ../issues/Playground.scala` (from the SBT console) and collecting various debug output in process. This section documents techniques you can use to collect the debug info.

[This](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/typer/Typer.scala#L2231) is the entry point to the Typer. The job of the Typer is to take an untyped tree, compute its type and turn it into a typed tree by attaching the type information to that tree. We will use this entry point to practice debugging techniques. E.g.:

```scala
  def typed(tree: untpd.Tree, pt: Type, locked: TypeVars)(implicit ctx: Context): Tree =
    trace(i"typing $tree", typr, show = true) {
      println("Hello Debug!")
      /*...*/
```

Then:

```shell
scalac ../issues/Playground.scala
```

The techniques discussed below can be tried out in place of `println("Hello Debug")` in that location. They are of course applicable throughout the codebase.

## Show for human readable output
Many objects in the compiler have a `show` method available on them via implicit rich wrapper:

```scala
println(tree.show)
```

This will output every single tree passing through the typer (or wherever else you inject it) in a human readable form. Try calling `show` on anything you want to be human-readable, and chances are it will be possible to do so.

## How to disable color
Note that the `show` command above outputs the code in color. This is achieved by injecting special characters into the strings which terminals interpret as commands to change color of the output. This however may not be what you want, e.g. if you want to zero-in on a particular tree:

```scala
if (tree.show == """println("Hello World")""")
  println(s"${tree.show}\n${pt.show}\n${tree.uniqueId}\n===\n")
```

The intention above is to output an extended debug info on a tree that matches a particular human-readable representation. However, because of the color characters, the comparison will fail.

To disable color output from `show`, run `scalac` as follows:

`scalac -color:never ../issues/Playground.scala`

## Reporting as a non-intrusive println
Consider you want to debug the `tree` that goes into `assertPositioned(tree)` in the `typed` method. You can do:

```scala
println(tree.show)
assertPositioned(tree)
```

But you can also do:

```scala
assertPositioned(tree.reporting(s"Tree is: $result"))
```

`extension (a: A) def reporting(f: WrappedResult[T] ?=> String, p: Printer = Printers.default): A` is defined on all types. The function `f` can be written without the argument since it is a context function. The `result` variable is a part of the `WrapperResult` – a tiny framework powering the `reporting` function. Basically, whenever you are using `reporting` on an object `A`, you can use the `result: A` variable from this function and it will be equal to the object you are calling `reporting` on.

## Printing out trees after phases
To print out the trees you are compiling after the FrontEnd (scanner, parser, namer, typer) phases:

```shell
scalac -Xprint:typer ../issues/Playground.scala
```

To print out the trees after Frontend and CollectSuperCalls phases:

```shell
scalac -Xprint:typer,collectSuperCalls ../issues/Playground.scala
```

To print out the trees after all phases:

```shell
scalac -Xprint:all ../issues/Playground.scala
```

To find out the list of all the phases and their names, check out [this](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/Compiler.scala#L34) line in `Compiler.scala`. Each `Phase` object has `phaseName` defined on it, this is the phase name.

## Printing out stack traces of compile time errors
You can use the flag `-Ydebug-error` to get the stack trace of all the compile-time errors. Consider the following file:

```scala
object Foo
object Foo
```

Clearly we cannot define an object `Foo` twice. Now compile it as follows: `scalac -Ydebug-error ../issues/Playground.scala` (use whatever path you saved it under). The result will be as follows:

```scala
-- Error: ../issues/Playground.scala:2:0 ---------------------------------------
2 |object Foo
  |^
  |object Foo has already been compiled once during this run
java.lang.Thread.getStackTrace(Thread.java:1552)
dotty.tools.dotc.reporting.Reporting.error(Reporter.scala:139)
dotty.tools.dotc.core.Contexts$Context.error(Contexts.scala:71)
dotty.tools.dotc.typer.Namer.errorName$2(Namer.scala:300)
dotty.tools.dotc.typer.Namer.checkNoConflict$1(Namer.scala:306)
dotty.tools.dotc.typer.Namer.createSymbol(Namer.scala:353)
dotty.tools.dotc.typer.Namer.recur$1(Namer.scala:490)
dotty.tools.dotc.typer.Namer.recur$3$$anonfun$2(Namer.scala:495)
...
```

So, the error happened in the Namer's `checkNoConflict` method (after which all the stack frames represent the mechanics of issuing an error, not an intent that produced the error in the first place).

## Configuring the printer output
Printing from the `show` and `-Xprint` is done from the Printers framework (discussed in more details below). The following settings influence the output of the printers:

```scala
val printLines        = BooleanSetting("-print-lines"        , "Show source code line numbers.") withAbbreviation "--print-lines"
val uniqid            = BooleanSetting("-uniqid"             , "Uniquely tag all identifiers in debugging output.") withAbbreviation "--unique-id"
val XprintInline      = BooleanSetting("-Xprint-inline"      , "Show  where inlined code comes from")
val XprintTypes       = BooleanSetting("-Xprint-types"       , "Print tree types (debugging option).")
val Ydebug            = BooleanSetting("-Ydebug"             , "Increase the quantity of debugging output.")
val YdebugFlags       = BooleanSetting("-Ydebug-flags"       , "Print all flags of definitions")
val YdebugMissingRefs = BooleanSetting("-Ydebug-missing-refs", "Print a stacktrace when a required symbol is missing")
val YdebugNames       = BooleanSetting("-Ydebug-names"       , "Show internal representation of names")
val YdebugPos         = BooleanSetting("-Ydebug-pos"         , "Show full source positions including spans")
val YdebugTrace       = BooleanSetting("-Ydebug-trace"       , "Trace core operations")
val YdebugTreeWithId  = IntSetting    ("-Ydebug-tree-with-id", "Print the stack trace when the tree with the given id is created", Int.MinValue)
val YprintDebug       = BooleanSetting("-Yprint-debug"       , "when printing trees, print some extra information useful for debugging.")
val YprintDebugOwners = BooleanSetting("-Yprint-debug-owners", "when printing trees, print owners of definitions.")
val YprintPos         = BooleanSetting("-Yprint-pos"         , "show tree positions.")
val YprintPosSyms     = BooleanSetting("-Yprint-pos-syms"    , "show symbol definitions positions.")
val YprintSyms        = BooleanSetting("-Yprint-syms"        , "when printing trees print info in symbols instead of corresponding info in trees.")
val YshowTreeIds      = BooleanSetting("-Yshow-tree-ids"     , "Uniquely tag all tree nodes in debugging output.")
val YshowVarBounds    = BooleanSetting("-Yshow-var-bounds"   , "Print type variables with their bounds")
val YtestPickler      = BooleanSetting("-Ytest-pickler"      , "self-test for pickling functionality; should be used with -Ystop-after:pickler")
```

They are defined in [ScalaSettings.scala](https://github.com/lampepfl/dotty/blob/main/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala). E.g. `YprintPos` is defined as:

```scala
val YprintPos: Setting[Boolean] = BooleanSetting("-Yprint-pos", "show tree positions.")
```

And is to be used as:

```scala
scalac -Yprint-pos  ../issues/Playground.scala
```

If used, all the trees output with `show` or via `-Xprint:typer` will also have positions attached to them, e.g.:

```scala
package <empty>@<Playground.scala:1> {
  module object Playground {
    def main(
      args:
        Array@<Playground.scala:2>[String@<Playground.scala:2>]@<
          Playground.scala:2
        >
      @<Playground.scala:2>
    ) =
      {
        println@<Playground.scala:3>("Hello World"@<Playground.scala:3>)@<
          Playground.scala:3
        >
      }@<Playground.scala:2>
    @<Playground.scala:2>
  }@<Playground.scala:1>
}@<Playground.scala:1>
<empty>@<Playground.scala:1>
```

## Figuring out an object creation site
### Via ID
Every [Positioned](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/ast/Positioned.scala) (a parent class of `Tree`) object has a `uniqueId` field. It is an integer that is unique for that tree and doesn't change from compile run to compile run. You can output these IDs from any printer (such as the ones used by `.show` and `-Xprint`) via `-Yshow-tree-ids` flag, e.g.:

```shell
scalac -Xprint:typer -Yshow-tree-ids  ../issues/Playground.scala
```

Gives:

```scala
package <empty>#1047 {
  final lazy module val Playground: Playground$#1049 =
    new Playground$#1049#1050#1051()#1052
  #1053
  final module class Playground$() extends Object#1090#1091#1092()#1093, _root_#
    1061
  .scala#1062.Serializable#1063 { this: Playground#1054.type#1055 =>
    def main(args: Array#1028[String#1033]#1034#1038): Unit#1039 =
      {
        println#1094("Hello World"#1041)#1095
      }#1096
    #1097
  }#1099
}#1100
```

You can then use these IDs to locate the creation site of a given tree using that ID via `-Ydebug-tree-with-id`, e.g.:

```shell
scalac -Ydebug-tree-with-id 1049 ../issues/Playground.scala
```

When the tree with the correspond id is allocated, the following prompt will appear:

```
Debug tree (id=1049) creation
Ident(Playground$)

a)bort, s)tack, r)esume
```

If you input `s`, you will get a stack trace like this:

```
java.lang.Throwable
  at dotty.tools.dotc.reporting.Reporter$.loop$1(Reporter.scala:55)
  at dotty.tools.dotc.reporting.Reporter$.displayPrompt(Reporter.scala:63)
  at dotty.tools.dotc.ast.Positioned.printTrace$1(Positioned.scala:32)
  at dotty.tools.dotc.ast.Positioned.uniqueId_$eq(Positioned.scala:34)
  at dotty.tools.dotc.ast.Positioned.<init>(Positioned.scala:45)
  at dotty.tools.dotc.ast.Trees$Tree.<init>(Trees.scala:53)
  at dotty.tools.dotc.ast.Trees$DenotingTree.<init>(Trees.scala:266)
  at dotty.tools.dotc.ast.Trees$NameTree.<init>(Trees.scala:292)
  at dotty.tools.dotc.ast.Trees$RefTree.<init>(Trees.scala:298)
  at dotty.tools.dotc.ast.Trees$Ident.<init>(Trees.scala:375)
  at dotty.tools.dotc.ast.untpd$.Ident(untpd.scala:301)
  at dotty.tools.dotc.ast.desugar$.moduleDef(Desugar.scala:804)
  at dotty.tools.dotc.ast.desugar$.defTree(Desugar.scala:1038)
  at dotty.tools.dotc.typer.Namer.expand(Namer.scala:441)
  at dotty.tools.dotc.typer.Namer.index$$anonfun$1(Namer.scala:722)
  at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
  at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
  at scala.collection.immutable.List.foreach(List.scala:392)
  at dotty.tools.dotc.typer.Namer.index(Namer.scala:722)
  at dotty.tools.dotc.typer.Namer.recur$1(Namer.scala:484)
  at dotty.tools.dotc.typer.Namer.indexExpanded(Namer.scala:501)
  at dotty.tools.dotc.typer.Namer.index(Namer.scala:474)
  at dotty.tools.dotc.typer.FrontEnd.enterSyms$$anonfun$1(FrontEnd.scala:69)
  at dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
  at dotty.tools.dotc.typer.FrontEnd.monitor(FrontEnd.scala:41)
  at dotty.tools.dotc.typer.FrontEnd.enterSyms(FrontEnd.scala:71)
  at dotty.tools.dotc.typer.FrontEnd.runOn(FrontEnd.scala:100)
  at dotty.tools.dotc.Run.runPhases$4$$anonfun$4(Run.scala:158)
  at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:15)
  at dotty.runtime.function.JProcedure1.apply(JProcedure1.java:10)
  at scala.collection.IndexedSeqOptimized.foreach(IndexedSeqOptimized.scala:36)
  at scala.collection.IndexedSeqOptimized.foreach$(IndexedSeqOptimized.scala:33)
  at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:198)
  at dotty.tools.dotc.Run.runPhases$5(Run.scala:170)
  at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:178)
  at dotty.runtime.function.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
  at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:102)
  at dotty.tools.dotc.Run.compileUnits(Run.scala:185)
  at dotty.tools.dotc.Run.compileSources(Run.scala:120)
  at dotty.tools.dotc.Run.compile(Run.scala:104)
  at dotty.tools.dotc.Driver.doCompile(Driver.scala:34)
  at dotty.tools.dotc.Driver.process(Driver.scala:172)
  at dotty.tools.dotc.Driver.process(Driver.scala:141)
  at dotty.tools.dotc.Driver.process(Driver.scala:153)
  at dotty.tools.dotc.Driver.main(Driver.scala:180)
  at dotty.tools.dotc.Main.main(Main.scala)
```

So that tree was created at:

```
  at dotty.tools.dotc.ast.desugar$.moduleDef(Desugar.scala:804)
```

Since all the stack frames above it are technical frames executing the tree creation command, and the frame in question is the location where the intent of the tree creation was expressed.

### Via tracer
Some objects may not be `Positioned` and hence their creation site is not debuggable via the technique in the section above. Say you target a tree at `Typer`'s `typed` method as follows:

```scala
if (tree.show == """println("Hello World")""") {
  val creationSite = "<creation site stack here>"
  println(creationSite)
}
```

In other words, you have a reference to the object and want to know were it was created. To do so, go to the class definition of that object. In our case, `tree` is a [`Tree`](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/ast/Trees.scala#L52). Now, create a new `val` member of that type:

```scala
val tracer = Thread.currentThread.getStackTrace.mkString("\n")
```

Then, from the `typed` method (or wherever you want to access the trace):

```scala
if (tree.show == """println("Hello World")""") {
  val creationSite = tree.tracer
  println(creationSite)
}
```

## Built-in Logging Architecture
Dotty has a lot of debug calls scattered throughout the code, most of which are disabled by default. At least three (possibly intertwined) architectures for logging are used for that:

- Printer
- Tracing
- Reporter

These do not follow any particular system and so probably it will be easier to go with `println` most of the times instead.

### Printers
Defined in [Printers.scala](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/config/Printers.scala) as a set of variables, each responsible for its own domain. To enable them, replace `noPrinter` with `default`. [Example](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/typer/Typer.scala#L2226) from the code:

```scala
typr.println(i"make contextual function $tree / $pt ---> $ifun")
```

`typr` is a printer.

### Tracing
Defined in [trace.scala](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/reporting/trace.scala). [Example](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/typer/Typer.scala#L2232) from the code:

```scala
trace(i"typing $tree", typr, show = true) { // ...
```

To enable globally, change [tracingEnabled](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/config/Config.scala#L164) to `true` (will recompile a lot of code).

You also need to set the printer referenced in the call (in the example, `typr`) to `default` as explained in the section on printers.

To enable for a single trace, do the following:

```scala
trace.force(i"typing $tree", typr, show = true) { // ...
```

### Reporter
Defined in [Reporter.scala](https://github.com/lampepfl/dotty/blob/10526a7d0aa8910729b6036ee51942e05b71abf6/compiler/src/dotty/tools/dotc/reporting/Reporter.scala). Enables calls such as `report.log`. To enable, run scalac with `-Ylog:typer` option.


text:
class DashboardController < ApplicationController

  def index
    @latest_domains = Domain.user(current_user).order('created_at DESC').limit(5)
  end
end


text:
package com.bbn.openmap.omGraphics.util;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.bbn.openmap.MoreMath;
import com.bbn.openmap.geo.Geo;
import com.bbn.openmap.geo.GeoArray;
import com.bbn.openmap.geo.Intersection;
import com.bbn.openmap.geo.Ribbon;
import com.bbn.openmap.geo.RibbonIterator;
import com.bbn.openmap.omGraphics.OMAreaList;
import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.omGraphics.OMPoly;
import com.bbn.openmap.proj.Length;

/**
 * The RibbonMaker class takes polygon coordinates and creates another polygon
 * from it, a buffer region based on ground distance, around the original poly.
 * It assumes that the polygon coordinates are going in a clockwise direction.
 * The returned polygon is actually an OMAreaList made up of OMPolys, OMArcs and
 * OMLines, depending on the shape of the original polygon.
 *

 *
 * The RibbonMaker is created from one of the factory methods that designates
 * whether the coordinates are radians or decimal degrees. FYI - OMPoly
 * coordinates retrieved from the getLatLonArray method are in radians. After
 * the RibbonMaker is created, call the method that creates the appropriate
 * shape. For now, getOuterRing is your only option. To use:
 *
 *

 *
 * llPoints = new double[] {
 *     40.0f,
 *     -92.0f,
 *     42.0f,
 *     -87.0f,
 *     38.57,
 *     -90.825,
 *     37.0f,
 *     -89.0f,
 *     35.0f,
 *     -94.0f,
 *     40.0f,
 *     -92.0f
 * };
 *
 * OMGraphic omg = RibbonMaker.createFromDecimalDegrees(llPoints).getOuterRing(Length.MILE.toRadians(100));
 *
 *

 *
 *
 * @author ddietrick
 */
public class RibbonMaker {

    protected GeoArray geoCoords;
    private static final Logger logger = Logger.getLogger("com.bbn.openmap.omGraphics.util.RibbonMaker");
    protected final static int STRAIGHT = 0;
    protected final static int BENDS_LEFT = -1;
    protected final static int BENDS_RIGHT = 1;
    protected double bufferLimit = 4.778825E-10;

    protected RibbonMaker(GeoArray gCoords) {
        geoCoords = gCoords;
    }

    /**
     * Create a RibbonMaker from decimal degree coordinates.
     *
     * @param coords lat,lon,lat,lon in decimal degrees.
     * @return RibbonMaker
     */
    public static RibbonMaker createFromDecimalDegrees(double[] coords) {
        return new RibbonMaker(GeoArray.Double.createFromLatLonDegrees(coords));
    }

    /**
     * Create a RibbonMaker from radian coordinates.
     *
     * @param coords lat,lon,lat,lon in radians.
     * @return RibbonMaker
     */
    public static RibbonMaker createFromRadians(double[] coords) {
        return new RibbonMaker(GeoArray.Double.createFromLatLonRadians(coords));
    }

    /**
     * Assumes coords represent a polygon, returns an OMAreaList representing
     * buffer zone around the outside of a polygon.
     *
     * @param dist distance of buffer area, in radians. Use Length to convert.
     * @return OMAreaList of a polygon that is a distance away from the
     *         coordinate polygon's edges.
     */
    public OMAreaList getOuterRing(double dist) {
        OMAreaList ret = new OMAreaList();

        if (dist <= bufferLimit) {
            return ret;
        }

        int numCoords = geoCoords.getSize();
        if (numCoords >= 3) {

            Geo g1 = geoCoords.get(0);
            Geo g2 = geoCoords.get(1);
            Geo g3 = geoCoords.get(2);

            handlePointsForOuterRing(g1, g2, g3, dist, ret);

            for (int i = 3; i < numCoords; i++) {
                g1 = g2;
                g2 = g3;
                g3 = geoCoords.get(i);

                handlePointsForOuterRing(g1, g2, g3, dist, ret);
            }

            // test, and close it off if needed
            if (!geoCoords.get(0).equals(geoCoords.get(numCoords - 1))) {
                g1 = g2;
                g2 = g3;
                g3 = geoCoords.get(0);

                handlePointsForOuterRing(g1, g2, g3, dist, ret);
            }

            // Now round out the first and last segment, centering on the first
            // coordinate
            g1 = g2;
            g2 = g3;
            g3 = geoCoords.get(1);

            handlePointsForOuterRing(g1, g2, g3, dist, ret);

        }
        return ret;
    }

    /**
     * Takes a corner represented by the three geos, and adds OMGraphics to the
     * OMAreaList depending on which way the corner bends - for right turns,
     * it'll add an OMLine, OMArc and OMLine. The OMLines will go from half the
     * distance of the legs to the rounded corner. The left turn will have a
     * polygon added.
     *
     * @param g1 point 1
     * @param g2 point 2
     * @param g3 point 3
     * @param dist buffer distance in radians
     * @param ret OMAreaList to add OMGraphics to.
     */
    protected void handlePointsForOuterRing(Geo g1, Geo g2, Geo g3, double dist, OMAreaList ret) {
        int bend = bends(g1, g2, g3);

        Geo gret = g3;
        RibbonIterator leg1 = new RibbonIterator(g1, g2, dist);
        OMPoly poly1 = getHalfPoly(leg1, Ribbon.LEFT, false);

        RibbonIterator leg2 = new RibbonIterator(g2, g3, dist);
        OMPoly poly2 = getHalfPoly(leg2, Ribbon.LEFT, true);

        if (bend == STRAIGHT || g2.equals(g3)) {
            ret.add(poly1);
            ret.add(poly2);
        } else {
            if (bend == BENDS_LEFT) {
                // short, need to find intersection of two legs and remove
                // points
                // from polys to only go to intersection

                double dg12 = g1.distance(g2);
                double dg23 = g2.distance(g3);
                double legTestDist = dist * 2;

                if (dg12 < legTestDist || dg23 < legTestDist) {
                    addShortLegPolyForIntersection(g1, g2, g3, Ribbon.LEFT, dist, ret);
                } else {
                    addPolyForIntersection(poly1, poly2, dist, ret);
                }

            } else {
                OMGraphic omp = getPushbackPoly(poly1, dist);
                if (omp != null) {
                    ret.add(omp);
                }
                // Add OMArc in the middle, rounding around a corner
                OMGraphic oma = getArc(g2, poly1, poly2);
                if (oma != null) {
                    ret.add(oma);
                }
                omp = getPushbackPoly(poly2, dist);
                if (omp != null) {
                    ret.add(omp);
                }
            }
        }

    }

    /**
     * Method that determines which way the angle between the three points
     * bends.
     *
     * @param g1
     * @param g2
     * @param g3
     * @return STRAIGHT if no bend, BENDS_LEFT if bends less than PI,
     *         BENDS_RIGHT if bends more than PI.
     */
    protected int bends(Geo g1, Geo g2, Geo g3) {
        double bend = g1.crossNormalize(g2).distance(g3) - (Math.PI / 2.0);

        if (Math.abs(bend) < .0001) {
            return STRAIGHT; // essentially straight
        } else {
            if (bend < 0) {
                return BENDS_LEFT;
            }
        }

        return BENDS_RIGHT;
    }

    /**
     * Checks to see if a point is too close to any side of the original
     * polygon.
     *
     * @param pnt
     * @param distance
     * @return true if is too close and should not be added to the buffer
     *         polygon.
     */
    protected boolean tooClose(Geo pnt, double distance) {
        return Intersection.isPointNearPoly(pnt, geoCoords, distance - bufferLimit);
    }

    /**
     * Takes a poly that's going to be added to the buffer and removes any
     * points that may be too close to the original poly.
     *
     * @param omp the buffer poly to be added later
     * @param dist the distance all points should be from the original
     * @return the OMGraphic with good points.
     */
    protected OMGraphic getPushbackPoly(OMPoly omp, double dist) {
        double[] coords = omp.getLatLonArray();
        List<Geo> results = new LinkedList<Geo>();
        for (int i = 0; i < coords.length - 2; i += 2) {
            Geo g = new Geo(coords[i], coords[i + 1], false);
            if (!tooClose(g, dist)) {
                results.add(g);
            }
        }

        if (results.size() == 1) {
            results.add(new Geo(results.get(0)));
        }

        if (results.size() > 1) {
            return getOMPolyFromGeos(results);
        }

        return null;

    }

    /**
     * Called when it's known that one of the legs between the corner is smaller
     * than the buffer depth. Does some extra work to figure out what points
     * should be added to the buffer.
     *
     * @param g1 point 1
     * @param g2 point 2, the corner
     * @param g3 point 3
     * @param ribbonSide which side of the ribbon should be calculated.
     * @param dist the distance the buffer should be from the legs
     * @param ret the OMGraphicList to add the resulting poly to.
     */
    protected void addShortLegPolyForIntersection(Geo g1, Geo g2, Geo g3, int ribbonSide, double dist, OMAreaList ret) {

        /**
         * We need to do some extra work here. Since one of the legs is shorter
         * than 2*dist of the buffer, half of the buffer polygon won't reach the
         * intersection point between the two legs. So, we need to recalculate
         * the polys so the represent the entire legs, in order to find the
         * intersection point.
         *
         * Once we have that, we can go back to the half polygons, and test for
         * that intersection point against each little segment. If any of those
         * points are further away than buffer distance to the opposite poly,
         * they should be included on the polygon added to the list. If a point
         * is inside that distance, it should be disregarded. If there is only
         * one point (i.e. the original intersection point), then a duplicate
         * intersection point should be added, so the OMAreaList will handle it
         * properly.
         */
        List<Geo> results = new LinkedList<Geo>();
        RibbonIterator leg1 = new RibbonIterator(g1, g2, dist);
        OMPoly fullPoly1 = getPoly(leg1, ribbonSide);

        RibbonIterator leg2 = new RibbonIterator(g2, g3, dist);
        OMPoly fullPoly2 = getPoly(leg2, ribbonSide);

        // Intersection is the point on both polys that is buffer distance away
        // from corner
        Geo intersection = getPolyIntersection(fullPoly1, fullPoly2);

        if (intersection == null) {
            // GAAH! This shouldn't happen
            return;
        }

        leg1 = new RibbonIterator(g1, g2, dist);
        OMPoly halfPoly1 = getHalfPoly(leg1, ribbonSide, false);
        GeoArray geoPoly2 = GeoArray.Double.createFromLatLonRadians(fullPoly2.getLatLonArray());

        double[] leg1Coords = halfPoly1.getLatLonArray();
        for (int i = 0; i < leg1Coords.length - 1; i += 2) {
            Geo pnt = new Geo(leg1Coords[i], leg1Coords[i + 1], false);

            if (!tooClose(pnt, dist)) {
                results.add(pnt);
            }
        }

        if (!tooClose(intersection, dist)) {
            results.add(intersection);
        }

        leg2 = new RibbonIterator(g2, g3, dist);
        OMPoly halfPoly2 = getHalfPoly(leg2, ribbonSide, true);
        GeoArray geoPoly1 = GeoArray.Double.createFromLatLonRadians(fullPoly1.getLatLonArray());

        double[] leg2Coords = halfPoly2.getLatLonArray();
        for (int i = 0; i < leg2Coords.length - 1; i += 2) {
            Geo pnt = new Geo(leg2Coords[i], leg2Coords[i + 1], false);

            if (!tooClose(pnt, dist)) {
                results.add(pnt);
            }
        }

        if (results.size() == 1 && !tooClose(intersection, dist)) {
            results.add(intersection);
        }

        if (results.size() > 1) {
            ret.add(getOMPolyFromGeos(results));
        }
    }

    /**
     * Just return the point where the two polygons cross.
     *
     * @param poly1
     * @param poly2
     * @return null if no point found.
     */
    protected Geo getPolyIntersection(OMPoly poly1, OMPoly poly2) {
        double[] p1Coords = poly1.getLatLonArray();
        double[] p2Coords = poly2.getLatLonArray();

        Geo a1, a2, b1, b2;
        Geo intersect = null;
        int index1 = 0, index2 = 0;
        for (; index2 + 3 < p2Coords.length; index2 += 2) {
            b1 = new Geo(p2Coords[index2], p2Coords[index2 + 1], false);
            b2 = new Geo(p2Coords[index2 + 2], p2Coords[index2 + 3], false);

            if (intersect == null) {
                for (; index1 + 3 < p1Coords.length; index1 += 2) {

                    a1 = new Geo(p1Coords[index1], p1Coords[index1 + 1], false);
                    a2 = new Geo(p1Coords[index1 + 2], p1Coords[index1 + 3], false);

                    intersect = Intersection.segmentsIntersect(a1, a2, b1, b2);

                    if (intersect != null) {
                        return intersect;
                    }
                }
            }
        }

        return intersect;
    }

    /**
     * Converts Vector of Geos to an OMPoly with linetype great_circle. Assumes
     * that the List has valid coordinates on it. Does not do a closeness check
     * to the original poly, expected that's been done.
     *
     * @param geos a set of coordinates
     * @return OMPoly
     */
    protected OMPoly getOMPolyFromGeos(List<Geo> geos) {
        double[] tmpCoords = new double[geos.size() * 2];
        int index = 0;
        for (Geo geo : geos) {
            tmpCoords[index++] = geo.getLatitudeRadians();
            tmpCoords[index++] = geo.getLongitudeRadians();
        }

        return new OMPoly(tmpCoords, OMPoly.RADIANS, OMGraphic.LINETYPE_GREATCIRCLE);
    }

    /**
     * Called to handle BENDS_LEFT, concave corners. RuntimeException is thrown
     * when one of the legs is much shorter than the other and the mid-point is
     * still in the buffer of one of the legs. In that special case, the
     * intersection point is not found.
     *
     * @param poly1
     * @param poly2
     * @param ret
     */
    protected void addPolyForIntersection(OMPoly poly1, OMPoly poly2, double dist, OMAreaList ret) {
        double[] p1Coords = poly1.getLatLonArray();
        double[] p2Coords = poly2.getLatLonArray();

        List<Geo> results = new LinkedList<Geo>();

        Geo a1, a2, b1, b2;
        Geo intersect = null;
        int index1 = 0, index2 = 0;
        for (; index2 + 3 < p2Coords.length; index2 += 2) {
            b1 = new Geo(p2Coords[index2], p2Coords[index2 + 1], false);
            b2 = new Geo(p2Coords[index2 + 2], p2Coords[index2 + 3], false);

            if (intersect == null) {
                for (; index1 + 3 < p1Coords.length; index1 += 2) {

                    a1 = new Geo(p1Coords[index1], p1Coords[index1 + 1], false);
                    a2 = new Geo(p1Coords[index1 + 2], p1Coords[index1 + 3], false);

                    intersect = Intersection.segmentsIntersect(a1, a2, b1, b2);

                    if (!tooClose(a1, dist)) {
                        results.add(a1);
                    }

                    if (intersect != null) {
                        if (!tooClose(intersect, dist)) {
                            results.add(intersect);
                        }
                        break;
                    }
                }
            }

            if (intersect != null && !tooClose(b2, dist)) {
                results.add(b2);
            }
        }

        if (results.size() > 1) {
            ret.add(getOMPolyFromGeos(results));
        }
    }

    /**
     * Given a RibbonIterator created from two Geos, create a poly from half of
     * that buffer path. Points are not checked for closeness to original poly.
     *
     * @param rIterator RibbonIterator for one of the legs of corner
     * @param side which RibbonIterator side
     * @param first which half you want, true for first part
     * @return OMPoly that represents half of the buffered path.
     */
    protected OMPoly getHalfPoly(RibbonIterator rIterator, int side, boolean first) {
        List<Geo> results = new LinkedList<Geo>();
        for (Ribbon rib : rIterator) {
            Geo g = rib.get(side);
            results.add(g);
        }

        int numCoords = results.size();

        if (numCoords > 0) {

            int startingIndex = 0;
            int copyLength = numCoords / 2;

            if (numCoords % 2 == 0) {
                if (!first) {
                    startingIndex = copyLength; // middle
                }
            } else {
                if (!first) {
                    startingIndex = copyLength;
                }
                copyLength++;
            }

            List<Geo> newGeoCoords = new LinkedList<Geo>();
            for (int index = 0; index < copyLength; index++) {
                Geo g = results.get(startingIndex + index);
                newGeoCoords.add(g);
            }

            return getOMPolyFromGeos(newGeoCoords);
        }
        return null;
    }

    /**
     * Given a RibbonIterator created from two Geos, create a poly from that
     * buffer path.
     *
     * @param rIterator RibbonIterator for one of the legs of corner
     * @param side which RibbonIterator side
     * @return OMPoly that represents buffered path between geos.
     */
    protected OMPoly getPoly(RibbonIterator rIterator, int side) {
        List<Geo> bufferCoords = new LinkedList<Geo>();
        for (Ribbon rib : rIterator) {
            bufferCoords.add(rib.get(side));
        }

        if (bufferCoords.size() > 1) {
            return getOMPolyFromGeos(bufferCoords);
        }
        return null;
    }

    /**
     * Given two polylines, with the end point of poly1 being the same distance
     * from a point as the starting point of poly2, create an arc that connects
     * them.
     *
     * @param gc point
     * @param poly1 polyline where the last end point is used
     * @param poly2 polyline where the first end point is used.
     * @return OMArc
     */
    public OMGraphic getArc(Geo gc, OMPoly poly1, OMPoly poly2) {

        double[] poly1Coords = poly1.getLatLonArray();
        Geo pt1 = new Geo(poly1Coords[poly1Coords.length - 2], poly1Coords[poly1Coords.length - 1], false);
        double radAngle1 = gc.azimuth(pt1);

        double[] poly2Coords = poly2.getLatLonArray();
        Geo pt2 = new Geo(poly2Coords[0], poly2Coords[1], false);
        double radAngle2 = gc.azimuth(pt2);

        double dist = gc.distance(pt1);

        if (radAngle2 < radAngle1) {
            radAngle2 += MoreMath.TWO_PI_D;
        }

        if (logger.isLoggable(Level.FINE)) {
            logger.fine(new StringBuilder("Making arg starting at ").append(Length.DECIMAL_DEGREE.fromRadians(radAngle1))
                                                                    .append(", ")
                                                                    .append(Length.DECIMAL_DEGREE.fromRadians(radAngle2 - radAngle1))
                                                                    .toString());
        }

        List<Geo> points = new LinkedList<Geo>();
        double inc = Length.DECIMAL_DEGREE.toRadians(2.0);
        double angle = radAngle1 + inc;

        while (angle < radAngle2 - inc) {
            Geo g = gc.offset(dist, angle);
            if (!tooClose(g, dist)) {
                points.add(g);
            }
            angle += inc;
        }

        return getOMPolyFromGeos(points);
        // return new OMArc(gc.getLatitude(), gc.getLongitude(), dist,
        // Length.RADIAN, 100, Length.DECIMAL_DEGREE.fromRadians(radAngle1),
        // Length.DECIMAL_DEGREE.fromRadians(radAngle2 - radAngle1));

    }
}