/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */

/* GIO - GLib Input, Output and Streaming Library
 *
 * Copyright (C) 2008 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"
#include <glib.h>
#include "glibintl.h"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef G_OS_UNIX
#include <unistd.h>
#endif

#include <gio/gio.h>

static GResolver *resolver;
static GCancellable *cancellable;
static GMainLoop *loop;
static int nlookups = 0;
static gboolean synchronous = FALSE;
static guint connectable_count = 0;
static GResolverRecordType record_type = 0;

static void G_GNUC_NORETURN
usage (void)
{
	fprintf (stderr, "Usage: resolver [-s] [hostname | IP | service/protocol/domain ] ...\n");
	fprintf (stderr, "Usage: resolver [-s] [-t MX|TXT|NS|SOA] rrname ...\n");
	fprintf (stderr, "       resolver [-s] -c NUMBER [hostname | IP | service/protocol/domain ]\n");
	fprintf (stderr, "       Use -s to do synchronous lookups.\n");
	fprintf (stderr, "       Use -c NUMBER (and only a single resolvable argument) to test GSocketConnectable.\n");
	fprintf (stderr, "       The given NUMBER determines how many times the connectable will be enumerated.\n");
	fprintf (stderr, "       Use -t with MX, TXT, NS or SOA to lookup DNS records of those types.\n");
	exit (1);
}

G_LOCK_DEFINE_STATIC (response);

static void
done_lookup (void)
{
  nlookups--;
  if (nlookups == 0)
    {
      /* In the sync case we need to make sure we don't call
       * g_main_loop_quit before the loop is actually running...
       */
      g_idle_add ((GSourceFunc)g_main_loop_quit, loop);
    }
}

static void
print_resolved_name (const char *phys,
                     char       *name,
                     GError     *error)
{
  G_LOCK (response);
  printf ("Address: %s\n", phys);
  if (error)
    {
      printf ("Error:   %s\n", error->message);
      g_error_free (error);
    }
  else
    {
      printf ("Name:    %s\n", name);
      g_free (name);
    }
  printf ("\n");

  done_lookup ();
  G_UNLOCK (response);
}

static void
print_resolved_addresses (const char *name,
                          GList      *addresses,
			  GError     *error)
{
  char *phys;
  GList *a;

  G_LOCK (response);
  printf ("Name:    %s\n", name);
  if (error)
    {
      printf ("Error:   %s\n", error->message);
      g_error_free (error);
    }
  else
    {
      for (a = addresses; a; a = a->next)
	{
	  phys = g_inet_address_to_string (a->data);
	  printf ("Address: %s\n", phys);
	  g_free (phys);
          g_object_unref (a->data);
	}
      g_list_free (addresses);
    }
  printf ("\n");

  done_lookup ();
  G_UNLOCK (response);
}

static void
print_resolved_service (const char *service,
                        GList      *targets,
			GError     *error)
{
  GList *t;

  G_LOCK (response);
  printf ("Service: %s\n", service);
  if (error)
    {
      printf ("Error: %s\n", error->message);
      g_error_free (error);
    }
  else
    {
      for (t = targets; t; t = t->next)
	{
	  printf ("%s:%u (pri %u, weight %u)\n",
		  g_srv_target_get_hostname (t->data),
		  (guint)g_srv_target_get_port (t->data),
		  (guint)g_srv_target_get_priority (t->data),
		  (guint)g_srv_target_get_weight (t->data));
          g_srv_target_free (t->data);
	}
      g_list_free (targets);
    }
  printf ("\n");

  done_lookup ();
  G_UNLOCK (response);
}

static void
print_resolved_mx (const char *rrname,
                   GList      *records,
                   GError     *error)
{
  const gchar *hostname;
  guint16 priority;
  GList *t;

  G_LOCK (response);
  printf ("Domain: %s\n", rrname);
  if (error)
    {
      printf ("Error: %s\n", error->message);
      g_error_free (error);
    }
  else if (!records)
    {
      printf ("no MX records\n");
    }
  else
    {
      for (t = records; t; t = t->next)
        {
          g_variant_get (t->data, "(q&s)", &priority, &hostname);
          printf ("%s (pri %u)\n", hostname, (guint)priority);
          g_variant_unref (t->data);
        }
      g_list_free (records);
    }
  printf ("\n");

  done_lookup ();
  G_UNLOCK (response);
}

static void
print_resolved_txt (const char *rrname,
                    GList      *records,
                    GError     *error)
{
  const gchar **contents;
  GList *t;
  gint i;

  G_LOCK (response);
  printf ("Domain: %s\n", rrname);
  if (error)
    {
      printf ("Error: %s\n", error->message);
      g_error_free (error);
    }
  else if (!records)
    {
      printf ("no TXT records\n");
    }
  else
    {
      for (t = records; t; t = t->next)
        {
          if (t != records)
            printf ("\n");
          g_variant_get (t->data, "(^a&s)", &contents);
          for (i = 0; contents[i] != NULL; i++)
            printf ("%s\n", contents[i]);
          g_variant_unref (t->data);
        }
      g_list_free (records);
    }
  printf ("\n");

  done_lookup ();
  G_UNLOCK (response);
}

static void
print_resolved_soa (const char *rrname,
                    GList      *records,
                    GError     *error)
{
  GList *t;
  const gchar *primary_ns;
  const gchar *administrator;
  guint32 serial, refresh, retry, expire, ttl;

  G_LOCK (response);
  printf ("Zone: %s\n", rrname);
  if (error)
    {
      printf ("Error: %s\n", error->message);
      g_error_free (error);
    }
  else if (!records)
    {
      printf ("no SOA records\n");
    }
  else
    {
      for (t = records; t; t = t->next)
        {
          g_variant_get (t->data, "(&s&suuuuu)", &primary_ns, &administrator,
                         &serial, &refresh, &retry, &expire, &ttl);
          printf ("%s %s (serial %u, refresh %u, retry %u, expire %u, ttl %u)\n",
                  primary_ns, administrator, (guint)serial, (guint)refresh,
                  (guint)retry, (guint)expire, (guint)ttl);
          g_variant_unref (t->data);
        }
      g_list_free (records);
    }
  printf ("\n");

  done_lookup ();
  G_UNLOCK (response);
}

static void
print_resolved_ns (const char *rrname,
                    GList      *records,
                    GError     *error)
{
  GList *t;
  const gchar *hostname;

  G_LOCK (response);
  printf ("Zone: %s\n", rrname);
  if (error)
    {
      printf ("Error: %s\n", error->message);
      g_error_free (error);
    }
  else if (!records)
    {
      printf ("no NS records\n");
    }
  else
    {
      for (t = records; t; t = t->next)
        {
          g_variant_get (t->data, "(&s)", &hostname);
          printf ("%s\n", hostname);
          g_variant_unref (t->data);
        }
      g_list_free (records);
    }
  printf ("\n");

  done_lookup ();
  G_UNLOCK (response);
}

static void
lookup_one_sync (const char *arg)
{
  GError *error = NULL;

  if (record_type != 0)
    {
      GList *records;

      records = g_resolver_lookup_records (resolver, arg, record_type, cancellable, &error);
      switch (record_type)
      {
        case G_RESOLVER_RECORD_MX:
          print_resolved_mx (arg, records, error);
          break;
        case G_RESOLVER_RECORD_SOA:
          print_resolved_soa (arg, records, error);
          break;
        case G_RESOLVER_RECORD_NS:
          print_resolved_ns (arg, records, error);
          break;
        case G_RESOLVER_RECORD_TXT:
          print_resolved_txt (arg, records, error);
          break;
        default:
          g_warn_if_reached ();
          break;
      }
    }
  else if (strchr (arg, '/'))
    {
      GList *targets;
      /* service/protocol/domain */
      char **parts = g_strsplit (arg, "/", 3);

      if (!parts || !parts[2])
	usage ();

      targets = g_resolver_lookup_service (resolver,
                                           parts[0], parts[1], parts[2],
                                           cancellable, &error);
      print_resolved_service (arg, targets, error);
    }
  else if (g_hostname_is_ip_address (arg))
    {
      GInetAddress *addr = g_inet_address_new_from_string (arg);
      char *name;

      name = g_resolver_lookup_by_address (resolver, addr, cancellable, &error);
      print_resolved_name (arg, name, error);
      g_object_unref (addr);
    }
  else
    {
      GList *addresses;

      addresses = g_resolver_lookup_by_name (resolver, arg, cancellable, &error);
      print_resolved_addresses (arg, addresses, error);
    }
}

static gpointer
lookup_thread (gpointer arg)
{
  lookup_one_sync (arg);
  return NULL;
}

static void
start_sync_lookups (char **argv, int argc)
{
  int i;

  for (i = 0; i < argc; i++)
    {
      GThread *thread;
      thread = g_thread_new ("lookup", lookup_thread, argv[i]);
      g_thread_unref (thread);
    }
}

static void
lookup_by_addr_callback (GObject *source, GAsyncResult *result,
                         gpointer user_data)
{
  const char *phys = user_data;
  GError *error = NULL;
  char *name;

  name = g_resolver_lookup_by_address_finish (resolver, result, &error);
  print_resolved_name (phys, name, error);
}

static void
lookup_by_name_callback (GObject *source, GAsyncResult *result,
                         gpointer user_data)
{
  const char *name = user_data;
  GError *error = NULL;
  GList *addresses;

  addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
  print_resolved_addresses (name, addresses, error);
}

static void
lookup_service_callback (GObject *source, GAsyncResult *result,
			 gpointer user_data)
{
  const char *service = user_data;
  GError *error = NULL;
  GList *targets;

  targets = g_resolver_lookup_service_finish (resolver, result, &error);
  print_resolved_service (service, targets, error);
}

static void
lookup_records_callback (GObject      *source,
                         GAsyncResult *result,
                         gpointer      user_data)
{
  const char *arg = user_data;
  GError *error = NULL;
  GList *records;

  records = g_resolver_lookup_records_finish (resolver, result, &error);

  switch (record_type)
  {
    case G_RESOLVER_RECORD_MX:
      print_resolved_mx (arg, records, error);
      break;
    case G_RESOLVER_RECORD_SOA:
      print_resolved_soa (arg, records, error);
      break;
    case G_RESOLVER_RECORD_NS:
      print_resolved_ns (arg, records, error);
      break;
    case G_RESOLVER_RECORD_TXT:
      print_resolved_txt (arg, records, error);
      break;
    default:
      g_warn_if_reached ();
      break;
  }
}

static void
start_async_lookups (char **argv, int argc)
{
  int i;

  for (i = 0; i < argc; i++)
    {
      if (record_type != 0)
	{
	  g_resolver_lookup_records_async (resolver, argv[i], record_type,
	                                   cancellable, lookup_records_callback, argv[i]);
	}
      else if (strchr (argv[i], '/'))
	{
	  /* service/protocol/domain */
	  char **parts = g_strsplit (argv[i], "/", 3);

	  if (!parts || !parts[2])
	    usage ();

	  g_resolver_lookup_service_async (resolver,
					   parts[0], parts[1], parts[2],
					   cancellable,
					   lookup_service_callback, argv[i]);
	}
      else if (g_hostname_is_ip_address (argv[i]))
	{
          GInetAddress *addr = g_inet_address_new_from_string (argv[i]);

	  g_resolver_lookup_by_address_async (resolver, addr, cancellable,
                                              lookup_by_addr_callback, argv[i]);
	  g_object_unref (addr);
	}
      else
	{
	  g_resolver_lookup_by_name_async (resolver, argv[i], cancellable,
                                           lookup_by_name_callback,
                                           argv[i]);
	}

      /* Stress-test the reloading code */
      g_signal_emit_by_name (resolver, "reload");
    }
}

static void
print_connectable_sockaddr (GSocketAddress *sockaddr,
                            GError         *error)
{
  char *phys;

  if (error)
    {
      printf ("Error:   %s\n", error->message);
      g_error_free (error);
    }
  else if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
    {
      printf ("Error:   Unexpected sockaddr type '%s'\n", g_type_name_from_instance ((GTypeInstance *)sockaddr));
      g_object_unref (sockaddr);
    }
  else
    {
      GInetSocketAddress *isa = G_INET_SOCKET_ADDRESS (sockaddr);
      phys = g_inet_address_to_string (g_inet_socket_address_get_address (isa));
      printf ("Address: %s%s%s:%d\n",
              strchr (phys, ':') ? "[" : "", phys, strchr (phys, ':') ? "]" : "",
              g_inet_socket_address_get_port (isa));
      g_free (phys);
      g_object_unref (sockaddr);
    }
}

static void
do_sync_connectable (GSocketAddressEnumerator *enumerator)
{
  GSocketAddress *sockaddr;
  GError *error = NULL;

  while ((sockaddr = g_socket_address_enumerator_next (enumerator, cancellable, &error)))
    print_connectable_sockaddr (sockaddr, error);

  g_object_unref (enumerator);
  done_lookup ();
}

static void do_async_connectable (GSocketAddressEnumerator *enumerator);

static void
got_next_async (GObject *source, GAsyncResult *result, gpointer user_data)
{
  GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (source);
  GSocketAddress *sockaddr;
  GError *error = NULL;

  sockaddr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
  if (sockaddr || error)
    print_connectable_sockaddr (sockaddr, error);
  if (sockaddr)
    do_async_connectable (enumerator);
  else
    {
      g_object_unref (enumerator);
      done_lookup ();
    }
}

static void
do_async_connectable (GSocketAddressEnumerator *enumerator)
{
  g_socket_address_enumerator_next_async (enumerator, cancellable,
                                          got_next_async, NULL);
}

static void
do_connectable (const char *arg, gboolean synchronous, guint count)
{
  char **parts;
  GSocketConnectable *connectable;
  GSocketAddressEnumerator *enumerator;

  if (strchr (arg, '/'))
    {
      /* service/protocol/domain */
      parts = g_strsplit (arg, "/", 3);
      if (!parts || !parts[2])
	usage ();

      connectable = g_network_service_new (parts[0], parts[1], parts[2]);
    }
  else
    {
      guint16 port;

      parts = g_strsplit (arg, ":", 2);
      if (parts && parts[1])
	{
	  arg = parts[0];
	  port = strtoul (parts[1], NULL, 10);
	}
      else
	port = 0;

      if (g_hostname_is_ip_address (arg))
	{
	  GInetAddress *addr = g_inet_address_new_from_string (arg);
	  GSocketAddress *sockaddr = g_inet_socket_address_new (addr, port);

	  g_object_unref (addr);
	  connectable = G_SOCKET_CONNECTABLE (sockaddr);
	}
      else
        connectable = g_network_address_new (arg, port);
    }

  while (count--)
    {
      enumerator = g_socket_connectable_enumerate (connectable);

      if (synchronous)
        do_sync_connectable (enumerator);
      else
        do_async_connectable (enumerator);
    }

  g_object_unref (connectable);
}

#ifdef G_OS_UNIX
static int cancel_fds[2];

static void
interrupted (int sig)
{
  gssize c;

  signal (SIGINT, SIG_DFL);
  c = write (cancel_fds[1], "x", 1);
  g_assert_cmpint(c, ==, 1);
}

static gboolean
async_cancel (GIOChannel *source, GIOCondition cond, gpointer cancel)
{
  g_cancellable_cancel (cancel);
  return FALSE;
}
#endif

static gboolean
record_type_arg (const gchar *option_name,
                 const gchar *value,
                 gpointer data,
                 GError **error)
{
  if (g_ascii_strcasecmp (value, "MX") == 0) {
    record_type = G_RESOLVER_RECORD_MX;
  } else if (g_ascii_strcasecmp (value, "TXT") == 0) {
    record_type = G_RESOLVER_RECORD_TXT;
  } else if (g_ascii_strcasecmp (value, "SOA") == 0) {
    record_type = G_RESOLVER_RECORD_SOA;
  } else if (g_ascii_strcasecmp (value, "NS") == 0) {
    record_type = G_RESOLVER_RECORD_NS;
  } else {
      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
                   "Specify MX, TXT, NS or SOA for the special record lookup types");
      return FALSE;
  }

  return TRUE;
}

static const GOptionEntry option_entries[] = {
  { "synchronous", 's', 0, G_OPTION_ARG_NONE, &synchronous, "Synchronous connections", NULL },
  { "connectable", 'c', 0, G_OPTION_ARG_INT, &connectable_count, "Connectable count", "C" },
  { "special-type", 't', 0, G_OPTION_ARG_CALLBACK, record_type_arg, "Record type like MX, TXT, NS or SOA", "RR" },
  { NULL },
};

int
main (int argc, char **argv)
{
  GOptionContext *context;
  GError *error = NULL;
#ifdef G_OS_UNIX
  GIOChannel *chan;
  guint watch;
#endif

  context = g_option_context_new ("lookups ...");
  g_option_context_add_main_entries (context, option_entries, NULL);
  if (!g_option_context_parse (context, &argc, &argv, &error))
    {
      g_printerr ("%s\n", error->message);
      g_error_free (error);
      usage();
    }

  if (argc < 2 || (argc > 2 && connectable_count))
    usage ();

  resolver = g_resolver_get_default ();

  cancellable = g_cancellable_new ();

#ifdef G_OS_UNIX
  /* Set up cancellation; we want to cancel if the user ^C's the
   * program, but we can't cancel directly from an interrupt.
   */
  signal (SIGINT, interrupted);

  if (pipe (cancel_fds) == -1)
    {
      perror ("pipe");
      exit (1);
    }
  chan = g_io_channel_unix_new (cancel_fds[0]);
  watch = g_io_add_watch (chan, G_IO_IN, async_cancel, cancellable);
  g_io_channel_unref (chan);
#endif

  nlookups = argc - 1;
  loop = g_main_loop_new (NULL, TRUE);

  if (connectable_count)
    {
      nlookups = connectable_count;
      do_connectable (argv[1], synchronous, connectable_count);
    }
  else
    {
      if (synchronous)
        start_sync_lookups (argv + 1, argc - 1);
      else
        start_async_lookups (argv + 1, argc - 1);
    }

  g_main_loop_run (loop);
  g_main_loop_unref (loop);

#ifdef G_OS_UNIX
  g_source_remove (watch);
#endif
  g_object_unref (cancellable);

  return 0;
}


mutated poppy flower

These strange flowers have appeared in the wake of the Cataclysm, and their buds can be used for medicinal purposes, like the seeds of the mundane poppy they're named after.  The dirt around them gently churns as their roots writhe beneath the soil, and it's surrounded by an overwhelming floral smell that makes you feel sleepy.

TRANSPARENT TINY FLAMMABLE_ASH NOCOLLIDE FLOWER

dandelion

A common weed with a yellow flower.  Produces seeds that get carried on the wind by thin, gray filaments.

burdock

A common weed with a purple thistle-like flower.  Its seeds tend to stick to clothing and fur.

chamomile

Ahh, soothing chamomile tea.

tulip

A bright, colorful flower with petals forming a small cup at its top.

spurge flower

A yellow-green flower that grows in densely packed bushes.

cattails

This useful plant is available all year round.  Many parts of the plant are edible.

TRANSPARENT TINY FLAMMABLE_ASH NOCOLLIDE ORGANIC

black eyed susan

A yellow flower that has a dark ball in the middle.  Sometimes known as an ox-eye daisy.

lily

A pretty flower that comes in a variety of colors.

lotus

A lovely flower that grows on the surface of bodies of freshwater.  Traditionally connected with many Eastern cultures.

sunflower

A tall, wide-headed flower with a large dark center.  Produces many nutritious seeds.

lilypad

These lilypads don't look they'd support the weight of the things you've heard croaking in the swamp.

bluebell

A common bluebell flower.  Pretty.

dahlia

A puffy flower with many tightly layered petals.

chicory

A blue flower imported from Europe, also known as a Cornflower.

datura

A pretty moonflower.

pile of leaves

A sizable pile of leaves.  You could sleep on it if you don't care about comfort or warmth.

TRANSPARENT FLAMMABLE_ASH ORGANIC MOUNTABLE SHORT EASY_DECONSTRUCT

mustard

Yellow flower known as Brassica Nigra.  Known for its seeds that can be used for making table mustard.

alder tree

A deciduous flowering tree with serrate, scalloped, round-obovate leaves, commonly forming dense groves alongside water.


import _ from 'lodash'

import reducer from 'src/dashboards/reducers/ui'
import {template, dashboard, cell} from 'test/resources'
import {initialState} from 'src/dashboards/reducers/ui'
import {TemplateType, TemplateValueType} from 'src/types'

import {
  setTimeRange,
  loadDashboards,
  deleteDashboard,
  syncDashboardCell,
  deleteDashboardFailed,
  templateVariableLocalSelected,
  setActiveCell,
  updateTemplates,
} from 'src/dashboards/actions'

let state

const t2 = {
  ...template,
  id: '2',
  type: TemplateType.CSV,
  label: 'test csv',
  tempVar: ':temperature:',
  values: [
    {
      value: '98.7',
      type: TemplateValueType.Measurement,
      selected: false,
      localSelected: true,
    },
    {
      value: '99.1',
      type: TemplateValueType.Measurement,
      selected: false,
      localSelected: false,
    },
    {
      value: '101.3',
      type: TemplateValueType.Measurement,
      selected: true,
      localSelected: false,
    },
  ],
}

const templates = [template, t2]

const d1 = {
  ...dashboard,
  templates,
}

const d2 = {...dashboard, id: '2', cells: [], name: 'd2', templates: []}
const dashboards = [d1, d2]

describe('DataExplorer.Reducers.UI', () => {
  it('can load the dashboards', () => {
    const actual = reducer(state, loadDashboards(dashboards, d1.id))
    const expected = {
      dashboards,
    }

    expect(actual.dashboards).toEqual(expected.dashboards)
  })

  it('can delete a dashboard', () => {
    const actual = reducer({...initialState, dashboards}, deleteDashboard(d1))
    const expected = dashboards.filter(dash => dash.id !== d1.id)

    expect(actual.dashboards).toEqual(expected)
  })

  it('can handle a failed dashboard deletion', () => {
    const loadedState = reducer(state, loadDashboards([d1]))
    const actual = reducer(loadedState, deleteDashboardFailed(d2))
    const actualFirst = _.first(actual.dashboards)

    expect(actual.dashboards.length).toBe(2)
    _.forOwn(d2, (v, k) => {
      expect(actualFirst[k]).toEqual(v)
    })
  })

  it('can set the time range', () => {
    const expected = {upper: null, lower: 'now() - 1h'}
    const actual = reducer(state, setTimeRange(expected))

    expect(actual.timeRange).toEqual(expected)
  })

  it('can sync a cell', () => {
    const newCellName = 'watts is kinda cool'
    const newCell = {
      ...cell,
      name: newCellName,
    }

    const dash = {...d1, cells: [cell]}
    state = {
      dashboards: [dash],
    }

    const actual = reducer(state, syncDashboardCell(dash, newCell))
    expect(actual.dashboards[0].cells[0].name).toBe(newCellName)
  })

  it('can pick a different template variable', () => {
    const dash = _.cloneDeep(d1)
    state = {
      dashboards: [dash],
    }

    const action = templateVariableLocalSelected(
      dash.id,
      dash.templates[0].id,
      dash.templates[0].values[2]
    )

    const actual = reducer(state, action).dashboards[0].templates[0].values

    expect(actual[0].localSelected).toBe(false)
    expect(actual[1].localSelected).toBe(false)
    expect(actual[2].localSelected).toBe(true)
  })

  describe('SET_ACTIVE_CELL', () => {
    it('can set the active cell', () => {
      const activeCellID = '1'
      const actual = reducer(initialState, setActiveCell(activeCellID))

      expect(actual.activeCellID).toEqual(activeCellID)
    })
  })

  describe('UPDATE_TEMPLATE_VARIABLES', () => {
    it('can update template variables', () => {
      const thisState = {
        ...initialState,
        dashboards: [
          {
            ...dashboard,
            templates: [
              {
                id: '0',
                tempVar: ':foo:',
                label: '',
                type: TemplateType.CSV,
                values: [],
              },
              {
                id: '1',
                tempVar: ':bar:',
                label: '',
                type: TemplateType.CSV,
                values: [],
              },
              {
                id: '2',
                tempVar: ':baz:',
                label: '',
                type: TemplateType.CSV,
                values: [],
              },
            ],
          },
        ],
      }

      const newTemplates = [
        {
          id: '0',
          tempVar: ':foo:',
          label: '',
          type: TemplateType.CSV,
          values: [
            {
              type: TemplateValueType.CSV,
              value: '',
              selected: true,
              localSelected: true,
            },
          ],
        },
        {
          id: '1',
          tempVar: ':bar:',
          label: '',
          type: TemplateType.CSV,
          values: [
            {
              type: TemplateValueType.CSV,
              value: '',
              selected: false,
              localSelected: false,
            },
          ],
        },
      ]

      const result = reducer(thisState, updateTemplates(newTemplates))

      // Variables present in payload are updated
      expect(result.dashboards[0].templates).toContainEqual(newTemplates[0])
      expect(result.dashboards[0].templates).toContainEqual(newTemplates[1])

      // Variables not present in action payload are left untouched
      expect(result.dashboards[0].templates).toContainEqual(
        thisState.dashboards[0].templates[2]
      )
    })
  })
})


-- Do not manually edit this file, it was auto-generated by dillonkearns/elm-graphql
-- https://github.com/dillonkearns/elm-graphql

module Swapi.Subscription exposing (..)

import CustomScalarCodecs
import Graphql.Internal.Builder.Argument as Argument exposing (Argument)
import Graphql.Internal.Builder.Object as Object
import Graphql.Internal.Encode as Encode exposing (Value)
import Graphql.Operation exposing (RootMutation, RootQuery, RootSubscription)
import Graphql.OptionalArgument exposing (OptionalArgument(..))
import Graphql.SelectionSet exposing (SelectionSet)
import Json.Decode as Decode exposing (Decoder)
import Swapi.InputObject
import Swapi.Interface
import Swapi.Object
import Swapi.Scalar
import Swapi.Union

newMessage :
    SelectionSet decodesTo Swapi.Object.ChatMessage
    -> SelectionSet decodesTo RootSubscription
newMessage object_ =
    Object.selectionForCompositeField "newMessage" [] object_ identity


/*
 * OMAP2 McSPI controller driver
 *
 * Copyright (C) 2005, 2006 Nokia Corporation
 * Author:	Samuel Ortiz <samuel.ortiz@nokia.com> and
 *		Juha Yrj�l� <juha.yrjola@nokia.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>

#include <linux/spi/spi.h>

#include <plat/dma.h>
#include <plat/clock.h>
#include <plat/mcspi.h>

#define OMAP2_MCSPI_MAX_FREQ		48000000

/* OMAP2 has 3 SPI controllers, while OMAP3 has 4 */
#define OMAP2_MCSPI_MAX_CTRL 		4

#define OMAP2_MCSPI_REVISION		0x00
#define OMAP2_MCSPI_SYSSTATUS		0x14
#define OMAP2_MCSPI_IRQSTATUS		0x18
#define OMAP2_MCSPI_IRQENABLE		0x1c
#define OMAP2_MCSPI_WAKEUPENABLE	0x20
#define OMAP2_MCSPI_SYST		0x24
#define OMAP2_MCSPI_MODULCTRL		0x28

/* per-channel banks, 0x14 bytes each, first is: */
#define OMAP2_MCSPI_CHCONF0		0x2c
#define OMAP2_MCSPI_CHSTAT0		0x30
#define OMAP2_MCSPI_CHCTRL0		0x34
#define OMAP2_MCSPI_TX0			0x38
#define OMAP2_MCSPI_RX0			0x3c

/* per-register bitmasks: */

#define OMAP2_MCSPI_MODULCTRL_SINGLE	BIT(0)
#define OMAP2_MCSPI_MODULCTRL_MS	BIT(2)
#define OMAP2_MCSPI_MODULCTRL_STEST	BIT(3)

#define OMAP2_MCSPI_CHCONF_PHA		BIT(0)
#define OMAP2_MCSPI_CHCONF_POL		BIT(1)
#define OMAP2_MCSPI_CHCONF_CLKD_MASK	(0x0f << 2)
#define OMAP2_MCSPI_CHCONF_EPOL		BIT(6)
#define OMAP2_MCSPI_CHCONF_WL_MASK	(0x1f << 7)
#define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY	BIT(12)
#define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY	BIT(13)
#define OMAP2_MCSPI_CHCONF_TRM_MASK	(0x03 << 12)
#define OMAP2_MCSPI_CHCONF_DMAW		BIT(14)
#define OMAP2_MCSPI_CHCONF_DMAR		BIT(15)
#define OMAP2_MCSPI_CHCONF_DPE0		BIT(16)
#define OMAP2_MCSPI_CHCONF_DPE1		BIT(17)
#define OMAP2_MCSPI_CHCONF_IS		BIT(18)
#define OMAP2_MCSPI_CHCONF_TURBO	BIT(19)
#define OMAP2_MCSPI_CHCONF_FORCE	BIT(20)

#define OMAP2_MCSPI_CHSTAT_RXS		BIT(0)
#define OMAP2_MCSPI_CHSTAT_TXS		BIT(1)
#define OMAP2_MCSPI_CHSTAT_EOT		BIT(2)

#define OMAP2_MCSPI_CHCTRL_EN		BIT(0)

#define OMAP2_MCSPI_WAKEUPENABLE_WKEN	BIT(0)

/* We have 2 DMA channels per CS, one for RX and one for TX */
struct omap2_mcspi_dma {
	int dma_tx_channel;
	int dma_rx_channel;

	int dma_tx_sync_dev;
	int dma_rx_sync_dev;

	struct completion dma_tx_completion;
	struct completion dma_rx_completion;
};

/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
 * cache operations; better heuristics consider wordsize and bitrate.
 */
#define DMA_MIN_BYTES			160

struct omap2_mcspi {
	struct work_struct	work;
	/* lock protects queue and registers */
	spinlock_t		lock;
	struct list_head	msg_queue;
	struct spi_master	*master;
	/* Virtual base address of the controller */
	void __iomem		*base;
	unsigned long		phys;
	/* SPI1 has 4 channels, while SPI2 has 2 */
	struct omap2_mcspi_dma	*dma_channels;
	struct  device		*dev;
	struct workqueue_struct *wq;
};

struct omap2_mcspi_cs {
	void __iomem		*base;
	unsigned long		phys;
	int			word_len;
	struct list_head	node;
	/* Context save and restore shadow register */
	u32			chconf0;
};

/* used for context save and restore, structure members to be updated whenever
 * corresponding registers are modified.
 */
struct omap2_mcspi_regs {
	u32 modulctrl;
	u32 wakeupenable;
	struct list_head cs;
};

static struct omap2_mcspi_regs omap2_mcspi_ctx[OMAP2_MCSPI_MAX_CTRL];

#define MOD_REG_BIT(val, mask, set) do { \
	if (set) \
		val |= mask; \
	else \
		val &= ~mask; \
} while (0)

static inline void mcspi_write_reg(struct spi_master *master,
		int idx, u32 val)
{
	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);

	__raw_writel(val, mcspi->base + idx);
}

static inline u32 mcspi_read_reg(struct spi_master *master, int idx)
{
	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);

	return __raw_readl(mcspi->base + idx);
}

static inline void mcspi_write_cs_reg(const struct spi_device *spi,
		int idx, u32 val)
{
	struct omap2_mcspi_cs	*cs = spi->controller_state;

	__raw_writel(val, cs->base +  idx);
}

static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx)
{
	struct omap2_mcspi_cs	*cs = spi->controller_state;

	return __raw_readl(cs->base + idx);
}

static inline u32 mcspi_cached_chconf0(const struct spi_device *spi)
{
	struct omap2_mcspi_cs *cs = spi->controller_state;

	return cs->chconf0;
}

static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
{
	struct omap2_mcspi_cs *cs = spi->controller_state;

	cs->chconf0 = val;
	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val);
	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
}

static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
		int is_read, int enable)
{
	u32 l, rw;

	l = mcspi_cached_chconf0(spi);

	if (is_read) /* 1 is read, 0 write */
		rw = OMAP2_MCSPI_CHCONF_DMAR;
	else
		rw = OMAP2_MCSPI_CHCONF_DMAW;

	MOD_REG_BIT(l, rw, enable);
	mcspi_write_chconf0(spi, l);
}

static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
{
	u32 l;

	l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
	/* Flash post-writes */
	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
}

static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
{
	u32 l;

	l = mcspi_cached_chconf0(spi);
	MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
	mcspi_write_chconf0(spi, l);
}

static void omap2_mcspi_set_master_mode(struct spi_master *master)
{
	u32 l;

	/* setup when switching from (reset default) slave mode
	 * to single-channel master mode
	 */
	l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
	MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
	MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
	MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
	mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);

	omap2_mcspi_ctx[master->bus_num - 1].modulctrl = l;
}

static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
{
	struct spi_master *spi_cntrl;
	struct omap2_mcspi_cs *cs;
	spi_cntrl = mcspi->master;

	/* McSPI: context restore */
	mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL,
			omap2_mcspi_ctx[spi_cntrl->bus_num - 1].modulctrl);

	mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE,
			omap2_mcspi_ctx[spi_cntrl->bus_num - 1].wakeupenable);

	list_for_each_entry(cs, &omap2_mcspi_ctx[spi_cntrl->bus_num - 1].cs,
			node)
		__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
}
static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi)
{
	pm_runtime_put_sync(mcspi->dev);
}

static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
{
	return pm_runtime_get_sync(mcspi->dev);
}

static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
{
	unsigned long timeout;

	timeout = jiffies + msecs_to_jiffies(1000);
	while (!(__raw_readl(reg) & bit)) {
		if (time_after(jiffies, timeout))
			return -1;
		cpu_relax();
	}
	return 0;
}

static unsigned
omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
{
	struct omap2_mcspi	*mcspi;
	struct omap2_mcspi_cs	*cs = spi->controller_state;
	struct omap2_mcspi_dma  *mcspi_dma;
	unsigned int		count, c;
	unsigned long		base, tx_reg, rx_reg;
	int			word_len, data_type, element_count;
	int			elements = 0;
	u32			l;
	u8			* rx;
	const u8		* tx;
	void __iomem		*chstat_reg;

	mcspi = spi_master_get_devdata(spi->master);
	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
	l = mcspi_cached_chconf0(spi);

	chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;

	count = xfer->len;
	c = count;
	word_len = cs->word_len;

	base = cs->phys;
	tx_reg = base + OMAP2_MCSPI_TX0;
	rx_reg = base + OMAP2_MCSPI_RX0;
	rx = xfer->rx_buf;
	tx = xfer->tx_buf;

	if (word_len <= 8) {
		data_type = OMAP_DMA_DATA_TYPE_S8;
		element_count = count;
	} else if (word_len <= 16) {
		data_type = OMAP_DMA_DATA_TYPE_S16;
		element_count = count >> 1;
	} else /* word_len <= 32 */ {
		data_type = OMAP_DMA_DATA_TYPE_S32;
		element_count = count >> 2;
	}

	if (tx != NULL) {
		omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
				data_type, element_count, 1,
				OMAP_DMA_SYNC_ELEMENT,
				mcspi_dma->dma_tx_sync_dev, 0);

		omap_set_dma_dest_params(mcspi_dma->dma_tx_channel, 0,
				OMAP_DMA_AMODE_CONSTANT,
				tx_reg, 0, 0);

		omap_set_dma_src_params(mcspi_dma->dma_tx_channel, 0,
				OMAP_DMA_AMODE_POST_INC,
				xfer->tx_dma, 0, 0);
	}

	if (rx != NULL) {
		elements = element_count - 1;
		if (l & OMAP2_MCSPI_CHCONF_TURBO)
			elements--;

		omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
				data_type, elements, 1,
				OMAP_DMA_SYNC_ELEMENT,
				mcspi_dma->dma_rx_sync_dev, 1);

		omap_set_dma_src_params(mcspi_dma->dma_rx_channel, 0,
				OMAP_DMA_AMODE_CONSTANT,
				rx_reg, 0, 0);

		omap_set_dma_dest_params(mcspi_dma->dma_rx_channel, 0,
				OMAP_DMA_AMODE_POST_INC,
				xfer->rx_dma, 0, 0);
	}

	if (tx != NULL) {
		omap_start_dma(mcspi_dma->dma_tx_channel);
		omap2_mcspi_set_dma_req(spi, 0, 1);
	}

	if (rx != NULL) {
		omap_start_dma(mcspi_dma->dma_rx_channel);
		omap2_mcspi_set_dma_req(spi, 1, 1);
	}

	if (tx != NULL) {
		wait_for_completion(&mcspi_dma->dma_tx_completion);
		dma_unmap_single(&spi->dev, xfer->tx_dma, count, DMA_TO_DEVICE);

		/* for TX_ONLY mode, be sure all words have shifted out */
		if (rx == NULL) {
			if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_TXS) < 0)
				dev_err(&spi->dev, "TXS timed out\n");
			else if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_EOT) < 0)
				dev_err(&spi->dev, "EOT timed out\n");
		}
	}

	if (rx != NULL) {
		wait_for_completion(&mcspi_dma->dma_rx_completion);
		dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE);
		omap2_mcspi_set_enable(spi, 0);

		if (l & OMAP2_MCSPI_CHCONF_TURBO) {

			if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
				   & OMAP2_MCSPI_CHSTAT_RXS)) {
				u32 w;

				w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
				if (word_len <= 8)
					((u8 *)xfer->rx_buf)[elements++] = w;
				else if (word_len <= 16)
					((u16 *)xfer->rx_buf)[elements++] = w;
				else /* word_len <= 32 */
					((u32 *)xfer->rx_buf)[elements++] = w;
			} else {
				dev_err(&spi->dev,
					"DMA RX penultimate word empty");
				count -= (word_len <= 8)  ? 2 :
					(word_len <= 16) ? 4 :
					/* word_len <= 32 */ 8;
				omap2_mcspi_set_enable(spi, 1);
				return count;
			}
		}

		if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
				& OMAP2_MCSPI_CHSTAT_RXS)) {
			u32 w;

			w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
			if (word_len <= 8)
				((u8 *)xfer->rx_buf)[elements] = w;
			else if (word_len <= 16)
				((u16 *)xfer->rx_buf)[elements] = w;
			else /* word_len <= 32 */
				((u32 *)xfer->rx_buf)[elements] = w;
		} else {
			dev_err(&spi->dev, "DMA RX last word empty");
			count -= (word_len <= 8)  ? 1 :
				 (word_len <= 16) ? 2 :
			       /* word_len <= 32 */ 4;
		}
		omap2_mcspi_set_enable(spi, 1);
	}
	return count;
}

static unsigned
omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
{
	struct omap2_mcspi	*mcspi;
	struct omap2_mcspi_cs	*cs = spi->controller_state;
	unsigned int		count, c;
	u32			l;
	void __iomem		*base = cs->base;
	void __iomem		*tx_reg;
	void __iomem		*rx_reg;
	void __iomem		*chstat_reg;
	int			word_len;

	mcspi = spi_master_get_devdata(spi->master);
	count = xfer->len;
	c = count;
	word_len = cs->word_len;

	l = mcspi_cached_chconf0(spi);

	/* We store the pre-calculated register addresses on stack to speed
	 * up the transfer loop. */
	tx_reg		= base + OMAP2_MCSPI_TX0;
	rx_reg		= base + OMAP2_MCSPI_RX0;
	chstat_reg	= base + OMAP2_MCSPI_CHSTAT0;

	if (c < (word_len>>3))
		return 0;

	if (word_len <= 8) {
		u8		*rx;
		const u8	*tx;

		rx = xfer->rx_buf;
		tx = xfer->tx_buf;

		do {
			c -= 1;
			if (tx != NULL) {
				if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
					dev_err(&spi->dev, "TXS timed out\n");
					goto out;
				}
				dev_vdbg(&spi->dev, "write-%d %02x\n",
						word_len, *tx);
				__raw_writel(*tx++, tx_reg);
			}
			if (rx != NULL) {
				if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
					dev_err(&spi->dev, "RXS timed out\n");
					goto out;
				}

				if (c == 1 && tx == NULL &&
				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
					omap2_mcspi_set_enable(spi, 0);
					*rx++ = __raw_readl(rx_reg);
					dev_vdbg(&spi->dev, "read-%d %02x\n",
						    word_len, *(rx - 1));
					if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
						dev_err(&spi->dev,
							"RXS timed out\n");
						goto out;
					}
					c = 0;
				} else if (c == 0 && tx == NULL) {
					omap2_mcspi_set_enable(spi, 0);
				}

				*rx++ = __raw_readl(rx_reg);
				dev_vdbg(&spi->dev, "read-%d %02x\n",
						word_len, *(rx - 1));
			}
		} while (c);
	} else if (word_len <= 16) {
		u16		*rx;
		const u16	*tx;

		rx = xfer->rx_buf;
		tx = xfer->tx_buf;
		do {
			c -= 2;
			if (tx != NULL) {
				if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
					dev_err(&spi->dev, "TXS timed out\n");
					goto out;
				}
				dev_vdbg(&spi->dev, "write-%d %04x\n",
						word_len, *tx);
				__raw_writel(*tx++, tx_reg);
			}
			if (rx != NULL) {
				if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
					dev_err(&spi->dev, "RXS timed out\n");
					goto out;
				}

				if (c == 2 && tx == NULL &&
				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
					omap2_mcspi_set_enable(spi, 0);
					*rx++ = __raw_readl(rx_reg);
					dev_vdbg(&spi->dev, "read-%d %04x\n",
						    word_len, *(rx - 1));
					if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
						dev_err(&spi->dev,
							"RXS timed out\n");
						goto out;
					}
					c = 0;
				} else if (c == 0 && tx == NULL) {
					omap2_mcspi_set_enable(spi, 0);
				}

				*rx++ = __raw_readl(rx_reg);
				dev_vdbg(&spi->dev, "read-%d %04x\n",
						word_len, *(rx - 1));
			}
		} while (c >= 2);
	} else if (word_len <= 32) {
		u32		*rx;
		const u32	*tx;

		rx = xfer->rx_buf;
		tx = xfer->tx_buf;
		do {
			c -= 4;
			if (tx != NULL) {
				if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
					dev_err(&spi->dev, "TXS timed out\n");
					goto out;
				}
				dev_vdbg(&spi->dev, "write-%d %08x\n",
						word_len, *tx);
				__raw_writel(*tx++, tx_reg);
			}
			if (rx != NULL) {
				if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
					dev_err(&spi->dev, "RXS timed out\n");
					goto out;
				}

				if (c == 4 && tx == NULL &&
				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
					omap2_mcspi_set_enable(spi, 0);
					*rx++ = __raw_readl(rx_reg);
					dev_vdbg(&spi->dev, "read-%d %08x\n",
						    word_len, *(rx - 1));
					if (mcspi_wait_for_reg_bit(chstat_reg,
						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
						dev_err(&spi->dev,
							"RXS timed out\n");
						goto out;
					}
					c = 0;
				} else if (c == 0 && tx == NULL) {
					omap2_mcspi_set_enable(spi, 0);
				}

				*rx++ = __raw_readl(rx_reg);
				dev_vdbg(&spi->dev, "read-%d %08x\n",
						word_len, *(rx - 1));
			}
		} while (c >= 4);
	}

	/* for TX_ONLY mode, be sure all words have shifted out */
	if (xfer->rx_buf == NULL) {
		if (mcspi_wait_for_reg_bit(chstat_reg,
				OMAP2_MCSPI_CHSTAT_TXS) < 0) {
			dev_err(&spi->dev, "TXS timed out\n");
		} else if (mcspi_wait_for_reg_bit(chstat_reg,
				OMAP2_MCSPI_CHSTAT_EOT) < 0)
			dev_err(&spi->dev, "EOT timed out\n");

		/* disable chan to purge rx datas received in TX_ONLY transfer,
		 * otherwise these rx datas will affect the direct following
		 * RX_ONLY transfer.
		 */
		omap2_mcspi_set_enable(spi, 0);
	}
out:
	omap2_mcspi_set_enable(spi, 1);
	return count - c;
}

static u32 omap2_mcspi_calc_divisor(u32 speed_hz)
{
	u32 div;

	for (div = 0; div < 15; div++)
		if (speed_hz >= (OMAP2_MCSPI_MAX_FREQ >> div))
			return div;

	return 15;
}

/* called only when no transfer is active to this device */
static int omap2_mcspi_setup_transfer(struct spi_device *spi,
		struct spi_transfer *t)
{
	struct omap2_mcspi_cs *cs = spi->controller_state;
	struct omap2_mcspi *mcspi;
	struct spi_master *spi_cntrl;
	u32 l = 0, div = 0;
	u8 word_len = spi->bits_per_word;
	u32 speed_hz = spi->max_speed_hz;

	mcspi = spi_master_get_devdata(spi->master);
	spi_cntrl = mcspi->master;

	if (t != NULL && t->bits_per_word)
		word_len = t->bits_per_word;

	cs->word_len = word_len;

	if (t && t->speed_hz)
		speed_hz = t->speed_hz;

	speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
	div = omap2_mcspi_calc_divisor(speed_hz);

	l = mcspi_cached_chconf0(spi);

	/* standard 4-wire master mode:  SCK, MOSI/out, MISO/in, nCS
	 * REVISIT: this controller could support SPI_3WIRE mode.
	 */
	l &= ~(OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE1);
	l |= OMAP2_MCSPI_CHCONF_DPE0;

	/* wordlength */
	l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
	l |= (word_len - 1) << 7;

	/* set chipselect polarity; manage with FORCE */
	if (!(spi->mode & SPI_CS_HIGH))
		l |= OMAP2_MCSPI_CHCONF_EPOL;	/* active-low; normal */
	else
		l &= ~OMAP2_MCSPI_CHCONF_EPOL;

	/* set clock divisor */
	l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
	l |= div << 2;

	/* set SPI mode 0..3 */
	if (spi->mode & SPI_CPOL)
		l |= OMAP2_MCSPI_CHCONF_POL;
	else
		l &= ~OMAP2_MCSPI_CHCONF_POL;
	if (spi->mode & SPI_CPHA)
		l |= OMAP2_MCSPI_CHCONF_PHA;
	else
		l &= ~OMAP2_MCSPI_CHCONF_PHA;

	mcspi_write_chconf0(spi, l);

	dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
			OMAP2_MCSPI_MAX_FREQ >> div,
			(spi->mode & SPI_CPHA) ? "trailing" : "leading",
			(spi->mode & SPI_CPOL) ? "inverted" : "normal");

	return 0;
}

static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
{
	struct spi_device	*spi = data;
	struct omap2_mcspi	*mcspi;
	struct omap2_mcspi_dma	*mcspi_dma;

	mcspi = spi_master_get_devdata(spi->master);
	mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);

	complete(&mcspi_dma->dma_rx_completion);

	/* We must disable the DMA RX request */
	omap2_mcspi_set_dma_req(spi, 1, 0);
}

static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
{
	struct spi_device	*spi = data;
	struct omap2_mcspi	*mcspi;
	struct omap2_mcspi_dma	*mcspi_dma;

	mcspi = spi_master_get_devdata(spi->master);
	mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);

	complete(&mcspi_dma->dma_tx_completion);

	/* We must disable the DMA TX request */
	omap2_mcspi_set_dma_req(spi, 0, 0);
}

static int omap2_mcspi_request_dma(struct spi_device *spi)
{
	struct spi_master	*master = spi->master;
	struct omap2_mcspi	*mcspi;
	struct omap2_mcspi_dma	*mcspi_dma;

	mcspi = spi_master_get_devdata(master);
	mcspi_dma = mcspi->dma_channels + spi->chip_select;

	if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
			omap2_mcspi_dma_rx_callback, spi,
			&mcspi_dma->dma_rx_channel)) {
		dev_err(&spi->dev, "no RX DMA channel for McSPI\n");
		return -EAGAIN;
	}

	if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
			omap2_mcspi_dma_tx_callback, spi,
			&mcspi_dma->dma_tx_channel)) {
		omap_free_dma(mcspi_dma->dma_rx_channel);
		mcspi_dma->dma_rx_channel = -1;
		dev_err(&spi->dev, "no TX DMA channel for McSPI\n");
		return -EAGAIN;
	}

	init_completion(&mcspi_dma->dma_rx_completion);
	init_completion(&mcspi_dma->dma_tx_completion);

	return 0;
}

static int omap2_mcspi_setup(struct spi_device *spi)
{
	int			ret;
	struct omap2_mcspi	*mcspi;
	struct omap2_mcspi_dma	*mcspi_dma;
	struct omap2_mcspi_cs	*cs = spi->controller_state;

	if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
		dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
			spi->bits_per_word);
		return -EINVAL;
	}

	mcspi = spi_master_get_devdata(spi->master);
	mcspi_dma = &mcspi->dma_channels[spi->chip_select];

	if (!cs) {
		cs = kzalloc(sizeof *cs, GFP_KERNEL);
		if (!cs)
			return -ENOMEM;
		cs->base = mcspi->base + spi->chip_select * 0x14;
		cs->phys = mcspi->phys + spi->chip_select * 0x14;
		cs->chconf0 = 0;
		spi->controller_state = cs;
		/* Link this to context save list */
		list_add_tail(&cs->node,
			&omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs);
	}

	if (mcspi_dma->dma_rx_channel == -1
			|| mcspi_dma->dma_tx_channel == -1) {
		ret = omap2_mcspi_request_dma(spi);
		if (ret < 0)
			return ret;
	}

	ret = omap2_mcspi_enable_clocks(mcspi);
	if (ret < 0)
		return ret;

	ret = omap2_mcspi_setup_transfer(spi, NULL);
	omap2_mcspi_disable_clocks(mcspi);

	return ret;
}

static void omap2_mcspi_cleanup(struct spi_device *spi)
{
	struct omap2_mcspi	*mcspi;
	struct omap2_mcspi_dma	*mcspi_dma;
	struct omap2_mcspi_cs	*cs;

	mcspi = spi_master_get_devdata(spi->master);

	if (spi->controller_state) {
		/* Unlink controller state from context save list */
		cs = spi->controller_state;
		list_del(&cs->node);

		kfree(spi->controller_state);
	}

	if (spi->chip_select < spi->master->num_chipselect) {
		mcspi_dma = &mcspi->dma_channels[spi->chip_select];

		if (mcspi_dma->dma_rx_channel != -1) {
			omap_free_dma(mcspi_dma->dma_rx_channel);
			mcspi_dma->dma_rx_channel = -1;
		}
		if (mcspi_dma->dma_tx_channel != -1) {
			omap_free_dma(mcspi_dma->dma_tx_channel);
			mcspi_dma->dma_tx_channel = -1;
		}
	}
}

static void omap2_mcspi_work(struct work_struct *work)
{
	struct omap2_mcspi	*mcspi;

	mcspi = container_of(work, struct omap2_mcspi, work);

	if (omap2_mcspi_enable_clocks(mcspi) < 0)
		return;

	spin_lock_irq(&mcspi->lock);

	/* We only enable one channel at a time -- the one whose message is
	 * at the head of the queue -- although this controller would gladly
	 * arbitrate among multiple channels.  This corresponds to "single
	 * channel" master mode.  As a side effect, we need to manage the
	 * chipselect with the FORCE bit ... CS != channel enable.
	 */
	while (!list_empty(&mcspi->msg_queue)) {
		struct spi_message		*m;
		struct spi_device		*spi;
		struct spi_transfer		*t = NULL;
		int				cs_active = 0;
		struct omap2_mcspi_cs		*cs;
		struct omap2_mcspi_device_config *cd;
		int				par_override = 0;
		int				status = 0;
		u32				chconf;

		m = container_of(mcspi->msg_queue.next, struct spi_message,
				 queue);

		list_del_init(&m->queue);
		spin_unlock_irq(&mcspi->lock);

		spi = m->spi;
		cs = spi->controller_state;
		cd = spi->controller_data;

		omap2_mcspi_set_enable(spi, 1);
		list_for_each_entry(t, &m->transfers, transfer_list) {
			if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
				status = -EINVAL;
				break;
			}
			if (par_override || t->speed_hz || t->bits_per_word) {
				par_override = 1;
				status = omap2_mcspi_setup_transfer(spi, t);
				if (status < 0)
					break;
				if (!t->speed_hz && !t->bits_per_word)
					par_override = 0;
			}

			if (!cs_active) {
				omap2_mcspi_force_cs(spi, 1);
				cs_active = 1;
			}

			chconf = mcspi_cached_chconf0(spi);
			chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
			chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;

			if (t->tx_buf == NULL)
				chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
			else if (t->rx_buf == NULL)
				chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;

			if (cd && cd->turbo_mode && t->tx_buf == NULL) {
				/* Turbo mode is for more than one word */
				if (t->len > ((cs->word_len + 7) >> 3))
					chconf |= OMAP2_MCSPI_CHCONF_TURBO;
			}

			mcspi_write_chconf0(spi, chconf);

			if (t->len) {
				unsigned	count;

				/* RX_ONLY mode needs dummy data in TX reg */
				if (t->tx_buf == NULL)
					__raw_writel(0, cs->base
							+ OMAP2_MCSPI_TX0);

				if (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)
					count = omap2_mcspi_txrx_dma(spi, t);
				else
					count = omap2_mcspi_txrx_pio(spi, t);
				m->actual_length += count;

				if (count != t->len) {
					status = -EIO;
					break;
				}
			}

			if (t->delay_usecs)
				udelay(t->delay_usecs);

			/* ignore the "leave it on after last xfer" hint */
			if (t->cs_change) {
				omap2_mcspi_force_cs(spi, 0);
				cs_active = 0;
			}
		}

		/* Restore defaults if they were overriden */
		if (par_override) {
			par_override = 0;
			status = omap2_mcspi_setup_transfer(spi, NULL);
		}

		if (cs_active)
			omap2_mcspi_force_cs(spi, 0);

		omap2_mcspi_set_enable(spi, 0);

		m->status = status;
		m->complete(m->context);

		spin_lock_irq(&mcspi->lock);
	}

	spin_unlock_irq(&mcspi->lock);

	omap2_mcspi_disable_clocks(mcspi);
}

static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
{
	struct omap2_mcspi	*mcspi;
	unsigned long		flags;
	struct spi_transfer	*t;

	m->actual_length = 0;
	m->status = 0;

	/* reject invalid messages and transfers */
	if (list_empty(&m->transfers) || !m->complete)
		return -EINVAL;
	list_for_each_entry(t, &m->transfers, transfer_list) {
		const void	*tx_buf = t->tx_buf;
		void		*rx_buf = t->rx_buf;
		unsigned	len = t->len;

		if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
				|| (len && !(rx_buf || tx_buf))
				|| (t->bits_per_word &&
					(  t->bits_per_word < 4
					|| t->bits_per_word > 32))) {
			dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
					t->speed_hz,
					len,
					tx_buf ? "tx" : "",
					rx_buf ? "rx" : "",
					t->bits_per_word);
			return -EINVAL;
		}
		if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
			dev_dbg(&spi->dev, "speed_hz %d below minimum %d Hz\n",
				t->speed_hz,
				OMAP2_MCSPI_MAX_FREQ >> 15);
			return -EINVAL;
		}

		if (m->is_dma_mapped || len < DMA_MIN_BYTES)
			continue;

		if (tx_buf != NULL) {
			t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf,
					len, DMA_TO_DEVICE);
			if (dma_mapping_error(&spi->dev, t->tx_dma)) {
				dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
						'T', len);
				return -EINVAL;
			}
		}
		if (rx_buf != NULL) {
			t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len,
					DMA_FROM_DEVICE);
			if (dma_mapping_error(&spi->dev, t->rx_dma)) {
				dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
						'R', len);
				if (tx_buf != NULL)
					dma_unmap_single(&spi->dev, t->tx_dma,
							len, DMA_TO_DEVICE);
				return -EINVAL;
			}
		}
	}

	mcspi = spi_master_get_devdata(spi->master);

	spin_lock_irqsave(&mcspi->lock, flags);
	list_add_tail(&m->queue, &mcspi->msg_queue);
	queue_work(mcspi->wq, &mcspi->work);
	spin_unlock_irqrestore(&mcspi->lock, flags);

	return 0;
}

static int __init omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
{
	struct spi_master	*master = mcspi->master;
	u32			tmp;
	int ret = 0;

	ret = omap2_mcspi_enable_clocks(mcspi);
	if (ret < 0)
		return ret;

	tmp = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
	mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, tmp);
	omap2_mcspi_ctx[master->bus_num - 1].wakeupenable = tmp;

	omap2_mcspi_set_master_mode(master);
	omap2_mcspi_disable_clocks(mcspi);
	return 0;
}

static int omap_mcspi_runtime_resume(struct device *dev)
{
	struct omap2_mcspi	*mcspi;
	struct spi_master	*master;

	master = dev_get_drvdata(dev);
	mcspi = spi_master_get_devdata(master);
	omap2_mcspi_restore_ctx(mcspi);

	return 0;
}

static struct omap2_mcspi_platform_config omap2_pdata = {
	.regs_offset = 0,
};

static struct omap2_mcspi_platform_config omap4_pdata = {
	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
};

static const struct of_device_id omap_mcspi_of_match[] = {
	{
		.compatible = "ti,omap2-mcspi",
		.data = &omap2_pdata,
	},
	{
		.compatible = "ti,omap4-mcspi",
		.data = &omap4_pdata,
	},
	{ },
};
MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);

static int __init omap2_mcspi_probe(struct platform_device *pdev)
{
	struct spi_master	*master;
	struct omap2_mcspi_platform_config *pdata;
	struct omap2_mcspi	*mcspi;
	struct resource		*r;
	int			status = 0, i;
	char			wq_name[20];
	u32			regs_offset = 0;
	static int		bus_num = 1;
	struct device_node	*node = pdev->dev.of_node;
	const struct of_device_id *match;

	master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
	if (master == NULL) {
		dev_dbg(&pdev->dev, "master allocation failed\n");
		return -ENOMEM;
	}

	/* the spi->mode bits understood by this driver: */
	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;

	master->setup = omap2_mcspi_setup;
	master->transfer = omap2_mcspi_transfer;
	master->cleanup = omap2_mcspi_cleanup;
	master->dev.of_node = node;

	match = of_match_device(omap_mcspi_of_match, &pdev->dev);
	if (match) {
		u32 num_cs = 1; /* default number of chipselect */
		pdata = match->data;

		of_property_read_u32(node, "ti,spi-num-cs", &num_cs);
		master->num_chipselect = num_cs;
		master->bus_num = bus_num++;
	} else {
		pdata = pdev->dev.platform_data;
		master->num_chipselect = pdata->num_cs;
		if (pdev->id != -1)
			master->bus_num = pdev->id;
	}
	regs_offset = pdata->regs_offset;

	dev_set_drvdata(&pdev->dev, master);

	mcspi = spi_master_get_devdata(master);
	mcspi->master = master;

	sprintf(wq_name, "omap2_mcspi/%d", master->bus_num);
	mcspi->wq = alloc_workqueue(wq_name, WQ_MEM_RECLAIM, 1);
	if (mcspi->wq == NULL) {
		status = -ENOMEM;
		goto free_master;
	}

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (r == NULL) {
		status = -ENODEV;
		goto free_master;
	}

	r->start += regs_offset;
	r->end += regs_offset;
	mcspi->phys = r->start;
	if (!request_mem_region(r->start, resource_size(r),
				dev_name(&pdev->dev))) {
		status = -EBUSY;
		goto free_master;
	}

	mcspi->base = ioremap(r->start, resource_size(r));
	if (!mcspi->base) {
		dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
		status = -ENOMEM;
		goto release_region;
	}

	mcspi->dev = &pdev->dev;
	INIT_WORK(&mcspi->work, omap2_mcspi_work);

	spin_lock_init(&mcspi->lock);
	INIT_LIST_HEAD(&mcspi->msg_queue);
	INIT_LIST_HEAD(&omap2_mcspi_ctx[master->bus_num - 1].cs);

	mcspi->dma_channels = kcalloc(master->num_chipselect,
			sizeof(struct omap2_mcspi_dma),
			GFP_KERNEL);

	if (mcspi->dma_channels == NULL)
		goto unmap_io;

	for (i = 0; i < master->num_chipselect; i++) {
		char dma_ch_name[14];
		struct resource *dma_res;

		sprintf(dma_ch_name, "rx%d", i);
		dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
							dma_ch_name);
		if (!dma_res) {
			dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
			status = -ENODEV;
			break;
		}

		mcspi->dma_channels[i].dma_rx_channel = -1;
		mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
		sprintf(dma_ch_name, "tx%d", i);
		dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
							dma_ch_name);
		if (!dma_res) {
			dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
			status = -ENODEV;
			break;
		}

		mcspi->dma_channels[i].dma_tx_channel = -1;
		mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start;
	}

	if (status < 0)
		goto dma_chnl_free;

	pm_runtime_enable(&pdev->dev);

	if (status || omap2_mcspi_master_setup(mcspi) < 0)
		goto disable_pm;

	status = spi_register_master(master);
	if (status < 0)
		goto err_spi_register;

	return status;

err_spi_register:
	spi_master_put(master);
disable_pm:
	pm_runtime_disable(&pdev->dev);
dma_chnl_free:
	kfree(mcspi->dma_channels);
unmap_io:
	iounmap(mcspi->base);
release_region:
	release_mem_region(r->start, resource_size(r));
free_master:
	kfree(master);
	platform_set_drvdata(pdev, NULL);
	return status;
}

static int __exit omap2_mcspi_remove(struct platform_device *pdev)
{
	struct spi_master	*master;
	struct omap2_mcspi	*mcspi;
	struct omap2_mcspi_dma	*dma_channels;
	struct resource		*r;
	void __iomem *base;

	master = dev_get_drvdata(&pdev->dev);
	mcspi = spi_master_get_devdata(master);
	dma_channels = mcspi->dma_channels;

	omap2_mcspi_disable_clocks(mcspi);
	pm_runtime_disable(&pdev->dev);
	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	release_mem_region(r->start, resource_size(r));

	base = mcspi->base;
	spi_unregister_master(master);
	iounmap(base);
	kfree(dma_channels);
	destroy_workqueue(mcspi->wq);
	platform_set_drvdata(pdev, NULL);

	return 0;
}

/* work with hotplug and coldplug */
MODULE_ALIAS("platform:omap2_mcspi");

#ifdef	CONFIG_SUSPEND
/*
 * When SPI wake up from off-mode, CS is in activate state. If it was in
 * unactive state when driver was suspend, then force it to unactive state at
 * wake up.
 */
static int omap2_mcspi_resume(struct device *dev)
{
	struct spi_master	*master = dev_get_drvdata(dev);
	struct omap2_mcspi	*mcspi = spi_master_get_devdata(master);
	struct omap2_mcspi_cs *cs;

	omap2_mcspi_enable_clocks(mcspi);
	list_for_each_entry(cs, &omap2_mcspi_ctx[master->bus_num - 1].cs,
			    node) {
		if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {

			/*
			 * We need to toggle CS state for OMAP take this
			 * change in account.
			 */
			MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1);
			__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
			MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0);
			__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
		}
	}
	omap2_mcspi_disable_clocks(mcspi);
	return 0;
}
#else
#define	omap2_mcspi_resume	NULL
#endif

static const struct dev_pm_ops omap2_mcspi_pm_ops = {
	.resume = omap2_mcspi_resume,
	.runtime_resume	= omap_mcspi_runtime_resume,
};

static struct platform_driver omap2_mcspi_driver = {
	.driver = {
		.name =		"omap2_mcspi",
		.owner =	THIS_MODULE,
		.pm =		&omap2_mcspi_pm_ops,
		.of_match_table = omap_mcspi_of_match,
	},
	.remove =	__exit_p(omap2_mcspi_remove),
};

static int __init omap2_mcspi_init(void)
{
	return platform_driver_probe(&omap2_mcspi_driver, omap2_mcspi_probe);
}
subsys_initcall(omap2_mcspi_init);

static void __exit omap2_mcspi_exit(void)
{
	platform_driver_unregister(&omap2_mcspi_driver);

}
module_exit(omap2_mcspi_exit);

MODULE_LICENSE("GPL");


function Install-RSAT {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$False)]
        [string]$DownloadDirectory = "$HOME\Downloads",

        [Parameter(Mandatory=$False)]
        [switch]$AllowRestart,

        [Parameter(Mandatory=$False)]
        [switch]$Force
    )

    Write-Host "Please wait..."

    if (!$(Get-Module -ListAvailable -Name ActiveDirectory) -or $Force) {
        $OSInfo = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
        $OSCimInfo = Get-CimInstance Win32_OperatingSystem
        $OSArchitecture = $OSCimInfo.OSArchitecture

        if ([version]$OSCimInfo.Version -lt [version]"6.3") {
            Write-Error "This function only handles RSAT Installation for Windows 8.1 and higher! Halting!"
            $global:FunctionResult = "1"
            return
        }

        if ($OSInfo.ProductName -notlike "*Server*") {
            $KBCheck = [bool]$(Get-WmiObject -query 'select * from win32_quickfixengineering' | Where-Object {
                $_.HotFixID -eq 'KB958830' -or $_.HotFixID -eq 'KB2693643'
            })

            if (!$KBCheck -or $Force) {
                if ($([version]$OSCimInfo.Version).Major -lt 10 -and [version]$OSCimInfo.Version -ge [version]"6.3") {
                    if ($OSArchitecture -eq "64-bit") {
                        $OutFileName = "Windows8.1-KB2693643-x64.msu"
                    }
                    if ($OSArchitecture -eq "32-bit") {
                        $OutFileName = "Windows8.1-KB2693643-x86.msu"
                    }

                    $DownloadUrl = "https://download.microsoft.com/download/1/8/E/18EA4843-C596-4542-9236-DE46F780806E/$OutFileName"
                }
                if ($([version]$OSCimInfo.Version).Major -ge 10) {
                    if ([int]$OSInfo.ReleaseId -ge 1803) {
                        if ($OSArchitecture -eq "64-bit") {
                            $OutFileName = "WindowsTH-RSAT_WS_1803-x64.msu"
                        }
                        if ($OSArchitecture -eq "32-bit") {
                            $OutFileName = "WindowsTH-RSAT_WS_1803-x86.msu"
                        }
                    }
                    if ([int]$OSInfo.ReleaseId -ge 1709 -and [int]$OSInfo.ReleaseId -lt 1803) {
                        if ($OSArchitecture -eq "64-bit") {
                            $OutFileName = "WindowsTH-RSAT_WS_1709-x64.msu"
                        }
                        if ($OSArchitecture -eq "32-bit") {
                            $OutFileName = "WindowsTH-RSAT_WS_1709-x86.msu"
                        }
                    }
                    if ([int]$OSInfo.ReleaseId -lt 1709) {
                        if ($OSArchitecture -eq "64-bit") {
                            $OutFileName = "WindowsTH-RSAT_WS2016-x64.msu"
                        }
                        if ($OSArchitecture -eq "32-bit") {
                            $OutFileName = "WindowsTH-RSAT_WS2016-x86.msu"
                        }
                    }

                    $DownloadUrl = "https://download.microsoft.com/download/1/D/8/1D8B5022-5477-4B9A-8104-6A71FF9D98AB/$OutFileName"
                }

                try {
                    # Make sure the Url exists...
                    $HTTP_Request = [System.Net.WebRequest]::Create($DownloadUrl)
                    $HTTP_Response = $HTTP_Request.GetResponse()
                }
                catch {
                    Write-Error $_
                    $global:FunctionResult = "1"
                    return
                }

                try {
                    # Download via System.Net.WebClient is a lot faster than Invoke-WebRequest...
                    $WebClient = [System.Net.WebClient]::new()
                    $WebClient.Downloadfile($DownloadUrl, "$DownloadDirectory\$OutFileName")
                }
                catch {
                    Write-Error $_
                    $global:FunctionResult = "1"
                    return
                }

                Write-Host "Beginning installation..."
                if ($AllowRestart) {
                    $Arguments = "`"$DownloadDirectory\$OutFileName`" /quiet /log:`"$DownloadDirectory\wusaRSATInstall.log`""
                }
                else {
                    $Arguments = "`"$DownloadDirectory\$OutFileName`" /quiet /norestart /log:`"$DownloadDirectory\wusaRSATInstall.log`""
                }
                #Start-Process -FilePath $(Get-Command wusa.exe).Source -ArgumentList "`"$DownloadDirectory\$OutFileName`" /quiet /log:`"$DownloadDirectory\wusaRSATInstall.log`"" -NoNewWindow -Wait

                $ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
                #$ProcessInfo.WorkingDirectory = $BinaryPath | Split-Path -Parent
                $ProcessInfo.FileName = $(Get-Command wusa.exe).Source
                $ProcessInfo.RedirectStandardError = $true
                $ProcessInfo.RedirectStandardOutput = $true
                #$ProcessInfo.StandardOutputEncoding = [System.Text.Encoding]::Unicode
                #$ProcessInfo.StandardErrorEncoding = [System.Text.Encoding]::Unicode
                $ProcessInfo.UseShellExecute = $false
                $ProcessInfo.Arguments = $Arguments
                $Process = New-Object System.Diagnostics.Process
                $Process.StartInfo = $ProcessInfo
                $Process.Start() | Out-Null
                # Below $FinishedInAlottedTime returns boolean true/false
                # Wait 20 seconds for wusa to finish...
                $FinishedInAlottedTime = $Process.WaitForExit(20000)
                if (!$FinishedInAlottedTime) {
                    $Process.Kill()
                }
                $stdout = $Process.StandardOutput.ReadToEnd()
                $stderr = $Process.StandardError.ReadToEnd()
                $AllOutput = $stdout + $stderr

                # Check the log to make sure there weren't any errors
                # NOTE: Get-WinEvent cmdlet does NOT work consistently on all Windows Operating Systems...
                Write-Host "Reviewing wusa.exe logs..."
                $EventLogReader = [System.Diagnostics.Eventing.Reader.EventLogReader]::new("$DownloadDirectory\wusaRSATInstall.log", [System.Diagnostics.Eventing.Reader.PathType]::FilePath)
                [System.Collections.ArrayList]$EventsFromLog = @()

                $Event = $EventLogReader.ReadEvent()
                $null = $EventsFromLog.Add($Event)
                while ($Event -ne $null) {
                    $Event = $EventLogReader.ReadEvent()
                    $null = $EventsFromLog.Add($Event)
                }

                if ($EventsFromLog.LevelDisplayName -contains "Error") {
                    $ErrorRecord = $EventsFromLog | Where-Object {$_.LevelDisplayName -eq "Error"}
                    $ProblemDetails = $ErrorRecord.Properties.Value | Where-Object {$_ -match "[\w]"}
                    $ProblemDetailsString = $ProblemDetails[0..$($ProblemDetails.Count-2)] -join ": "

                    $ErrMsg = "wusa.exe failed to install '$DownloadDirectory\$OutFileName' due to '$ProblemDetailsString'. " +
                    "This could be because of a pending restart. Please restart $env:ComputerName and try the Install-RSAT function again."
                    Write-Error $ErrMsg
                    $global:FunctionResult = "1"
                    return
                }

                if ($AllowRestart) {
                    Restart-Computer -Confirm:$false -Force
                }
                else{
                    $Output = "RestartNeeded"
                }
            }
        }
        if ($OSInfo.ProductName -like "*Server*") {
            #Import-Module ServerManager
            if (!$(Get-WindowsFeature RSAT-AD-Tools).Installed) {
                Write-Host "Beginning installation..."
                if ($AllowRestart) {
                    Install-WindowsFeature -Name RSAT -IncludeAllSubFeature -IncludeManagementTools -Restart
                }
                else {
                    Install-WindowsFeature -Name RSAT -IncludeAllSubFeature -IncludeManagementTools
                    $Output = "RestartNeeded"
                }
            }
        }
    }
    else {
        Write-Warning "RSAT is already installed! No action taken."
    }

    if ($Output -eq "RestartNeeded") {
        Write-Warning "You must restart your computer in order to finish RSAT installation."
    }

    $Output
}

# SIG # Begin signature block
# MIIMiAYJKoZIhvcNAQcCoIIMeTCCDHUCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUwiTlQ0TxzdhgBpKbXmxJNTNE
# C/Kgggn9MIIEJjCCAw6gAwIBAgITawAAAB/Nnq77QGja+wAAAAAAHzANBgkqhkiG
# 9w0BAQsFADAwMQwwCgYDVQQGEwNMQUIxDTALBgNVBAoTBFpFUk8xETAPBgNVBAMT
# CFplcm9EQzAxMB4XDTE3MDkyMDIxMDM1OFoXDTE5MDkyMDIxMTM1OFowPTETMBEG
# CgmSJomT8ixkARkWA0xBQjEUMBIGCgmSJomT8ixkARkWBFpFUk8xEDAOBgNVBAMT
# B1plcm9TQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCwqv+ROc1
# bpJmKx+8rPUUfT3kPSUYeDxY8GXU2RrWcL5TSZ6AVJsvNpj+7d94OEmPZate7h4d
# gJnhCSyh2/3v0BHBdgPzLcveLpxPiSWpTnqSWlLUW2NMFRRojZRscdA+e+9QotOB
# aZmnLDrlePQe5W7S1CxbVu+W0H5/ukte5h6gsKa0ktNJ6X9nOPiGBMn1LcZV/Ksl
# lUyuTc7KKYydYjbSSv2rQ4qmZCQHqxyNWVub1IiEP7ClqCYqeCdsTtfw4Y3WKxDI
# JaPmWzlHNs0nkEjvnAJhsRdLFbvY5C2KJIenxR0gA79U8Xd6+cZanrBUNbUC8GCN
# wYkYp4A4Jx+9AgMBAAGjggEqMIIBJjASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsG
# AQQBgjcVAgQWBBQ/0jsn2LS8aZiDw0omqt9+KWpj3DAdBgNVHQ4EFgQUicLX4r2C
# Kn0Zf5NYut8n7bkyhf4wGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwDgYDVR0P
# AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUdpW6phL2RQNF
# 7AZBgQV4tgr7OE0wMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL3BraS9jZXJ0ZGF0
# YS9aZXJvREMwMS5jcmwwPAYIKwYBBQUHAQEEMDAuMCwGCCsGAQUFBzAChiBodHRw
# Oi8vcGtpL2NlcnRkYXRhL1plcm9EQzAxLmNydDANBgkqhkiG9w0BAQsFAAOCAQEA
# tyX7aHk8vUM2WTQKINtrHKJJi29HaxhPaHrNZ0c32H70YZoFFaryM0GMowEaDbj0
# a3ShBuQWfW7bD7Z4DmNc5Q6cp7JeDKSZHwe5JWFGrl7DlSFSab/+a0GQgtG05dXW
# YVQsrwgfTDRXkmpLQxvSxAbxKiGrnuS+kaYmzRVDYWSZHwHFNgxeZ/La9/8FdCir
# MXdJEAGzG+9TwO9JvJSyoGTzu7n93IQp6QteRlaYVemd5/fYqBhtskk1zDiv9edk
# mHHpRWf9Xo94ZPEy7BqmDuixm4LdmmzIcFWqGGMo51hvzz0EaE8K5HuNvNaUB/hq
# MTOIB5145K8bFOoKHO4LkTCCBc8wggS3oAMCAQICE1gAAAH5oOvjAv3166MAAQAA
# AfkwDQYJKoZIhvcNAQELBQAwPTETMBEGCgmSJomT8ixkARkWA0xBQjEUMBIGCgmS
# JomT8ixkARkWBFpFUk8xEDAOBgNVBAMTB1plcm9TQ0EwHhcNMTcwOTIwMjE0MTIy
# WhcNMTkwOTIwMjExMzU4WjBpMQswCQYDVQQGEwJVUzELMAkGA1UECBMCUEExFTAT
# BgNVBAcTDFBoaWxhZGVscGhpYTEVMBMGA1UEChMMRGlNYWdnaW8gSW5jMQswCQYD
# VQQLEwJJVDESMBAGA1UEAxMJWmVyb0NvZGUyMIIBIjANBgkqhkiG9w0BAQEFAAOC
# AQ8AMIIBCgKCAQEAxX0+4yas6xfiaNVVVZJB2aRK+gS3iEMLx8wMF3kLJYLJyR+l
# rcGF/x3gMxcvkKJQouLuChjh2+i7Ra1aO37ch3X3KDMZIoWrSzbbvqdBlwax7Gsm
# BdLH9HZimSMCVgux0IfkClvnOlrc7Wpv1jqgvseRku5YKnNm1JD+91JDp/hBWRxR
# 3Qg2OR667FJd1Q/5FWwAdrzoQbFUuvAyeVl7TNW0n1XUHRgq9+ZYawb+fxl1ruTj
# 3MoktaLVzFKWqeHPKvgUTTnXvEbLh9RzX1eApZfTJmnUjBcl1tCQbSzLYkfJlJO6
# eRUHZwojUK+TkidfklU2SpgvyJm2DhCtssFWiQIDAQABo4ICmjCCApYwDgYDVR0P
# AQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBS5d2bhatXq
# eUDFo9KltQWHthbPKzAfBgNVHSMEGDAWgBSJwtfivYIqfRl/k1i63yftuTKF/jCB
# 6QYDVR0fBIHhMIHeMIHboIHYoIHVhoGubGRhcDovLy9DTj1aZXJvU0NBKDEpLENO
# PVplcm9TQ0EsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNl
# cnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9emVybyxEQz1sYWI/Y2VydGlmaWNh
# dGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlv
# blBvaW50hiJodHRwOi8vcGtpL2NlcnRkYXRhL1plcm9TQ0EoMSkuY3JsMIHmBggr
# BgEFBQcBAQSB2TCB1jCBowYIKwYBBQUHMAKGgZZsZGFwOi8vL0NOPVplcm9TQ0Es
# Q049QUlBLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENO
# PUNvbmZpZ3VyYXRpb24sREM9emVybyxEQz1sYWI/Y0FDZXJ0aWZpY2F0ZT9iYXNl
# P29iamVjdENsYXNzPWNlcnRpZmljYXRpb25BdXRob3JpdHkwLgYIKwYBBQUHMAKG
# Imh0dHA6Ly9wa2kvY2VydGRhdGEvWmVyb1NDQSgxKS5jcnQwPQYJKwYBBAGCNxUH
# BDAwLgYmKwYBBAGCNxUIg7j0P4Sb8nmD8Y84g7C3MobRzXiBJ6HzzB+P2VUCAWQC
# AQUwGwYJKwYBBAGCNxUKBA4wDDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOC
# AQEAszRRF+YTPhd9UbkJZy/pZQIqTjpXLpbhxWzs1ECTwtIbJPiI4dhAVAjrzkGj
# DyXYWmpnNsyk19qE82AX75G9FLESfHbtesUXnrhbnsov4/D/qmXk/1KD9CE0lQHF
# Lu2DvOsdf2mp2pjdeBgKMRuy4cZ0VCc/myO7uy7dq0CvVdXRsQC6Fqtr7yob9NbE
# OdUYDBAGrt5ZAkw5YeL8H9E3JLGXtE7ir3ksT6Ki1mont2epJfHkO5JkmOI6XVtg
# anuOGbo62885BOiXLu5+H2Fg+8ueTP40zFhfLh3e3Kj6Lm/NdovqqTBAsk04tFW9
# Hp4gWfVc0gTDwok3rHOrfIY35TGCAfUwggHxAgEBMFQwPTETMBEGCgmSJomT8ixk
# ARkWA0xBQjEUMBIGCgmSJomT8ixkARkWBFpFUk8xEDAOBgNVBAMTB1plcm9TQ0EC
# E1gAAAH5oOvjAv3166MAAQAAAfkwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwx
# CjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGC
# NwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFCPCH0kfwGabgI71
# zMGcTSAm2/rHMA0GCSqGSIb3DQEBAQUABIIBAIhqqLqnSSZu/q6CWOHACp9hbHu6
# jQlseRenv4xwvy6wsyp+uxOHyOtfO7S5q7zgq4JTKqeTY825GGkmtFFxUcNSYELF
# l8PedBEJ/FHejOPF9PeKyT+fw2DlSwjO1Qj9spzKTKaogU/t4I7ed2WHsfeQriGg
# G1muByYMiaGiwT68qL5vdAs10MAW4b4fRyv/C2UTphHhGOAHV0p/AF9oIkFBI/8v
# YZR+hNwHUpqnYg3N1jvcTkfx0b91xGWU7YD8t62bSUYX71i8LNdaKDQD3Wc/4MJN
# TwAiIgTjobp/GE5rLurDNWoJdDsfk79uxUUu/HVXAn+GtWsKfs/Xt13ZjSY=
# SIG # End signature block


using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Shop.Infrastructure;
using Shop.Infrastructure.Data;
using Shop.Module.Core.Abstractions.Extensions;
using Shop.Module.ShoppingCart.Abstractions.Entities;
using Shop.Module.ShoppingCart.Abstractions.Services;
using Shop.Module.ShoppingCart.Abstractions.ViewModels;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace Shop.Module.ShoppingCart.Controllers
{
    [Authorize()]
    [Route("api/cart")]
    public class CartApiController : ControllerBase
    {
        private readonly IRepository<CartItem> _cartItemRepository;
        private readonly ICartService _cartService;
        private readonly IWorkContext _workContext;

        public CartApiController(
            IRepository<CartItem> cartItemRepository,
            ICartService cartService,
            IWorkContext workContext)
        {
            _cartItemRepository = cartItemRepository;
            _cartService = cartService;
            _workContext = workContext;
        }

        [HttpGet()]
        [AllowAnonymous]
        public async Task<Result> List()
        {
            var user = await _workContext.GetCurrentUserOrNullAsync();
            var cart = new CartResult();
            if (user != null)
            {
                cart = await _cartService.GetActiveCartDetails(user.Id);
            }
            return Result.Ok(cart);
        }

        [HttpPost("add-item")]
        public async Task<Result> AddToCart([FromBody]AddToCartParam model)
        {
            var currentUser = await _workContext.GetCurrentUserAsync();
            await _cartService.AddToCart(currentUser.Id, model.ProductId, model.Quantity);
            var cart = await _cartService.GetActiveCartDetails(currentUser.Id);
            return Result.Ok(cart);
        }

        [HttpPut("update-item-quantity")]
        public async Task<Result> UpdateItemQuantity([FromBody]AddToCartParam model)
        {
            var currentUser = await _workContext.GetCurrentUserAsync();
            await _cartService.UpdateItemQuantity(currentUser.Id, currentUser.Id, model.ProductId, model.Quantity);
            var cart = await _cartService.GetActiveCartDetails(currentUser.Id);
            return Result.Ok(cart);
        }

        [HttpPut("checked")]
        public async Task<Result> CheckedItem([FromBody]CheckedItemParam model)
        {
            var currentUser = await _workContext.GetCurrentUserAsync();
            await _cartService.CheckedItem(currentUser.Id, model);
            var cart = await _cartService.GetActiveCartDetails(currentUser.Id);
            return Result.Ok(cart);
        }

        [HttpDelete("remove-items")]
        public async Task<Result> Remove([FromBody]DeleteItemParam model)
        {
            var currentUser = await _workContext.GetCurrentUserAsync();
            var cartItems = _cartItemRepository.Query().Where(x => model.ProductIds.Contains(x.ProductId) && x.Cart.CustomerId == currentUser.Id).ToList();
            foreach (var item in cartItems)
            {
                item.IsDeleted = true;
                item.UpdatedOn = DateTime.Now;
                _cartItemRepository.SaveChanges();
            }
            var cart = await _cartService.GetActiveCartDetails(currentUser.Id);
            return Result.Ok(cart);
        }

        //[HttpGet("api/customers/{customerId}/cart")]
        //public async Task<IActionResult> List(long customerId)
        //{
        //    var currentUser = await _workContext.GetCurrentUser();
        //    var cart = await _cartService.GetActiveCartDetails(customerId, currentUser.Id);

        //    return Json(cart);
        //}

        //[HttpPost("api/customers/{customerId}/add-cart-item")]
        //public async Task<IActionResult> AddToCart(long customerId, [FromBody] AddToCartModel model)
        //{
        //    var currentUser = await _workContext.GetCurrentUser();
        //    await _cartService.AddToCart(customerId, currentUser.Id, model.ProductId, model.Quantity);

        //    return Accepted();
        //}

        //[HttpPut("api/carts/items/{itemId}")]
        //public async Task<IActionResult> UpdateQuantity(long itemId, [FromBody] CartQuantityUpdate model)
        //{
        //    var currentUser = await _workContext.GetCurrentUser();
        //    var cartItem = _cartItemRepository.Query().FirstOrDefault(x => x.Id == itemId && x.Cart.CreatedById == currentUser.Id);
        //    if (cartItem == null)
        //    {
        //        return NotFound();
        //    }

        //    cartItem.Quantity = model.Quantity;
        //    _cartItemRepository.SaveChanges();

        //    return Accepted();
        //}

        //[HttpPost("api/carts/{cartId}/apply-coupon")]
        //public async Task<ActionResult> ApplyCoupon(long cartId, [FromBody] ApplyCouponForm model)
        //{
        //    var currentUser = await _workContext.GetCurrentUser();
        //    var cart = await _cartService.Query().FirstOrDefaultAsync(x => x.Id == cartId && x.CreatedById == currentUser.Id);
        //    if (cart == null)
        //    {
        //        return NotFound();
        //    }

        //    var validationResult = await _cartService.ApplyCoupon(cart.Id, model.CouponCode);
        //    if (validationResult.Succeeded)
        //    {
        //        var cartVm = await _cartService.GetActiveCartDetails(currentUser.Id);
        //        return Json(cartVm);
        //    }

        //    return Json(validationResult);
        //}

        //[HttpPost("api/carts/{cartId}/save-ordernote")]
        //public async Task<IActionResult> SaveOrderNote(long cartId, [FromBody] SaveOrderNote model)
        //{
        //    var currentUser = await _workContext.GetCurrentUser();
        //    var cart = await _cartService.Query().FirstOrDefaultAsync(x => x.Id == cartId && x.CreatedById == currentUser.Id);
        //    if (cart == null)
        //    {
        //        return NotFound();
        //    }

        //    cart.OrderNote = model.OrderNote;
        //    await _cartItemRepository.SaveChangesAsync();
        //    return Accepted();
        //}

        //[HttpDelete("api/carts/items/{itemId}")]
        //public async Task<IActionResult> Remove(long itemId)
        //{
        //    var currentUser = await _workContext.GetCurrentUser();
        //    var cartItem = _cartItemRepository.Query().FirstOrDefault(x => x.Id == itemId && x.Cart.CreatedById == currentUser.Id);
        //    if (cartItem == null)
        //    {
        //        return NotFound();
        //    }

        //    _cartItemRepository.Remove(cartItem);
        //    _cartItemRepository.SaveChanges();

        //    return NoContent();
        //}
    }
}


/*
Copyright 2016 Avraham Weinstock

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

use std::error::Error;

pub fn err(s: &str) -> Box<Error> {
    Box::<Error + Send + Sync>::from(s)
}

/// Trait for clipboard access
pub trait ClipboardProvider: Sized {
    /// Create a context with which to access the clipboard
    // TODO: consider replacing Box<Error> with an associated type?
    fn new() -> Result<Self, Box<Error>>;
    /// Method to get the clipboard contents as a String
    fn get_contents(&mut self) -> Result<String, Box<Error>>;
    /// Method to set the clipboard contents as a String
    fn set_contents(&mut self, String) -> Result<(), Box<Error>>;
    // TODO: come up with some platform-agnostic API for richer types
    // than just strings (c.f. issue #31)
}


#!/bin/bash
set -e

case "$1" in
	java8)
		 echo "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u265-b01/OpenJDK8U-jdk_x64_linux_hotspot_8u265b01.tar.gz"
	;;
	java11)
		 echo "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.8%2B10/OpenJDK11U-jdk_x64_linux_hotspot_11.0.8_10.tar.gz"
	;;
	java15)
		 echo "https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15%2B36/OpenJDK15U-jdk_x64_linux_hotspot_15_36.tar.gz"
	;;
  *)
		echo $"Unknown java version"
		exit 1
esac


File: kt3444_ReturnFromLocalFunctions.kt - a7d490d50cbeac180acf743f93e5cd70
  packageHeader
    PACKAGE("package")
    identifier
      simpleIdentifier
        Identifier("f")
    semi
      NL("\n")
      NL("\n")
      NL("\n")
      NL("\n")
      NL("\n")
  importList
  topLevelObject
    declaration
      functionDeclaration
        FUN("fun")
        simpleIdentifier
          Identifier("box")
        functionValueParameters
          LPAREN("(")
          RPAREN(")")
        COLON(":")
        type
          typeReference
            userType
              simpleUserType
                simpleIdentifier
                  Identifier("Int")
        functionBody
          block
            LCURL("{")
            NL("\n")
            NL("\n")
            statements
              statement
                declaration
                  functionDeclaration
                    FUN("fun")
                    simpleIdentifier
                      Identifier("local")
                    functionValueParameters
                      LPAREN("(")
                      RPAREN(")")
                    COLON(":")
                    type
                      typeReference
                        userType
                          simpleUserType
                            simpleIdentifier
                              Identifier("Int")
                    functionBody
                      block
                        LCURL("{")
                        NL("\n")
                        statements
                        RCURL("}")
              semis
                NL("\n")
                NL("\n")
              statement
                expression
                  disjunction
                    conjunction
                      equality
                        comparison
                          genericCallLikeComparison
                            infixOperation
                              elvisExpression
                                infixFunctionCall
                                  rangeExpression
                                    additiveExpression
                                      multiplicativeExpression
                                        asExpression
                                          prefixUnaryExpression
                                            postfixUnaryExpression
                                              primaryExpression
                                                jumpExpression
                                                  RETURN("return")
                                                  expression
                                                    disjunction
                                                      conjunction
                                                        equality
                                                          comparison
                                                            genericCallLikeComparison
                                                              infixOperation
                                                                elvisExpression
                                                                  infixFunctionCall
                                                                    rangeExpression
                                                                      additiveExpression
                                                                        multiplicativeExpression
                                                                          asExpression
                                                                            prefixUnaryExpression
                                                                              postfixUnaryExpression
                                                                                primaryExpression
                                                                                simpleIdentifier
                                                                                Identifier("local")
                                                              callSuffix
                                                                valueArguments
                                                                  LPAREN("(")
                                                                  RPAREN(")")
              semis
                NL("\n")
            RCURL("}")
    semis
      NL("\n")
      NL("\n")
  topLevelObject
    declaration
      functionDeclaration
        FUN("fun")
        simpleIdentifier
          Identifier("main")
        functionValueParameters
          LPAREN("(")
          RPAREN(")")
        functionBody
          block
            LCURL("{")
            NL("\n")
            statements
              statement
                expression
                  disjunction
                    conjunction
                      equality
                        comparison
                          genericCallLikeComparison
                            infixOperation
                              elvisExpression
                                infixFunctionCall
                                  rangeExpression
                                    additiveExpression
                                      multiplicativeExpression
                                        asExpression
                                          prefixUnaryExpression
                                            postfixUnaryExpression
                                              primaryExpression
                                                simpleIdentifier
                                                  Identifier("box")
                            callSuffix
                              valueArguments
                                LPAREN("(")
                                RPAREN(")")
              semis
                NL("\n")
            RCURL("}")
    semis
      NL("\n")
      NL("\n")
  EOF("<EOF>")


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.opengis.net/swe/1.0.1" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:swe="http://www.opengis.net/swe/1.0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0.1">
	<xs:annotation>
		<xs:documentation>Schema for defining different types of curves based on aggregate data types

				Copyright (c) 2007 OGC, All Rights Reserved.
				For conditions, see OGC Software Notice - http://www.opengeospatial.org/legal/
		</xs:documentation>
	</xs:annotation>
	<!-- ================================================= -->
	<xs:import namespace="http://www.opengis.net/gml" schemaLocation="../../gml/3.1.1/base/gml.xsd"/>
	<xs:include schemaLocation="./aggregateTypes.xsd"/>
	<!-- ================================================= -->
	<!--                  Curve Components                 -->
	<!-- ================================================= -->
	<xs:element name="Curve" type="swe:CurveType" substitutionGroup="swe:AbstractDataArray">
		<xs:annotation>
			<xs:documentation>Curve describing variations of a parameter vs. another quantity</xs:documentation>
		</xs:annotation>
	</xs:element>
	<!-- ........ -->
	<xs:complexType name="CurveType">
		<xs:complexContent>
			<xs:extension base="swe:AbstractDataArrayType">
				<xs:sequence>
					<xs:element name="elementType" type="swe:SimpleDataRecordPropertyType"/>
					<xs:group ref="swe:EncodedValuesGroup" minOccurs="0"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
	<!-- ........ -->
	<xs:complexType name="CurvePropertyType">
		<xs:annotation>
			<xs:documentation>Curve is a data-type so usually appears "by value" rather than by reference.</xs:documentation>
		</xs:annotation>
		<xs:sequence>
			<xs:element ref="swe:Curve"/>
		</xs:sequence>
	</xs:complexType>
	<!-- ================================================= -->
	<xs:element name="NormalizedCurve" type="swe:NormalizedCurveType" substitutionGroup="swe:AbstractDataRecord"/>
	<xs:complexType name="NormalizedCurveType">
		<xs:complexContent>
			<xs:extension base="swe:AbstractDataRecordType">
				<xs:sequence>
					<xs:element name="inputGain" type="swe:QuantityPropertyType" minOccurs="0"/>
					<xs:element name="inputBias" type="swe:QuantityPropertyType" minOccurs="0"/>
					<xs:element name="outputGain" type="swe:QuantityPropertyType" minOccurs="0"/>
					<xs:element name="outputBias" type="swe:QuantityPropertyType" minOccurs="0"/>
					<xs:element name="interpolationMethod" type="swe:CategoryPropertyType" minOccurs="0"/>
					<xs:element name="extrapolationMethod" type="swe:CategoryPropertyType" minOccurs="0"/>
					<xs:element name="function" type="swe:CurvePropertyType"/>
				</xs:sequence>
			</xs:extension>
		</xs:complexContent>
	</xs:complexType>
	<!-- ================================================= -->
	<!--               Data Component Groups               -->
	<!-- ================================================= -->
	<xs:group name="Curves">
		<xs:choice>
			<xs:element ref="swe:Curve"/>
			<xs:element ref="swe:NormalizedCurve"/>
		</xs:choice>
	</xs:group>
</xs:schema>


A force directed graph layout algorithm in JavaScript


package swarm

import "time"

// Service represents a service.
type Service struct {
	ID string
	Meta
	Spec         ServiceSpec  `json:",omitempty"`
	PreviousSpec *ServiceSpec `json:",omitempty"`
	Endpoint     Endpoint     `json:",omitempty"`
	UpdateStatus UpdateStatus `json:",omitempty"`
}

// ServiceSpec represents the spec of a service.
type ServiceSpec struct {
	Annotations

	// TaskTemplate defines how the service should construct new tasks when
	// orchestrating this service.
	TaskTemplate TaskSpec      `json:",omitempty"`
	Mode         ServiceMode   `json:",omitempty"`
	UpdateConfig *UpdateConfig `json:",omitempty"`

	// Networks field in ServiceSpec is deprecated. The
	// same field in TaskSpec should be used instead.
	// This field will be removed in a future release.
	Networks     []NetworkAttachmentConfig `json:",omitempty"`
	EndpointSpec *EndpointSpec             `json:",omitempty"`
}

// ServiceMode represents the mode of a service.
type ServiceMode struct {
	Replicated *ReplicatedService `json:",omitempty"`
	Global     *GlobalService     `json:",omitempty"`
}

// UpdateState is the state of a service update.
type UpdateState string

const (
	// UpdateStateUpdating is the updating state.
	UpdateStateUpdating UpdateState = "updating"
	// UpdateStatePaused is the paused state.
	UpdateStatePaused UpdateState = "paused"
	// UpdateStateCompleted is the completed state.
	UpdateStateCompleted UpdateState = "completed"
)

// UpdateStatus reports the status of a service update.
type UpdateStatus struct {
	State       UpdateState `json:",omitempty"`
	StartedAt   time.Time   `json:",omitempty"`
	CompletedAt time.Time   `json:",omitempty"`
	Message     string      `json:",omitempty"`
}

// ReplicatedService is a kind of ServiceMode.
type ReplicatedService struct {
	Replicas *uint64 `json:",omitempty"`
}

// GlobalService is a kind of ServiceMode.
type GlobalService struct{}

const (
	// UpdateFailureActionPause PAUSE
	UpdateFailureActionPause = "pause"
	// UpdateFailureActionContinue CONTINUE
	UpdateFailureActionContinue = "continue"
)

// UpdateConfig represents the update configuration.
type UpdateConfig struct {
	// Maximum number of tasks to be updated in one iteration.
	// 0 means unlimited parallelism.
	Parallelism uint64

	// Amount of time between updates.
	Delay time.Duration `json:",omitempty"`

	// FailureAction is the action to take when an update failures.
	FailureAction string `json:",omitempty"`

	// Monitor indicates how long to monitor a task for failure after it is
	// created. If the task fails by ending up in one of the states
	// REJECTED, COMPLETED, or FAILED, within Monitor from its creation,
	// this counts as a failure. If it fails after Monitor, it does not
	// count as a failure. If Monitor is unspecified, a default value will
	// be used.
	Monitor time.Duration `json:",omitempty"`

	// MaxFailureRatio is the fraction of tasks that may fail during
	// an update before the failure action is invoked. Any task created by
	// the current update which ends up in one of the states REJECTED,
	// COMPLETED or FAILED within Monitor from its creation counts as a
	// failure. The number of failures is divided by the number of tasks
	// being updated, and if this fraction is greater than
	// MaxFailureRatio, the failure action is invoked.
	//
	// If the failure action is CONTINUE, there is no effect.
	// If the failure action is PAUSE, no more tasks will be updated until
	// another update is started.
	MaxFailureRatio float32
}


package academy.kot.portal.mobile

import android.util.Log

fun Any.log(message: String) {
    if (BuildConfig.DEBUG) Log.e(this::class.simpleName, message)
}

fun Any.log(error: Throwable) {
    log(error.message ?: "Error", error)
}

fun Any.log(message: String, error: Throwable) {
    if (BuildConfig.DEBUG) Log.e(this::class.simpleName, message, error)
}


const parser = require('git-log-parser'); // eslint-disable-line

// this is hack which allows to use semantic-release for monorepo
// https://github.com/semantic-release/semantic-release/issues/193#issuecomment-578436666
parser.parse = ((parse) => (config, options) => {
  if (Array.isArray(config._)) {
    config._.push(options.cwd);
  } else if (config._) {
    config._ = [config._, options.cwd];
  } else {
    config._ = options.cwd;
  }
  return parse(config, options);
})(parser.parse);

module.exports = {
  tagFormat: `${process.env.npm_package_name}@\${version}`,
  branches: ['master', { name: 'next', prerelease: true }],
  verifyConditions: [
    '@semantic-release/changelog',
    '@semantic-release/npm',
    '@semantic-release/git',
    '@semantic-release/github'
  ],
  prepare: [
    {
      path: '@semantic-release/changelog',
      changelogTitle: '# Change Log\n\nAll notable changes to this project will be documented in this file.'
    },
    '@semantic-release/npm',
    {
      path: '@semantic-release/git',
      message: `chore(release): ${process.env.npm_package_name}@\${nextRelease.version} [skip ci]`
    }
  ],
  success: []
};


{{"""
this is an example of usage of google map
the web2py action should be something like:

def map():
    return dict(
      googlemap_key='...',
      center_latitude = 41.878,
      center_longitude = -87.629,
      scale = 7,
      maker = lambda point: A(row.id,_href='...')
      points = db(db.point).select() where a points have latitute and longitude
    )

the corresponding views/defaut/map.html should be something like:

    \{\{extend 'layout.html'\}\}
    \{\{include 'generic.map'\}\}

"""}}


DROP VIEW IF EXISTS Fact_Acct_Transactions_View;

CREATE VIEW Fact_Acct_Transactions_View AS
SELECT fact_acct_id,
       ad_client_id,
       ad_org_id,
       isactive,
       created,
       createdby,
       updated,
       updatedby,
       c_acctschema_id,
       account_id,
       datetrx,
       dateacct,
       c_period_id,
       ad_table_id,
       record_id,
       line_id,
       gl_category_id,
       gl_budget_id,
       c_tax_id,
       m_locator_id,
       postingtype,
       c_currency_id,
       amtsourcedr,
       amtsourcecr,
       amtacctdr,
       amtacctcr,
       c_uom_id,
       qty,
       m_product_id,
       c_bpartner_id,
       ad_orgtrx_id,
       c_locfrom_id,
       c_locto_id,
       c_salesregion_id,
       c_project_id,
       c_campaign_id,
       c_activity_id,
       user1_id,
       user2_id,
       description,
       a_asset_id,
       c_subacct_id,
       userelement1_id,
       userelement2_id,
       c_projectphase_id,
       c_projecttask_id,
       currencyrate,
       docstatus,
       subline_id,
       documentno,
       c_doctype_id,
       docbasetype,
       vatcode,
       counterpart_fact_acct_id,
       --
       acctbalance(account_id, AmtAcctDr, amtacctcr) AS balance
FROM Fact_Acct fact;