text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.resourcemanager.network.models;

import com.azure.core.annotation.Fluent;
import com.azure.core.management.SubResource;
import com.azure.resourcemanager.network.fluent.models.ApplicationGatewayBackendAddressPoolPropertiesFormat;
import com.azure.resourcemanager.network.fluent.models.NetworkInterfaceIpConfigurationInner;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;

/** Backend Address Pool of an application gateway. */
@Fluent
public final class ApplicationGatewayBackendAddressPool extends SubResource {
    /*
     * Properties of the application gateway backend address pool.
     */
    @JsonProperty(value = "properties")
    private ApplicationGatewayBackendAddressPoolPropertiesFormat innerProperties;

    /*
     * Name of the backend address pool that is unique within an Application Gateway.
     */
    @JsonProperty(value = "name")
    private String name;

    /*
     * A unique read-only string that changes whenever the resource is updated.
     */
    @JsonProperty(value = "etag", access = JsonProperty.Access.WRITE_ONLY)
    private String etag;

    /*
     * Type of the resource.
     */
    @JsonProperty(value = "type", access = JsonProperty.Access.WRITE_ONLY)
    private String type;

    /** Creates an instance of ApplicationGatewayBackendAddressPool class. */
    public ApplicationGatewayBackendAddressPool() {
    }

    /**
     * Get the innerProperties property: Properties of the application gateway backend address pool.
     *
     * @return the innerProperties value.
     */
    private ApplicationGatewayBackendAddressPoolPropertiesFormat innerProperties() {
        return this.innerProperties;
    }

    /**
     * Get the name property: Name of the backend address pool that is unique within an Application Gateway.
     *
     * @return the name value.
     */
    public String name() {
        return this.name;
    }

    /**
     * Set the name property: Name of the backend address pool that is unique within an Application Gateway.
     *
     * @param name the name value to set.
     * @return the ApplicationGatewayBackendAddressPool object itself.
     */
    public ApplicationGatewayBackendAddressPool withName(String name) {
        this.name = name;
        return this;
    }

    /**
     * Get the etag property: A unique read-only string that changes whenever the resource is updated.
     *
     * @return the etag value.
     */
    public String etag() {
        return this.etag;
    }

    /**
     * Get the type property: Type of the resource.
     *
     * @return the type value.
     */
    public String type() {
        return this.type;
    }

    /** {@inheritDoc} */
    @Override
    public ApplicationGatewayBackendAddressPool withId(String id) {
        super.withId(id);
        return this;
    }

    /**
     * Get the backendIpConfigurations property: Collection of references to IPs defined in network interfaces.
     *
     * @return the backendIpConfigurations value.
     */
    public List<NetworkInterfaceIpConfigurationInner> backendIpConfigurations() {
        return this.innerProperties() == null ? null : this.innerProperties().backendIpConfigurations();
    }

    /**
     * Get the backendAddresses property: Backend addresses.
     *
     * @return the backendAddresses value.
     */
    public List<ApplicationGatewayBackendAddress> backendAddresses() {
        return this.innerProperties() == null ? null : this.innerProperties().backendAddresses();
    }

    /**
     * Set the backendAddresses property: Backend addresses.
     *
     * @param backendAddresses the backendAddresses value to set.
     * @return the ApplicationGatewayBackendAddressPool object itself.
     */
    public ApplicationGatewayBackendAddressPool withBackendAddresses(
        List<ApplicationGatewayBackendAddress> backendAddresses) {
        if (this.innerProperties() == null) {
            this.innerProperties = new ApplicationGatewayBackendAddressPoolPropertiesFormat();
        }
        this.innerProperties().withBackendAddresses(backendAddresses);
        return this;
    }

    /**
     * Get the provisioningState property: The provisioning state of the backend address pool resource.
     *
     * @return the provisioningState value.
     */
    public ProvisioningState provisioningState() {
        return this.innerProperties() == null ? null : this.innerProperties().provisioningState();
    }

    /**
     * Validates the instance.
     *
     * @throws IllegalArgumentException thrown if the instance is not valid.
     */
    public void validate() {
        if (innerProperties() != null) {
            innerProperties().validate();
        }
    }
}


text:
FactoryGirl.define do
  factory :metric_result, class: 'MetricResult' do
    association :cookbook_version
    association :quality_metric
    failure true
    feedback 'it failed'
  end
end

redpajama_set_name: RedPajamaGithub


text:
<!doctype html>

    <title>Code coverage report for app/Components/Test/codeSplitting.js</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="../../../prettify.css" />
    <link rel="stylesheet" href="../../../base.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1">

      All files / app/Components/Test codeSplitting.js

        0%
        Statements
        0/6

        100%
        Branches
        0/0

        0%
        Functions
        0/4

        0%
        Lines
        0/5

1
2
3
4
5
6
7
8
9
10

function determineDate() {
  import('moment').then(function (moment) {
    console.log(moment().format())
  }).catch(function (err) {
    console.log('Failed to load moment', err)
  })
}

export {determineDate}

  Code coverage
  generated by istanbul at Mon Sep 18 2017 17:44:25 GMT+0800 (CST)


text:
require 'spec_helper'

describe Praxis::ApiGeneralInfo do

  subject(:info){ Praxis::ApiGeneralInfo.new }

  before do
    allow(Praxis::Application.instance).to receive(:versioning_scheme=).with([:header, :params])
  end

  let(:info_block) do
    Proc.new do
      name "Name"
      title "Title"
      description "Description"
      endpoint 'api.example.com'
      base_path "/base"
      base_params do
        attribute :name, String
      end
    end
  end

  context 'setting' do
    it 'accepts the appropriate DSLs' do
      expect{
        info.instance_exec &info_block
      }.to_not raise_error
    end
  end

  context 'getting values' do
    before do
      info.instance_exec &info_block
    end

    its(:name) { should eq 'Name' }

  end
  context '.describe' do
    before do
      info.instance_exec &info_block
    end

    subject(:output){ info.describe }
    its([:schema_version]) {should eq '1.0' }
    its([:name]) {should eq 'Name' }
    its([:title]) {should eq 'Title' }
    its([:description]) {should eq 'Description' }
    its([:base_path]) {should eq '/base' }
    its([:base_params]) { should have_key :name }
    its([:base_params, :name, :type, :name]) { should eq 'String' }
    its([:version_with]) { should eq([:header, :params]) }
    its([:endpoint]) { should eq 'api.example.com' }
  end

  context 'base_path with versioning' do
    let(:global_info){ Praxis::ApiGeneralInfo.new }
    subject(:info){ Praxis::ApiGeneralInfo.new(global_info, version: '1.0') }

    before do
      global_info

      expect(Praxis::Application.instance).to receive(:versioning_scheme=).with(:path)

      global_info.version_with :path
      global_info.base_path '/api/v:api_version'
    end

    its(:base_path) { should eq '/api/v1.0'}
  end

end


text:
var fs = require('fs'),
  events = require('events'),
  util = require('util'),
  spawn = require('child_process').spawn,
  async = require('async'),
  debug = require('debug')('redis-server-manager'),
  stream = require('stream'),
  temp = require('temp');

/**
 * Redis Server Manager
 * ====================
 *
 * This is the main entry for redis-server-manager.
 *
 */
var rbin = 'redis-server',
  RedisServer = require('./lib/redis-server'),
  StoppableRedisServer = require('./lib/stoppable-redis-server');

// List of named redis servers
var namedServers = {}, serverConfig = {};

var redis = module.exports = {

  /*
   * Gathers some information about the redis installation
   */
  getInfo: require('./lib/getinfo')(rbin),

  /*
   * Starts up a redis server with the given command-line `args`.
   * `cb` is called whith the server object when the server is ready
   * to accept connections. Alternatively, the function returns the
   * server object and you may listen for a 'ready' event.
   */
  startServer: require('./lib/start')(rbin),

  /*
   * Starts up a redis server with a given configuration (as string)
   */
  startServerFromConfig: function (addr, config, cb) {
    var server = redis.startServer(addr, ['-'], cb);
    server.child.stdin.write(config);
    server.child.stdin.end();
    return server;
  },

  createServer: function (addr, opts) {
    return new RedisServer(addr, opts);
  },

  createTestServer: function (cb) {
    var socket = temp.path({suffix: '.sock'});
    var config = "port 0\n" +
      "unixsocket " + socket + "\n" +
      "unixsocketperm 755";
    return redis.startServerFromConfig(socket, config, cb);
  },

  // Helper to create clients from an options hash
  //
  // Options may contain one of
  //
  // - `createClient`
  //   A synchronous function that creates a single client.
  //
  // - `server`
  //   A redis server object or a string key of a named server
  //
  // - `clients`
  //   Pre-configured clients object/array
  //
  createClients: function (createFromServer, options) {
    if (typeof createFromServer === 'object') {
      options = createFromServer;
      // Default to creating a single client
      createFromServer = function (server) {
        return server.createClient();
      };
    }

    var clients, clientsWait;
    // Fall-through for pre-configured clients
    if (options.clients) {
      clients = options.clients;
    }

    function returnClients(cb) {
      process.nextTick(function () {
        debug("Clients %j", Object.keys(clients));
        cb(null, clients);
      });
    }

    function doCreateFromServer(server, cb) {
      debug("Creating from server");
      clients = createFromServer(server);
      if (!clients) {
        return cb(new Error('Could not create clients!'));
      }
      clientsWait.emit('ready');
      returnClients(cb);
    }

    // Create clients from a server object or name
    function fromServer(server, cb) {
      clientsWait = new events.EventEmitter();
      switch (typeof server) {
      case 'string':
        redis.byName(server, function (err, s) {
          if (err) {
            return cb(err);
          }
          doCreateFromServer(s, cb);
        });
        break;
      case 'object':
        process.nextTick(doCreateFromServer.bind(undefined, server, cb));
        break;
      default:
        cb(new Error('Invalid server option', server));
      }
    }

    function fn(cb) {
      if (clients) {
        // Return clients right away
        returnClients(cb);
      } else if (clientsWait) {
        // Wait for a client being constructed
        clientsWait.once('ready', returnClients.bind(undefined, cb));
      } else {
        // Create a new client
        if (options.createClient) {
          clients = options.createClient();
          returnClients(cb);
        } else if (options.server) {
          fromServer(options.server, cb);
        } else {
          cb(new Error('Invalid options hash, could not create Redis client!'));
        }
      }
    }

    fn.reset = function () {
      if (clients && clients.quit) {
        clients.quit();
      }
      clientsWait = clients = undefined;
    };

    return fn;
  },

  setConfig: function (config) {
    serverConfig = config;
  },

  // Get a pre-configured redis-server by name
  byName: function (name, cb) {
    var server;
    if (!!(server = namedServers[name])) {
      if (server.ready) {
        cb(null, server);
      } else {
        server.once('ready', function () {
          cb(null, server);
        });
      }
      return server;
    }

    // Try to start up the server from configuration
    var conf = serverConfig[name];
    if (!conf) {
      return cb(new Error('Named redis server "' + name + '" not found!'));
    }

    if (conf.config && conf.address) {
      debug('Spinning up Redis instance %s', name);
      namedServers[name] = server = redis.startServerFromConfig(conf.address, conf.config, cb);
    } else if (conf.args && conf.address) {
      debug('Spinning up Redis instance %s', name);
      namedServers[name] = server = redis.startServer(conf.address, conf.args, cb);
      server.once('stop', function () {
        delete namedServers[name];
      });
    } else {
      return cb(new Error('Invalid configuration for redis server "' + name + '"'));
    }
    server.once('stop', function () {
      delete namedServers[name];
    });
    return server;
  },

  shutdownAll: function () {
    Object.keys(namedServers).forEach(function (key) {
      debug('Shutting down managed Redis "%s"', key);
      namedServers[key].stop();
    });
    namedServers = {};
  }

};

process.on('exit', function () {
  redis.shutdownAll();
});


text:
package edu.berkeley.cs.amplab.spark.intervalrdd

import org.apache.spark.rdd.MetricsContext._
import org.apache.spark.rdd.RDD
import org.apache.spark.storage.StorageLevel
import org.apache.spark.{Logging, Partition, TaskContext, _}
import org.bdgenomics.adam.models.Interval

import scala.reflect.ClassTag

class IntervalRDD[K<: Interval: ClassTag, V: ClassTag](
    /** The underlying representation of the IndexedRDD as an RDD of partitions. */
    private val partitionsRDD: RDD[IntervalPartition[K, V]])
  extends RDD[(K, V)](partitionsRDD.context, List(new OneToOneDependency(partitionsRDD))) with Logging {

  require(partitionsRDD.partitioner.isDefined)

  override val partitioner = partitionsRDD.partitioner

  override protected def getPartitions: Array[Partition] = partitionsRDD.partitions

  /** Provides the `RDD[(K, V)]` equivalent output. */
  override def compute(part: Partition, context: TaskContext): Iterator[(K, V)] = {
    // This needs to be present to compile
    null
  }

  def toRDD: RDD[(K, V)] = {
    partitionsRDD.flatMap(_.get)
  }

  override def setName(_name: String): this.type = {
    partitionsRDD.setName(_name)
    this
  }

  /** Persists the interval partitions using `targetStorageLevel`, which defaults to MEMORY_ONLY. */
  override def persist(newLevel: StorageLevel): this.type = {
    partitionsRDD.persist(newLevel)
    this
  }
  /** Unpersists the interval partitions using */
  override def unpersist(blocking: Boolean = true): this.type = {
    partitionsRDD.unpersist(blocking)
    this
  }

  /** The number of elements in the RDD. */
  override def count: Long = {
    partitionsRDD.map(_.getTree.size).reduce(_ + _)
  }

  override def collect: Array[(K, V)] = partitionsRDD.flatMap(r => r.get()).collect

  def filterByInterval(r: K): IntervalRDD[K, V] = {
    mapIntervalPartitions(_.filterByInterval(r))
  }

  /**
   * Performs filtering given a predicate
   */
  override def filter(pred: Tuple2[K,V] => Boolean): IntervalRDD[K, V] = {
    this.mapIntervalPartitions(_.filter(Function.untupled(pred)))
  }

  /**
    * Maps each value, preserving the index.
    */
  def mapValues[V2: ClassTag](f: V => V2): IntervalRDD[K, V2] = {
    this.mapIntervalPartitions(_.mapValues(f))
  }

  /**
   * Maps interval partitions in partitionsRDD
   * @param f mapping function for interval partitions
   * @tparam K2 key type extending Interval
   * @tparam V2 data type
   * @return new IntervalRDD of type [K2, V2]
   */
  def mapIntervalPartitions[K2 <: Interval: ClassTag, V2: ClassTag](
                            f: (IntervalPartition[K, V]) => IntervalPartition[K2, V2]): IntervalRDD[K2, V2] = {

    val newPartitionsRDD = partitionsRDD.mapPartitions(_.map(f), preservesPartitioning = true)
    new IntervalRDD(newPartitionsRDD)
  }

  private def withPartitionsRDD[K2 <: Interval: ClassTag, V2: ClassTag](
      partitionsRDD: RDD[IntervalPartition[K2, V2]]): IntervalRDD[K2, V2] = {
    new IntervalRDD(partitionsRDD)
  }

  /** Gets the values corresponding to the specified key, if any
  * Assume that we're only getting data that exists (if it doesn't exist,
  * would have been handled by upper LazyMaterialization layer
  */
  def get(region: K): List[(K,V)] = {

    val results: Array[Array[(K, V)]] = {
      context.runJob(partitionsRDD, (context: TaskContext, partIter: Iterator[IntervalPartition[K, V]]) => {
       if (partIter.hasNext) {
          val intPart = partIter.next()
          intPart.get(region).toArray
       } else {
          Array[(K, V)]()
       }
      })
    }
    results.flatten.toList
  }

  /**
   * Unconditionally updates the specified keys to have the specified value. Returns a new IntervalRDD
   **/
  def multiput(elems: Array[(K, V)]): IntervalRDD[K, V] = {
    val partitioned: RDD[(K, V)] = context.parallelize(elems.toSeq).partitionBy(partitioner.get)

    val convertedPartitions: RDD[IntervalPartition[K, V]] = partitioned.mapPartitions[IntervalPartition[K, V]](
      iter => Iterator(IntervalPartition(iter)),
      preservesPartitioning = true)

    // merge the new partitions with existing partitions
    val merger = new PartitionMerger[K, V]()
    val newPartitionsRDD = partitionsRDD.zipPartitions(convertedPartitions, true)((aiter, biter) => merger(aiter, biter))
    new IntervalRDD(newPartitionsRDD)
  }

  /**
   * Unconditionally updates the specified keys to have the specified value. Returns a new IntervalRDD
   **/
  def multiput(elem: (K, V)): IntervalRDD[K, V] = multiput(Array(elem))

  /**
   * Unconditionally updates the specified keys to have the specified value. Returns a new IntervalRDD
   **/
  def multiput(elems: RDD[(K, V)]): IntervalRDD[K, V] = {
    val partitioned =
      if (elems.partitioner.isDefined) elems
      else {
        elems.partitionBy(new HashPartitioner(elems.partitions.size))
      }

    val convertedPartitions: RDD[IntervalPartition[K, V]] = partitioned.mapPartitions[IntervalPartition[K, V]](
      iter => Iterator(IntervalPartition(iter)),
      preservesPartitioning = true)

    // merge the new partitions with existing partitions
    val merger = new PartitionMerger[K, V]()
    val newPartitionsRDD = partitionsRDD.zipPartitions(convertedPartitions, true)((aiter, biter) => merger(aiter, biter))
    new IntervalRDD(newPartitionsRDD)
  }
}

class PartitionMerger[K <: Interval, V: ClassTag]() extends Serializable {
  def apply(thisIter: Iterator[IntervalPartition[K, V]], otherIter: Iterator[IntervalPartition[K, V]]): Iterator[IntervalPartition[K, V]] = {
    val thisPart = thisIter.next
    val otherPart = otherIter.next
    Iterator(thisPart.mergePartitions(otherPart))
  }
}

object IntervalRDD extends Logging {

  /**
  * Constructs an IntervalRDD from a set of ReferenceRegion, V tuples
  */
  def apply[K <: Interval: ClassTag, V: ClassTag](elems: RDD[(K, V)]) : IntervalRDD[K, V] = {
    val partitioned =
      if (elems.partitioner.isDefined) elems
      else {
        elems.partitionBy(new HashPartitioner(elems.partitions.size))
      }
    val convertedPartitions: RDD[IntervalPartition[K, V]] = partitioned.mapPartitions[IntervalPartition[K, V]](
      iter => Iterator(IntervalPartition(iter)),
      preservesPartitioning = true)

    new IntervalRDD(convertedPartitions)
  }

}


text:
> Removes all occurences of an item from an array or an object, adressed by its value

## Signature

**path** *(String/Array)* - The path to the iterable

**value** *(String/Array)* - The value to be removed

**subject** *(Object)* - The object that contains the iterable

**TYPE SIGNATURES**
```
String -> * -> Object -> Object
(String, *) -> Object -> Object
(String, *,  Object) -> Object
Array -> * -> Object -> Object
(Array, *) -> Object -> Object
(Array, *,  Object) -> Object
```

**EXAMPLE**
```js
const myObject = {
    itemsInTheFrige: ['eggs', 'beer', 'milk', 'beer', 'bacon', 'beer']
};

//
// Too much beer...
//
$remove('itemsInTheFrige', 'beer', myObject);
// returns {
//     itemsInTheFrige: ['eggs', 'milk', 'bacon']
// }
```

**IMMUTABLE JS SUPPORT**
*the following types are supported for values targeted by `path`*:
```
List
Set
Map
OrderedSet
OrderedMap
```


text:
<!doctype html>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link type="text/css" rel='stylesheet' href='JSON.css'>
    <title>JSON Interoperability Example</title>

        Your web browser must have JavaScript enabled
        in order for this application to display correctly.

JSON Interop Using JSNI

      This example application demonstrates a simple approach to
      interoperating with services that return their output in JSON format.
      It uses GWT's JavaScript Native Interface (JSNI) to analyze a JSON
      response and create Java-accessible objects.  The JSON classes in this sample
      are general-purpose and can be reused in other projects if you find
      them useful.

      When you click the "Search" button below, you can browse the cached
      results of a Yahoo JSON image search for "potato."  The response is
      parsed into Java objects which are used to populate a tree view below.

For more details on how the JSON response is parsed into a set
            of Java objects, see the JSONParser class.

This is the
          JSON file used in this example.

JSON Response Tree View


text:
#ifndef GODOT_MASTER_MAIN_MAP_H
#define GODOT_MASTER_MAIN_MAP_H

#include "../../../core/resource.h"
#include "../../../scene/resources/texture.h"

class MainMap : public Resource {
    GDCLASS(MainMap, Resource);
private:
    int width;
    int height;
    int x;
    int y;
    bool *map_checked;

    Ref<Texture> texture;

    void update_size();

protected:
    static void _bind_methods();
public:
    _FORCE_INLINE_ int get_width() {return width;}
    _FORCE_INLINE_ void set_width(int p_width) {width=p_width;update_size();}

    _FORCE_INLINE_ int get_height() {return height;}
    _FORCE_INLINE_ void set_height(int p_height) {height=p_height;update_size();}

    _FORCE_INLINE_ void set_texture(const Ref<Texture>& p_texture) {texture = p_texture;}
    _FORCE_INLINE_ Ref<Texture> get_texture() {return texture;}

    bool checked_at(int x, int y);
    void set_checked(int x, int y, bool checked);
    void at(int x, int y);
    _FORCE_INLINE_ int get_x() {return x;}
    _FORCE_INLINE_ int get_y() {return y;}

    Dictionary get_data();
    void set_data(Dictionary data);

    MainMap() {
        width=0;
        height=0;
        map_checked=NULL;
    }
};

#endif //GODOT_MASTER_MAIN_MAP_H


text:
const giphy = require('giphy-api')();

exports.run = (bot, msg, args) => {
    if (args.length < 1) {
        throw 'You must provide something to search for!';
    }

    msg.edit(':arrows_counterclockwise:').then(() => {
        giphy.random(`${args.join(' ')}`, function (err, res) {
            if (err) {
                return msg.error(err);
            }

            if (!res.data.url) {
                return msg.error('No results found!');
            }

            let key = res.data.url.substr(res.data.url.lastIndexOf('-') + 1);
            let url = `https://media.giphy.com/media/${key}/giphy.gif`;

            msg.channel.send({
                embed: bot.utils.embed('', '', [], { image: url })
            }).then(() => msg.delete()).catch(msg.error);
        });
    });
};

exports.info = {
    name: 'gif',
    usage: 'gif <query>',
    description: 'Searches Giphy for GIFs'
};


text:
module EOL
  module Api
    module Search
      class V1_0 < EOL::Api::MethodVersion
        VERSION = '1.0'
        BRIEF_DESCRIPTION = Proc.new { I18n.t(:search_method_description) }
        DESCRIPTION = Proc.new { I18n.t('the_xml_search_response_implements',
          :link => view_context.link_to('http://www.opensearch.org/Specifications/OpenSearch/1.1', 'http://www.opensearch.org/Specifications/OpenSearch/1.1')) +
          '</p><p>' + I18n.t('given_the_vast_number') }
        PARAMETERS = Proc.new {
          [
            EOL::Api::DocumentationParameter.new(
              :name => 'q',
              :type => String,
              :required => true,
              :test_value => 'Ursus',
              :notes => I18n.t('the_query_string') ),
            EOL::Api::DocumentationParameter.new(
              :name => 'page',
              :type => Integer,
              :default => 1,
              :required => true,
              :notes => I18n.t('a_maximum_of_30_results_are_returned') ),
            EOL::Api::DocumentationParameter.new(
              :name => 'exact',
              :type => 'Boolean',
              :notes => I18n.t('will_find_taxon_pages_matching_the_search_term') ),
            EOL::Api::DocumentationParameter.new(
              :name => 'filter_by_taxon_concept_id',
              :type => Integer,
              :notes => I18n.t('provide_a_concept_id') ),
            EOL::Api::DocumentationParameter.new(
              :name => 'filter_by_hierarchy_entry_id',
              :type => Integer,
              :notes => I18n.t('provide_a_hierarchy_entry_id') ),
            EOL::Api::DocumentationParameter.new(
              :name => 'filter_by_string',
              :type => String,
              :notes => I18n.t('provide_a_search_string') ),
            EOL::Api::DocumentationParameter.new(
              :name => 'cache_ttl',
              :type => Integer,
              :notes => I18n.t('api_cache_time_to_live_parameter'))
          ] }

        def self.call(params={})
          params[:q] ||= params[:id]
          # ID is used later when logging API requests
          params[:id] = params[:q]
          validate_and_normalize_input_parameters!(params)
          params[:per_page] = 30

          # we had a bunch of searches like "link:QLlHJCZzx" which were throwing errors
          if params[:q].match(/^link:[a-z]+$/i)
            raise EOL::Exceptions::ApiException.new("Invalid search term: \"#{params[:q]}\"")
          end
          prepare_hash(params)
        end

        def self.prepare_hash(params={})
          if params[:q] =~ /^".*"$/
            params[:q] = params[:q][1...-1]
            params[:exact] = true
          end
          search_response = EOL::Solr::SiteSearch.search_with_pagination(params[:q], :page => params[:page],
            :per_page => params[:per_page], :type => [ 'taxon_concept' ], :exact => params[:exact],
            :filter_by_taxon_concept_id => params[:filter_by_taxon_concept_id],
            :filter_by_hierarchy_entry_id => params[:filter_by_hierarchy_entry_id],
            :filter_by_string => params[:filter_by_string] )
          solr_results = search_response[:results]

          results = []
          solr_results.each do |result|
            result_hash = {}
            result_hash['id'] = result['resource_id']
            result_hash['title'] = result['instance'].title.strip_italics
            result_hash['link'] = url_for(:controller => 'taxa', :action => 'overview', :id => result['resource_id'], :only_path => false)
            result_hash['content'] = result['keyword'].join('; ')
            results << result_hash
          end

          last_page = (solr_results.total_entries/params[:per_page].to_f).ceil
          search_api_url = url_for(:controller => 'api', :action => 'search', :id => params[:q], :format => params[:format], :only_path => false)
          return_hash = {}
          return_hash['totalResults'] = solr_results.total_entries
          return_hash['startIndex']   = ((params[:page]) * params[:per_page]) - params[:per_page] + 1
          return_hash['itemsPerPage'] = params[:per_page]
          return_hash['results']      = results
          return_hash['first']        = "#{search_api_url}?page=1" if params[:page] <= last_page
          return_hash['previous']     = "#{search_api_url}?page=#{params[:page]-1}" if params[:page] > 1 && params[:page] <= last_page
          return_hash['self']         = "#{search_api_url}?page=#{params[:page]}" if params[:page] <= last_page
          return_hash['next']         = "#{search_api_url}?page=#{params[:page]+1}" if params[:page] < last_page
          return_hash['last']         = "#{search_api_url}?page=#{last_page}" if params[:page] <= last_page
          return return_hash
        end
      end
    end
  end
end


text:
.. _tune-pytorch-lightning:

Using PyTorch Lightning with Tune
=================================

PyTorch Lightning is a framework which brings structure into training PyTorch models. It
aims to avoid boilerplate code, so you don't have to write the same training
loops all over again when building a new model.

.. image:: /images/pytorch_lightning_full.png
  :align: center

The main abstraction of PyTorch Lightning is the ``LightningModule`` class, which
should be extended by your application. There is `a great post on how to transfer
your models from vanilla PyTorch to Lightning <https://towardsdatascience.com/from-pytorch-to-pytorch-lightning-a-gentle-introduction-b371b7caaf09>`_.

The class structure of PyTorch Lightning makes it very easy to define and tune model
parameters. This tutorial will show you how to use Tune to find the best set of
parameters for your application on the example of training a MNIST classifier. Notably,
the ``LightningModule`` does not have to be altered at all for this - so you can
use it plug and play for your existing models, assuming their parameters are configurable!

.. note::

    To run this example, you will need to install the following:

    .. code-block:: bash

        $ pip install "ray[tune]" torch torchvision pytorch-lightning

.. contents::
    :local:
    :backlinks: none

PyTorch Lightning classifier for MNIST
--------------------------------------
Let's first start with the basic PyTorch Lightning implementation of an MNIST classifier.
This classifier does not include any tuning code at this point.

Our example builds on the MNIST example from the `blog post we talked about
earlier <https://towardsdatascience.com/from-pytorch-to-pytorch-lightning-a-gentle-introduction-b371b7caaf09>`_.

First, we run some imports:

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __import_lightning_begin__
   :end-before: __import_lightning_end__

And then there is the Lightning model adapted from the blog post.
Note that we left out the test set validation and made the model parameters
configurable through a ``config`` dict that is passed on initialization.
Also, we specify a ``data_dir`` where the MNIST data will be stored.
Lastly, we added a new metric, the validation accuracy, to the logs.

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __lightning_begin__
   :end-before: __lightning_end__

And that's it! You can now run ``train_mnist(config)`` to train the classifier, e.g.
like so:

.. code-block:: python

    config = {
        "layer_1_size": 128,
        "layer_2_size": 256,
        "lr": 1e-3,
        "batch_size": 64
    }
    train_mnist(config)

Tuning the model parameters
---------------------------
The parameters above should give you a good accuracy of over 90% already. However,
we might improve on this simply by changing some of the hyperparameters. For instance,
maybe we get an even higher accuracy if we used a larger batch size.

Instead of guessing the parameter values, let's use Tune to systematically try out
parameter combinations and find the best performing set.

First, we need some additional imports:

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __import_tune_begin__
   :end-before: __import_tune_end__

Talking to Tune with a PyTorch Lightning callback
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

PyTorch Lightning introduced `Callbacks <https://pytorch-lightning.readthedocs.io/en/latest/callbacks.html>`_
that can be used to plug custom functions into the training loop. This way the original
``LightningModule`` does not have to be altered at all. Also, we could use the same
callback for multiple modules.

Ray Tune comes with ready-to-use PyTorch Lightning callbacks. To report metrics
back to Tune after each validation epoch, we will use the ``TuneReportCallback``:

.. code-block:: python

    from ray.tune.integration.pytorch_lightning import TuneReportCallback
    callback = TuneReportCallback({
        "loss": "avg_val_loss",
        "mean_accuracy": "avg_val_accuracy"
    }, on="validation_end")

This callback will take the ``avg_val_loss`` and ``avg_val_accuracy`` values
from the PyTorch Lightning trainer and report them to Tune as the ``loss``
and ``mean_accuracy``, respectively.

Adding the Tune training function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Then we specify our training function. Note that we added the ``data_dir`` as a
parameter here to avoid
that each training run downloads the full MNIST dataset. Instead, we want to access
a shared data location.

We are also able to specify the number of epochs to train each model, and the number
of GPUs we want to use for training. We also create a TensorBoard logger that writes
logfiles directly into Tune's root trial directory - if we didn't do that PyTorch
Lightning would create subdirectories, and each trial would thus be shown twice in
TensorBoard, one time for Tune's logs, and another time for PyTorch Lightning's logs.

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_train_begin__
   :end-before: __tune_train_end__

Sharing the data
~~~~~~~~~~~~~~~~

All our trials are using the MNIST data. To avoid that each training instance downloads
their own MNIST dataset, we download it once and share the ``data_dir`` between runs.

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_asha_begin__
   :end-before: __tune_asha_end__
   :lines: 2-3
   :dedent: 4

We also delete this data after training to avoid filling up our disk or memory space.

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_asha_begin__
   :end-before: __tune_asha_end__
   :lines: 36
   :dedent: 4

Configuring the search space
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now we configure the parameter search space. We would like to choose between three
different layer and batch sizes. The learning rate should be sampled uniformly between
``0.0001`` and ``0.1``. The ``tune.loguniform()`` function is syntactic sugar to make
sampling between these different orders of magnitude easier, specifically
we are able to also sample small values.

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_asha_begin__
   :end-before: __tune_asha_end__
   :lines: 5-10
   :dedent: 4

Selecting a scheduler
~~~~~~~~~~~~~~~~~~~~~

In this example, we use an `Asynchronous Hyperband <https://blog.ml.cmu.edu/2018/12/12/massively-parallel-hyperparameter-optimization/>`_
scheduler. This scheduler decides at each iteration which trials are likely to perform
badly, and stops these trials. This way we don't waste any resources on bad hyperparameter
configurations.

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_asha_begin__
   :end-before: __tune_asha_end__
   :lines: 12-17
   :dedent: 4

Changing the CLI output
~~~~~~~~~~~~~~~~~~~~~~~

We instantiate a ``CLIReporter`` to specify which metrics we would like to see in our
output tables in the command line. This is optional, but can be used to make sure our
output tables only include information we would like to see.

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_asha_begin__
   :end-before: __tune_asha_end__
   :lines: 19-21
   :dedent: 4

Passing constants to the train function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``data_dir``, ``num_epochs`` and ``num_gpus`` we pass to the training function
are constants. To avoid including them as non-configurable parameters in the ``config``
specification, we can use ``functools.partial`` to wrap around the training function.

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_asha_begin__
   :end-before: __tune_asha_end__
   :lines: 24-28
   :dedent: 8

Training with GPUs
~~~~~~~~~~~~~~~~~~
We can specify how many resources Tune should request for each trial.
This also includes GPUs.

PyTorch Lightning takes care of moving the training to the GPUs. We
already made sure that our code is compatible with that, so there's
nothing more to do here other than to specify the number of GPUs
we would like to use:

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_asha_begin__
   :end-before: __tune_asha_end__
   :lines: 29
   :dedent: 4

Please note that in the current state of PyTorch Lightning, training
on :doc:`fractional GPUs </using-ray-with-gpus>` or
multiple GPUs requires some workarounds. We will address these in a
separate tutorial - for now this example works with no or exactly one
GPU.

Putting it together
~~~~~~~~~~~~~~~~~~~

Lastly, we need to start Tune with ``tune.run()``.

The full code looks like this:

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_asha_begin__
   :end-before: __tune_asha_end__

In the example above, Tune runs 10 trials with different hyperparameter configurations.
An example output could look like so:

.. code-block:: bash
  :emphasize-lines: 12

    +------------------------------+------------+-------+----------------+----------------+-------------+--------------+----------+-----------------+----------------------+
    | Trial name                   | status     | loc   |   layer_1_size |   layer_2_size |          lr |   batch_size |     loss |   mean_accuracy |   training_iteration |
    |------------------------------+------------+-------+----------------+----------------+-------------+--------------+----------+-----------------+----------------------|
    | train_mnist_tune_63ecc_00000 | TERMINATED |       |            128 |             64 | 0.00121197  |          128 | 0.120173 |       0.972461  |                   10 |
    | train_mnist_tune_63ecc_00001 | TERMINATED |       |             64 |            128 | 0.0301395   |          128 | 0.454836 |       0.868164  |                    4 |
    | train_mnist_tune_63ecc_00002 | TERMINATED |       |             64 |            128 | 0.0432097   |          128 | 0.718396 |       0.718359  |                    1 |
    | train_mnist_tune_63ecc_00003 | TERMINATED |       |             32 |            128 | 0.000294669 |           32 | 0.111475 |       0.965764  |                   10 |
    | train_mnist_tune_63ecc_00004 | TERMINATED |       |             32 |            256 | 0.000386664 |           64 | 0.133538 |       0.960839  |                    8 |
    | train_mnist_tune_63ecc_00005 | TERMINATED |       |            128 |            128 | 0.0837395   |           32 | 2.32628  |       0.0991242 |                    1 |
    | train_mnist_tune_63ecc_00006 | TERMINATED |       |             64 |            128 | 0.000158761 |          128 | 0.134595 |       0.959766  |                   10 |
    | train_mnist_tune_63ecc_00007 | TERMINATED |       |             64 |             64 | 0.000672126 |           64 | 0.118182 |       0.972903  |                   10 |
    | train_mnist_tune_63ecc_00008 | TERMINATED |       |            128 |             64 | 0.000502428 |           32 | 0.11082  |       0.975518  |                   10 |
    | train_mnist_tune_63ecc_00009 | TERMINATED |       |             64 |            256 | 0.00112894  |           32 | 0.13472  |       0.971935  |                    8 |
    +------------------------------+------------+-------+----------------+----------------+-------------+--------------+----------+-----------------+----------------------+

As you can see in the ``training_iteration`` column, trials with a high loss
(and low accuracy) have been terminated early. The best performing trial used
``layer_1_size=128``, ``layer_2_size=64``, ``lr=0.000502428`` and
``batch_size=32``.

Using Population Based Training to find the best parameters
-----------------------------------------------------------
The ``ASHAScheduler`` terminates those trials early that show bad performance.
Sometimes, this stops trials that would get better after more training steps,
and which might eventually even show better performance than other configurations.

Another popular method for hyperparameter tuning, called
`Population Based Training <https://deepmind.com/blog/article/population-based-training-neural-networks>`_,
instead perturbs hyperparameters during the training run. Tune implements PBT, and
we only need to make some slight adjustments to our code.

Adding checkpoints to the PyTorch Lightning module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

First, we need to introduce
another callback to save model checkpoints. Since Tune requires a call to
``tune.report()`` after creating a new checkpoint to register it, we will use
a combined reporting and checkpointing callback:

.. code-block:: python

    from ray.tune.integration.pytorch_lightning import TuneReportCheckpointCallback
    callback = TuneReportCheckpointCallback(
        metrics={"loss": "val_loss", "mean_accuracy": "val_accuracy"},
        filename="checkpoint",
        on="validation_end")

The ``checkpoint`` value is the name of the checkpoint file within the
checkpoint directory.

We also include checkpoint loading in our training function:

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_train_checkpoint_begin__
   :end-before: __tune_train_checkpoint_end__

Configuring and running Population Based Training
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

We need to call Tune slightly differently:

.. literalinclude:: /../../python/ray/tune/examples/mnist_pytorch_lightning.py
   :language: python
   :start-after: __tune_pbt_begin__
   :end-before: __tune_pbt_end__

Instead of passing tune parameters to the ``config`` dict, we start
with fixed values, though we are also able to sample some of them, like the
layer sizes. Additionally, we have to tell PBT how to perturb the hyperparameters.
Note that the layer sizes are not tuned right here. This is because we cannot simply
change layer sizes during a training run - which is what would happen in PBT.

An example output could look like this:

.. code-block:: bash

    +-----------------------------------------+------------+-------+----------------+----------------+-----------+--------------+-----------+-----------------+----------------------+
    | Trial name                              | status     | loc   |   layer_1_size |   layer_2_size |        lr |   batch_size |      loss |   mean_accuracy |   training_iteration |
    |-----------------------------------------+------------+-------+----------------+----------------+-----------+--------------+-----------+-----------------+----------------------|
    | train_mnist_tune_checkpoint_85489_00000 | TERMINATED |       |            128 |            128 | 0.001     |           64 | 0.108734  |        0.973101 |                   10 |
    | train_mnist_tune_checkpoint_85489_00001 | TERMINATED |       |            128 |            128 | 0.001     |           64 | 0.093577  |        0.978639 |                   10 |
    | train_mnist_tune_checkpoint_85489_00002 | TERMINATED |       |            128 |            256 | 0.0008    |           32 | 0.0922348 |        0.979299 |                   10 |
    | train_mnist_tune_checkpoint_85489_00003 | TERMINATED |       |             64 |            256 | 0.001     |           64 | 0.124648  |        0.973892 |                   10 |
    | train_mnist_tune_checkpoint_85489_00004 | TERMINATED |       |            128 |             64 | 0.001     |           64 | 0.101717  |        0.975079 |                   10 |
    | train_mnist_tune_checkpoint_85489_00005 | TERMINATED |       |             64 |             64 | 0.001     |           64 | 0.121467  |        0.969146 |                   10 |
    | train_mnist_tune_checkpoint_85489_00006 | TERMINATED |       |            128 |            256 | 0.00064   |           32 | 0.053446  |        0.987062 |                   10 |
    | train_mnist_tune_checkpoint_85489_00007 | TERMINATED |       |            128 |            256 | 0.001     |           64 | 0.129804  |        0.973497 |                   10 |
    | train_mnist_tune_checkpoint_85489_00008 | TERMINATED |       |             64 |            256 | 0.0285125 |          128 | 0.363236  |        0.913867 |                   10 |
    | train_mnist_tune_checkpoint_85489_00009 | TERMINATED |       |             32 |            256 | 0.001     |           64 | 0.150946  |        0.964201 |                   10 |
    +-----------------------------------------+------------+-------+----------------+----------------+-----------+--------------+-----------+-----------------+----------------------+

As you can see, each sample ran the full number of 10 iterations.
All trials ended with quite good parameter combinations and showed relatively good performances.
In some runs, the parameters have been perturbed. And the best configuration even reached a
mean validation accuracy of ``0.987062``!

In summary, PyTorch Lightning Modules are easy to extend to use with Tune. It just took
us importing one or two callbacks and a small wrapper function to get great performing
parameter configurations.


text:
// The MIT License (MIT)
//
// Copyright (c) 2017 Smart&Soft
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package com.smartnsoft.droid4me.widget;

import android.view.View;

/**
 * A simple interface method will be invoked every time its underlying {@link View view} size {@link View#onSizeChanged(int, int, int, int)} changes}.
 *

 *

 * It Enables to capture the event when the widget size changes.
 *

 *
 * @param <ViewClass> the {@link View view} the size change listener applies to
 * @author Édouard Mercier
 * @since 2011.04.01
 */
public interface OnSizeChangedListener<ViewClass extends View>
{

  /**
   * Triggered when the widget view size has changed, and in particular when it is known for the first time.
   *
   * @param widget    the view related to that event
   * @param newWidth  the new width
   * @param newHeight the new height
   * @param oldWidth  the old width
   * @param oldHeight the old height
   */
  void onSizeChanged(ViewClass widget, int newWidth, int newHeight, int oldWidth, int oldHeight);

}


text:
module Network.DHT.Native.Util where

import           Control.Monad.Codensity
import           Foreign.C.Types (CInt)
import qualified Foreign.Marshal.Alloc as P
import qualified Foreign.Ptr as P
import qualified Foreign.Storable as P

afIPv4, afIPv6 :: CInt
afIPv4 = 2
afIPv6 = 10

alloca :: (P.Storable a) => Codensity IO (P.Ptr a)
alloca = Codensity P.alloca


text:
#include "postgres.h"

#include <math.h>

#include "fmgr.h"
#include "funcapi.h"
#include "executor/spi.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"

#include "tablefunc.h"

PG_MODULE_MAGIC;

static HTAB *load_categories_hash(char *cats_sql, MemoryContext per_query_ctx);
static Tuplestorestate *get_crosstab_tuplestore(char *sql,
						HTAB *crosstab_hash,
						TupleDesc tupdesc,
						MemoryContext per_query_ctx);
static void validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial);
static bool compatCrosstabTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
static bool compatConnectbyTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
static void get_normal_pair(float8 *x1, float8 *x2);
static Tuplestorestate *connectby(char *relname,
		  char *key_fld,
		  char *parent_key_fld,
		  char *orderby_fld,
		  char *branch_delim,
		  char *start_with,
		  int max_depth,
		  bool show_branch,
		  bool show_serial,
		  MemoryContext per_query_ctx,
		  AttInMetadata *attinmeta);
static Tuplestorestate *build_tuplestore_recursively(char *key_fld,
							 char *parent_key_fld,
							 char *relname,
							 char *orderby_fld,
							 char *branch_delim,
							 char *start_with,
							 char *branch,
							 int level,
							 int *serial,
							 int max_depth,
							 bool show_branch,
							 bool show_serial,
							 MemoryContext per_query_ctx,
							 AttInMetadata *attinmeta,
							 Tuplestorestate *tupstore);
static char *quote_literal_cstr(char *rawstr);

typedef struct
{
	float8		mean;			/* mean of the distribution */
	float8		stddev;			/* stddev of the distribution */
	float8		carry_val;		/* hold second generated value */
	bool		use_carry;		/* use second generated value */
}	normal_rand_fctx;

typedef struct
{
	SPITupleTable *spi_tuptable;	/* sql results from user query */
	char	   *lastrowid;		/* rowid of the last tuple sent */
}	crosstab_fctx;

#define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
#define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
#define xpfree(var_) \
	do { \
		if (var_ != NULL) \
		{ \
			pfree(var_); \
			var_ = NULL; \
		} \
	} while (0)

#define xpstrdup(tgtvar_, srcvar_) \
	do { \
		if (srcvar_) \
			tgtvar_ = pstrdup(srcvar_); \
		else \
			tgtvar_ = NULL; \
	} while (0)

#define xstreq(tgtvar_, srcvar_) \
	(((tgtvar_ == NULL) && (srcvar_ == NULL)) || \
	 ((tgtvar_ != NULL) && (srcvar_ != NULL) && (strcmp(tgtvar_, srcvar_) == 0)))

/* sign, 10 digits, '\0' */
#define INT32_STRLEN	12

/* stored info for a crosstab category */
typedef struct crosstab_cat_desc
{
	char	   *catname;		/* full category name */
	int			attidx;			/* zero based */
}	crosstab_cat_desc;

#define MAX_CATNAME_LEN			NAMEDATALEN
#define INIT_CATS				64

#define crosstab_HashTableLookup(HASHTAB, CATNAME, CATDESC) \
do { \
	crosstab_HashEnt *hentry; char key[MAX_CATNAME_LEN]; \
	\
	MemSet(key, 0, MAX_CATNAME_LEN); \
	snprintf(key, MAX_CATNAME_LEN - 1, "%s", CATNAME); \
	hentry = (crosstab_HashEnt*) hash_search(HASHTAB, \
										 key, HASH_FIND, NULL); \
	if (hentry) \
		CATDESC = hentry->catdesc; \
	else \
		CATDESC = NULL; \
} while(0)

#define crosstab_HashTableInsert(HASHTAB, CATDESC) \
do { \
	crosstab_HashEnt *hentry; bool found; char key[MAX_CATNAME_LEN]; \
	\
	MemSet(key, 0, MAX_CATNAME_LEN); \
	snprintf(key, MAX_CATNAME_LEN - 1, "%s", CATDESC->catname); \
	hentry = (crosstab_HashEnt*) hash_search(HASHTAB, \
										 key, HASH_ENTER, &found); \
	if (found) \
		ereport(ERROR, \
				(errcode(ERRCODE_DUPLICATE_OBJECT), \
				 errmsg("duplicate category name"))); \
	hentry->catdesc = CATDESC; \
} while(0)

/* hash table */
typedef struct crosstab_hashent
{
	char		internal_catname[MAX_CATNAME_LEN];
	crosstab_cat_desc *catdesc;
}	crosstab_HashEnt;

/*
 * normal_rand - return requested number of random values
 * with a Gaussian (Normal) distribution.
 *
 * inputs are int numvals, float8 mean, and float8 stddev
 * returns setof float8
 */
PG_FUNCTION_INFO_V1(normal_rand);
Datum
normal_rand(PG_FUNCTION_ARGS)
{
	FuncCallContext *funcctx;
	int			call_cntr;
	int			max_calls;
	normal_rand_fctx *fctx;
	float8		mean;
	float8		stddev;
	float8		carry_val;
	bool		use_carry;
	MemoryContext oldcontext;

	/* stuff done only on the first call of the function */
	if (SRF_IS_FIRSTCALL())
	{
		/* create a function context for cross-call persistence */
		funcctx = SRF_FIRSTCALL_INIT();

		/*
		 * switch to memory context appropriate for multiple function calls
		 */
		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

		/* total number of tuples to be returned */
		funcctx->max_calls = PG_GETARG_UINT32(0);

		/* allocate memory for user context */
		fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx));

		/*
		 * Use fctx to keep track of upper and lower bounds from call to call.
		 * It will also be used to carry over the spare value we get from the
		 * Box-Muller algorithm so that we only actually calculate a new value
		 * every other call.
		 */
		fctx->mean = PG_GETARG_FLOAT8(1);
		fctx->stddev = PG_GETARG_FLOAT8(2);
		fctx->carry_val = 0;
		fctx->use_carry = false;

		funcctx->user_fctx = fctx;

		MemoryContextSwitchTo(oldcontext);
	}

	/* stuff done on every call of the function */
	funcctx = SRF_PERCALL_SETUP();

	call_cntr = funcctx->call_cntr;
	max_calls = funcctx->max_calls;
	fctx = funcctx->user_fctx;
	mean = fctx->mean;
	stddev = fctx->stddev;
	carry_val = fctx->carry_val;
	use_carry = fctx->use_carry;

	if (call_cntr < max_calls)	/* do when there is more left to send */
	{
		float8		result;

		if (use_carry)
		{
			/*
			 * reset use_carry and use second value obtained on last pass
			 */
			fctx->use_carry = false;
			result = carry_val;
		}
		else
		{
			float8		normval_1;
			float8		normval_2;

			/* Get the next two normal values */
			get_normal_pair(&normval_1, &normval_2);

			/* use the first */
			result = mean + (stddev * normval_1);

			/* and save the second */
			fctx->carry_val = mean + (stddev * normval_2);
			fctx->use_carry = true;
		}

		/* send the result */
		SRF_RETURN_NEXT(funcctx, Float8GetDatum(result));
	}
	else
		/* do when there is no more left */
		SRF_RETURN_DONE(funcctx);
}

/*
 * get_normal_pair()
 * Assigns normally distributed (Gaussian) values to a pair of provided
 * parameters, with mean 0, standard deviation 1.
 *
 * This routine implements Algorithm P (Polar method for normal deviates)
 * from Knuth's _The_Art_of_Computer_Programming_, Volume 2, 3rd ed., pages
 * 122-126. Knuth cites his source as "The polar method", G. E. P. Box, M. E.
 * Muller, and G. Marsaglia, _Annals_Math,_Stat._ 29 (1958), 610-611.
 *
 */
static void
get_normal_pair(float8 *x1, float8 *x2)
{
	float8		u1,
				u2,
				v1,
				v2,
				s;

	do
	{
		u1 = (float8) random() / (float8) MAX_RANDOM_VALUE;
		u2 = (float8) random() / (float8) MAX_RANDOM_VALUE;

		v1 = (2.0 * u1) - 1.0;
		v2 = (2.0 * u2) - 1.0;

		s = v1 * v1 + v2 * v2;
	} while (s >= 1.0);

	if (s == 0)
	{
		*x1 = 0;
		*x2 = 0;
	}
	else
	{
		s = sqrt((-2.0 * log(s)) / s);
		*x1 = v1 * s;
		*x2 = v2 * s;
	}
}

/*
 * crosstab - create a crosstab of rowids and values columns from a
 * SQL statement returning one rowid column, one category column,
 * and one value column.
 *
 * e.g. given sql which produces:
 *
 *			rowid	cat		value
 *			------+-------+-------
 *			row1	cat1	val1
 *			row1	cat2	val2
 *			row1	cat3	val3
 *			row1	cat4	val4
 *			row2	cat1	val5
 *			row2	cat2	val6
 *			row2	cat3	val7
 *			row2	cat4	val8
 *
 * crosstab returns:
 *					<===== values columns =====>
 *			rowid	cat1	cat2	cat3	cat4
 *			------+-------+-------+-------+-------
 *			row1	val1	val2	val3	val4
 *			row2	val5	val6	val7	val8
 *
 * NOTES:
 * 1. SQL result must be ordered by 1,2.
 * 2. The number of values columns depends on the tuple description
 *	  of the function's declared return type.  The return type's columns
 *	  must match the datatypes of the SQL query's result.  The datatype
 *	  of the category column can be anything, however.
 * 3. Missing values (i.e. not enough adjacent rows of same rowid to
 *	  fill the number of result values columns) are filled in with nulls.
 * 4. Extra values (i.e. too many adjacent rows of same rowid to fill
 *	  the number of result values columns) are skipped.
 * 5. Rows with all nulls in the values columns are skipped.
 */
PG_FUNCTION_INFO_V1(crosstab);
Datum
crosstab(PG_FUNCTION_ARGS)
{
	FuncCallContext *funcctx;
	TupleDesc	ret_tupdesc;
	int			call_cntr;
	int			max_calls;
	AttInMetadata *attinmeta;
	SPITupleTable *spi_tuptable = NULL;
	TupleDesc	spi_tupdesc;
	char	   *lastrowid = NULL;
	crosstab_fctx *fctx;
	int			i;
	int			num_categories;
	bool		firstpass = false;
	MemoryContext oldcontext;

	/* stuff done only on the first call of the function */
	if (SRF_IS_FIRSTCALL())
	{
		char	   *sql = GET_STR(PG_GETARG_TEXT_P(0));
		TupleDesc	tupdesc;
		int			ret;
		int			proc;

		/* create a function context for cross-call persistence */
		funcctx = SRF_FIRSTCALL_INIT();

		/* Connect to SPI manager */
		if ((ret = SPI_connect()) < 0)
			/* internal error */
			elog(ERROR, "crosstab: SPI_connect returned %d", ret);

		/* Retrieve the desired rows */
		ret = SPI_execute(sql, true, 0);
		proc = SPI_processed;

		/* Check for qualifying tuples */
		if ((ret == SPI_OK_SELECT) && (proc > 0))
		{
			spi_tuptable = SPI_tuptable;
			spi_tupdesc = spi_tuptable->tupdesc;

			/*----------
			 * The provided SQL query must always return three columns.
			 *
			 * 1. rowname
			 *	the label or identifier for each row in the final result
			 * 2. category
			 *	the label or identifier for each column in the final result
			 * 3. values
			 *	the value for each column in the final result
			 *----------
			 */
			if (spi_tupdesc->natts != 3)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
						 errmsg("invalid source data SQL statement"),
						 errdetail("The provided SQL must return 3 "
								   "columns: rowid, category, and values.")));
		}
		else
		{
			/* no qualifying tuples */
			SPI_finish();
			SRF_RETURN_DONE(funcctx);
		}

		/* get a tuple descriptor for our result type */
		switch (get_call_result_type(fcinfo, NULL, &tupdesc))
		{
			case TYPEFUNC_COMPOSITE:
				/* success */
				break;
			case TYPEFUNC_RECORD:
				/* failed to determine actual type of RECORD */
				ereport(ERROR,
						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
						 errmsg("function returning record called in context "
								"that cannot accept type record")));
				break;
			default:
				/* result type isn't composite */
				elog(ERROR, "return type must be a row type");
				break;
		}

		/*
		 * Check that return tupdesc is compatible with the data we got from
		 * SPI, at least based on number and type of attributes
		 */
		if (!compatCrosstabTupleDescs(tupdesc, spi_tupdesc))
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("return and sql tuple descriptions are " \
							"incompatible")));

		/*
		 * switch to memory context appropriate for multiple function calls
		 */
		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

		/* make sure we have a persistent copy of the tupdesc */
		tupdesc = CreateTupleDescCopy(tupdesc);

		/*
		 * Generate attribute metadata needed later to produce tuples from raw
		 * C strings
		 */
		attinmeta = TupleDescGetAttInMetadata(tupdesc);
		funcctx->attinmeta = attinmeta;

		/* allocate memory for user context */
		fctx = (crosstab_fctx *) palloc(sizeof(crosstab_fctx));

		/*
		 * Save spi data for use across calls
		 */
		fctx->spi_tuptable = spi_tuptable;
		fctx->lastrowid = NULL;
		funcctx->user_fctx = fctx;

		/* total number of tuples to be returned */
		funcctx->max_calls = proc;

		MemoryContextSwitchTo(oldcontext);
		firstpass = true;
	}

	/* stuff done on every call of the function */
	funcctx = SRF_PERCALL_SETUP();

	/*
	 * initialize per-call variables
	 */
	call_cntr = funcctx->call_cntr;
	max_calls = funcctx->max_calls;

	/* user context info */
	fctx = (crosstab_fctx *) funcctx->user_fctx;
	lastrowid = fctx->lastrowid;
	spi_tuptable = fctx->spi_tuptable;

	/* the sql tuple */
	spi_tupdesc = spi_tuptable->tupdesc;

	/* attribute return type and return tuple description */
	attinmeta = funcctx->attinmeta;
	ret_tupdesc = attinmeta->tupdesc;

	/* the return tuple always must have 1 rowid + num_categories columns */
	num_categories = ret_tupdesc->natts - 1;

	if (call_cntr < max_calls)	/* do when there is more left to send */
	{
		HeapTuple	tuple;
		Datum		result;
		char	  **values;
		bool		skip_tuple = false;

		while (true)
		{
			/* allocate space */
			values = (char **) palloc((1 + num_categories) * sizeof(char *));

			/* and make sure it's clear */
			memset(values, '\0', (1 + num_categories) * sizeof(char *));

			/*
			 * now loop through the sql results and assign each value in
			 * sequence to the next category
			 */
			for (i = 0; i < num_categories; i++)
			{
				HeapTuple	spi_tuple;
				char	   *rowid = NULL;

				/* see if we've gone too far already */
				if (call_cntr >= max_calls)
					break;

				/* get the next sql result tuple */
				spi_tuple = spi_tuptable->vals[call_cntr];

				/* get the rowid from the current sql result tuple */
				rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);

				/*
				 * If this is the first pass through the values for this
				 * rowid, set the first column to rowid
				 */
				if (i == 0)
				{
					xpstrdup(values[0], rowid);

					/*
					 * Check to see if the rowid is the same as that of the
					 * last tuple sent -- if so, skip this tuple entirely
					 */
					if (!firstpass && xstreq(lastrowid, rowid))
					{
						skip_tuple = true;
						break;
					}
				}

				/*
				 * If rowid hasn't changed on us, continue building the ouput
				 * tuple.
				 */
				if (xstreq(rowid, values[0]))
				{
					/*
					 * Get the next category item value, which is always
					 * attribute number three.
					 *
					 * Be careful to assign the value to the array index based
					 * on which category we are presently processing.
					 */
					values[1 + i] = SPI_getvalue(spi_tuple, spi_tupdesc, 3);

					/*
					 * increment the counter since we consume a row for each
					 * category, but not for last pass because the API will do
					 * that for us
					 */
					if (i < (num_categories - 1))
						call_cntr = ++funcctx->call_cntr;
				}
				else
				{
					/*
					 * We'll fill in NULLs for the missing values, but we need
					 * to decrement the counter since this sql result row
					 * doesn't belong to the current output tuple.
					 */
					call_cntr = --funcctx->call_cntr;
					break;
				}
				xpfree(rowid);
			}

			/*
			 * switch to memory context appropriate for multiple function
			 * calls
			 */
			oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

			xpfree(fctx->lastrowid);
			xpstrdup(fctx->lastrowid, values[0]);
			lastrowid = fctx->lastrowid;

			MemoryContextSwitchTo(oldcontext);

			if (!skip_tuple)
			{
				/* build the tuple */
				tuple = BuildTupleFromCStrings(attinmeta, values);

				/* make the tuple into a datum */
				result = HeapTupleGetDatum(tuple);

				/* Clean up */
				for (i = 0; i < num_categories + 1; i++)
					if (values[i] != NULL)
						xpfree(values[i]);
				xpfree(values);

				SRF_RETURN_NEXT(funcctx, result);
			}
			else
			{
				/*
				 * Skipping this tuple entirely, but we need to advance the
				 * counter like the API would if we had returned one.
				 */
				call_cntr = ++funcctx->call_cntr;

				/* we'll start over at the top */
				xpfree(values);

				/* see if we've gone too far already */
				if (call_cntr >= max_calls)
				{
					/* release SPI related resources */
					SPI_finish();
					SRF_RETURN_DONE(funcctx);
				}

				/* need to reset this before the next tuple is started */
				skip_tuple = false;
			}
		}
	}
	else
		/* do when there is no more left */
	{
		/* release SPI related resources */
		SPI_finish();
		SRF_RETURN_DONE(funcctx);
	}
}

/*
 * crosstab_hash - reimplement crosstab as materialized function and
 * properly deal with missing values (i.e. don't pack remaining
 * values to the left)
 *
 * crosstab - create a crosstab of rowids and values columns from a
 * SQL statement returning one rowid column, one category column,
 * and one value column.
 *
 * e.g. given sql which produces:
 *
 *			rowid	cat		value
 *			------+-------+-------
 *			row1	cat1	val1
 *			row1	cat2	val2
 *			row1	cat4	val4
 *			row2	cat1	val5
 *			row2	cat2	val6
 *			row2	cat3	val7
 *			row2	cat4	val8
 *
 * crosstab returns:
 *					<===== values columns =====>
 *			rowid	cat1	cat2	cat3	cat4
 *			------+-------+-------+-------+-------
 *			row1	val1	val2	null	val4
 *			row2	val5	val6	val7	val8
 *
 * NOTES:
 * 1. SQL result must be ordered by 1.
 * 2. The number of values columns depends on the tuple description
 *	  of the function's declared return type.
 * 3. Missing values (i.e. missing category) are filled in with nulls.
 * 4. Extra values (i.e. not in category results) are skipped.
 */
PG_FUNCTION_INFO_V1(crosstab_hash);
Datum
crosstab_hash(PG_FUNCTION_ARGS)
{
	char	   *sql = GET_STR(PG_GETARG_TEXT_P(0));
	char	   *cats_sql = GET_STR(PG_GETARG_TEXT_P(1));
	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
	TupleDesc	tupdesc;
	MemoryContext per_query_ctx;
	MemoryContext oldcontext;
	HTAB	   *crosstab_hash;

	/* check to see if caller supports us returning a tuplestore */
	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("set-valued function called in context that cannot accept a set")));
	if (!(rsinfo->allowedModes & SFRM_Materialize))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("materialize mode required, but it is not " \
						"allowed in this context")));

	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
	oldcontext = MemoryContextSwitchTo(per_query_ctx);

	/* get the requested return tuple description */
	tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);

	/*
	 * Check to make sure we have a reasonable tuple descriptor
	 *
	 * Note we will attempt to coerce the values into whatever the return
	 * attribute type is and depend on the "in" function to complain if
	 * needed.
	 */
	if (tupdesc->natts < 2)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("query-specified return tuple and " \
						"crosstab function are not compatible")));

	/* load up the categories hash table */
	crosstab_hash = load_categories_hash(cats_sql, per_query_ctx);

	/* let the caller know we're sending back a tuplestore */
	rsinfo->returnMode = SFRM_Materialize;

	/* now go build it */
	rsinfo->setResult = get_crosstab_tuplestore(sql,
												crosstab_hash,
												tupdesc,
												per_query_ctx);

	/*
	 * SFRM_Materialize mode expects us to return a NULL Datum. The actual
	 * tuples are in our tuplestore and passed back through rsinfo->setResult.
	 * rsinfo->setDesc is set to the tuple description that we actually used
	 * to build our tuples with, so the caller can verify we did what it was
	 * expecting.
	 */
	rsinfo->setDesc = tupdesc;
	MemoryContextSwitchTo(oldcontext);

	return (Datum) 0;
}

/*
 * load up the categories hash table
 */
static HTAB *
load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
{
	HTAB	   *crosstab_hash;
	HASHCTL		ctl;
	int			ret;
	int			proc;
	MemoryContext SPIcontext;

	/* initialize the category hash table */
	MemSet(&ctl, 0, sizeof(ctl));
	ctl.keysize = MAX_CATNAME_LEN;
	ctl.entrysize = sizeof(crosstab_HashEnt);
	ctl.hcxt = per_query_ctx;

	/*
	 * use INIT_CATS, defined above as a guess of how many hash table entries
	 * to create, initially
	 */
	crosstab_hash = hash_create("crosstab hash",
								INIT_CATS,
								&ctl,
								HASH_ELEM | HASH_CONTEXT);

	/* Connect to SPI manager */
	if ((ret = SPI_connect()) < 0)
		/* internal error */
		elog(ERROR, "load_categories_hash: SPI_connect returned %d", ret);

	/* Retrieve the category name rows */
	ret = SPI_execute(cats_sql, true, 0);
	proc = SPI_processed;

	/* Check for qualifying tuples */
	if ((ret == SPI_OK_SELECT) && (proc > 0))
	{
		SPITupleTable *spi_tuptable = SPI_tuptable;
		TupleDesc	spi_tupdesc = spi_tuptable->tupdesc;
		int			i;

		/*
		 * The provided categories SQL query must always return one column:
		 * category - the label or identifier for each column
		 */
		if (spi_tupdesc->natts != 1)
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("provided \"categories\" SQL must " \
							"return 1 column of at least one row")));

		for (i = 0; i < proc; i++)
		{
			crosstab_cat_desc *catdesc;
			char	   *catname;
			HeapTuple	spi_tuple;

			/* get the next sql result tuple */
			spi_tuple = spi_tuptable->vals[i];

			/* get the category from the current sql result tuple */
			catname = SPI_getvalue(spi_tuple, spi_tupdesc, 1);

			SPIcontext = MemoryContextSwitchTo(per_query_ctx);

			catdesc = (crosstab_cat_desc *) palloc(sizeof(crosstab_cat_desc));
			catdesc->catname = catname;
			catdesc->attidx = i;

			/* Add the proc description block to the hashtable */
			crosstab_HashTableInsert(crosstab_hash, catdesc);

			MemoryContextSwitchTo(SPIcontext);
		}
	}

	if (SPI_finish() != SPI_OK_FINISH)
		/* internal error */
		elog(ERROR, "load_categories_hash: SPI_finish() failed");

	return crosstab_hash;
}

/*
 * create and populate the crosstab tuplestore using the provided source query
 */
static Tuplestorestate *
get_crosstab_tuplestore(char *sql,
						HTAB *crosstab_hash,
						TupleDesc tupdesc,
						MemoryContext per_query_ctx)
{
	Tuplestorestate *tupstore;
	int			num_categories = hash_get_num_entries(crosstab_hash);
	AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tupdesc);
	char	  **values;
	HeapTuple	tuple;
	int			ret;
	int			proc;
	MemoryContext SPIcontext;

	/* initialize our tuplestore */
	tupstore = tuplestore_begin_heap(true, false, work_mem);

	/* Connect to SPI manager */
	if ((ret = SPI_connect()) < 0)
		/* internal error */
		elog(ERROR, "get_crosstab_tuplestore: SPI_connect returned %d", ret);

	/* Now retrieve the crosstab source rows */
	ret = SPI_execute(sql, true, 0);
	proc = SPI_processed;

	/* Check for qualifying tuples */
	if ((ret == SPI_OK_SELECT) && (proc > 0))
	{
		SPITupleTable *spi_tuptable = SPI_tuptable;
		TupleDesc	spi_tupdesc = spi_tuptable->tupdesc;
		int			ncols = spi_tupdesc->natts;
		char	   *rowid;
		char	   *lastrowid = NULL;
		bool		firstpass = true;
		int			i,
					j;
		int			result_ncols;

		if (num_categories == 0)
		{
			/* no qualifying category tuples */
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("provided \"categories\" SQL must " \
							"return 1 column of at least one row")));
		}

		/*
		 * The provided SQL query must always return at least three columns:
		 *
		 * 1. rowname	the label for each row - column 1 in the final result
		 * 2. category	the label for each value-column in the final result 3.
		 * value	 the values used to populate the value-columns
		 *
		 * If there are more than three columns, the last two are taken as
		 * "category" and "values". The first column is taken as "rowname".
		 * Additional columns (2 thru N-2) are assumed the same for the same
		 * "rowname", and are copied into the result tuple from the first time
		 * we encounter a particular rowname.
		 */
		if (ncols < 3)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
					 errmsg("invalid source data SQL statement"),
					 errdetail("The provided SQL must return 3 " \
							   " columns; rowid, category, and values.")));

		result_ncols = (ncols - 2) + num_categories;

		/* Recheck to make sure we tuple descriptor still looks reasonable */
		if (tupdesc->natts != result_ncols)
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("invalid return type"),
					 errdetail("Query-specified return " \
							   "tuple has %d columns but crosstab " \
							   "returns %d.", tupdesc->natts, result_ncols)));

		/* allocate space */
		values = (char **) palloc(result_ncols * sizeof(char *));

		/* and make sure it's clear */
		memset(values, '\0', result_ncols * sizeof(char *));

		for (i = 0; i < proc; i++)
		{
			HeapTuple	spi_tuple;
			crosstab_cat_desc *catdesc;
			char	   *catname;

			/* get the next sql result tuple */
			spi_tuple = spi_tuptable->vals[i];

			/* get the rowid from the current sql result tuple */
			rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);

			/*
			 * if we're on a new output row, grab the column values up to
			 * column N-2 now
			 */
			if (firstpass || !xstreq(lastrowid, rowid))
			{
				/*
				 * a new row means we need to flush the old one first, unless
				 * we're on the very first row
				 */
				if (!firstpass)
				{
					/* rowid changed, flush the previous output row */
					tuple = BuildTupleFromCStrings(attinmeta, values);

					/* switch to appropriate context while storing the tuple */
					SPIcontext = MemoryContextSwitchTo(per_query_ctx);
					tuplestore_puttuple(tupstore, tuple);
					MemoryContextSwitchTo(SPIcontext);

					for (j = 0; j < result_ncols; j++)
						xpfree(values[j]);
				}

				values[0] = rowid;
				for (j = 1; j < ncols - 2; j++)
					values[j] = SPI_getvalue(spi_tuple, spi_tupdesc, j + 1);

				/* we're no longer on the first pass */
				firstpass = false;
			}

			/* look up the category and fill in the appropriate column */
			catname = SPI_getvalue(spi_tuple, spi_tupdesc, ncols - 1);

			if (catname != NULL)
			{
				crosstab_HashTableLookup(crosstab_hash, catname, catdesc);

				if (catdesc)
					values[catdesc->attidx + ncols - 2] =
						SPI_getvalue(spi_tuple, spi_tupdesc, ncols);
			}

			xpfree(lastrowid);
			xpstrdup(lastrowid, rowid);
		}

		/* flush the last output row */
		tuple = BuildTupleFromCStrings(attinmeta, values);

		/* switch to appropriate context while storing the tuple */
		SPIcontext = MemoryContextSwitchTo(per_query_ctx);
		tuplestore_puttuple(tupstore, tuple);
		MemoryContextSwitchTo(SPIcontext);
	}

	if (SPI_finish() != SPI_OK_FINISH)
		/* internal error */
		elog(ERROR, "get_crosstab_tuplestore: SPI_finish() failed");

	tuplestore_donestoring(tupstore);

	return tupstore;
}

/*
 * connectby_text - produce a result set from a hierarchical (parent/child)
 * table.
 *
 * e.g. given table foo:
 *
 *			keyid	parent_keyid pos
 *			------+------------+--
 *			row1	NULL		 0
 *			row2	row1		 0
 *			row3	row1		 0
 *			row4	row2		 1
 *			row5	row2		 0
 *			row6	row4		 0
 *			row7	row3		 0
 *			row8	row6		 0
 *			row9	row5		 0
 *
 *
 * connectby(text relname, text keyid_fld, text parent_keyid_fld
 *			  [, text orderby_fld], text start_with, int max_depth
 *			  [, text branch_delim])
 * connectby('foo', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~') returns:
 *
 *		keyid	parent_id	level	 branch				serial
 *		------+-----------+--------+-----------------------
 *		row2	NULL		  0		  row2				  1
 *		row5	row2		  1		  row2~row5			  2
 *		row9	row5		  2		  row2~row5~row9	  3
 *		row4	row2		  1		  row2~row4			  4
 *		row6	row4		  2		  row2~row4~row6	  5
 *		row8	row6		  3		  row2~row4~row6~row8 6
 *
 */
PG_FUNCTION_INFO_V1(connectby_text);

#define CONNECTBY_NCOLS					4
#define CONNECTBY_NCOLS_NOBRANCH		3

Datum
connectby_text(PG_FUNCTION_ARGS)
{
	char	   *relname = GET_STR(PG_GETARG_TEXT_P(0));
	char	   *key_fld = GET_STR(PG_GETARG_TEXT_P(1));
	char	   *parent_key_fld = GET_STR(PG_GETARG_TEXT_P(2));
	char	   *start_with = GET_STR(PG_GETARG_TEXT_P(3));
	int			max_depth = PG_GETARG_INT32(4);
	char	   *branch_delim = NULL;
	bool		show_branch = false;
	bool		show_serial = false;
	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
	TupleDesc	tupdesc;
	AttInMetadata *attinmeta;
	MemoryContext per_query_ctx;
	MemoryContext oldcontext;

	/* check to see if caller supports us returning a tuplestore */
	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("set-valued function called in context that cannot accept a set")));
	if (!(rsinfo->allowedModes & SFRM_Materialize))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("materialize mode required, but it is not " \
						"allowed in this context")));

	if (fcinfo->nargs == 6)
	{
		branch_delim = GET_STR(PG_GETARG_TEXT_P(5));
		show_branch = true;
	}
	else
		/* default is no show, tilde for the delimiter */
		branch_delim = pstrdup("~");

	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
	oldcontext = MemoryContextSwitchTo(per_query_ctx);

	/* get the requested return tuple description */
	tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);

	/* does it meet our needs */
	validateConnectbyTupleDesc(tupdesc, show_branch, show_serial);

	/* OK, use it then */
	attinmeta = TupleDescGetAttInMetadata(tupdesc);

	/* OK, go to work */
	rsinfo->returnMode = SFRM_Materialize;
	rsinfo->setResult = connectby(relname,
								  key_fld,
								  parent_key_fld,
								  NULL,
								  branch_delim,
								  start_with,
								  max_depth,
								  show_branch,
								  show_serial,
								  per_query_ctx,
								  attinmeta);
	rsinfo->setDesc = tupdesc;

	MemoryContextSwitchTo(oldcontext);

	/*
	 * SFRM_Materialize mode expects us to return a NULL Datum. The actual
	 * tuples are in our tuplestore and passed back through rsinfo->setResult.
	 * rsinfo->setDesc is set to the tuple description that we actually used
	 * to build our tuples with, so the caller can verify we did what it was
	 * expecting.
	 */
	return (Datum) 0;
}

PG_FUNCTION_INFO_V1(connectby_text_serial);
Datum
connectby_text_serial(PG_FUNCTION_ARGS)
{
	char	   *relname = GET_STR(PG_GETARG_TEXT_P(0));
	char	   *key_fld = GET_STR(PG_GETARG_TEXT_P(1));
	char	   *parent_key_fld = GET_STR(PG_GETARG_TEXT_P(2));
	char	   *orderby_fld = GET_STR(PG_GETARG_TEXT_P(3));
	char	   *start_with = GET_STR(PG_GETARG_TEXT_P(4));
	int			max_depth = PG_GETARG_INT32(5);
	char	   *branch_delim = NULL;
	bool		show_branch = false;
	bool		show_serial = true;

	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
	TupleDesc	tupdesc;
	AttInMetadata *attinmeta;
	MemoryContext per_query_ctx;
	MemoryContext oldcontext;

	/* check to see if caller supports us returning a tuplestore */
	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("set-valued function called in context that cannot accept a set")));
	if (!(rsinfo->allowedModes & SFRM_Materialize))
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				 errmsg("materialize mode required, but it is not " \
						"allowed in this context")));

	if (fcinfo->nargs == 7)
	{
		branch_delim = GET_STR(PG_GETARG_TEXT_P(6));
		show_branch = true;
	}
	else
		/* default is no show, tilde for the delimiter */
		branch_delim = pstrdup("~");

	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
	oldcontext = MemoryContextSwitchTo(per_query_ctx);

	/* get the requested return tuple description */
	tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);

	/* does it meet our needs */
	validateConnectbyTupleDesc(tupdesc, show_branch, show_serial);

	/* OK, use it then */
	attinmeta = TupleDescGetAttInMetadata(tupdesc);

	/* OK, go to work */
	rsinfo->returnMode = SFRM_Materialize;
	rsinfo->setResult = connectby(relname,
								  key_fld,
								  parent_key_fld,
								  orderby_fld,
								  branch_delim,
								  start_with,
								  max_depth,
								  show_branch,
								  show_serial,
								  per_query_ctx,
								  attinmeta);
	rsinfo->setDesc = tupdesc;

	MemoryContextSwitchTo(oldcontext);

	/*
	 * SFRM_Materialize mode expects us to return a NULL Datum. The actual
	 * tuples are in our tuplestore and passed back through rsinfo->setResult.
	 * rsinfo->setDesc is set to the tuple description that we actually used
	 * to build our tuples with, so the caller can verify we did what it was
	 * expecting.
	 */
	return (Datum) 0;
}

/*
 * connectby - does the real work for connectby_text()
 */
static Tuplestorestate *
connectby(char *relname,
		  char *key_fld,
		  char *parent_key_fld,
		  char *orderby_fld,
		  char *branch_delim,
		  char *start_with,
		  int max_depth,
		  bool show_branch,
		  bool show_serial,
		  MemoryContext per_query_ctx,
		  AttInMetadata *attinmeta)
{
	Tuplestorestate *tupstore = NULL;
	int			ret;
	MemoryContext oldcontext;

	int			serial = 1;

	/* Connect to SPI manager */
	if ((ret = SPI_connect()) < 0)
		/* internal error */
		elog(ERROR, "connectby: SPI_connect returned %d", ret);

	/* switch to longer term context to create the tuple store */
	oldcontext = MemoryContextSwitchTo(per_query_ctx);

	/* initialize our tuplestore */
	tupstore = tuplestore_begin_heap(true, false, work_mem);

	MemoryContextSwitchTo(oldcontext);

	/* now go get the whole tree */
	tupstore = build_tuplestore_recursively(key_fld,
											parent_key_fld,
											relname,
											orderby_fld,
											branch_delim,
											start_with,
											start_with, /* current_branch */
											0,	/* initial level is 0 */
											&serial,	/* initial serial is 1 */
											max_depth,
											show_branch,
											show_serial,
											per_query_ctx,
											attinmeta,
											tupstore);

	SPI_finish();

	return tupstore;
}

static Tuplestorestate *
build_tuplestore_recursively(char *key_fld,
							 char *parent_key_fld,
							 char *relname,
							 char *orderby_fld,
							 char *branch_delim,
							 char *start_with,
							 char *branch,
							 int level,
							 int *serial,
							 int max_depth,
							 bool show_branch,
							 bool show_serial,
							 MemoryContext per_query_ctx,
							 AttInMetadata *attinmeta,
							 Tuplestorestate *tupstore)
{
	TupleDesc	tupdesc = attinmeta->tupdesc;
	MemoryContext oldcontext;
	int			ret;
	int			proc;
	int			serial_column;
	StringInfoData sql;
	char	  **values;
	char	   *current_key;
	char	   *current_key_parent;
	char		current_level[INT32_STRLEN];
	char		serial_str[INT32_STRLEN];
	char	   *current_branch;
	HeapTuple	tuple;

	if (max_depth > 0 && level > max_depth)
		return tupstore;

	initStringInfo(&sql);

	/* Build initial sql statement */
	if (!show_serial)
	{
		appendStringInfo(&sql, "SELECT %s, %s FROM %s WHERE %s = %s AND %s IS NOT NULL AND %s <> %s",
						 key_fld,
						 parent_key_fld,
						 relname,
						 parent_key_fld,
						 quote_literal_cstr(start_with),
						 key_fld, key_fld, parent_key_fld);
		serial_column = 0;
	}
	else
	{
		appendStringInfo(&sql, "SELECT %s, %s FROM %s WHERE %s = %s AND %s IS NOT NULL AND %s <> %s ORDER BY %s",
						 key_fld,
						 parent_key_fld,
						 relname,
						 parent_key_fld,
						 quote_literal_cstr(start_with),
						 key_fld, key_fld, parent_key_fld,
						 orderby_fld);
		serial_column = 1;
	}

	if (show_branch)
		values = (char **) palloc((CONNECTBY_NCOLS + serial_column) * sizeof(char *));
	else
		values = (char **) palloc((CONNECTBY_NCOLS_NOBRANCH + serial_column) * sizeof(char *));

	/* First time through, do a little setup */
	if (level == 0)
	{
		/* root value is the one we initially start with */
		values[0] = start_with;

		/* root value has no parent */
		values[1] = NULL;

		/* root level is 0 */
		sprintf(current_level, "%d", level);
		values[2] = current_level;

		/* root branch is just starting root value */
		if (show_branch)
			values[3] = start_with;

		/* root starts the serial with 1 */
		if (show_serial)
		{
			sprintf(serial_str, "%d", (*serial)++);
			if (show_branch)
				values[4] = serial_str;
			else
				values[3] = serial_str;
		}

		/* construct the tuple */
		tuple = BuildTupleFromCStrings(attinmeta, values);

		/* switch to long lived context while storing the tuple */
		oldcontext = MemoryContextSwitchTo(per_query_ctx);

		/* now store it */
		tuplestore_puttuple(tupstore, tuple);

		/* now reset the context */
		MemoryContextSwitchTo(oldcontext);

		/* increment level */
		level++;
	}

	/* Retrieve the desired rows */
	ret = SPI_execute(sql.data, true, 0);
	proc = SPI_processed;

	/* Check for qualifying tuples */
	if ((ret == SPI_OK_SELECT) && (proc > 0))
	{
		HeapTuple	spi_tuple;
		SPITupleTable *tuptable = SPI_tuptable;
		TupleDesc	spi_tupdesc = tuptable->tupdesc;
		int			i;
		StringInfoData branchstr;
		StringInfoData chk_branchstr;
		StringInfoData chk_current_key;

		/* First time through, do a little more setup */
		if (level == 0)
		{
			/*
			 * Check that return tupdesc is compatible with the one we got
			 * from the query, but only at level 0 -- no need to check more
			 * than once
			 */

			if (!compatConnectbyTupleDescs(tupdesc, spi_tupdesc))
				ereport(ERROR,
						(errcode(ERRCODE_SYNTAX_ERROR),
						 errmsg("invalid return type"),
						 errdetail("Return and SQL tuple descriptions are " \
								   "incompatible.")));
		}

		initStringInfo(&branchstr);
		initStringInfo(&chk_branchstr);
		initStringInfo(&chk_current_key);

		for (i = 0; i < proc; i++)
		{
			/* initialize branch for this pass */
			appendStringInfo(&branchstr, "%s", branch);
			appendStringInfo(&chk_branchstr, "%s%s%s", branch_delim, branch, branch_delim);

			/* get the next sql result tuple */
			spi_tuple = tuptable->vals[i];

			/* get the current key and parent */
			current_key = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
			appendStringInfo(&chk_current_key, "%s%s%s", branch_delim, current_key, branch_delim);
			current_key_parent = pstrdup(SPI_getvalue(spi_tuple, spi_tupdesc, 2));

			/* get the current level */
			sprintf(current_level, "%d", level);

			/* check to see if this key is also an ancestor */
			if (strstr(chk_branchstr.data, chk_current_key.data))
				elog(ERROR, "infinite recursion detected");

			/* OK, extend the branch */
			appendStringInfo(&branchstr, "%s%s", branch_delim, current_key);
			current_branch = branchstr.data;

			/* build a tuple */
			values[0] = pstrdup(current_key);
			values[1] = current_key_parent;
			values[2] = current_level;
			if (show_branch)
				values[3] = current_branch;
			if (show_serial)
			{
				sprintf(serial_str, "%d", (*serial)++);
				if (show_branch)
					values[4] = serial_str;
				else
					values[3] = serial_str;
			}

			tuple = BuildTupleFromCStrings(attinmeta, values);

			xpfree(current_key);
			xpfree(current_key_parent);

			/* switch to long lived context while storing the tuple */
			oldcontext = MemoryContextSwitchTo(per_query_ctx);

			/* store the tuple for later use */
			tuplestore_puttuple(tupstore, tuple);

			/* now reset the context */
			MemoryContextSwitchTo(oldcontext);

			heap_freetuple(tuple);

			/* recurse using current_key_parent as the new start_with */
			tupstore = build_tuplestore_recursively(key_fld,
													parent_key_fld,
													relname,
													orderby_fld,
													branch_delim,
													values[0],
													current_branch,
													level + 1,
													serial,
													max_depth,
													show_branch,
													show_serial,
													per_query_ctx,
													attinmeta,
													tupstore);

			/* reset branch for next pass */
			resetStringInfo(&branchstr);
			resetStringInfo(&chk_branchstr);
			resetStringInfo(&chk_current_key);
		}

		xpfree(branchstr.data);
		xpfree(chk_branchstr.data);
		xpfree(chk_current_key.data);
	}

	return tupstore;
}

/*
 * Check expected (query runtime) tupdesc suitable for Connectby
 */
static void
validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial)
{
	int			serial_column = 0;

	if (show_serial)
		serial_column = 1;

	/* are there the correct number of columns */
	if (show_branch)
	{
		if (tupdesc->natts != (CONNECTBY_NCOLS + serial_column))
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("invalid return type"),
					 errdetail("Query-specified return tuple has " \
							   "wrong number of columns.")));
	}
	else
	{
		if (tupdesc->natts != CONNECTBY_NCOLS_NOBRANCH + serial_column)
			ereport(ERROR,
					(errcode(ERRCODE_SYNTAX_ERROR),
					 errmsg("invalid return type"),
					 errdetail("Query-specified return tuple has " \
							   "wrong number of columns.")));
	}

	/* check that the types of the first two columns match */
	if (tupdesc->attrs[0]->atttypid != tupdesc->attrs[1]->atttypid)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("invalid return type"),
				 errdetail("First two columns must be the same type.")));

	/* check that the type of the third column is INT4 */
	if (tupdesc->attrs[2]->atttypid != INT4OID)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("invalid return type"),
				 errdetail("Third column must be type %s.",
						   format_type_be(INT4OID))));

	/* check that the type of the fourth column is TEXT if applicable */
	if (show_branch && tupdesc->attrs[3]->atttypid != TEXTOID)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("invalid return type"),
				 errdetail("Fourth column must be type %s.",
						   format_type_be(TEXTOID))));

	/* check that the type of the fifth column is INT4 */
	if (show_branch && show_serial && tupdesc->attrs[4]->atttypid != INT4OID)
		elog(ERROR, "query-specified return tuple not valid for Connectby: "
			 "fifth column must be type %s", format_type_be(INT4OID));

	/* check that the type of the fifth column is INT4 */
	if (!show_branch && show_serial && tupdesc->attrs[3]->atttypid != INT4OID)
		elog(ERROR, "query-specified return tuple not valid for Connectby: "
			 "fourth column must be type %s", format_type_be(INT4OID));

	/* OK, the tupdesc is valid for our purposes */
}

/*
 * Check if spi sql tupdesc and return tupdesc are compatible
 */
static bool
compatConnectbyTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc)
{
	Oid			ret_atttypid;
	Oid			sql_atttypid;

	/* check the key_fld types match */
	ret_atttypid = ret_tupdesc->attrs[0]->atttypid;
	sql_atttypid = sql_tupdesc->attrs[0]->atttypid;
	if (ret_atttypid != sql_atttypid)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("invalid return type"),
				 errdetail("SQL key field datatype does " \
						   "not match return key field datatype.")));

	/* check the parent_key_fld types match */
	ret_atttypid = ret_tupdesc->attrs[1]->atttypid;
	sql_atttypid = sql_tupdesc->attrs[1]->atttypid;
	if (ret_atttypid != sql_atttypid)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("invalid return type"),
				 errdetail("SQL parent key field datatype does " \
						   "not match return parent key field datatype.")));

	/* OK, the two tupdescs are compatible for our purposes */
	return true;
}

/*
 * Check if two tupdescs match in type of attributes
 */
static bool
compatCrosstabTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc)
{
	int			i;
	Form_pg_attribute ret_attr;
	Oid			ret_atttypid;
	Form_pg_attribute sql_attr;
	Oid			sql_atttypid;

	/* check the rowid types match */
	ret_atttypid = ret_tupdesc->attrs[0]->atttypid;
	sql_atttypid = sql_tupdesc->attrs[0]->atttypid;
	if (ret_atttypid != sql_atttypid)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("invalid return type"),
				 errdetail("SQL rowid datatype does not match " \
						   "return rowid datatype.")));

	/*
	 * - attribute [1] of the sql tuple is the category; no need to check it -
	 * attribute [2] of the sql tuple should match attributes [1] to [natts]
	 * of the return tuple
	 */
	sql_attr = sql_tupdesc->attrs[2];
	for (i = 1; i < ret_tupdesc->natts; i++)
	{
		ret_attr = ret_tupdesc->attrs[i];

		if (ret_attr->atttypid != sql_attr->atttypid)
			return false;
	}

	/* OK, the two tupdescs are compatible for our purposes */
	return true;
}

/*
 * Return a properly quoted literal value.
 * Uses quote_literal in quote.c
 */
static char *
quote_literal_cstr(char *rawstr)
{
	text	   *rawstr_text;
	text	   *result_text;
	char	   *result;

	rawstr_text = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(rawstr)));
	result_text = DatumGetTextP(DirectFunctionCall1(quote_literal, PointerGetDatum(rawstr_text)));
	result = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(result_text)));

	return result;
}


text:
using FluentValidation;
using Nop.Admin.Models.Polls;
using Nop.Services.Localization;
using Nop.Web.Framework.Validators;

namespace Nop.Admin.Validators.Polls
{
    public class PollAnswerValidator : BaseNopValidator<PollAnswerModel>
    {
        public PollAnswerValidator(ILocalizationService localizationService)
        {
            RuleFor(x => x.Name).NotEmpty().WithMessage(localizationService.GetResource("Admin.ContentManagement.Polls.Answers.Fields.Name.Required"));
        }
    }
}


text:
module SCSSLint::AutoCorrect
  class CLI
    attr_accessor :correctors, :paths, :options, :writer, :config

    def initialize
      @paths = []
      @options = {}
      @writer = FilesystemWriter.new
      @correctors = Correctors.all
    end

    def parse_args!(argv)
      @paths = []
      @options = {}
      argv.each do |arg|
        if arg[0..1] == "--"
          @options[arg[2..-1].to_sym] = true
        elsif arg[0] == "-"
          @options[arg[1..-1].to_sym] = true
        elsif File.directory?(arg)
          Dir["#{arg.chomp('/')}/**/*.scss"].each do |f|
            @paths << f
          end
        else
          @paths << arg
        end
      end
    end

    def option?(*names)
      names.each do |name|
        return true if @options[name.to_sym]
      end
      false
    end

    def run(argv)
      parse_args! argv
      if option? :version
        puts VERSION
        return 0
      end
      load_config!
      if option? :help, :h
        print_help
        return 0
      end
      if option? :list
        print_list
        return 0
      end
      if @paths.empty?
        puts "Nothing to process"
        return 1
      end
      puts "Dry run. Nothing written" if option? :dry
      process_all @paths
      0
    end

    def print_help
      puts "Fix your messy code"
      puts "USAGE: scss-lint-auto-correct [OPTIONS] PATH [PATH ...]"
      puts "OPTIONS are:"
      puts "  --help, -h"
      puts "  --verbose, -v"
      puts "  --debug  Prints extended debugging information"
      puts "  --dry"
      puts "  --list"
      puts "  --force  Ignore config disabling of corrector"
      puts "Only apply specific correctors, using any combination of:"
      @correctors.each do |c|
        puts "  --#{c.short_name}"
      end
      puts "Disable specific correctors, using any combination of:"
      @correctors.each do |c|
        puts "  --no-#{c.short_name}"
      end
    end

    def print_list
      puts "Configured correctors:"
      @correctors.each do |c|
        puts "  #{c.short_name}: #{c.description}"
      end
    end

    def load_config!
      config_file = relevant_configuration_file
      @config = config_file ? SCSSLint::Config.load(config_file) : SCSSLint::Config.default
    end

    def relevant_configuration_file
      if File.exist?(SCSSLint::Config::FILE_NAME)
        SCSSLint::Config::FILE_NAME
      elsif File.exist?(SCSSLint::Config.user_file)
        SCSSLint::Config.user_file
      end
    end

    def process_all(paths)
      paths.each do |path|
        process_file path
      end
    end

    def process_file(path)
      puts "Processing file #{path}" if option? :verbose, :v
      before = File.read(path)
      after = invoke_correctors(before)

      write_file(path, after) if before != after
    end

    def write_file(path, contents)
      puts "Writing file #{path}" if option? :verbose, :v
      writer.write_file(path, contents) unless option? :dry
    end

    def selected_correctors
      selected = []
      unselected = []
      @correctors.each do |c|
        selected << c if option? c.short_name
        unselected << c if option? "no-#{c.short_name}"
      end
      all = selected.any? ? selected : @correctors
      all - unselected
    end

    def invoke_correctors(contents)
      selected_correctors.each do |corrector|
        config = corrector.linter_name ? @config.options['linters'].fetch(corrector.linter_name, nil) : {}
        instance = corrector.new(config)
        contents_was = contents
        contents = instance.call(contents) if instance.enabled? || option?(:force)
        if option?(:debug) && contents != contents_was
          puts "* #{corrector.name} applied"
          print_diff contents_was, contents
        end
      end
      contents
    end

    def print_diff(before, after)
      @has_diff = `[ -x "$(command -v diff)" ] && echo "yay"`.strip == "yay" if @has_diff.nil?
      return puts after unless @has_diff
      require "tempfile"
      files = []
      file_before = Tempfile.new("before")
      files << file_before
      file_before.write before
      file_before.close
      file_after = Tempfile.new("after")
      files << file_after
      file_after.write after
      file_after.close
      cmd = "diff -u #{file_before.path} #{file_after.path}"
      output = `#{cmd}`
      puts output.lines[2..-1].join
    ensure
      files.each(&:unlink)
    end

    class FilesystemWriter
      def write_file(path, contents)
        File.open(path, "w+") { |f| f.write contents }
      end
    end

    class DummyWriter
      def files
        @files ||= []
      end

      def write_file(path, contents)
        files << { path: path, contents: contents }
      end
    end
  end
end


text:
```
<type>(<scope>): <subject>
<body>
```

#### Message subject (first line)

First line cannot be longer than 70 characters, second line is always blank and other lines should be wrapped at 80 characters. The type and scope should always be lowercase as shown below.
Allowed `<type>` values:
* add (new algorithm was added)
* fix (bug fix or implementation fix)
* feat (new feature to an existing algorithm, add methods or interfaces)
* docs (changes to the documentation)
* chore (changes in the project structure or build scripts)
* test (adding test cases, refactoring tests)
* style (formatting and styling)

#### `<scope>` values

Are equal to the corresponding package name

* datastructures
* graphs
* math
* search
* sorts

or file

* gradle
* readme

or vcs

* git

#### `<subject>` is required and briefly describes your changes

#### `<body>` is optional