text:
# Logging

- [Introduction](#introduction)
- [Configuration](#configuration)
    - [Building Log Stacks](#building-log-stacks)
- [Writing Log Messages](#writing-log-messages)
    - [Writing To Specific Channels](#writing-to-specific-channels)
- [Advanced Monolog Channel Customization](#advanced-monolog-channel-customization)
    - [Customizing Monolog For Channels](#customizing-monolog-for-channels)
    - [Creating Monolog Handler Channels](#creating-monolog-handler-channels)
    - [Creating Channels Via Factories](#creating-channels-via-factories)

## Introduction

To help you learn more about what's happening within your application, Laravel provides robust logging services that allow you to log messages to files, the system error log, and even to Slack to notify your entire team.

Under the hood, Laravel utilizes the [Monolog](https://github.com/Seldaek/monolog) library, which provides support for a variety of powerful log handlers. Laravel makes it a cinch to configure these handlers, allowing you to mix and match them to customize your application's log handling.

## Configuration

All of the configuration for your application's logging system is housed in the `config/logging.php` configuration file. This file allows you to configure your application's log channels, so be sure to review each of the available channels and their options. We'll review a few common options below.

By default, Laravel will use the `stack` channel when logging messages. The `stack` channel is used to aggregate multiple log channels into a single channel. For more information on building stacks, check out the [documentation below](#building-log-stacks).

#### Configuring The Channel Name

By default, Monolog is instantiated with a "channel name" that matches the current environment, such as `production` or `local`. To change this value, add a `name` option to your channel's configuration:

    'stack' => [
        'driver' => 'stack',
        'name' => 'channel-name',
        'channels' => ['single', 'slack'],
    ],

#### Available Channel Drivers

Name | Description
------------- | -------------
`stack` | A wrapper to facilitate creating "multi-channel" channels
`single` | A single file or path based logger channel (`StreamHandler`)
`daily` | A `RotatingFileHandler` based Monolog driver which rotates daily
`slack` | A `SlackWebhookHandler` based Monolog driver
`papertrail` | A `SyslogUdpHandler` based Monolog driver
`syslog` | A `SyslogHandler` based Monolog driver
`errorlog` | A `ErrorLogHandler` based Monolog driver
`monolog` | A Monolog factory driver that may use any supported Monolog handler
`custom` | A driver that calls a specified factory to create a channel

> {tip} Check out the documentation on [advanced channel customization](#advanced-monolog-channel-customization) to learn more about the `monolog` and `custom` drivers.

#### Configuring The Single and Daily Channels

The `single` and `daily` channels have three optional configuration options: `bubble`, `permission`, and `locking`.

Name | Description | Default
------------- | ------------- | -------------
`bubble` | Indicates if messages should bubble up to other channels after being handled | `true`
`permission` | The log file's permissions | `0644`
`locking` | Attempt to lock the log file before writing to it | `false`

#### Configuring The Papertrail Channel

The `papertrail` channel requires the `url` and `port` configuration options. You can obtain these values from [Papertrail](https://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-php-apps/#send-events-from-php-app).

#### Configuring The Slack Channel

The `slack` channel requires a `url` configuration option. This URL should match a URL for an [incoming webhook](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks) that you have configured for your Slack team.

### Building Log Stacks

As previously mentioned, the `stack` driver allows you to combine multiple channels into a single log channel. To illustrate how to use log stacks, let's take a look at an example configuration that you might see in a production application:

    'channels' => [
        'stack' => [
            'driver' => 'stack',
            'channels' => ['syslog', 'slack'],
        ],

        'syslog' => [
            'driver' => 'syslog',
            'level' => 'debug',
        ],

        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'emoji' => ':boom:',
            'level' => 'critical',
        ],
    ],

Let's dissect this configuration. First, notice our `stack` channel aggregates two other channels via its `channels` option: `syslog` and `slack`. So, when logging messages, both of these channels will have the opportunity to log the message.

#### Log Levels

Take note of the `level` configuration option present on the `syslog` and `slack` channel configurations in the example above. This option determines the minimum "level" a message must be in order to be logged by the channel. Monolog, which powers Laravel's logging services, offers all of the log levels defined in the [RFC 5424 specification](https://tools.ietf.org/html/rfc5424): **emergency**, **alert**, **critical**, **error**, **warning**, **notice**, **info**, and **debug**.

So, imagine we log a message using the `debug` method:

    Log::debug('An informational message.');

Given our configuration, the `syslog` channel will write the message to the system log; however, since the error message is not `critical` or above, it will not be sent to Slack. However, if we log an `emergency` message, it will be sent to both the system log and Slack since the `emergency` level is above our minimum level threshold for both channels:

    Log::emergency('The system is down!');

## Writing Log Messages

You may write information to the logs using the `Log` [facade](/docs/{{version}}/facades). As previously mentioned, the logger provides the eight logging levels defined in the [RFC 5424 specification](https://tools.ietf.org/html/rfc5424): **emergency**, **alert**, **critical**, **error**, **warning**, **notice**, **info** and **debug**:

    Log::emergency($message);
    Log::alert($message);
    Log::critical($message);
    Log::error($message);
    Log::warning($message);
    Log::notice($message);
    Log::info($message);
    Log::debug($message);

So, you may call any of these methods to log a message for the corresponding level. By default, the message will be written to the default log channel as configured by your `config/logging.php` configuration file:

    <?php

    namespace App\Http\Controllers;

    use App\Http\Controllers\Controller;
    use App\User;
    use Illuminate\Support\Facades\Log;

    class UserController extends Controller
    {
        /**
         * Show the profile for the given user.
         *
         * @param  int  $id
         * @return Response
         */
        public function showProfile($id)
        {
            Log::info('Showing user profile for user: '.$id);

            return view('user.profile', ['user' => User::findOrFail($id)]);
        }
    }

#### Contextual Information

An array of contextual data may also be passed to the log methods. This contextual data will be formatted and displayed with the log message:

    Log::info('User failed to login.', ['id' => $user->id]);

### Writing To Specific Channels

Sometimes you may wish to log a message to a channel other than your application's default channel. You may use the `channel` method on the `Log` facade to retrieve and log to any channel defined in your configuration file:

    Log::channel('slack')->info('Something happened!');

If you would like to create an on-demand logging stack consisting of multiple channels, you may use the `stack` method:

    Log::stack(['single', 'slack'])->info('Something happened!');

## Advanced Monolog Channel Customization

### Customizing Monolog For Channels

Sometimes you may need complete control over how Monolog is configured for an existing channel. For example, you may want to configure a custom Monolog `FormatterInterface` implementation for a given channel's handlers.

To get started, define a `tap` array on the channel's configuration. The `tap` array should contain a list of classes that should have an opportunity to customize (or "tap" into) the Monolog instance after it is created:

    'single' => [
        'driver' => 'single',
        'tap' => [App\Logging\CustomizeFormatter::class],
        'path' => storage_path('logs/laravel.log'),
        'level' => 'debug',
    ],

Once you have configured the `tap` option on your channel, you're ready to define the class that will customize your Monolog instance. This class only needs a single method: `__invoke`, which receives an `Illuminate\Log\Logger` instance. The `Illuminate\Log\Logger` instance proxies all method calls to the underlying Monolog instance:

    <?php

    namespace App\Logging;

    class CustomizeFormatter
    {
        /**
         * Customize the given logger instance.
         *
         * @param  \Illuminate\Log\Logger  $logger
         * @return void
         */
        public function __invoke($logger)
        {
            foreach ($logger->getHandlers() as $handler) {
                $handler->setFormatter(...);
            }
        }
    }

> {tip} All of your "tap" classes are resolved by the [service container](/docs/{{version}}/container), so any constructor dependencies they require will automatically be injected.

### Creating Monolog Handler Channels

Monolog has a variety of [available handlers](https://github.com/Seldaek/monolog/tree/master/src/Monolog/Handler). In some cases, the type of logger you wish to create is merely a Monolog driver with an instance of a specific handler.  These channels can be created using the `monolog` driver.

When using the `monolog` driver, the `handler` configuration option is used to specify which handler will be instantiated. Optionally, any constructor parameters the handler needs may be specified using the `with` configuration option:

    'logentries' => [
        'driver'  => 'monolog',
        'handler' => Monolog\Handler\SyslogUdpHandler::class,
        'with' => [
            'host' => 'my.logentries.internal.datahubhost.company.com',
            'port' => '10000',
        ],
    ],

#### Monolog Formatters

When using the `monolog` driver, the Monolog `LineFormatter` will be used as the default formatter. However, you may customize the type of formatter passed to the handler using the `formatter` and `formatter_with` configuration options:

    'browser' => [
        'driver' => 'monolog',
        'handler' => Monolog\Handler\BrowserConsoleHandler::class,
        'formatter' => Monolog\Formatter\HtmlFormatter::class,
        'formatter_with' => [
            'dateFormat' => 'Y-m-d',
        ],
    ],

If you are using a Monolog handler that is capable of providing its own formatter, you may set the value of the `formatter` configuration option to `default`:

    'newrelic' => [
        'driver' => 'monolog',
        'handler' => Monolog\Handler\NewRelicHandler::class,
        'formatter' => 'default',
    ],

### Creating Channels Via Factories

If you would like to define an entirely custom channel in which you have full control over Monolog's instantiation and configuration, you may specify a `custom` driver type in your `config/logging.php` configuration file. Your configuration should include a `via` option to point to the factory class which will be invoked to create the Monolog instance:

    'channels' => [
        'custom' => [
            'driver' => 'custom',
            'via' => App\Logging\CreateCustomLogger::class,
        ],
    ],

Once you have configured the `custom` channel, you're ready to define the class that will create your Monolog instance. This class only needs a single method: `__invoke`, which should return the Monolog instance:

    <?php

    namespace App\Logging;

    use Monolog\Logger;

    class CreateCustomLogger
    {
        /**
         * Create a custom Monolog instance.
         *
         * @param  array  $config
         * @return \Monolog\Logger
         */
        public function __invoke(array $config)
        {
            return new Logger(...);
        }
    }


text:
namespace SimpleGoogleAnalytics.Plugin.Abstractions
{
	class PreserveAttribute : System.Attribute
	{
		public bool Conditional { get; set; }
	}
}

redpajama_set_name: RedPajamaGithub


text:
.. _boards_nrf_battery:

Battery Voltage Measurement
###########################

Overview
********

This sample demonstrates using Nordic configurations of the Zephyr ADC
infrastructure to measure the voltage of the device power supply.  Two
power supply configurations are supported:

* If the board devicetree has a ``/vbatt`` node with compatible
  ``voltage-divider`` then the voltage is measured using that divider. An
  example of a devicetree node describing a voltage divider for battery
  monitoring is:

   .. code-block:: devicetree

      / {
         vbatt {
            compatible = "voltage-divider";
            io-channels = <&adc 4>;
            output-ohms = <180000>;
            full-ohms = <(1500000 + 180000)>;
            power-gpios = <&sx1509b 4 0>;
         };
      };

* If the board does not have a voltage divider and so no ``/vbatt`` node
  present, the ADC configuration (device and channel) needs to be provided via
  the ``zephyr,user`` node. In this case the power source is assumed to be
  directly connected to the digital voltage signal, and the internal source for
  ``Vdd`` is selected. An example of a Devicetree configuration for this case is
  shown below:

   .. code-block :: devicetree

      / {
         zephyr,user {
            io-channels = <&adc 4>;
         };
      };

Note that in many cases where there is no voltage divider the digital
voltage will be fed from a regulator that provides a fixed voltage
regardless of source voltage, rather than by the source directly. In
configuration involving a regulator the measured voltage will be
constant.

The sample provides discharge curves that map from a measured voltage to
an estimate of remaining capacity.  The correct curve depends on the
battery source: a standard LiPo cell requires a curve that is different
from a standard alkaline battery.  Curves can be measured, or estimated
using the data sheet for the battery.

Application Details
===================

The application initializes battery measurement on startup, then loops
displaying the battery status every five seconds.

Requirements
************

A Nordic-based board, optionally with a voltage divider specified in its
devicetree configuration as noted above.

Building and Running
********************

The code can be found in :zephyr_file:`samples/boards/nrf/battery`.

.. zephyr-app-commands::
   :zephyr-app: samples/boards/nrf/battery
   :board: thingy52_nrf52832
   :goals: build flash
   :compact:

Sample Output
=============

.. code-block:: console

   *** Booting Zephyr OS build zephyr-v2.2.0-318-g84219bdc1ac2  ***
   [0:00:00.016]: 4078 mV; 10000 pptt
   [0:00:04.999]: 4078 mV; 10000 pptt
   [0:00:09.970]: 4078 mV; 10000 pptt
   [0:00:14.939]: 4069 mV; 10000 pptt
   [0:00:19.910]: 4078 mV; 10000 pptt
   [0:00:24.880]: 4069 mV; 10000 pptt


text:
sealed trait CoffeeRequest

case object CappuccinoRequest extends CoffeeRequest
case object EspressoRequest extends CoffeeRequest

import akka.actor.Actor

class Barista extends Actor {

  def receive = {

    case CappuccinoRequest => println("Preparing a Cappuccino")
    case EspressoRequest => println("Preparing a Espresso")
  }
}


text:
package org.apache.hive.hcatalog.streaming.mutate.worker;

import org.apache.hadoop.hive.ql.io.RecordIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Verifies that the sequence of {@link RecordIdentifier RecordIdentifiers} are in a valid order for insertion into an
 * ACID delta file in a given partition and bucket.
 */
class SequenceValidator {

  private static final Logger LOG = LoggerFactory.getLogger(SequenceValidator.class);

  private Long lastTxId;
  private Long lastRowId;

  SequenceValidator() {
  }

  boolean isInSequence(RecordIdentifier recordIdentifier) {
    if (lastTxId != null && recordIdentifier.getTransactionId() < lastTxId) {
      LOG.debug("Non-sequential transaction ID. Expected >{}, recordIdentifier={}", lastTxId, recordIdentifier);
      return false;
    } else if (lastTxId != null && recordIdentifier.getTransactionId() == lastTxId && lastRowId != null
        && recordIdentifier.getRowId() <= lastRowId) {
      LOG.debug("Non-sequential row ID. Expected >{}, recordIdentifier={}", lastRowId, recordIdentifier);
      return false;
    }
    lastTxId = recordIdentifier.getTransactionId();
    lastRowId = recordIdentifier.getRowId();
    return true;
  }

  /**
   * Validator must be reset for each new partition and or bucket.
   */
  void reset() {
    lastTxId = null;
    lastRowId = null;
    LOG.debug("reset");
  }

  @Override
  public String toString() {
    return "SequenceValidator [lastTxId=" + lastTxId + ", lastRowId=" + lastRowId + "]";
  }

}


text:
require 'rails_helper'

RSpec.describe Account::BugsController, type: :controller do
  describe "#index" do
    def sort(bugs, field, reverse=false)
      bugs.sort_by! { |b| [b.send(field), b.number] }
      bugs.reverse! if reverse
      bugs
    end

    include_context "setup for required logged-in user"
    it "should require a logged-in user" do
      get :index
      expect(response).to redirect_to(login_required_redirection_url(next: request.fullpath))
    end

    context '[authenticated]' do
      before(:each) { login_as @user }

      context '[JSON]' do
        context "[type = watched]" do
          before :all do
            @user = FactoryGirl.create(:user)
            env   = FactoryGirl.create(:environment)
            FactoryGirl.create :membership, user: @user, project: env.project
            @bugs = FactoryGirl.create_list(:bug, 10, environment: env)
            @bugs.each { |bug| FactoryGirl.create :watch, user: @user, bug: bug }

            # create an increasing number of occurrences per each bug
            # also creates a random first and latest occurrence
            @bugs.each_with_index do |bug, i|
              Bug.where(id: bug.id).update_all occurrences_count: i + 1,
                                               first_occurrence:  Time.now - rand*86400,
                                               latest_occurrence: Time.now - rand*86400
            end
            @watches = @user.watches.includes(:bug).order('created_at DESC') # reload to get new triggered values
          end

          before(:each) { stub_const 'Account::BugsController::PER_PAGE', 5 } # speed it up

          it "should load 50 of the most recently watched bugs by default" do
            get :index, format: 'json', type: 'watched'
            expect(response.status).to eql(200)
            expect(JSON.parse(response.body).map { |r| r['number'] }).to eql(@watches.map(&:bug).map(&:number)[0, 5])
          end

          it "should return the next 50 bugs when given a last parameter" do
            get :index, last: @watches[4].bug.id, format: 'json', type: 'watched'
            expect(response.status).to eql(200)
            expect(JSON.parse(response.body).map { |r| r['number'] }).to eql(@watches.map(&:bug).map(&:number)[5, 5])
          end

          it "should decorate the bug JSON" do
            get :index, format: 'json', type: 'watched'
            JSON.parse(response.body).each { |bug| expect(bug['href']).to match(/\/projects\/.+?\/environments\/.+?\/bugs\/#{bug['number']}/) }
          end
        end

        context "[type = assigned]" do
          before :all do
            @user = FactoryGirl.create(:user)
            env   = FactoryGirl.create(:environment)
            FactoryGirl.create :membership, user: @user, project: env.project
            @bugs = FactoryGirl.create_list(:bug, 10, environment: env, assigned_user: @user)

            # create an increasing number of occurrences per each bug
                                # also creates a random first and latest occurrence
            @bugs.each_with_index do |bug, i|
              Bug.where(id: bug.id).update_all occurrences_count: i + 1,
                                               first_occurrence:  Time.now - rand*86400,
                                               latest_occurrence: Time.now - rand*86400
            end
            @bugs.map(&:reload) # get the new triggered values
            sort @bugs, 'latest_occurrence', true
          end

          before(:each) { stub_const 'Account::BugsController::PER_PAGE', 5 } # speed it up

          it "should load 50 of the newest assigned bugs by default" do
            get :index, format: 'json'
            expect(response.status).to eql(200)
            expect(JSON.parse(response.body).map { |r| r['number'] }).to eql(@bugs.map(&:number)[0, 5])
          end

          it "should return the next 50 bugs when given a last parameter" do
            get :index, last: @bugs[4].number, format: 'json'
            expect(response.status).to eql(200)
            expect(JSON.parse(response.body).map { |r| r['number'] }).to eql(@bugs.map(&:number)[5, 5])
          end

          it "should decorate the bug JSON" do
            get :index, format: 'json'
            JSON.parse(response.body).each { |bug| expect(bug['href']).to match(/\/projects\/.+?\/environments\/.+?\/bugs\/#{bug['number']}/) }
          end
        end
      end
    end
  end
end


text:
//
//  MM.cpp
//  hog2 glut
//
//  Created by Nathan Sturtevant on 8/31/15.
//  Copyright (c) 2015 University of Denver. All rights reserved.
//

#include "MMRubik.h"
#include "IDAStar.h"
#include "ParallelIDAStar.h"
#include "Timer.h"
#include <string>
#include <unordered_set>
#include <iomanip>
#include "SharedQueue.h"
#include "FixedSizeSet.h"

NAMESPACE_OPEN(MM)

//const int fileBuckets = 8; // must be at least 8
//const uint64_t bucketBits = 3;
//const int bucketMask = 0x7;
//const int fileBuckets = 32; // must be at least 8
const uint64_t bucketBits = 5;
const int bucketMask = ((1<<bucketBits)-1);//0x1F;

const char *prefix1;
const char *prefix2;
const char *hprefix;
bool finished = false;

int bestSolution;
int currentC;
int minGForward;
int minGBackward;
int minFForward;
int minFBackward;
uint64_t expanded;
std::vector<uint64_t> gDistForward;
std::vector<uint64_t> gDistBackward;
std::mutex printLock;
std::mutex countLock;
std::mutex openLock;

RubiksState startState, goalState;
//unsigned __int128 i;
//typedef RubiksState diskState;
typedef uint64_t diskState;
#define MY_SET

#ifdef MY_SET
typedef FixedSizeSet<diskState> bucketSet;
#else
typedef std::unordered_set<diskState> bucketSet;
#endif

void GetBucketAndData(const RubiksState &s, int &bucket, diskState &data);
void GetState(RubiksState &s, int bucket, diskState data);
int GetBucket(const RubiksState &s);

void BuildHeuristics(RubiksState start, RubiksState goal, Heuristic<RubiksState> &result, heuristicType h);
RubiksCube cube;

Heuristic<RubiksState> forward;
Heuristic<RubiksState> reverse;

//namespace std
//{
//	template<>
//	struct hash<unsigned __int128> {
//		size_t operator()(const unsigned __int128 &x) const {
//			return (size_t)((x>>66)^(x<<3)^(x>>3));
//		}
//	};
//}

enum  tSearchDirection {
	kForward,
	kBackward,
};

//const int kWorkUnitSize = 128;
//
//struct workUnit {
//	uint8_t count;
//	diskState work[kWorkUnitSize];
//};
//
//SharedQueue<workUnit> work;

// This tells us the open list buckets
struct openData {
	tSearchDirection dir;  // at most 2 bits
	uint8_t priority;      // at most 6 bits
	uint8_t gcost;         // at most 4 bits
	uint8_t fcost;         // at most 4 bits
	uint16_t bucket;        // at most (3) bits
};

static bool operator==(const openData &a, const openData &b)
{
	return (a.dir == b.dir && a.priority == b.priority && a.gcost == b.gcost && a.fcost == b.fcost && a.bucket == b.bucket);
}

static std::ostream &operator<<(std::ostream &out, const openData &d)
{
	out << "[" << ((d.dir==kForward)?"forward":"backward") << ", p:" << +d.priority << ", g:" << +d.gcost << ", f:" << +d.fcost;
	out << ", b:" << +d.bucket << "]";
	return out;
}

struct openDataHash
{
	std::size_t operator()(const openData & x) const
	{
		return (x.dir)|(x.priority<<2)|(x.gcost<<8)|(x.fcost<<12)|(x.bucket<<20);
	}
};

struct openList {
	openList() :f(0), writtenStates(0) {}
	//std::unordered_set<uint64_t> states;
	FILE *f;
	uint64_t writtenStates;
	uint8_t minf;
};

struct closedData {
	tSearchDirection dir;
	uint8_t depth;
	uint8_t bucket;
};

struct closedList {
	closedList() :f(0) {}
	FILE *f;
};

static bool operator==(const closedData &a, const closedData &b)
{
	return (a.dir == b.dir && a.depth == b.depth && a.bucket == b.bucket);
}

struct closedDataHash
{
	std::size_t operator()(const closedData & x) const
	{
		return (x.dir)|(x.bucket<<2)|(x.bucket<<7);
	}
};

//std::vector<std::unordered_set<uint64_t>> closed(fileBuckets);
std::unordered_map<closedData, closedList, closedDataHash> closed;
std::unordered_map<openData, openList, openDataHash> open;

std::string GetClosedName(closedData d)
{
	std::string s;
	if (d.dir == kForward)
	{
		if ((d.bucket%16) < 8)
		{
			s += prefix1;
		}
		else {
			s += prefix2;
		}
		s += "forward-";
	}
	else {
		if ((d.bucket%16) >= 8)
		{
			s += prefix1;
		}
		else {
			s += prefix2;
		}
		s += "backward-";
	}
	s += std::to_string(d.bucket);
	s += "-";
	s += std::to_string(d.depth);
	s += ".closed";
	return s;
}

std::string GetOpenName(const openData &d)
{
	/* Previously we split across disks according to forward/backward, but
	 * this is unbalanced. Now we split according to buckets. With an even
	 * number of buckets the files should now be even split across two disks.
	 */
	std::string s;
	if ((d.bucket%16) < 8)
	{
		s += prefix1;
	}
	else {
		s += prefix2;
	}
	if (d.dir == kForward)
	{
		s += "forward-";
	}
	else {
		s += "backward-";
	}
	s += std::to_string(d.priority);
	s += "-";
	s += std::to_string(d.gcost);
	s += "-";
	s += std::to_string(d.fcost);
//	s += "-";
//	s += std::to_string(d.hcost2);
	s += "-";
	s += std::to_string(d.bucket);
	s += ".open";
	return s;
}

openData GetBestFile()
{
	minGForward = 100;
	minGBackward = 100;
	minFForward = 100;
	minFBackward = 100;
	// actually do priority here
	openData best =(open.begin())->first;
	//return (open.begin())->first;
	for (const auto &s : open)
	{
		if (s.first.dir == kForward && s.first.gcost < minGForward)
			minGForward = s.first.gcost;
		else if (s.first.dir == kBackward && s.first.gcost < minGBackward)
			minGBackward = s.first.gcost;

		//if (s.first.dir == kForward && s.first.gcost+s.first.hcost < minFForward)
		if (s.first.dir == kForward && s.first.fcost < minFForward)
			minFForward = s.first.fcost;
		else if (s.first.dir == kBackward && s.first.fcost < minFBackward)
			minFBackward = s.first.fcost;

		if (s.first.priority < best.priority)
		{
			best = s.first;
		}
		else if (s.first.priority == best.priority)
		{
			if (s.first.gcost < best.gcost)
				best = s.first;
			else if (s.first.gcost == best.gcost)
			{
				if (s.first.dir == best.dir)
				{
					if (s.first.fcost < best.fcost)
						best = s.first;
					else if (s.first.fcost == best.fcost)
					{
						if (s.first.bucket < best.bucket)
							best = s.first;
					}
				}
				else if (s.first.dir == kForward)
					best = s.first;
			}
		}
	}
	return best;
}

void GetOpenData(const RubiksState &from, tSearchDirection dir, int cost,
				 openData &d, diskState &data)
{
	int bucket;
	//uint64_t data;
	GetBucketAndData(from, bucket, data);
	d.dir = dir;
	d.gcost = cost;
	d.fcost = cost + ((dir==kForward)?forward.HCost(from, goalState):reverse.HCost(from, startState));
	//d.hcost2 = (dir==kForward)?reverse.HCost(start, start):forward.HCost(start, start);
	d.bucket = bucket;
	//d.priority = d.gcost+d.hcost;
	d.priority = std::max(d.fcost, uint8_t(d.gcost*2));
}

void AddStatesToQueue(const openData &d, diskState *data, size_t count)
{
	openLock.lock();
	auto iter = open.find(d);
	if (iter == open.end())
	{
		open[d].f = fopen(GetOpenName(d).c_str(), "w+b");
		if (open[d].f == 0)
		{
			printf("Error opening %s; Aborting!\n", GetOpenName(d).c_str());
			perror("Reason: ");
			exit(0);
		}
		iter = open.find(d);
	}
	if (iter->second.f == 0)
	{
		printf("Error - file is null!\n");
		exit(0);
	}
	iter->second.minf = std::min(iter->second.minf, d.fcost);
	size_t written = fwrite(data, sizeof(diskState), count, open[d].f);
	open[d].writtenStates += written;
	openLock.unlock();
}

void AddStateToQueue(openData &d, diskState data)
{
	AddStatesToQueue(d, &data, 1);
}

void AddStateToQueue(const RubiksState &start, tSearchDirection dir, int cost)
{
	openData d;
	diskState rank;
	GetOpenData(start, dir, cost, d, rank);
	AddStateToQueue(d, rank);
}

bool CanTerminateSearch()
{
	int val;
	if (bestSolution <= (val = std::max(currentC, std::max(minFForward, std::max(minFBackward, minGBackward+minGForward+1)))))
	{
		printf("Done!\n");
		printf("%llu nodes expanded\n", expanded);
		printf("Forward Distribution:\n");
		for (int x = 0; x < gDistForward.size(); x++)
			if (gDistForward[x] != 0)
				printf("%d\t%llu\n", x, gDistForward[x]);
		printf("Backward Distribution:\n");
		for (int x = 0; x < gDistBackward.size(); x++)
			if (gDistBackward[x] != 0)
				printf("%d\t%llu\n", x, gDistBackward[x]);
		finished = true;
		if (val == currentC)
			printf("-Triggered by current priority\n");
		if (val == minFForward)
			printf("-Triggered by f in the forward direction\n");
		if (val == minFBackward)
			printf("-Triggered by f in the backward direction\n");
		if (val == minGBackward+minGForward+1)
			printf("-Triggered by gforward+gbackward+1\n");
		return true;
	}
	return false;
}

void FindSolutionThread(const openData &d, const openList &l, const bucketSet &states)
{
	const size_t bufferSize = 128;
	diskState buffer[bufferSize];
	if (l.f == 0)
	{
		std::cout << "Error opening " << d << "\n";
		exit(0);
	}
	rewind(l.f);
	size_t numRead;
	do {
		numRead = fread(buffer, sizeof(diskState), bufferSize, l.f);
		for (int x = 0; x < numRead; x++)
		{
			if (states.find(buffer[x]) != states.end())
			{
				printLock.lock();
				printf("\nFound solution cost %d+%d=%d\n", d.gcost, d.gcost, d.gcost + d.gcost);
				bestSolution = std::min(d.gcost + d.gcost, bestSolution);
				printf("Current best solution: %d\n", bestSolution);
				printLock.unlock();

				if (CanTerminateSearch())
					return;
			}
		}
	} while (numRead == bufferSize);
}

void CheckSolution(std::unordered_map<openData, openList, openDataHash> currentOpen, openData d,
				   const bucketSet &states)
{
	std::vector<std::thread *> threads;
	for (const auto &s : currentOpen)
	{
		// Opposite direction, same bucket AND could be a solution (g+g >= C)
		// TODO: only need to check if we find a better solution (g+g < U)
		if (s.first.dir != d.dir && s.first.bucket == d.bucket &&
			d.gcost + s.first.gcost >= currentC)// && d.hcost2 == s.first.hcost)
		{
//			std::thread *t = new std::thread(FindSolutionThread, s.first, s.second, states);
//			threads.push_back(t);
			FindSolutionThread(s.first, s.second, states);
		}
	}
//	while (threads.size() > 0)
//	{
//		threads.back()->join();
//		delete threads.back();
//		threads.pop_back();
//	}
}

void ReadBucket(bucketSet &states, openData d)
{
	const size_t bufferSize = 128;
	diskState buffer[bufferSize];
	rewind(open[d].f);
#ifdef MY_SET
	states.resize(open[d].writtenStates);
#endif
	size_t numRead;
	do {
		numRead = fread(buffer, sizeof(diskState), bufferSize, open[d].f);
		for (int x = 0; x < numRead; x++)
			states.insert(buffer[x]);
	} while (numRead == bufferSize);
	fclose(open[d].f);
	remove(GetOpenName(d).c_str());
	open[d].f = 0;
}

void RemoveDuplicates(bucketSet &states, openData d)
{
	for (int depth = d.gcost-2; depth < d.gcost; depth++)
	{
		closedData c;
		c.bucket = d.bucket;
		c.depth = depth;
		c.dir = d.dir;

		closedList &cd = closed[c];
		if (cd.f == 0)
			continue;
		rewind(cd.f);

		const size_t bufferSize = 1024;
		diskState buffer[bufferSize];
		rewind(cd.f);
		size_t numRead;
		do {
			numRead = fread(buffer, sizeof(diskState), bufferSize, cd.f);
			for (int x = 0; x < numRead; x++)
			{
				auto i = states.find(buffer[x]);
				if (i != states.end())
					states.erase(i);
			}
		} while (numRead == bufferSize);
	}
}

void WriteToClosed(bucketSet &states, openData d)
{
	closedData c;
	c.bucket = d.bucket;
	c.depth = d.gcost;
	c.dir = d.dir;

	closedList &cd = closed[c];
	if (cd.f == 0)
	{
		cd.f = fopen(GetClosedName(c).c_str(), "w+b");
	}
	for (const auto &i : states)
	{
		fwrite(&i, sizeof(diskState), 1, cd.f);
	}
}

void ParallelExpandBucket(openData d, bucketSet &states, int myThread, int totalThreads)
{
	const int cacheSize = 1024;
	std::unordered_map<openData, std::vector<diskState>, openDataHash> cache;
	RubiksState tmp;
	uint64_t localExpanded = 0;
	int count = 0;
	for (const auto &values : states)
	{
		count++;
		if (myThread != count%totalThreads)
			continue;
		diskState v;
#ifdef MY_SET
		if (!values.valid)
			continue;
		v = values.item;
#else
		v = values;
#endif
		localExpanded++;
		for (int x = 0; x < 18; x++) // TODO: use getactions
		{
			GetState(tmp, d.bucket, v);
			// copying 2 64-bit values is faster than undoing a move
			cube.ApplyAction(tmp, x);
			openData newData;
			diskState newRank;
			GetOpenData(tmp, d.dir, d.gcost+1, newData, newRank);

			std::vector<diskState> &c = cache[newData];
			c.push_back(newRank);
			if (c.size() > cacheSize)
			{
				AddStatesToQueue(newData, &c[0], c.size());
				c.clear();
			}
		}
	}
	for (auto &i : cache)
	{
		AddStatesToQueue(i.first, &(i.second[0]), i.second.size());
	}

	countLock.lock();
	expanded += localExpanded;
	if (d.dir == kForward)
		gDistForward[d.gcost]+=localExpanded;
	else
		gDistBackward[d.gcost]+=localExpanded;
	countLock.unlock();
}

void ReadAndDDBucket(bucketSet &states, const openData &d)
{
	ReadBucket(states, d);
	RemoveDuplicates(states, d); // delayed duplicate detection
	WriteToClosed(states, d); // this could run in parallel!
}

#define DO_PRELOAD

void ExpandNextFile()
{
	static bool preLoaded = false;
	static bucketSet nextStates(0);
	static bucketSet states(0);
	static openData next;
	// 1. Get next expansion target
	openData d = GetBestFile();
	currentC = d.priority;

	if (CanTerminateSearch())
		return;

	Timer timer;
	timer.StartTimer();

	states.clear();
	if (preLoaded == false)
	{
		ReadAndDDBucket(states, d);
	}
	else {
		if (d == next)
		{
			states.swap(nextStates);
			preLoaded = false;
		}
		else {
			std::cout << "ERROR: pre-loading changed buckets!\n";
			ReadAndDDBucket(states, d);
		}
	}
	open.erase(open.find(d));
	timer.EndTimer();

	printLock.lock();
	std::cout << "Next: " << d << " (" << states.size() << " entries) [" << timer.GetElapsedTime() << "s reading/dd] ";
	printLock.unlock();

	timer.StartTimer();
	// Read in opposite buckets to check for solutions in parallel to expanding this bucket
	openLock.lock();
	std::thread t(CheckSolution, open, d, std::ref(states));
	openLock.unlock();

	std::thread *pre = 0;

#ifdef DO_PRELOAD
	// 2. Pre-read next bucket if it is the same as us
	next = GetBestFile();
	if (next.dir == d.dir && next.gcost == d.gcost && next.bucket != d.bucket)
	{
		pre = new std::thread(ReadAndDDBucket, std::ref(nextStates), std::ref(next));
		preLoaded = true;
	}
#endif

	// 3. expand all states in current bucket & write out successors
	const int numThreads = std::thread::hardware_concurrency();
	std::vector<std::thread *> threads;
	for (int x = 0; x < numThreads; x++)
		threads.push_back(new std::thread(ParallelExpandBucket, d, std::ref(states), x, numThreads));
	// Put work for states into queue and send it to threads
//	{
//		int count = 0;
//		workUnit w;
//		for (const auto &values : states)
//		{
//#ifdef MY_SET
//			if (values.valid == false)
//				continue;
//			w.work[count] = values.item;
//#else
//			w.work[count] = values;
//#endif
//			count++;
//			if (count == kWorkUnitSize)
//			{
//				w.count = count;
//				work.WaitAdd(w);
//				count = 0;
//			}
//		}
//		if (count > 0)
//		{
//			w.count = count;
//			work.WaitAdd(w);
//		}
//		w.count = 0;
//		for (int x = 0; x < threads.size(); x++)
//			work.WaitAdd(w);
//	}
	for (int x = 0; x < threads.size(); x++)
	{
		threads[x]->join();
		delete threads[x];
	}
	timer.EndTimer();
	printLock.lock();
	std::cout << "[" << timer.GetElapsedTime() << "s expanding]+";
	printLock.unlock();

	// Close thread that is doing DSD
	timer.StartTimer();
	t.join();
	timer.EndTimer();
	printLock.lock();
	std::cout << "[" << timer.GetElapsedTime() << "s] ";
	printLock.unlock();

	// Close thread that is reading previous bucket
	timer.StartTimer();
	if (pre != 0)
	{
		pre->join();
		delete pre;
		pre = 0;
	}
	timer.EndTimer();
	printLock.lock();
	std::cout << "[" << timer.GetElapsedTime() << "s]\n";
	printLock.unlock();

}

//#define ZERO
//#define KORF97
//#define RUBIK_888
//#define RUBIK_10_2
//#define RUBIK_9_3
//#define SMALL
//#define TINY

void BuildHeuristics(RubiksState start, RubiksState goal, Heuristic<RubiksState> &result, heuristicType h)
{
	RubiksCube cube;
	std::vector<int> blank;

	switch (h)
	{
		case kNone:
		{
			ZeroHeuristic<RubiksState> *zero = new ZeroHeuristic<RubiksState>();
			result.lookups.push_back({kLeafNode, 0, 0});
			result.heuristics.push_back(zero);
			break;
		}
		case k444:
		{
			std::vector<int> edges1 = {1, 3, 8, 9}; // first 4
			std::vector<int> edges2 = {0, 2, 4, 5}; // first 4
			std::vector<int> corners = {0, 1, 2, 3}; // first 4
			RubikPDB *pdb1 = new RubikPDB(&cube, goal, edges1, blank);
			RubikPDB *pdb2 = new RubikPDB(&cube, goal, edges2, blank);
			RubikPDB *pdb3 = new RubikPDB(&cube, goal, blank, corners);
			if (!pdb1->Load(hprefix))
			{
				pdb1->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb1->Save(hprefix);
			}
			if (!pdb2->Load(hprefix))
			{
				pdb2->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb2->Save(hprefix);
			}
			if (!pdb3->Load(hprefix))
			{
				pdb3->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb3->Save(hprefix);
			}
			result.lookups.push_back({kMaxNode, 1, 3});
			result.lookups.push_back({kLeafNode, 0, 0});
			result.lookups.push_back({kLeafNode, 1, 0});
			result.lookups.push_back({kLeafNode, 2, 0});
			result.heuristics.push_back(pdb1);
			result.heuristics.push_back(pdb2);
			result.heuristics.push_back(pdb3);
			break;
		}
		case kSmall:
		{
			assert(!"PDB not being saved!");
			std::vector<int> edges1 = {0, 1, 2, 4, 6};
			std::vector<int> edges2 = {3, 5};
			std::vector<int> edges3 = {7, 8, 9, 10, 11};
			std::vector<int> corners1 = {0, 1, 2, 3, 4, 5};
			std::vector<int> corners2 = {2, 3, 4, 5, 6, 7};
			RubikPDB *pdb1 = new RubikPDB(&cube, goal, edges1, blank);
			RubikPDB *pdb2 = new RubikPDB(&cube, goal, edges2, blank);
			RubikPDB *pdb3 = new RubikPDB(&cube, goal, edges3, blank);
			RubikPDB *pdb4 = new RubikPDB(&cube, goal, blank, corners1);
			RubikPDB *pdb5 = new RubikPDB(&cube, goal, blank, corners2);
			pdb1->BuildPDB(goal, std::thread::hardware_concurrency());
			pdb2->BuildPDB(goal, std::thread::hardware_concurrency());
			pdb3->BuildPDB(goal, std::thread::hardware_concurrency());
			pdb4->BuildPDB(goal, std::thread::hardware_concurrency());
			pdb5->BuildPDB(goal, std::thread::hardware_concurrency());
			result.lookups.push_back({kMaxNode, 1, 5});
			result.lookups.push_back({kLeafNode, 0, 0});
			result.lookups.push_back({kLeafNode, 1, 0});
			result.lookups.push_back({kLeafNode, 2, 0});
			result.lookups.push_back({kLeafNode, 3, 0});
			result.lookups.push_back({kLeafNode, 4, 0});
			result.heuristics.push_back(pdb1);
			result.heuristics.push_back(pdb2);
			result.heuristics.push_back(pdb3);
			result.heuristics.push_back(pdb4);
			result.heuristics.push_back(pdb5);
			break;
		}
		case k1997:
		{
			std::vector<int> edges1 = {1, 3, 8, 9, 10, 11};
			std::vector<int> edges2 = {0, 2, 4, 5, 6, 7};
			std::vector<int> corners = {0, 1, 2, 3, 4, 5, 6, 7};
			RubikPDB *pdb1 = new RubikPDB(&cube, goal, edges1, blank);
			RubikPDB *pdb2 = new RubikPDB(&cube, goal, edges2, blank);
			RubikPDB *pdb3 = new RubikPDB(&cube, goal, blank, corners);

			if (!pdb1->Load(hprefix))
			{
				pdb1->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb1->Save(hprefix);
			}
			else {
				printf("Loaded previous heuristic\n");
			}
			if (!pdb2->Load(hprefix))
			{
				pdb2->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb2->Save(hprefix);
			}
			else {
				printf("Loaded previous heuristic\n");
			}
			if (!pdb3->Load(hprefix))
			{
				pdb3->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb3->Save(hprefix);
			}
			else {
				printf("Loaded previous heuristic\n");
			}
			result.lookups.push_back({kMaxNode, 1, 3});
			result.lookups.push_back({kLeafNode, 0, 0});
			result.lookups.push_back({kLeafNode, 1, 0});
			result.lookups.push_back({kLeafNode, 2, 0});
			result.heuristics.push_back(pdb1);
			result.heuristics.push_back(pdb2);
			result.heuristics.push_back(pdb3);
			break;
		}
		case k888:
		{
			std::vector<int> edges1 = {0, 1, 2, 3, 4, 5, 6, 7};
			std::vector<int> edges2 = {1, 3, 5, 7, 8, 9, 10, 11};
			std::vector<int> corners = {0, 1, 2, 3, 4, 5, 6, 7}; // first 4
			RubikPDB *pdb1 = new RubikPDB(&cube, goal, edges1, blank);
			RubikPDB *pdb2 = new RubikPDB(&cube, goal, edges2, blank);
			RubikPDB *pdb3 = new RubikPDB(&cube, goal, blank, corners);
			if (!pdb1->Load(hprefix))
			{
				pdb1->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb1->Save(hprefix);
			}
			if (!pdb2->Load(hprefix))
			{
				pdb2->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb2->Save(hprefix);
			}
			if (!pdb3->Load(hprefix))
			{
				pdb3->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb3->Save(hprefix);
			}
			result.lookups.push_back({kMaxNode, 1, 3});
			result.lookups.push_back({kLeafNode, 0, 0});
			result.lookups.push_back({kLeafNode, 1, 0});
			result.lookups.push_back({kLeafNode, 2, 0});
			result.heuristics.push_back(pdb1);
			result.heuristics.push_back(pdb2);
			result.heuristics.push_back(pdb3);
		}
		case k839:
		{
			std::vector<int> edges1 = {0, 1, 2, 3, 4, 5, 6, 7, 8};
			std::vector<int> edges2 = {9, 10, 11};
			std::vector<int> corners = {0, 1, 2, 3, 4, 5, 6, 7};
			RubikPDB *pdb1 = new RubikPDB(&cube, goal, edges1, blank);
			RubikPDB *pdb2 = new RubikPDB(&cube, goal, edges2, blank);
			RubikPDB *pdb3 = new RubikPDB(&cube, goal, blank, corners);
			if (!pdb1->Load(hprefix))
			{
				pdb1->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb1->Save(hprefix);
			}
			if (!pdb2->Load(hprefix))
			{
				pdb2->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb2->Save(hprefix);
			}
			if (!pdb3->Load(hprefix))
			{
				pdb3->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb3->Save(hprefix);
			}
			result.lookups.push_back({kMaxNode, 1, 3});
			result.lookups.push_back({kLeafNode, 0, 0});
			result.lookups.push_back({kLeafNode, 1, 0});
			result.lookups.push_back({kLeafNode, 2, 0});
			result.heuristics.push_back(pdb1);
			result.heuristics.push_back(pdb2);
			result.heuristics.push_back(pdb3);
			break;
		}
		case k8210:
		{
			std::vector<int> edges1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
			std::vector<int> edges2 = {10, 11};
			std::vector<int> corners = {0, 1, 2, 3, 4, 5, 6, 7};
			RubikPDB *pdb1 = new RubikPDB(&cube, goal, edges1, blank);
			RubikPDB *pdb2 = new RubikPDB(&cube, goal, edges2, blank);
			RubikPDB *pdb3 = new RubikPDB(&cube, goal, blank, corners);
			if (!pdb1->Load(hprefix))
			{
				pdb1->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb1->Save(hprefix);
			}
			if (!pdb2->Load(hprefix))
			{
				pdb2->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb2->Save(hprefix);
			}
			if (!pdb3->Load(hprefix))
			{
				pdb3->BuildPDB(goal, std::thread::hardware_concurrency());
				pdb3->Save(hprefix);
			}
			result.lookups.push_back({kMaxNode, 1, 3});
			result.lookups.push_back({kLeafNode, 0, 0});
			result.lookups.push_back({kLeafNode, 1, 0});
			result.lookups.push_back({kLeafNode, 2, 0});
			result.heuristics.push_back(pdb1);
			result.heuristics.push_back(pdb2);
			result.heuristics.push_back(pdb3);
			break;
		}
	}
}

int GetBucket(const RubiksState &s)
{
	diskState ehash = RubikEdgePDB::GetStateHash(s.edge);
	return ehash&bucketMask;
//	return (s.edge.state^(s.corner.state<<2))&bucketMask;
}

void GetBucketAndData(const RubiksState &s, int &bucket, uint64_t &data)
{
	uint64_t ehash = RubikEdgePDB::GetStateHash(s.edge);
	uint64_t chash = RubikCornerPDB::GetStateHash(s.corner);
	bucket = ehash&bucketMask;
	data = (ehash>>bucketBits)*RubikCornerPDB::GetStateSpaceSize()+chash;
}

void GetBucketAndData(const RubiksState &s, int &bucket, RubiksState &data)
{
	bucket = GetBucket(s);
	data = s;
}

void GetState(RubiksState &s, int bucket, uint64_t data)
{
	RubikCornerPDB::GetStateFromHash(s.corner, data%RubikCornerPDB::GetStateSpaceSize());
	RubikEdgePDB::GetStateFromHash(s.edge, bucket|((data/RubikCornerPDB::GetStateSpaceSize())<<bucketBits));
}

void GetState(RubiksState &s, int bucket, RubiksState data)
{
	s = data;
}

#pragma mark Main Code

void MM(RubiksState &start, RubiksState &goal, const char *p1, const char *p2,
		heuristicType h, const char *hloc)
//void MM(RubiksState &start, RubiksState &goal, const char *p1, const char *p2, const char *hloc)
{
#ifdef MY_SET
	printf("Using custom set container\n");
#endif
	startState = start;
	goalState = goal;
	prefix1 = p1;
	prefix2 = p2;
	hprefix = hloc;

	bestSolution = 100;
	gDistBackward.resize(12);
	gDistForward.resize(12);
	expanded = 0;
	BuildHeuristics(start, goal, forward, h);

	reverse = forward;
	for (int x = 0; x < reverse.heuristics.size(); x++)
	{
		reverse.heuristics[x] = new RubikArbitraryGoalPDB((RubikPDB*)reverse.heuristics[x]);
	}
	//BuildHeuristics(goal, start, reverse);

	std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
	std::cout << std::setprecision(2);

	Timer t;
	t.StartTimer();
	printf("---MM*---\n");
	AddStateToQueue(start, kForward, 0);
	AddStateToQueue(goal, kBackward, 0);
	while (!open.empty() && !finished)
	{
		ExpandNextFile();
	}
	t.EndTimer();
	printf("%1.2fs elapsed\n", t.GetElapsedTime());
}

void CompareIDA(RubiksState &start, RubiksState &goal, heuristicType h, const char *hloc)
//void CompareIDA(RubiksState &start, RubiksState &goal, const char *p1, const char *p2, const char *hloc)
{
	hprefix = hloc;

	bestSolution = 100;
	gDistBackward.resize(12);
	gDistForward.resize(12);
	expanded = 0;
	BuildHeuristics(start, goal, forward, h);
	//BuildHeuristics(goal, start, reverse);

	std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
	std::cout << std::setprecision(2);

	printf("---IDA*---\n");
	std::vector<RubiksAction> path;
	Timer t;
	t.StartTimer();
	cube.SetPruneSuccessors(true);
	ParallelIDAStar<RubiksCube, RubiksState, RubiksAction> ida;
	ida.SetHeuristic(&forward);
	ida.GetPath(&cube, start, goal, path);
	t.EndTimer();
	printf("%1.5fs elapsed\n", t.GetElapsedTime());
	printf("%llu nodes expanded (%1.3f nodes/sec)\n", ida.GetNodesExpanded(),
		   ida.GetNodesExpanded()/t.GetElapsedTime());
	printf("%llu nodes generated (%1.3f nodes/sec)\n", ida.GetNodesTouched(),
		   ida.GetNodesTouched()/t.GetElapsedTime());
	printf("Solution cost: %lu\n", path.size());

	std::cout << "Acts: ";
	for (unsigned int x = 0; x < path.size(); x++)
	{
		std::cout << path[x] << " ";
	}
	std::cout << "\n";
}

NAMESPACE_CLOSE(MM)


text:
import sys
import os.path
import argparse
import xmlrpc.client
import re

from lib.inventory import Inventory
import lib.genesis as gen
import lib.logger as logger

def cobbler_add_systems(cfg_file=None):
    LOG = logger.getlogger()

    cobbler_user = gen.get_cobbler_user()
    cobbler_pass = gen.get_cobbler_pass()
    cobbler_server = xmlrpc.client.Server("http://127.0.0.1/cobbler_api")
    token = cobbler_server.login(cobbler_user, cobbler_pass)

    inv = Inventory(cfg_file=cfg_file)

    for index, hostname in enumerate(inv.yield_nodes_hostname()):
        ipv4_ipmi = inv.get_nodes_ipmi_ipaddr(0, index)
        userid_ipmi = inv.get_nodes_ipmi_userid(index)
        password_ipmi = inv.get_nodes_ipmi_password(index)
        ipv4_pxe = inv.get_nodes_pxe_ipaddr(0, index)
        mac_pxe = inv.get_nodes_pxe_mac(0, index)
        cobbler_profile = gen.check_os_profile(
            re.sub("[.]iso", "", inv.get_nodes_os_profile(index)))
        raid1_enabled = False

        new_system_create = cobbler_server.new_system(token)

        cobbler_server.modify_system(
            new_system_create,
            "name",
            hostname,
            token)
        cobbler_server.modify_system(
            new_system_create,
            "hostname",
            hostname,
            token)
        cobbler_server.modify_system(
            new_system_create,
            "power_address",
            ipv4_ipmi,
            token)
        cobbler_server.modify_system(
            new_system_create,
            "power_user",
            userid_ipmi,
            token)
        cobbler_server.modify_system(
            new_system_create,
            "power_pass",
            password_ipmi,
            token)
        cobbler_server.modify_system(
            new_system_create,
            "power_type",
            "ipmilan",
            token)
        cobbler_server.modify_system(
            new_system_create,
            "profile",
            cobbler_profile,
            token)
        cobbler_server.modify_system(
            new_system_create,
            'modify_interface',
            {
                "macaddress-eth0": mac_pxe,
                "ipaddress-eth0": ipv4_pxe,
                "dnsname-eth0": hostname},
            token)
        ks_meta = ""
        disks = inv.get_nodes_os_install_device(index)
        if disks is not None:
            if isinstance(disks, str):
                ks_meta += 'install_disk=%s ' % disks
            elif isinstance(disks, list) and len(disks) == 2:
                ks_meta += (
                    'install_disk=%s install_disk_2=%s ' %
                    (disks[0], disks[1]))
                raid1_enabled = True
            else:
                LOG.error(
                    '%s: Invalid install_device value: %s '
                    'Must be string or two item list.' %
                    (hostname, disks))
        if raid1_enabled:
            ks_meta += 'raid1_enabled=true '
        domain = inv.get_nodes_os_domain(index)
        if domain is not None:
            ks_meta += 'domain=%s ' % domain
        users = inv.get_nodes_os_users(index)
        if users is not None:
            for user in users:
                if 'name' in user and user['name'] != 'root':
                    ks_meta += 'default_user=%s ' % user['name']
                    LOG.debug("%s: Using \'%s\' as default user" %
                              (hostname, user['name']))
                    if 'password' in user:
                        ks_meta += ('passwd=%s passwdcrypted=true ' %
                                    user['password'])
                    break
            else:
                LOG.debug("%s: No default user found" % hostname)
        else:
            LOG.debug("%s: No users defined" % hostname)
        if ks_meta != "":
            cobbler_server.modify_system(
                new_system_create,
                "ks_meta",
                ks_meta,
                token)
        kernel_options = inv.get_nodes_os_kernel_options(index)
        if 'ubuntu-18.04' in cobbler_profile.lower():
            if kernel_options is None:
                kernel_options = ''
            if 'netcfg/do_not_use_netplan=true' not in kernel_options:
                kernel_options += ' netcfg/do_not_use_netplan=true'
        if kernel_options is not None:
            cobbler_server.modify_system(
                new_system_create,
                "kernel_options",
                kernel_options,
                token)
            cobbler_server.modify_system(
                new_system_create,
                "kernel_options_post",
                kernel_options,
                token)
        comment = ""
        cobbler_server.modify_system(
            new_system_create,
            "comment",
            comment,
            token)

        cobbler_server.save_system(new_system_create, token)

        LOG.info(
            "Cobbler Add System: name=%s, profile=%s" %
            (hostname, cobbler_profile))

    cobbler_server.sync(token)
    LOG.info("Running Cobbler sync")

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('config_path', default='config.yml',
                        help='Config file path.  Absolute path or relative '
                        'to power-up/')

    parser.add_argument('--print', '-p', dest='log_lvl_print',
                        help='print log level', default='info')

    parser.add_argument('--file', '-f', dest='log_lvl_file',
                        help='file log level', default='info')

    args = parser.parse_args()

    logger.create(args.log_lvl_print, args.log_lvl_file)

    if not os.path.isfile(args.config_path):
        args.config_path = gen.GEN_PATH + args.config_path
        print('Using config path: {}'.format(args.config_path))
    if not os.path.isfile(args.config_path):
        sys.exit('{} does not exist'.format(args.config_path))

    cobbler_add_systems(args.config_path)


text:
package de.jeanpierrehotz.severalpictureswallpaper;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;

import java.io.File;
import java.util.Collections;
import java.util.Locale;

import de.jeanpierrehotz.severalpictureswallpaper.utils.WallpaperPictureSelector;
import de.jeanpierrehotz.severalpictureswallpaper.views.WallpaperImageAdapter;
import de.jeanpierrehotz.severalpictureswallpaper.views.color.ColorView;
import de.jeanpierrehotz.severalpictureswallpaper.wallpaper.data.WallpaperDataManager;
import de.jeanpierrehotz.severalpictureswallpaper.wallpaper.data.WallpaperImage;
import de.jeanpierrehotz.severalpictureswallpaper.wallpaper.data.WallpaperSettings;

/**
 *
 */
public class ChangeWallpaperActivity extends AppCompatActivity {

    ///
    /// BottomSheet
    ///

    private static final int CODE_TRIED_SELECTING_IMAGE = 0x12345;
    // Views & Objects
    private LinearLayout bottomSheet;
    private BottomSheetBehavior<LinearLayout> bottomSheetBehaviour;
    private TextView bottomSheetCaption;
    private TextView furtherSettings_Value_TextView;
    private SeekBar furtherSettings_Value_SeekBar;
    private Switch furtherSettings_DetectGestures_Switch;
    private Switch furtherSettings_LockWallpaper_Switch;
    private ColorView furtherSettings_Fallbackcolor_ColorView;
    private WallpaperSettings settings;
    // Listener
    private View.OnClickListener bottomSheetCaption_onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if(bottomSheetBehaviour.getState() == BottomSheetBehavior.STATE_COLLAPSED) {
                bottomSheetBehaviour.setState(BottomSheetBehavior.STATE_EXPANDED);
            } else {
                bottomSheetBehaviour.setState(BottomSheetBehavior.STATE_COLLAPSED);
            }
        }
    };
    private SeekBar.OnSeekBarChangeListener furtherSettings_Value_SeekBar_OnChangeListener = new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean userInput) {
            furtherSettings_Value_TextView.setText(String.format(Locale.getDefault(), "%1$.1fs", ((double) furtherSettings_Value_SeekBar.getProgress())));
            if (userInput) {
                settings.setShowPictureTime(furtherSettings_Value_SeekBar.getProgress());
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        }
    };
    private CompoundButton.OnCheckedChangeListener furtherSettings_DetectGestures_Switch_OnCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            settings.setDetectGestures(isChecked);
        }
    };
    private CompoundButton.OnCheckedChangeListener furtherSettings_LockWallpaper_Switch_OnCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            settings.setLockWallpaper(isChecked);
        }
    };

    ///
    /// Main content
    ///
    private ColorView.OnColorChangedListener furtherSettings_Fallbackcolor_ColorView_OnColorChangedListener = new ColorView.OnColorChangedListener() {
        @Override
        public void onColorChanged(int color, boolean finalvalue) {
            if (finalvalue) {
                settings.setFallbackcolor(color);
            }
        }
    };
    // Views & Objects
    private RecyclerView recyclerView;
    private WallpaperImageAdapter recyclerAdapter;
    private RecyclerView.LayoutManager recyclerManager;
    // Listener
    private WallpaperImageAdapter.OnItemNormalButtonClickListener recyclerNormalButtonClickListener = new WallpaperImageAdapter.OnItemNormalButtonClickListener() {
        @Override
        public void onClick(RecyclerView.ViewHolder vh, int pos) {
            settings.setCurrentImage(pos);
        }
    };
    private ItemTouchHelper wallpaperImageHelper;

    ///
    /// Data
    ///
    private ItemTouchHelper.Callback wallpaperImageHelperCallback = new ItemTouchHelper.Callback() {
        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
        }

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
            int from = source.getAdapterPosition();
            int to = target.getAdapterPosition();

            Collections.swap(settings.getImageList(), from, to);
            recyclerAdapter.notifyItemMoved(from, to);

            return true;
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            int pos = viewHolder.getAdapterPosition();

            WallpaperImage removed = settings.getImageList().get(pos);
            settings.removeImage(pos);
            recyclerAdapter.notifyItemRemoved(pos);
            removed.releaseImage();
        }
    };
    private int wallpaperindex;
    private WallpaperPictureSelector mWallpaperSelector;
    private WallpaperPictureSelector.Callback mWallpaperSelectorCallback = new WallpaperPictureSelector.Callback() {
        @Override
        public void onSelectedResult(String file) {
        }

        @Override
        public void onCropperResult(WallpaperPictureSelector.CropResult result, File srcFile, File outFile) {
            if (result == WallpaperPictureSelector.CropResult.success) {
                settings.addImage(new WallpaperImage(outFile.getAbsolutePath()));
                recyclerAdapter.notifyItemInserted(settings.getImageList().size() - 1);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_changewallpaper);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        wallpaperindex = getIntent().getIntExtra(getString(R.string.prefs_wallpaperindex), 0);

        bottomSheet = (LinearLayout) findViewById(R.id.layout_content_main_bottomsheet_rootlinearlayout);
        bottomSheetBehaviour = BottomSheetBehavior.from(bottomSheet);

        bottomSheetCaption = (TextView) findViewById(R.id.bottomSheetCaption);
        bottomSheetCaption.setOnClickListener(bottomSheetCaption_onClickListener);

        furtherSettings_Value_TextView = (TextView) findViewById(R.id.furthersettings_time_value);
        furtherSettings_Value_SeekBar = (SeekBar) findViewById(R.id.furthersettings_time_seekbar);
        furtherSettings_Value_SeekBar.setOnSeekBarChangeListener(furtherSettings_Value_SeekBar_OnChangeListener);

        furtherSettings_DetectGestures_Switch = (Switch) findViewById(R.id.furthersettings_swipetoswitch_switch);
        furtherSettings_DetectGestures_Switch.setOnCheckedChangeListener(furtherSettings_DetectGestures_Switch_OnCheckedChangeListener);

        furtherSettings_LockWallpaper_Switch = (Switch) findViewById(R.id.furthersettings_swipetoswitchwallpaper_switch);
        furtherSettings_LockWallpaper_Switch.setOnCheckedChangeListener(furtherSettings_LockWallpaper_Switch_OnCheckedChangeListener);

        furtherSettings_Fallbackcolor_ColorView = (ColorView) findViewById(R.id.furthersettings_fallbackcolor_colorview);
        furtherSettings_Fallbackcolor_ColorView.setOnColorChangedListener(furtherSettings_Fallbackcolor_ColorView_OnColorChangedListener);

        mWallpaperSelector = new WallpaperPictureSelector(this);
        mWallpaperSelector.setCallback(mWallpaperSelectorCallback);

        settings = WallpaperDataManager.loadSetting(this, wallpaperindex);

        recyclerView = (RecyclerView) findViewById(R.id.images_recyclerview);
        recyclerAdapter = new WallpaperImageAdapter(settings);
        recyclerAdapter.setOnItemNormalButtonClickListener(recyclerNormalButtonClickListener);
        recyclerManager = new LinearLayoutManager(this);

        recyclerView.setLayoutManager(recyclerManager);
        recyclerView.setAdapter(recyclerAdapter);

        wallpaperImageHelper = new ItemTouchHelper(wallpaperImageHelperCallback);
        wallpaperImageHelper.attachToRecyclerView(recyclerView);

        furtherSettings_Value_SeekBar.setProgress(0);
        furtherSettings_Value_SeekBar.setProgress(1);

        furtherSettings_Value_SeekBar.setProgress(settings.getShowPictureTime());
        furtherSettings_DetectGestures_Switch.setChecked(settings.isDetectGestures());
        furtherSettings_LockWallpaper_Switch.setChecked(settings.isLockWallpaper());

        furtherSettings_Fallbackcolor_ColorView.setColor(settings.getFallbackcolor());

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                selectImage();
            }
        });
    }

    private void selectImage() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, CODE_TRIED_SELECTING_IMAGE);
            return;
        }
        mWallpaperSelector.selectImage(this);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == CODE_TRIED_SELECTING_IMAGE && grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            selectImage();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_changewallpaper, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.menu_changewallpaper_selectwallpaper) {
            WallpaperDataManager.saveSelectedSettingsIndex(this, wallpaperindex);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        mWallpaperSelector.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mWallpaperSelector.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        mWallpaperSelector.onRestoreInstanceState(savedInstanceState);
    }

    @Override
    protected void onPause() {
        super.onPause();

        WallpaperDataManager.saveSetting(this, settings, wallpaperindex);
    }

}


text:
ShapeBasedInterpolation
=======================

The shape-based interpolation method described by Raya and Udupa in 1990 for three-dimensional images


text:
package tf.gpx.edit.viewer;

import javafx.application.HostServices;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Modality;
import jfxtras.styles.jmetro.JMetro;
import jfxtras.styles.jmetro.Style;
import tf.gpx.edit.helper.LatLonHelper;
import tf.gpx.edit.leafletmap.LatLonElev;
import tf.helper.javafx.AbstractStage;
import tf.helper.javafx.RestrictiveTextField;
import tf.helper.javafx.TooltipHelper;

/**
 *
 * @author thomas
 */
public class EnterLatLon extends AbstractStage {
    // this is a singleton for everyones use
    // http://www.javaworld.com/article/2073352/core-java/simply-singleton.html
    private final static EnterLatLon INSTANCE = new EnterLatLon();

    private final RestrictiveTextField waypointLatitudeTxt = new RestrictiveTextField();
    private final RestrictiveTextField waypointLongitudeTxt = new RestrictiveTextField();

    private LatLonElev latLon = null;

    // host services from main application
    private HostServices myHostServices;

    private EnterLatLon() {
        super();
        // Exists only to defeat instantiation.

        initViewer();
    }

    public static EnterLatLon getInstance() {
        return INSTANCE;
    }

    private void initViewer() {
        (new JMetro(Style.LIGHT)).setScene(getScene());
        getScene().getStylesheets().add(EnterLatLon.class.getResource("/GPXEditor.min.css").toExternalForm());

        // create new scene
        setTitle("Enter Lat/Lon values");
        initModality(Modality.WINDOW_MODAL);

        int rowNum = 0;
        // 10th row: latitude & longitude
        final Label latLbl = new Label("Latitude:");
        getGridPane().add(latLbl, 0, rowNum);
        GridPane.setMargin(latLbl, INSET_TOP);

        // latitude can be N/S 0°0'0.0" - N/S 89°59'59.99" OR N/S 90°0'0.0"
        // minimum is N/S°'"
        waypointLatitudeTxt.setMaxLength(14).setRestrict(LatLonHelper.LAT_REGEXP).setErrorTextMode(RestrictiveTextField.ErrorTextMode.HIGHLIGHT);

        final Tooltip latTooltip = new Tooltip("Formats: N/S DD°MM'SS.SS\" or DD°MM'SS.SS\" N/S or +/-dd.dddddd");
        TooltipHelper.updateTooltipBehavior(latTooltip, 0, 10000, 0, true);
        waypointLatitudeTxt.setTooltip(latTooltip);

        getGridPane().add(waypointLatitudeTxt, 1, rowNum);
        GridPane.setMargin(waypointLatitudeTxt, INSET_TOP);

        rowNum++;
        final Label lonLbl = new Label("Longitude:");
        getGridPane().add(lonLbl, 0, rowNum);
        GridPane.setMargin(lonLbl, INSET_TOP);

        // longitude can be E/W 0°0'0.0" - E/W 179°59'59.99" OR E/W 180°0'0.0"
        // minimum is E/W°'"
        waypointLongitudeTxt.setMaxLength(15).setRestrict(LatLonHelper.LON_REGEXP).setErrorTextMode(RestrictiveTextField.ErrorTextMode.HIGHLIGHT);

        final Tooltip lonTooltip = new Tooltip("Formats: E/W DDD°MM'SS.SS\" or DDD°MM'SS.SS\" E/W or +/-ddd.dddddd");
        TooltipHelper.updateTooltipBehavior(lonTooltip, 0, 10000, 0, true);
        waypointLongitudeTxt.setTooltip(lonTooltip);

        getGridPane().add(waypointLongitudeTxt, 1, rowNum);
        GridPane.setMargin(waypointLongitudeTxt, INSET_TOP);

        rowNum++;
        // 7th row: store elevation
        final Button findButton = new Button("Done");
        findButton.setOnAction((ActionEvent event) -> {
            if (Double.isNaN(LatLonHelper.latFromString(waypointLatitudeTxt.getText())) ||
                    Double.isNaN(LatLonHelper.lonFromString(waypointLongitudeTxt.getText()))) {
                latLon = null;
            } else {
                latLon = new LatLonElev(LatLonHelper.latFromString(waypointLatitudeTxt.getText()), LatLonHelper.lonFromString(waypointLongitudeTxt.getText()));
            }
            close();
        });
        setActionAccelerator(findButton);
        getGridPane().add(findButton, 0, rowNum, 1, 1);
        GridPane.setMargin(findButton, INSET_TOP_BOTTOM);

        final Button cancelBtn = new Button("Cancel");
        cancelBtn.setOnAction((ActionEvent arg0) -> {
            close();
        });
        getGridPane().add(cancelBtn, 1, rowNum, 1, 1);
        setCancelAccelerator(cancelBtn);
        HBox.setMargin(cancelBtn, INSET_SMALL);
   }

    public void get(final HostServices hostServices) {
        myHostServices = hostServices;

        showAndWait();
    }

    public LatLonElev getLatLon() {
        return latLon;
    }
}


text:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using GygaxCore;
using GygaxCore.Ifc;
using GygaxCore.Interfaces;
using GygaxVisu.Helpers;
using HelixToolkit.Wpf.SharpDX;
using NLog;
using SharpDX;
using Xceed.Wpf.Toolkit.Core.Converters;
using Binding = System.Windows.Data.Binding;
using Color = SharpDX.Color;
using ContextMenu = System.Windows.Controls.ContextMenu;
using UserControl = System.Windows.Controls.UserControl;

namespace GygaxVisu.Controls
{
    /// <summary>
    /// Interaction logic for Common3DSpace.xaml
    /// </summary>
    public partial class Common3DSpace : UserControl
    {
        public ObservableCollection<IStreamable> Items
        {
            get; set;
        }

        public PhongMaterial Material = PhongMaterials.Red;

        public Common3DSpace()
        {
            InitializeComponent();

            Viewport.RenderTechniquesManager = new DefaultRenderTechniquesManager();
            Viewport.RenderTechnique = Viewport.RenderTechniquesManager.RenderTechniques[DefaultRenderTechniqueNames.Blinn];
            Viewport.EffectsManager = new DefaultEffectsManager(Viewport.RenderTechniquesManager);

            InitViewport();

            SetBinding(DataContextProperty, new Binding());

            Viewport.MouseDoubleClick += ViewportOnMouseDoubleClick;

            DatastreamTree.SelectedItemChanged += DatastreamTreeOnSelectedItemChanged;
        }

        private void DatastreamTreeOnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> routedPropertyChangedEventArgs)
        {
            try
            {
                if (routedPropertyChangedEventArgs.OldValue != null)
                ((MeshGeometryModel3D)((TreeViewItem)routedPropertyChangedEventArgs.OldValue).DataContext).Material = originalMaterialOfSelectedItem;

                var element =
                    (MeshGeometryModel3D) ((TreeViewItem) routedPropertyChangedEventArgs.NewValue).DataContext;

                element.IsSelected = true;
                originalMaterialOfSelectedItem = (PhongMaterial) element.Material;

                element.Material = PhongMaterials.Blue;
            }
            catch (Exception)
            {
            }
        }

        private void ViewportOnMouseDoubleClick(object sender, MouseButtonEventArgs mouseButtonEventArgs)
        {
            var x = Viewport.CurrentPosition;
        }
        public void InitViewport()
        {
            Viewport.Items.Clear();

            var model = new AmbientLight3D { Color = new Color4(1, 1, 1, 1) };

            if (Viewport.RenderHost != null && Viewport.RenderHost.RenderTechnique != null)
                model.Attach(Viewport.RenderHost);
            Viewport.Items.Add(model);

            var model2 = new DirectionalLight3D { Direction = new Vector3(1, 1, 1) };
            if (Viewport.RenderHost != null && Viewport.RenderHost.RenderTechnique != null)
                model2.Attach(Viewport.RenderHost);
            Viewport.Items.Add(model2);

            var model3 = new DirectionalLight3D { Direction = new Vector3(-1, -1, -1) };
            if (Viewport.RenderHost != null && Viewport.RenderHost.RenderTechnique != null)
                model3.Attach(Viewport.RenderHost);

            Viewport.Items.Add(model3);

        }

        public void UpdateView()
        {
            if (Visibility != Visibility.Visible)
                return;

            foreach (var streamable in Items)
            {
                if (streamable.Name == null || streamable.Name == "")
                    continue;

                var foundOne = false;

                //Check if datastream is already in the tree
                foreach (var item in DatastreamTree.Items)
                {
                    if ((TreeViewItem)item == null || ((TreeViewItem) item).DataContext == streamable)
                    {
                        foundOne = true;
                        break;
                    }
                }

                if (foundOne) continue;

                var elements = Visualizer.Visualizer.GetModels(streamable.Data);

                var adds = Visualizer.Visualizer.GetTreeItems(streamable, elements);

                if (adds == null)
                    continue;

                DatastreamTree.Items.Add(adds);

                if (elements == null) continue;
                if (elements == null) continue;

                foreach (var m in elements)
                {
                    var model = m;

                    if (model.Parent != null)
                    {
                        if (model is MeshGeometryModel3D)
                        {
                            model = new MeshGeometryModel3D()
                            {
                                Geometry = ((MeshGeometryModel3D)m).Geometry,
                                Material = ((MeshGeometryModel3D)m).Material,
                                Transform = ((MeshGeometryModel3D)m).Transform,
                            };
                        }
                        else if (model is PointGeometryModel3D)
                        {
                            model = new PointGeometryModel3D()
                            {
                                Geometry = ((PointGeometryModel3D)m).Geometry,
                                Transform = ((PointGeometryModel3D)m).Transform,
                                Color = ((PointGeometryModel3D)m).Color
                            };
                        }
                        else if (model is LineGeometryModel3D)
                        {
                            model = new LineGeometryModel3D()
                            {
                                Geometry = ((LineGeometryModel3D)m).Geometry,
                                Transform = ((LineGeometryModel3D)m).Transform,
                                Color = ((LineGeometryModel3D)m).Color
                            };
                        }
                        else
                        {
                            continue;
                        }
                    }

                    if (Viewport.RenderHost.RenderTechnique != null)
                    {
                        model.Attach(Viewport.RenderHost);
                    }

                    Viewport.Items.Add(model);
                }
            }

            ViewportHelper.ZoomExtents(Viewport);
        }

        public void ItemsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
        {
            UpdateView();
        }

        public static readonly DependencyProperty DataContextProperty = DependencyProperty.Register(
            "DataContext",
            typeof(Object),
            typeof(Common3DSpace),
            new PropertyMetadata(DataContextChanged)
        );

        private static void DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            Common3DSpace myControl = (Common3DSpace)sender;
            myControl.Items = (e.NewValue as ViewModel).Items;

            if (myControl.Items != null)
            {
                myControl.Items.CollectionChanged += myControl.ItemsOnCollectionChanged;
            }
        }

        public void ViewModelOnClearWorkspace(object sender, EventArgs eventArgs)
        {
            Viewport.Items.Clear();
            DatastreamTree.Items.Clear();
        }

        private PhongMaterial originalMaterialOfSelectedItem;

        private void Viewport_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton != MouseButton.Left)
                return;

            var hits = Viewport.FindHits(e.GetPosition(this));

            if (hits.Count == 0) return;

            var txt = hits[0].PointHit.X + "," + hits[0].PointHit.Y + "," + hits[0].PointHit.Z;
            LogManager.GetCurrentClassLogger().Info("Hit at " + txt);

            try
            {
                var element =
                    hits.OrderBy(q => q.Distance).Select(r => r.ModelHit).First(s => s.Visibility == Visibility.Visible);

                var treeItem = getTreeItem(element, DatastreamTree.Items);
                treeItem.IsSelected = true;
                treeItem.IsExpanded = true;

                ContextMenu contextMenu = new ContextMenu();
                contextMenu.Items.Add(Visualizer.Visualizer.GetTreeItems(treeItem, element));

                contextMenu.IsOpen = true;
            }
            catch (Exception ex)
            {
            }
        }

        private TreeViewItem getTreeItem(object element, ItemCollection items)
        {
            foreach (TreeViewItem item in items)
            {
                if (item.DataContext.Equals(element))
                    return item;

                if (item.Items.Count <= 0) continue;

                var ti = getTreeItem(element, item.Items);
                if (ti != null)
                    return ti;
            }

            return null;
        }
    }
}


text:
spec_dir = File.expand_path(File.dirname(__FILE__))
root_dir = File.expand_path(File.join(spec_dir, '..'))
lib_dir = File.expand_path(File.join(root_dir, 'lib'))

$LOAD_PATH.unshift(spec_dir)
$LOAD_PATH.unshift(lib_dir)
$LOAD_PATH.uniq!

# set up coverage
require 'simplecov'
SimpleCov.start do
  add_filter 'spec'
  add_filter 'bin'
  SimpleCov.command_name ENV['COVERAGE_NAME']
end if ENV['COVERAGE_NAME']

require 'rspec'
require 'logging'
require 'rspec/logging_helper'

# Configure RSpec to capture log messages for each test. The output from the
# logs will be stored in the @log_output variable. It is a StringIO instance.
RSpec.configure do |config|
  include RSpec::LoggingHelper
  config.capture_log_messages
end

RSpec::Expectations.configuration.warn_about_potential_false_positives = false


text:
.DEFAULT_GOAL:=help

# Optional flag to run target in a docker container.
# (example `make test USE_DOCKER=true`)
ifeq ($(USE_DOCKER),true)
	DOCKER_CMD := docker-compose run --rm test
endif

.PHONY: dev
dev: ## Installs dbt-* packages in develop mode along with development dependencies.
	pip install -r dev-requirements.txt -r editable-requirements.txt

.PHONY: mypy
mypy: .env ## Runs mypy for static type checking.
	$(DOCKER_CMD) tox -e mypy

.PHONY: flake8
flake8: .env ## Runs flake8 to enforce style guide.
	$(DOCKER_CMD) tox -e flake8

.PHONY: lint
lint: .env ## Runs all code checks in parallel.
	$(DOCKER_CMD) tox -p -e flake8,mypy

.PHONY: unit
unit: .env ## Runs unit tests with py38.
	$(DOCKER_CMD) tox -e py38

.PHONY: test
test: .env ## Runs unit tests with py38 and code checks in parallel.
	$(DOCKER_CMD) tox -p -e py38,flake8,mypy

.PHONY: integration
integration: .env integration-postgres ## Alias for integration-postgres.

.PHONY: integration-fail-fast
integration-fail-fast: .env integration-postgres-fail-fast ## Alias for integration-postgres-fail-fast.

.PHONY: integration-postgres
integration-postgres: .env ## Runs postgres integration tests with py38.
	$(DOCKER_CMD) tox -e py38-postgres -- -nauto

.PHONY: integration-postgres-fail-fast
integration-postgres-fail-fast: .env ## Runs postgres integration tests with py38 in "fail fast" mode.
	$(DOCKER_CMD) tox -e py38-postgres -- -x -nauto

.PHONY: setup-db
setup-db: ## Setup Postgres database with docker-compose for system testing.
	docker-compose up -d database
	PGHOST=localhost PGUSER=root PGPASSWORD=password PGDATABASE=postgres bash test/setup_db.sh

# This rule creates a file named .env that is used by docker-compose for passing
# the USER_ID and GROUP_ID arguments to the Docker image.
.env: ## Setup step for using using docker-compose with make target.
	@touch .env
ifneq ($(OS),Windows_NT)
ifneq ($(shell uname -s), Darwin)
	@echo USER_ID=$(shell id -u) > .env
	@echo GROUP_ID=$(shell id -g) >> .env
endif
endif

.PHONY: clean
clean: ## Resets development environment.
	rm -f .coverage
	rm -rf .eggs/
	rm -f .env
	rm -rf .tox/
	rm -rf build/
	rm -rf dbt.egg-info/
	rm -f dbt_project.yml
	rm -rf dist/
	rm -f htmlcov/*.{css,html,js,json,png}
	rm -rf logs/
	rm -rf target/
	find . -type f -name '*.pyc' -delete
	find . -type d -name '__pycache__' -depth -delete

.PHONY: help
help: ## Show this help message.
	@echo 'usage: make [target] [USE_DOCKER=true]'
	@echo
	@echo 'targets:'
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
	@echo
	@echo 'options:'
	@echo 'use USE_DOCKER=true to run target in a docker container'


text:
'use strict';

const isHTML = require('is-html'),
    isURL = require('is-absolute-url'),
    request = require('request'),
    fs = require('fs'),
    os = require('os'),
    path = require('path'),
    url = require('url');

function isWindows() {
    return os.platform() === 'win32';
}

/**
 * Check if the supplied string might be a RegExp and, if so, return the corresponding RegExp.
 * @param  {String} str     The regex to transform.
 * @return {RegExp|String}  The final RegExp
 */
function strToRegExp(str) {
    if (str[0] === '/') {
        return new RegExp(str.replace(/^\/|\/$/g, ''));
    }
    return str;
}

/**
 * Parse a given uncssrc file.
 * @param  {String} filename The location of the uncssrc file
 * @return {Object}          The options object
 */
function parseUncssrc(filename) {
    const options = JSON.parse(fs.readFileSync(filename, 'utf-8'));

    /* RegExps can't be stored as JSON, therefore we need to parse them manually.
     * A string is a RegExp if it starts with '/', since that wouldn't be a valid CSS selector.
     */
    options.ignore = options.ignore ? options.ignore.map(strToRegExp) : undefined;
    options.ignoreSheets = options.ignoreSheets ? options.ignoreSheets.map(strToRegExp) : [];

    return options;
}

/**
 * Parse paths relatives to a source.
 * @param  {String} source      Where the paths originate from
 * @param  {Array}  stylesheets List of paths
 * @param  {Object} options     Options, as passed to UnCSS
 * @return {Array}              List of paths
 */
function parsePaths(source, stylesheets, options) {
    return stylesheets.map(sheet => {
        let sourceProtocol;
        const isLocalFile = sheet.substr(0, 5) === 'file:';

        if (sheet.substr(0, 4) === 'http') {
            /* No need to parse, it's already a valid path */
            return sheet;
        }

        /* Check if we are fetching over http(s) */
        if (isURL(source) && !isLocalFile) {
            sourceProtocol = url.parse(source).protocol;

            if (sheet.substr(0, 2) === '//') {
                /* Use the same protocol we used for fetching this page.
                 * Default to http.
                 */
                return sourceProtocol ? sourceProtocol + sheet : `http:${sheet}`;
            }
            return url.resolve(source, sheet);
        }

        /* We are fetching local files
         * Should probably report an error if we find an absolute path and
         *   have no htmlroot specified.
         */
        /* Fix the case when there is a query string or hash */
        sheet = sheet.split('?')[0].split('#')[0];

        /* Path already parsed by jsdom or user supplied local file */
        if (isLocalFile) {
            sheet = url.parse(sheet).path.replace('%20', ' ');
            /* If on windows, remove first '/' */
            sheet = isWindows() ? sheet.substring(1) : sheet;

            if (options.htmlroot) {
                return path.join(options.htmlroot, sheet);
            }
            sheet = path.relative(path.join(path.dirname(source)), sheet);
        }

        if (sheet[0] === '/' && options.htmlroot) {
            return path.join(options.htmlroot, sheet);
        } else if (isHTML(source)) {
            return path.join(options.csspath, sheet);
        }
        return path.join(path.dirname(source), options.csspath, sheet);
    });
}

/**
 * Given an UTF8 string, return a version of this string without the first byte if it corresponds
 *   to the Byte Order Mark
 * @param {String}  utf8String the string to strip
 * @return {String}
 */
function stripBom(utf8String) {
    if (utf8String.charCodeAt(0) === 0xfeff) {
        return utf8String.substr(1);
    }
    return utf8String;
}

/**
 * Given an array of filenames, return an array of the files' contents,
 *   only if the filename matches a regex
 * @param  {Array}   files  An array of the filenames to read
 * @return {Promise}
 */
async function readStylesheets(files, outputBanner) {
    const res = await Promise.all(
        files.map(filename => {
            if (isURL(filename)) {
                return new Promise((resolve, reject) => {
                    request(
                        {
                            url: filename,
                            headers: { 'User-Agent': 'UnCSS' },
                        },
                        (err, response, body) => {
                            if (err) {
                                return reject(err);
                            }
                            return resolve(body);
                        }
                    );
                });
            } else if (fs.existsSync(filename)) {
                return new Promise((resolve, reject) => {
                    fs.readFile(filename, 'utf-8', (err, contents) => {
                        if (err) {
                            return reject(err);
                        }
                        return resolve(stripBom(contents));
                    });
                });
            }
            throw new Error(`UnCSS: could not open ${path.join(process.cwd(), filename)}`);
        })
    );

    // res is an array of the content of each file in files (in the same order)
    if (outputBanner) {
        for (let i = 0, len = files.length; i < len; i++) {
            // We append a small banner to keep track of which file we are currently processing
            // super helpful for debugging
            const banner = `/*** uncss> filename: ${files[i].replace(/\\/g, '/')} ***/\n`;
            res[i] = banner + res[i];
        }
    }
    return res;
}

function parseErrorMessage(error, cssStr) {
    /* TODO: FIXME */
    /* Base line for conveying the line number in the error message */
    let zeroLine = 0;

    if (error.line) {
        const lines = cssStr.split('\n');
        if (lines.length) {
            /* We get the filename of the css file that contains the error */
            let i = error.line - 1;
            while (i >= 0 && !error.filename) {
                if (lines[i].substr(0, 21) === '/*** uncss> filename:') {
                    error.filename = lines[i].substring(22, lines[i].length - 4);
                    zeroLine = i;
                }
                i--;
            }
            for (let j = error.line - 6; j < error.line + 5; j++) {
                if (j - zeroLine < 0 || j >= lines.length) {
                    continue;
                }
                let line = lines[j];
                /* It could be minified CSS */
                if (line.length > 120 && error.column) {
                    line = line.substring(error.column - 40, error.column);
                }
                error.message += `\n\t${j + 1 - zeroLine}:    `;
                error.message += j === error.line - 1 ? ' -> ' : '    ';
                error.message += line;
            }
        }
    }
    if (zeroLine > 0) {
        error.message = error.message.replace(/[0-9]+:/, `${error.line - zeroLine}:`);
    }
    error.message = `uncss/node_modules/css: unable to parse ${error.filename}:\n${error.message}\n`;
    return error;
}

module.exports = {
    isWindows,
    parseUncssrc,
    parseErrorMessage,
    parsePaths,
    readStylesheets,
};


text:
import communication_app.models

def get_my_pets(request):
    if not request.user:
        return []
    return communication_app.models.Pet.objects.filter(
        user=request.user)


text:
- Java 8
- Postgres 9.6
- Hibernate 5.2
- Spring MVC, Boot, Security 4.3
- Spring OAuth 2
- Maven 3

## Deploy and configuration
- Create database in Postgres and restore from dump `shopDump.sql`
- Edit `application.properties` in resources accordingly to your database settings
- Run application as Spring Boot app in IDE
- Alternatively you can build a jar using `mvn clean install spring-boot:repackage`
 and run it by `java -jar shopAPI.jar`

## Authentication, authorization and credentials
 - In database dump there is already one admin user: `admin:abc123`
 - For client's authorization use default HTTP authorization header `Authorization: Basic dHJ1c3RlZDphYmMxMjM=
 or trusted:secret login/password combination`
 - For simplicity OAuth default tables located in the same schema
 - You can edit access and refresh token validity in `oauth_client_details` table
 - To access REST API secured actions you have to provide access token in request params e.g.
 ``access_token=c15de2f5-d7ec-4948-82ac-07ba2d1fb27d``
 But without Authorization header.

## REST actions

### Authentication

- Obtain access token
``POST oauth/token?grant_type=password&username=admin&password=abc123``
You must provide client's authorization headers
- Refresh access token
``POST oauth/token?grant_type=refresh_token&refresh_token=<REFRESH_TOKEN>``
You must provide client's authorization headers

### Cart Controller Actions

- addProductToCart - public
``POST /api/shop/cart/{cartId}/add/{productId}``
- createCart - public
``POST /api/shop/cart/customer/{customerId}``

### Order Controller Actions

- createOrder - public
``POST /api/shop/customer/{id}/order``
- listAllOrders - admin
``GET /api/shop/orders``

### Customer Controller Actions

- createCustomer - admin
``POST /api/shop/customers/{name}``

### Product Controller Actions

- listAllProducts - public
``GET /api/shop/products``
- getProduct - admin
``GET /api/shop/products/{id}``
- createProduct - admin
``POST /api/shop/products``
- updateProduct - admin
``PUT /api/shop/products/{id}``
- deleteProduct - admin
``DELETE /api/shop/products/{id}``