We have update Wwe Supercard generator today, many user has been success generated Token and Credits for free.
Wwe Supercard hack cheats tool unlimited Token and Credits directly in your browser. Do not hesitate is free! You can download now Wwe Supercard hack cheats tool. This cheat tool is available for your Android or iOS device, it has a user-friendly interface and is easy manageable. Instructions for beginers on how to use are included. Its important to know that hack cheats tool has been scanned with all the latest antivirus solutions on the market and its 100% safe to download and use. Now with this particular application Wwe Supercard Hack Tool you can, add free Token and Credits in your account only in few seconds by few clicks!
Add Unlimited Token and Credits!
Wwe Supercard [Latest & Updated Version]!
The Wwe Supercard Hack makes it possible that you can basically receive an unlimited quantity of free Token and Credits for Wwe Supercard within just with 3 minutes of time and very little effort at almost all.
The Hack Tool for Wwe Supercard also work for Android, iOS and Facebook which you decide on before using the generator and follow the instructions.
Wwe Supercard Add Token and Credits, Wwe Supercard Add Free Wwe Supercard, Wwe Supercard Add Unlimited Token and Wwe Supercard Add Unlimited Credits, Wwe Supercard Add Unlimited Gold, Wwe Supercard Apk Hack, Wwe Supercard No Download, Wwe Supercard Free No Ads, Wwe Supercard Cheat No Download, Wwe Supercard No Survey, Wwe Supercard Hack No Root, Wwe Supercard No Root Free, Wwe Supercard Android Hack No Survey, Wwe Supercard Cheat, Wwe Supercard Cheat Android, Wwe Supercard Cheats, Wwe Supercard Free Token and Wwe Supercard Free Credits, Wwe Supercard Free Gold, Wwe Supercard Free Hack, Wwe Supercard Free Hacks Cheat, Wwe Supercard Free Hacks Tools, Wwe Supercard Hack, Wwe Supercard Hack Android, Wwe Supercard Hack Unlimited Token and Wwe Supercard Hack Unlimited Credits, Wwe Supercard Hack Unlimited Gold, Wwe Supercard Free Cheats, Wwe Supercard Generator, Wwe Supercard Hack Apk, Wwe Supercard Hack Cheat, Wwe Supercard Hack Cheat Tools, Wwe Supercard Hack Tool, Wwe Supercard Tools Online, Wwe Supercard Online Tools, Wwe Supercard Tools Hack Generator, Wwe Supercard Android Generator Hack, Wwe Supercard Last Hack, Wwe Supercard iPhone, Wwe Supercard Last Cheat, Wwe Supercard Last Update, Wwe Supercard New Cheat, Wwe Supercard New Hacks, Wwe Supercard Remove All Ads, Wwe Supercard Tips and Tricks, Wwe Supercard Tools, Wwe Supercard Tricks Hack, Wwe Supercard Work, Wwe Supercard Working Hack, Wwe Supercard Work Hack Cheat, Wwe Supercard Token Hack, Wwe Supercard Credits Cheat, Wwe Supercard Cheats, Wwe Supercard Generator, Wwe Supercard Token Hack Tools, Wwe Supercard Credits Hack Cheat, Wwe Supercard Cheat Online, Wwe Supercard Hack Online, Wwe Supercard Token Hack Free, Wwe Supercard Tools Generator, Wwe Supercard Tools Online Game, Wwe Supercard Game Tools Online, Wwe Supercard Game Hack Online, Wwe Supercard Android Hot Cheat, Wwe Supercard Hot Cheat Games, Wwe Supercard Games Generator Hot, Wwe Supercard New Generator, Wwe Supercard New Hack Online, Wwe Supercard New Android Hack Cheat.
Wwe Supercard apk offline, Wwe Supercard apk modded, Wwe Supercard apk and data, Wwe Supercard apk cheat, Wwe Supercard hack no survey.


This is a dark brown with red undertones in lustre finish. It's great! Very intense color but not too pigmented for those who don't want to dare too much.
This is a gorgeous color! It's got a matte finish and looks amazing once applied. It's a chocolate brown with micro shimmers in it.
As the name suggests, this is a super shiny lipstick, referring to the Mac finishes I'd say it's a lustre with super cute sparkles. It's a burgundy-red with pink sparkles, very sheer but very pretty!
Another amazing shade! A deep brown plum in lustre finish. Gorgeous!
All Nyx round lipsticks are super creamy and very pigmented...This one is no exception! A deep plum (looks red-ish in picture =P) that once applied is very nice and "not too much"
Last, but not least, another Layla lipstick. This is a stunning shade! a pure dark purple with multicolor shimmers in it. It's sheer but gorgeous!! If you like purples/violets, you'll love this one!
As you can see, there are many shades to choose...So are you ready to wear dark lips?? Do you like this trend? Let me know!
il nyx lala mi piace molto, e anche i 2 layla sono molto carini!
io ho pochi rossetti scuri..chissà se quest'anno cambio idea!
Molto belli, soprattutto i due che appaiono alla fine...a destra. Bellissimi!!! due colori stupendi.
I love dark lips (love the trend), but don't wear it myself, because my lips are to small and weirdly shaped. I looks ridiculous with dark lipstick.
Quello di NYX è molto carino. A me i rossetti scuri piacciono ma purtroppo non mi stanno molto bene.
Belli i rossetti scuri ma non li metto praticamente mai :-) Magari quest'anno oserò!


text:
Q: How to create global navigation from another graph i am trying to do global navigation to fragment from activity but getting exception
    java.lang.IllegalArgumentException: Navigation action/destination com.android:id/action_global_serviceUnavailableFragment cannot be found from the current destination Destination(com.android:id/authFragment) label=fragment_auth class=com.android.ui.auth.AuthFragment

the fragment I want to navigate to is in another graph, but I don't think it should affect
my code :
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/service_unavailable_graph"
    app:startDestination="@id/serviceUnavailableFragment">

    <fragment
        android:id="@+id/serviceUnavailableFragment"
        android:name="com.android.ui.serviceunavailable.ServiceUnavailableFragment"
        android:label="fragment_service_unavailable"
        tools:layout="@layout/fragment_service_unavailable">
    </fragment>

    <action
        android:id="@+id/action_global_serviceUnavailableFragment"
        app:destination="@id/serviceUnavailableFragment" />

</navigation>

    override fun serviceUnavailable() {
        lifecycle.coroutineScope.launch(Dispatchers.Main) {
            navController.navigate(R.id.action_global_serviceUnavailableFragment)
        }
    }

redpajama_set_name: RedPajamaStackExchange


text:
Q: Define a val later in Scala I use this code to save an image uploaded by a form to DB:
  def saveImage(userIdSource: String) = Action.async(gridFSBodyParser(gridFS)) { request =>
    // here is the future file!
    val futureFile = request.body.files.head.ref
    // when the upload is complete, we add the article id to the file entry (in order to find the attachments of the article)

    val futureUpdate = for {
      file <- futureFile
      // here, the file is completely uploaded, so it is time to update the user
      updateResult <- {

        gridFS.files.update(
          BSONDocument("_id" -> file.id),
          BSONDocument("$set" -> BSONDocument("metadata" ->
            BSONDocument("user" -> BSONObjectID(userIdSource),
              "size" -> "original"))))

        val iterator = gridFS.enumerate(file).run(Iteratee.consume[Array[Byte]]())
        iterator.flatMap {
          bytes => {
            // Create resized image
            val enumerator: Enumerator[Array[Byte]] = Enumerator.outputStream(
              out => {
                Image(bytes).bound(120, 120).writer(Format.JPEG).withCompression(90).write(out)
              }
            )

            val data = DefaultFileToSave(
              filename = file.filename,
              contentType = file.contentType,
              uploadDate = Some(DateTime.now().getMillis),
              metadata = file.metadata ++ BSONDocument(
                "user" -> BSONObjectID(userIdSource),
                "size" -> "thumb"
              )
            )

            Logger.warn(s"Saving resized image: [id=$userIdSource, metadata=${data.metadata}}]")
            gridFS.save(enumerator, data).map {
              image => Some(image)
            }
          }
        }
      }
    } yield updateResult

    futureUpdate.flatMap {
      case _ =>  //Some(_)

        val img = Image(BSONObjectID(userIdSource), DateTime.now(), None)
       //  insert the user
        val futureResult2 = snapsCollection.insert(img)
     //    when the insert is performed, send a OK 200 result
        futureResult2.map(_ => Ok("saved"))
    }.recover {
      case e => InternalServerError(e.getMessage())
    }
  }

This code takes an image from a form and stores it twice in Mongo DB Grid FS:

*

*Original image

*Thumb Image

I would like to store in the "img" object 2 additional parameters:

*

*The id of the original image - it is stored in "file.id"

*The id of the thumb image - It is stored in "image.id"

How can I pass these 2 values to the: "futureUpdate.flatMap"?

A: Change your yield statement to a tuple (updateResult, file.id, image.id)  Then extract them in the pattern match for futureUpdate.flatMap.


text:
NEWS: Gospel singer Muyiwa Olarewaju awarded OBE by Queen Elizabeth II
SOURCE:PULSE.ng
Gospel singer Muyiwa Olarewaju awarded OBE by Queen Elizabeth II
The music star joins the list of several Nigerians who have been honoured with the prestigious award.
British Nigerian gospel singer, Muyiwa Olarewaju, awarded OBE in Queen's Birthday Honours List 2020
BBC One talent show judge, radio host and award-winning British gospel singer, Muyiwa Olarewaju, has been awarded an OBE in the Queen's Birthday Honours List 2020.
The vibrant performer is known to television audiences as a star of Songs of Praise's Gospel Choir of the Year.
READ ALSO: Billionaire businesswoman, Folorunsho Alakija preaches the gospel on streets of Lagos
He has been hugely instrumental in popularising the gospel music genre on a global scale by mixing traditional gospel music with elements from Africa, the Caribbean and Asia, with soul, R&B and pop.
Given the honour for his music service, Muyiwa has brought his unique style to music fans around the world as he's toured with legends such as Stevie Wonder and Mariah Carey.
He has worked alongside superstars Bob Dylan and Lauryn Hill.
Prince William handed the OBE medal to Muyiwa at the event on the 12th of January 2022.
Previous articleNEWS: Billionaire businesswoman, Folorunsho Alakija preaches the gospel on streets of Lagos
Next articleNEWS: Chairo debuts her gospel album on SABC 1

redpajama_set_name: RedPajamaCommonCrawl


text:
Watch Moonlight
Moonlight is an American paranormal activity television related series created by Ron Koslow and writer Trevor Munson. The series was first created as a presentation lasting for fourteen to twenty minutes long. When the television series was actually recast into a show, the people from the presentation were almost all replaced by new actors. The series includes romance and drama, which is about a private investigator Mick St. John, who was turned into a vampire by his bride Coraline, on the happy couple's wedding night fifty - five years ago. In the present day, Mick struggles with his fatal attraction to a mortal woman Beth, his friendship with Josef, and his other dealings with vampires in Los Angeles.
Moonlight's characters were conceived in a book by Trevor Munson who spent two and a half years writing the novel containing them. The story was adapted into a feature film script, and then into a television series. Moonlight was originally named Twilight. In the book, Mick is now eighty - five years old, and does not hunt women, children, or those who are innocent, and his love interest Beth is an internet reporter and has vague memories of being rescued by Mick from a kidnapper twenty two years prior to the present. Josef is a four hundred and ten year old vampire who is a business man who doesn't stint himself in luxuries, from an expensive house to the company of numerous beautiful women who are more than happy to be a part of his desire for blood, he is also Mick's mentor and friend. Coraline is Mick's ex - wife and sire, she is approximately three hundred and forty years old and was presumed dead for twenty years after the couple was estranged. When she returns from France, she appears to be completely human and claims to have a cure for vampirism, which consequently, Mick just so happens to be very desperate to obtain from her so he can give up his immortality so that he and Beth can be together as mortals until they die.
Moonlight is paranormal because it is based on a very unique mythology, between biting, drinking blood, turning humans to vampires by sires, etc.
Moonlight is a series that is currently running and has 1 seasons (16 episodes). The series first aired on September 28, 2007.
Where do I stream Moonlight online? Moonlight is available for streaming on The CW, both individual episodes and full seasons. You can also watch Moonlight on demand at Vudu, iTunes, CW Seed online.
Science Fiction, Action & Adventure, Fantasy, Horror & Suspense
Cast: Alex O'Loughlin, Sophia Myles, Jason Dohring, Shannyn Sossamon, Brian J. White
Watch Full Episodes of Moonlight
Sonata (43:47)
What's Left Behind ...
Click (41:13)
Fated to Pretend (4...
The Mortal Cure (43...
Love Lasts Forever ...
Moonlight Full Episode Guide
16 CW Seed Episodes
Episode 16 - Sonata
Mick and Beth must face mortality and immortality when a vampire kills a human during the heat of passion. But when the investigation threatens to identify all those with vampire identities, Mick and Josef must take action.
Episode 15 - What's Left Behind
Beth is given more information about Mick's secretive past after the grandson of Mick's World War II friend is kidnapped.
Episode 14 - Click
A Hollywood starlet is murdered after hiring Mick as a part of her security team, thinking that her life was in danger by the paparazzi. Meanwhile, Beth's ethics are questioned.
Episode 13 - Fated to Pretend
Episode 12 - The Mortal Cure
Mick's desire to become human may be realized when he discovers Coraline's secret, but answers come with a costly price. Meanwhile, Beth has to deal with bad news alone.
Episode 11 - Love Lasts Forever
Josh is working on the biggest case of his career, a conviction against a member of the MS-13 gang, possibly the most dangerous gang in the world. In an attempt to force Josh to drop the case, the gang threatens Beth, but Josh refuses to fold and enlists Mick's help in protecting her. Unfortunately, Josh is left unguarded and is kidnapped with devastating results. Beth discovers an unwanted blood connection.
Episode 10 - Sleeping Beauty
When a hit is put out on Josef by a dying man that has a vendetta with him, Mick finds out things Josef has been keeping from him for over 40 years, also the reason why he believes Mick and Beth can never have a relationship.
Episode 9 - Fleur de Lis
Mick begins working closely with a photographer, much to Beth's dismay. Jealous, Beth looks into the photographer's background, and is shocked by what she finds.
Episode 8 - 12:04 AM
Mick protects a woman from a killer's followers after the followers swear to follow out their leader's last wish -- to kill those responsible for his execution.
Episode 7 - The Ringer
Mick has flashbacks to the night when Coraline died while investigating a fire that destroyed a Hollywood hotel. Mick becomes even more wrapped up in the past when the woman he works the case with has a close resemblance to his ex-wife.
Episode 6 - B.C.
Mick and Beth work together again to find a vampire from Josef's past who may be linked to a drug overdose they're investigating.
Episode 5 - Arrested Development
Mick hunts for a young vampire who is preying on females he locates via the Internet. Meanwhile, Mick and Beth go to lengths to avoid each other after an intimate encounter.
Episode 4 - Fever
Mick helps protect a young woman who is wanted by an arms dealer but when they become stranded in the desert, Mick becomes the one who desperately needs help to survive.
Episode 3 - Dr. Feelgood
Episode 2 - Out Of The Past
A murderer from Mick's past is released from prison, forcing Mick to deal with one of his worst fears -- his immorality being revealed to Beth.
Episode 1 - No Such Thing As Vampires
After a series of vampire-style murders are committed in Los Angeles, investigator Mick St. John begins to search for those behind the deaths. While doing so, Mick reconnects with Internet reporter Beth Turner, a woman from his past.
Most Popular Moonlight Episodes
Season 1 Episode 2 Out Of The Past 10/05/2007
Season 1 Episode 1 No Such Thing As Vampires 9/28/2007
Season 1 Episode 16 Sonata 5/16/2008
Season 1 Episode 14 Click 5/02/2008
If You Like Moonlight, Then Try...
Also on The CW


142 Hopewell Road (MLS #4489264) is a colonial single family home located in Alton, NH. This single family home is 17,228 sqft and on a lot of 209,524 sqft (or 4.81 acres) with 5 bedrooms, 9 baths and is 16 years old. This property was listed on 05/02/2018 and has been priced for sale at $4,900,000.
Nearby zip codes are 03810, 03853, 03860, 03894 0389 and 03894. This property neighbors other cities such as Hales Location, Meredith, New Durham, Tuftonboro and Wolfeboro.
Listing Last updated 03/18/2019 6:00 PM CDT . Some properties which appear for sale on this web site may subsequently have sold or may no longer be available. Walk Score provided by Walk Score. Mapping data provided by Google and Bing.


text:
Team Tananet January 9, 2023 in Business - 5 Minutes
Mircari is one of the most popular social media platforms that can be used to grow your business. It has been around for more than 10 years, and it has a large user base of more than 53 million people worldwide. Mircari allows you to create a profile and connect with other users through posts, messages, comments, and more. You can also make money by selling goods or services on Mercari using its platform
What Is Mircari?
Mircari is a peer-to-peer mobile marketplace that allows users to buy and sell used items. It's an app that lets you list your items for sale, browse other users' listings, and make purchases.
Mircari connects sellers with buyers through its mobile app. Buyers can search for items they want or browse through the catalogs of sellers nearby them. Sellers set their prices based on what they believe are fair value in relation to the condition of each item (i.e. if an item looks like brand new but has been used for less than a year). When someone makes a purchase from you, you get paid in cash via Paypal or Venmo (a popular money transfer platform).
How Does Mircari Work?
Mircari is a mobile app that connects you to people in your community. It's a mobile marketplace where people can buy and sell new and used items.
Mircari also has a social network, where you can connect with your friends and make new ones.
Why Use Mircari?
Mircari is a fast, easy and secure way to buy and sell items online. It is perfect for both newbies and experienced traders who want to make money by selling their unwanted items in their local community.
Mircari allows you to buy or sell anything from clothes, electronics, books etc at affordable prices without having to leave your house. All you need is an internet connection!
How to Get the Most Out of Mircari
Mircari is a tool that can be used to grow your business and expand it. Use Mircari to increase your profit, because it allows you to create new products, services and even make money from old ones.
The first step in using this software is finding out what kind of results are possible for your business by analyzing how much revenue each month comes into the company. You can do this by creating a tracking spreadsheet that tracks all sales transactions made during the month along with some basic information about those transactions (such as name of customer). This will help determine whether there are any areas where more sales could be made if certain changes were made or if there are areas where profit margins may not be as high as expected due t
How to Login To Mircari through Facebook?
To log in to Mercari through Facebook, go to www.mercari.com and click on the sign in button. Then go to the Facebook login button, enter your credentials and hit "Login" when prompted by Facebook. You will be redirected to your profile page where you can access other features of Mercari such as shopping or making payments via credit card or PayPal account with just one click!
How To Create Mircari Account?
To get started with Mercari, you will have to create an account. The website provides a convenient sign up form where you can fill up your details and submit it for verification.
When you are done with filling the form, click on "Sign In" button at the bottom-right corner of your screen. You will be redirected to your new profile page where all of your accounts are listed under My Stuff section. Now, go through each account and add some products into them by clicking on Add button or dragging & dropping images/files from computer onto that particular product's description box (or just type anything). After this step is complete, go back again by clicking on My Stuff menu option which appears just below Your Account heading on top right hand side corner; here again there is another option called "Add New Listings". Clicking this link brings up another window where sellers list their items available for sale in Mircari marketplace; click Add New Listings once again then follow instructions provided by seller as per their own terms & conditions before proceeding further along with making purchase order for those desired items
Steps To follow if you Forget your Password.
To access your account, you need to follow these steps:
Go to the forgot password page and enter your email address.
Click on the link that is sent by email. This will take you to a new page where you can enter a new password for your Mircari account and click on reset password button.
Is Mercari Legitimate?
You may be wondering if Mercari is a legitimate company. The answer is yes, it is. Mercari has been operating for over six years and has over 2 million users worldwide who use the platform to sell their goods.
Mercari does not charge any fees for selling products on their site or for shipping them to buyers in other countries, which makes it one of the most inexpensive platforms available online today (compared to Ebay or Amazon).
Mircari is a platform that allows users to sell their items using social media. It was created in 2017 by a former Google employee, who wanted to make selling on the internet easier for everyone. This guide will show you how to sign up and start using Mircari today!
Previous: What is IFVOD Tv, Here's All You Need to Know
Next: How BPO Outsourcing Services Are Revolutionizing Healthcare Industry


text:
[![GitHub release](https://img.shields.io/github/release/maltimor/GenericRest.svg)]()

# GenericRest.
Autor: Andrés García Meroño

Fecha: 20/10/2016

## Índice de contenido

## Introducción

Este documento explica de forma básica el funcionamiento y configuración de GenericRest.

## Alta de un servicio

La pantalla de un servicio facilita su mantenimiento. Desde aquí se define el servicio REST, su
comportamiento y la seguridad de acceso al servicio como de los datos a los que se puede acceder.

![GitHub Logo](http://www.subirimagenes.com/imagedata.php?url=http://s2.subirimagenes.com/otros/9649202imagenservicio.jpg)

A continuación se describe cada uno de los campos:

* TABLE_NAME: nombre público del servicio. Es la etiqueta con la que se identifica cada servicio.

* NEW_TABLE_NAME: (obligatorio) permite cambiar el nombre del servicio.

* FINAL_TABLE: para servicios CRUD básicos de una tabla, es el nombre real de la tabla que se está maepando. Si se deja en blanco equivale a TABLE_NAME.

* TYPE: tipo de servicio. Dependiendo de este valor el servicio se comporta como un CRUD (campo en blanco), una llamada a una función (valor FUNCTION) o una llamada a un procedimiento (PROCEDURE). Este campo afecta a los métodos que expone el servicio.

* FIELDS: (obligatorio) lista de campos separada por comas de la definición de los campos del servicio. Permite definir también el tipo de dato y su longitud y cómo se intercambia la información desde o hacia el servicio. Ver apartado "Sintaxis de fields".

* KEYS: (obligatorio) lista de campos separada por comas de los que identifican la clave primaria de un registro.

* SEPARATOR: carácter que se usa para separar los diferentes campos de la clave primaria al invoar el servicio REST. Por defecto es '/'. Útil en aquellos casos donde algún campo de la clave primaria pueda contener el carácter '/'.

* RESOLVER: clase java que implementa cómo acceder a los datos. Por defecto es el defaultResolver de la configuración Spring.

* SEC_RESOLVER: clase java que implementa la seguridad de acceso a los datos. Por defecto es el defaultSecResolver de la configuración Spring.

* SEC_INFO: contiene la definición de la seguridad. Ver sintaxis SEC_INFO.

* SELECT_VALUE, INSERT_VALUE, UPDATE_VALUE, DELETE_VALUE: sobreescribe la implementación por defecto del resolver. Pudiendo escribir las diferentes cláusulas para un servicio tipo CRUD, o la llamada al un PL/SQL para un servicio de tipo procedure o function.
SELECT_VALUE se comprueba al arrancar el servidor o al recargal los servicios para verificar que la definición del campo FIELDS es compatible y no se ha cometido un error sintáctico. Esto implica que la definición de SELECT_VALUE es estática y no depende del usuario que la ejecuta. Por lo que no es aconsejable utilizar la sintaxis de Mybatis aqui.
En el caso de un procedure o función SELECT_VALUE es el campo donde se almacena el código PL/SQL y no se realiza comprobación alguna, por lo que el servicio puede fallar en tiempo de ejecución. El resto de campos no tienen asociada ninguna funcionalidad y deberían estar en blanco.

* SELECT_FILTER: Permite modificar la cláusula SELECT_VALUE de un servicio tipo CRUD con datos dinámicos en tiempo de ejecución, es decir, permite modificar los datos que devuelve el servicio en función del usuario que lo ejecuta. Aquí es normal utilizar la sintaxis de Mybatis para acceder a los metadatos del usuario.

* TEST_PARAMS: campo Json que define los parametros de sustitución durante la etapa TestSQL en el caso de que el campo SELECT_VALUE contenga elementos con la notación #{...}. Los parametros de sustitución son del tipo key:valor, por ejemplo si en SELECT_VALUE se escribe #{data.CAMPO} en TEST_PARAMS debe haber { .... "data.CAMPO":"'valor'"....} . La sustitución es literal, de manera que el campo SELECT_VALUE se pueda ejecutar.

## Servicios que despliega

Hay tres tipos de servicios: CRUD, PROCEDURE y FUNCTION, dependiendo del tipo de servicio la configuración REST variará y las operaciones que muestra son diferentes.

## *Tipos de servicios*

* CRUD: Este se caracteriza porque no tiene tipo, es el tipo por defecto. Despliega un servicio REST con las operaciones de crear, ver, editar y borrar.

  * Ejemplo de servicio CRUD simple sin configuración de las consultas

    ![CRUD simple](http://www.subirimagenes.com/imagedata.php?url=http://s2.subirimagenes.com/otros/9649205crudsime.jpg)

   * Ejemplo de servicio CRUD complejo, en el cual se configuran las consultas

    ![CRUD complejo](http://www.subirimagenes.com/imagedata.php?url=http://s2.subirimagenes.com/otros/9649207crudcomejo.jpg)

* PROCEDURE: El valor del campo TYPE es "PROCEDURE" permite la ejecución de un código PL/SQL, normalmente una llamada a un procedimiento. Este tipo de operación de devuelve un valor.

  ![Procedure](http://www.subirimagenes.com/imagedata.php?url=http://s2.subirimagenes.com/otros/9649204procedure.jpg)

* FUNCTION: El valor del campo TYPE es "FUNCTION" permite la ejecución de un código PL/SQL, normalmente la llamada a una función, el resultado se pasa a la salida sin procesar.

  ![Function](http://www.subirimagenes.com/imagedata.php?url=http://s2.subirimagenes.com/otros/9649203function.jpg)

## *Operaciones del servicio*

### @GET ("/:table")

Consulta de datos con selección de campos, paginación, ordenación, búsqueda full-text, búsqueda avanzada y formato de los datos devueltos.

PathParam:

  - table: nombre del servicio, que es el valor del campo TABLE_NAME.

QueryParams:

  - filter: permite seleccionar aquellos registros que cumplan una condición. Ver sintaxis de filtro. Por defecto no hay.

  - limit: cantidad de registros que devuelve el servicio, por defecto 30.

  - offset: a partir de qué registro devuelve los datos. Por defecto 0.

  - orderby: lista de columnas separada por comas de los campos a ordenar.

  - order: lista de sentido de ordenación separada por comas (sólo ASC y DESC).

  - fields: lista de campos separada por comas o '*' para todos. Por defecto '*'.

  - format: formato de salida de los datos (JSON, XLS, CSV, HTML, TXT). Por defecto JSON.

  - Según el tipo de exportación (excepto JSON) se pueden introducir mas parámetros

    - alias: permite definir un alias al nombre de las columnas (todas las exportaciones)
    - separator: define el carácter de separación de los campos (CSV y TXT)

  - ReturnData: dependiendo del valor de format cambia el content-type:

  - JSON: un array con el resultSet asociado a la consulta.

  - XLS: los datos vienen en formato excel.

  - CSV: los datos vienen separados por comas, una linea por registro.

  - HTML: los datos vienen formateados usando TABLE, TR, TD en html.

  - TXT: los datos vienen en texto separados por comas.

### @GET ("/:table/count")

Devuelve la cantidad de registros que cumplen la condición. Se le debe pasar los mismos valores que el servicio de consulta para que el resultado sea coherente con los datos mostrados.

PathParam:

  - table: nombre del servicio, que el valor del campo TABLE_NAME.

QueryParam:

  - filter: igual que en el servicio de consulta.

  - ReturnData: un JSON tipo object con una propiedad "count" con el resultado. (ej: { count: 12345 })

### @GET ("/:table/:id(.*)")

Devuelve un registro concreto en función de su clave primaria.

PathParam:

  - table: nombre del servicio.

  - id: lista de valores separados por el campo SEPARATOR uno por cada valor de la clave primaria en el orden en el que se definió en el campo KEYS.

  - ReturnData: un JSON tipo object con el registro asociado a la clave primaria.

Si la consulta devuelve más de un valor retorna un error.
El contenido de la clave primaria no puede contener el campo SEPARADOR, por ello hay que seleccionar otro valor si una campo de la clave primaria puede contener el caracter de SEPARADOR.

### @POST ("/:table")
Realiza una inserción de un nuevo registro o la ejecución de una operación PL/SQL.

PathParam:
table: nombre del servicio.
Body: objeto JSON con los datos del nuevo registro.
ResultData: en caso de servicios tipo CRUD devuelve el mismo objeto JSON que se pasa en el body. En otro caso el valor que devuelve la llamada PL/SQL.

### @DELETE ("/:table/:id(.*)")
Borra un registro de datos según su clave primaria.

PathParam:
table: nombre del servicio.
id: lista de valores separados por el campo SEPARATOR uno por cada valor de la clave primaria en el orden en el que se definió en el campo KEYS.
ReturnData: Este servicio sólo responde un codigo de estado 200.

NOTA: aquí la lista de ids puede ser incompleta o NULA, lo que permite eliminar elementos que comparten parte de la clave primaria o incluso TODOS los datos si no se aporta id's.

### @PUT ("/:table/:id(.*)")
Actualiza un registro de datos según su clave primaria.

PathParam:
table: nombre del servicio.
id: lista de valores separados por el campo SEPARATOR uno por cada valor de la clave primaria en el orden en el que se definió en el campo KEYS.
Body: objeto JSON con los datos del registro.
ReturnData: devuelve el mismo objeto JSON que se pasa en el body.

Este servicio permite cambiar la clave primaria. En la lista de id's se identifica la cláusula WHERE mientras que en body se identifica la cláusula SET.

NOTA: aquí la lista de ids puede ser incompleta, lo que permite actualizar elementos que comparten parte de la clave primaria.

## *Otros servicios adicionales*

### @GET ("/mapperinfotable/:table")

Devuelve los metadatos del servicio: tipo, nombre, fields, keys, ....

### @GET ("/mapperinfolist")

Devuelve una lista de los servicios desplegados

### @GET ("/_inituser")

Devuelve el objeto User de la llamada a UserDao.initUser.

Este método obtiene el login/id del usuario llamando a UserDao.getLogin, y le pasa como parámetro el nombre de la aplicación que tiene desplegado GenericRest.

La llamada a este método invalida la caché y actualiza los atributos/metadatos del usuario sin que tenga que volver a logearse.

### @GET ("/_getuser")

Devuelve el objeto User de la llamda a UserDao.getUser.

Este método obtiene el login/id del usuario llamando a UserDao.getLogin, y le pasa como parámetro el nombre de la aplicación que tiene desplegado GenericRest.

### *Sintaxis de fields*

fields -> * | campo | fields ',' fields

campo -> field  [ ':' descripcion ] [ '#' tipo ]

field -> [_0-9A-Za-z]* [ '-' ]

descripcion -> [_0-9A-Za-z]*

tipo -> T [ '#' size ] | N | F | D | S [ '#' secuenceName ]

size -> [0-9]*

secuenceName -> [_0-9A-Za-z]*

Fields puede contener únicamente el símbolo '*' para denotar todos los campos resultantes de la ejecución de la consulta, o puede ser una lista parcial de columnas y terminada en '*' para poder especificar diferentes funcionalidades para algunos campos.

Si field acaba en '-' significa que no se tiene en cuenta para el full-text.

Los tipos de datos son:

  * T: texto, permite definir el tamaño.
  * N: numero
  * F, D: Fecha y Date, el primero con tiempo, el segundo sin tiempo, sólo fecha.
  * S: secuencia de base de datos, viene acompañada del nombre de la secuencia.

Cuando Estos tipos de datos se mapean según el driver con los diferentes tipos de datos que hay en la base de datos:

  * T: CHAR, VARCHAR, VARCHAR2.
  * F: DATE, DATETIME, TIMESTAMP.
  * N: LONG, LONG RAW, NUMBER, DECIMAL, INT, DOUBLE.

El tipo de dato 'D' es equivalente a 'F' salvo que transforma la entrada y salida de datos al formato de sólo fecha.

## *Sintaxis de filtro*

filter -> valor | '['campo']' op valor | '['campo']' op '[' campo ']'
	 | '(' filter ')' | filter 'AND' filter | filter 'OR' filter

op -> = | == | < | > | >= | <= | =>

valor -> [_0-9A-Za-z]*

campo -> [#{}._0-9A-Za-z]*

Si algunas de las expresiones booleanas contienen 'valor' se entiende que es búsqueda full-text.
'campo' puede hacer referencia:

  * al nombre de una columna (ej: IMPORTE)
  * un atributo de los metadatos del usuario (ej: #{user.login}, #{user.roles}, #{user.grupos}, #{user.attr.CENTROS})
  * un valor de los datos (ej: #{data.SALARIO})
  * un valor de la clave primaria (ej: #{id.ID_SOLICITUD})
  * el nombre del servicio (ej: #{table} )
  * un campo de la url (ej: #{ui.CAMPO})
  * cualquier referencia tipo Mybatis de los objetos presentes en la llamada.

Resumiendo, los objetos accesibles para 'campo' son: user, table, info, filter, limit, offset, order, orderby, fields, ui, query, out, id y data.

## *Sintaxis de SEC_INFO*

sec_info -> key '=' valor [ ',' sec_info ]

key -> ( S | I | U | D | E )*

valor -> filter [ ':' valor ]

Una linea de sec_info es una lista de pares key/valor para cada una de las operaciones que expone el servicio: S (select), I (insert), U (update), D (delete), E (execute) y la condición que se debe cumplir para que el servicio se ejecute.

La sintaxis de 'valor' es idéntica a la utilizada en el filtro de datos, pero la semántica es diferente:
'valor' sin operación: hace referencia a un rol dentro del array de valores User.getRoles.
'campo' puede hacer referencia:

  * un atributo de los metadatos del usuario (ej: #{user.login}, #{user.roles}, #{user.grupos}, #{user.attr.CENTROS})
  * un valor de los datos (ej: #{data.SALARIO})
  * un valor de la clave primaria (ej: #{id.ID_SOLICITUD})
  * el nombre del servicio (ej: #{table} )

Los objetos accesibles aqui son: user.login, user.roles, user.grupos, user.attr, data, id y table.

## *Sintaxis de mapperInfo dentro del fichero Spring para info y secInfo*
-- TODO --

## Estructura de clases

![Clases](http://www.subirimagenes.com/imagedata.php?url=http://s2.subirimagenes.com/otros/9649208clases.jpg)

GenericREST implementa un servicio como cualquier otro, tiene asociado un ServiceDao, un ServiceDaoImpl y un ServiceMapper de Ibatis. También tiene asociado un SecurityDao que implementa la seguridad y un UserDao que implementa los atributos/metadatos del usuario.

La implementación del UserDao es específica de cada implantación, su única misión es implementar los métodos "getLogin" (devolver el login/id de la pesona que está accediendo al servicio), "initUser" y "getUser" que devuelven los metadatos del usuario. Un usuario es básicamente un contendor de atributos.

La implementación de SecurityDao corre a cuenta de GenericRest y se apoya en los metadatos del usuario que devuelve UserDao. También se apoya en la información que suministra GenericMapperInfo.

GenericMapperInfo mantiene información de todos los servicios desplegados por GenericRest, su nombre, las columnas, la clave primaria, etc...Esta información proviene de dos fuentes: dentro de la configuración del objeto: "info" y "security" y otro que delega en base de datos la información de los servicios.

La idea de tener dos fuentes es que hay servicios que se pueden definir estáticamente y otros dinámicamente. Un error en los datos podría provocar la no recuperación de la aplicación hasta que se corrijan, esto permitiría tener siempre algún servicio mínimo funcionando.

GenericDatabaseInfo implementa la definición de los servicios en base de datos, tiene asociado el nombre de la tabla que almacenará la definición, y las sentencias SQL asociadas a las diferentes acciones.

## *Acerca de los Resolvers*
Un resolver es un trozo de código que sabe qué sentencia SQL debe hacer en cada momento usando los datos que el servicio REST provee (en función del tipo y de la llamada al resolver le llegan unos datos u otros). Con esa información el resolver es capaz de costruir dinámicamente una sentencia SQL usando la misma sintaxis que permite MyBatis en un provider.

En GenericRest hay implementados dos resolvers:

  * GenericMapperInfoTableResolverImpl: resuelve el caso más simple del CRUD a una tabla de la base de datos.
  * BasicDatabaseResolver: este resolver, además de estar en base de datos, permite indicar la cláusula SELECT, INSERT, DELETE y UPDATE de un CRUD y la de definir el código PL/SQL de la llamada a un FUNCTION o PREOCEDURE.

Se pueden crear resolvers particulares con otras funcionalidades, o bien extendiendo de los existentes o implementando la interfaz.

## *Acerca de los SecurityResolvers*

Un SecurityResolver es un trozo de código que decide si una petición puede ejecutarla o no un usuario con todos los parámetros que se le pasan al servicio.

En GenericRest hay implementado un resolver:

  * GenericMapperSecurityTableResolverImpl: es el que dota de significado al campo SEC_INFO y define la sintaxis del valor (del par key=valor) y su semántica.

Se pueden crear resolvers que implementen relaciones complejas de seguridad.

## *Formato de la tabla G_SERVICES*

Si se utiliza la clase GenericDatabaseInfo se espera que esta contenga, al menos, los siguientes campos: TYPE, TABLE_NAME, FINAL_TABLE, RESOLVER, FIELDS, KEYS, SEPARATOR, SEC_RESOLVER, SEC_INFO.

Si, además, se utiliza como defaultResolver la clase BasicDatabaseResolver, es necesario que la tabla contenga estos otros campos: SELECT_VALUE, SELECT_FILTER, INSERT_VALUE, UPDATE_VALUE, DELETE_VALUE.

Todos los campos deben ser del tipo VARCHAR2 con tamaño suficiente para contener toda la información.

Un ejemplo de sql de puede ser:

CREATE TABLE G_SERVICES
(
  TABLE_NAME VARCHAR2(4000) NOT NULL
, TYPE VARCHAR2(4000)
, FINAL_TABLE VARCHAR2(4000)
, FIELDS VARCHAR2(4000)
, KEYS VARCHAR2(4000)
, SEPARATOR VARCHAR2(4000)
, SEC_INFO VARCHAR2(4000)
, RESOLVER VARCHAR2(4000)
, SEC_RESOLVER VARCHAR2(4000)
, SELECT_VALUE VARCHAR2(4000)
, SELECT_FILTER VARCHAR2(4000)
, INSERT_VALUE VARCHAR2(4000)
, UPDATE_VALUE VARCHAR2(4000)
, DELETE_VALUE VARCHAR2(4000)
);

redpajama_set_name: RedPajamaGithub


text:
Q: Swift 3/4 dash to camel case (Snake to camelCase) I am trying to perform a simple dash to camel case so:
"this-is-my-id" will become "thisIsMyId" in swift 3 (or 4).
No matter what I do I can't find an elegant enough way to do it..:
The following doesn't work:
str.split(separator: "-").enumerated().map { (index, element) in
    return index > 0 ? element.capitalized : element
}.reduce("", +)

It cries about all bunch of stuff. I am sure there is a simple enough way... Anyone?

A: Your code is almost correct. The following is the most readable implementation I have found:
let str: String = "this-is-my-id"

let result = str
    .split(separator: "-")  // split to components
    .map { String($0) }   // convert subsequences to String
    .enumerated()  // get indices
    .map { $0.offset > 0 ? $0.element.capitalized : $0.element.lowercased() } // added lowercasing
    .joined() // join to one string

print(result)

A: Just a better implementation of @sulthan's answer with Swift 4.1.
extension String {
    func camelCased(with separator: Character) -> String {
        return self.lowercased()
            .split(separator: separator)
            .enumerated()
            .map { $0.offset > 0 ? $0.element.capitalized : $0.element.lowercased() }
            .joined()
    }
}

A: What you could do is to spilt your string based on the dash "-" (creating an array of strings) and combine its elements with the desired case:
let myString = "this-is-my-id"
let newString = myString.split(separator: "-").reduce("", { $0 + $1.capitalized })

print(newString) // "ThisIsMyId"

A: Your syntax works if you destructure the String.Subsequence elements by creating new strings:
str.split(separator: "-").enumerated().map { (index, element) in
     return index > 0 ? String(element).capitalized : String(element)
}.joined() // better than `reduce`

A: Maybe the smallest implementation of conversioning from dash to camel case using reduce:
extension String {
    var camelCased: String {
        self.split(separator: "-")
            .reduce("", { $0 + ($0.isEmpty ? String($1) : $1.capitalized) })
    }
}

print("this-is-my-id".camelCased) // Prints "thisIsMyId"

A: You can iterate over the characters (String is a collection of characters) while holding a flag telling if the character came after a dash, in order to capitalize it:
let dashCase = "this-is-my-id"
let camelCase = dashCase.reduce(into: ("", false)) {
    // mark the dash
    guard $1 != "-" else { $0.1 = true; return }
    $0.0 += $0.1 ? String($1).uppercased() : String($1)
    // reset the flag so we don't capitalize the next ones
    $0.1 = false
}.0
print(camelCase)  // thisIsMyId

A: A combination of all these answers will lead to the following, shortest way (I think - only 2 interations):
let str: String = "this-is-my-id"

let result = str.split(separator: "-").reduce("") {(acc, name) in
    "\(acc)\(acc.count > 0 ? String(name.capitalized) : String(name))"
}

Thanks all!


text:
Winemaker's Comment Autumn 2010
You may have noticed on our current newsletter we are featuring a shot of our new labels. An ongoing irritation for us has been the reference to our "regular", "standard", "basic", "entry level" and all the other ghastly sounding names that have been used to describe it over the years. So, we've finally decided to name it. 2009 Felton Road Pinot Noir Bannockburn, is the new official naming of Felton Road Pinot Noir. The wine is unchanged, just the addition of a name. Since the addition of the Cornish Point Pinot Noir to the range, we began talking more and more about our three vineyards - all located in Bannockburn and all farmed under the same organic and biodynamic regime. The Felton Road Pinot Noir is usually about a third from each of the three vineyards: Elms, Calvert and Cornish Point. We also began describing the wine as essentially our village Bannockburn wine with the single vineyard wines above that from Cornish Point and Calvert, then the two single Block wines from within Elms: Block 3 and Block 5. The Chardonnay has also been given the same Bannockburn designation as it is also a blend from each of our three Bannockburn vineyards.
Nigel and I were completely humbled and very honoured to receive an inaugural award presented to just two wineries at the international Pinot Noir 2010 event in Wellington earlier this year. The award 'Tipuranga Teitei o Aotearoa' translates from Maori as Great Growth or Grand Cru of New Zealand. In presenting the award at the grand finale Gala Dinner, Alastair Maling, Master of Wine and Chairman of Pinot Noir 2010, said: "The Tipuranga Teitei o Aotearoa award recognises those who have taken time to evolve and develop Pinot Noir. They are widely considered a Premier Producer of Pinot Noir; the top echelon and an inspiration to the rest of the industry. This award is a uniquely New Zealand one, combining terroir with winemaking philosophy and consistent quality. It can only be achieved with vine age, proven wine quality, authenticity and undoubted global recognition." It is a great honour; firstly to be recognized by our peers in the New Zealand wine industry, but also for Nigel and I to be standing next to our friends at Ata Rangi in accepting this award.
We're very pleased to introduce Tracy Thomson to our team. Tracy is the one who receives you at our cellar door, processes and despatches orders and manages allocations - not to mention the myriad of other tasks that need to be done in a small team like ours. Most importantly for us in the winery, Tracy has been expertly and keenly driving the espresso machine throughout harvest keeping myself and my team well fuelled during our busy days in the cellar! Speaking of which, 2010 has turned out to be another exceptional vintage for us. We, very thankfully, finished harvesting the day before the heavy rains arrived that threatened to flood Queenstown. Another excellent growing season provided wonderful quality fruit. The wines are now all quietly resting in barrel and we look forward to following their development.
Last on the news list is a new look to our website (www.feltonroad.com). We really hope you take the time to have a look around and enjoy visiting Felton Road online. It has been, as all these things are, a hair tearing exercise at times. It reminds us what a harmonious process growing grapes and making wine really is. We are very fortunate.
We trust you enjoy these new releases: 2009 is certainly a vintage for us to be proud of. We are always nervous of making grand proclamations on the release of a young wine, but we would have to say we feel confident that this vintage will be a reference benchmark in years to come.
Blair Walter
Blair Walter's Blog Nigel Greening's Blog Sustainability Articles Reviews Privacy Policy Cookie Policy


This is classic "Hey youse guys, how bouta slice?" kind of "New York Style" pizza. I suppose there are some New Yorkers out there who stick their noses up at this, but I think it's pretty darn good. In my mind, it's the best pizza in the area.
NYPD also serves deep dish style pizza, salads, pasta, a bunch of different kinds of sandwiches, etc. I have no idea why you would get any of these things. The reason why one goes to NYPD is to eat a slice of New York style pizza. Simple as that.
They do have some more "modern" flavors here (for example, they frequently have some kind of chicken pizza available), but Will and I tend to favor the classics. Will likes pepperoni, and I like the "white" pizza, which is mozzarella, ricotta, parmesan, and seasonings– no red sauce.
They've recently (like in the last year or so) remodeled the inside of this place and made it a lot bigger, though it is still not exactly what you call elegant dinning. There is also a branch/franchise on University Ave., but I've never been to that one.


text:
Hobhouse, Edmund
Kōrero: Hobhouse, Edmund
Edmund Hobhouse photographed in the 1860s or 1870s
I tuhia tēnei haurongo e Katherine W. Orr,, ā, i tāngia tuatahitia ki Ngā Tāngata Taumata Rau Ko te wāhanga , 1990.
Edmund Hobhouse was born in London, England, on 17 April 1817, the son of Henry Hobhouse and his wife, Harriet Turton. Henry Hobhouse was a prominent government official, and Edmund had a privileged upbringing and education. In 1828 he went to Eton, where his tendency to overwork first manifested itself. Recurrent and virulent headaches, beginning in 1830, forced him to finish his schooling privately. Nevertheless he completed a BA at Oxford in 1838. Between 1838 and 1840 he studied at the theological school of the University of Durham, and in 1841 was elected to a fellowship at Merton College, Oxford. He was ordained deacon that Christmas and priest a year later.
Although financially independent, Hobhouse became vicar of St Peter's-in-the-East, Oxford, in 1843. He subsequently became involved in Bishop Samuel Wilberforce's reform of the diocese of Oxford. This made him familiar with diocesan administration. In 1853 he attended a general convention of the Protestant Episcopal Church of the United States of America, gaining valuable knowledge of synodical church government.
In 1855–56 Hobhouse, who was a friend of Bishop G. A. Selwyn, nearly became the first bishop of Christchurch. He withdrew when sufficient funds became available to allow Henry Harper to accept the office. On 1 January 1858 he married Mary Elizabeth Brodrick at Wells, Somerset, England. There were two sons of the marriage. In September 1858 he was consecrated as the first bishop of Nelson. He now added honorary DDs from Oxford, Cambridge and Durham to an Oxford MA (1842) and BD (1850). He arrived in New Zealand in late January 1859, just in time to participate in the first General Synod.
Hobhouse spent much of his episcopate organising the diocesan and parochial structure of the new diocese. In August 1859 he held the first of Nelson's annual diocesan synods. He streamlined the administration of existing endowments and tried, with limited success, to encourage voluntary contributions. In the end he subsidised diocesan finances very substantially from his own stipend and his private income. Diocesan and local trusts were created to manage estates previously held by Selwyn.
Hobhouse himself became trustee of the Wakarewa Trust, a large endowment of land by the Crown to provide education for children of every race. His efforts to set up a Maori boys' school were unavailing. Neither boys nor parents favoured the sort of boarding establishment Hobhouse envisaged. His desire to start a school in Nelson for Maori girls was also fruitless. But he succeeded in reopening a Church of England boys' school in Nelson.
Hobhouse experienced severe difficulties in obtaining sufficient clergy for parish and Maori work. One of his small band of assistants was the Reverend R. H. Codrington, his former curate, later a notable scholar in Melanesian languages. Codrington was the first clergyman Hobhouse sent to the populous Golden Bay goldfields. Another of Hobhouse's recruits was his cousin, the Reverend H. M. Turton.
Stress caused by staff shortages and exacerbated by conscientiousness, a tendency to overwork and an inability to delegate meant that Hobhouse's health, never good despite his apparently robust physique, was always a concern. Initially, however, long visitations of the diocese on foot or horseback controlled his headaches.
His devotion to duty at first won admiration. But three factors probably helped create distrust of episcopacy in Nelson. A dispute festered between Selwyn and some Nelson members of the church over a contribution to the Nelson episcopal endowment which Selwyn refused to pay. The wars of the 1860s generated anti-episcopal feeling. Moreover, class feeling ran high in Nelson, and the shy and reserved Hobhouse, who was clearly a gentleman, may have met with a negative response from some quarters.
Two aspects of his beliefs also undermined his popularity. Firstly, many Nelsonians were more fervent supporters of religious tolerance than was usual in contemporary England. Hobhouse was attacked as unacceptably intolerant. Secondly, Hobhouse's churchmanship displeased the strong evangelical element in Nelson. Although he rejected the Tractarian label, Hobhouse firmly believed that his church was 'Catholic' as well as reformed. He openly said the daily offices, and his sermons did not suit evangelical tastes.
Turton, who took charge of Nelson city from the bishop, was also a high churchman and he aroused considerable opposition. His public standing, already under attack, was irreparably damaged when in 1863 he was charged with sodomy. The motivation of the accuser and the truth of the accusation were questionable, and remain so. Turton was in any case acquitted and returned to England. As a consequence, additional duties were thrust on Hobhouse. This burden, combined with a feeling that the other clergy had given him and Turton inadequate support over the sodomy accusation, apparently upset the precarious balance of his health. In August 1864 he announced that he would resign as bishop, but continue to serve in the diocese under his successor. His resignation took effect in 1865. The death in October 1864 of his wife, to whom he was devoted, led him to reconsider his decision to stay. He left for England in June 1866.
Back in England Hobhouse first held the living of Beech Hill, near Reading. He remarried on 14 January 1868 at Bramshill, Southampton: his second wife was Anna Maria Williams. From 1869 he acted as assistant to Selwyn, now bishop of Lichfield. He was also chancellor of Lichfield diocese in 1874–75. In 1881 he retired to Wells, Somerset. A keen amateur historian, Hobhouse was active in founding the Somerset Record Society in 1886. His publications were confined to historical subjects. He died on 20 April 1904 aged 87 years.
Historians have tended to ignore or minimise the effect on Hobhouse's health of difficulties caused by his and Turton's churchmanship and, in particular, by the sodomy case. Without these problems his episcopate might have lasted much longer. Because of his rather rigid temperament and uncertain health Hobhouse was not an ideal choice for a colonial bishop. But his piety, zeal and liking for travel to some extent compensated for these factors. During his brief episcopate Hobhouse laid the foundations of diocesan organisation, and his munificent financial contributions, particularly his gift of the Bishopdale estate, were of lasting benefit to the diocese of Nelson.
Katherine W. Orr. 'Hobhouse, Edmund', Dictionary of New Zealand Biography, first published in 1990. Te Ara - the Encyclopedia of New Zealand, https://teara.govt.nz/mi/biographies/1h28/hobhouse-edmund (accessed 21 January 2020)


For those brave enough to go out in the snow and wind, there's been some good fishing around Sooke and Victoria lately. Here's Ryan from Vancouver Island Lodge with a couple new friends, one of which is a 15 pound winter chinook salmon.
When the tides are right there are some halibut around too ... Trevor from No Bananas Fishing Charters caught a couple halibut while trolling for salmon, sending home some white gold with these Fort MacMurray visitors.


text:
Oblique Seville (born 16 March 2001) is a Jamaican sprinter.

Seville attended Calabar High School and is coached by Racers Track Club coach Glen Mills.
2019 was a breakthrough year for Seville: At the 2019 CARIFTA Games in George Town, Cayman Islands, he won the 100 metres in a time of 10.24s as well as the 4x100 metres relay. He also won the 100m at the Jamaican U20 Championships in Kingston in 10.13s. He also finished second in the 100m at the 2019 Pan American U20 Championships in San José, Costa Rica in 10.21s and won silver in the 4x100 metres relay.

The COVID-19 pandemic prevented him from competing for most of 2020 but Seville impressed again in April 2021 at the Jamaican Olympic Trials qualification, running the fastest 100m time. At the actual Jamaican Olympic trials in June 2021 for the delayed 2020 Summer Games, he was the fourth fastest with 10.10 seconds. In the final Seville finished third in the 100m behind Tyquendo Tracey, and Yohan Blake to secure his place at the Olympics.

References

External links

Living people
2001 births
Jamaican male sprinters
Athletes (track and field) at the 2020 Summer Olympics
Olympic athletes of Jamaica

redpajama_set_name: RedPajamaWikipedia


Announcement Welcome Folks!! I am a Canadian Artist working with paints, mixed media and digital photography to make wall art, clothing and gift items. I do this seven days a week and it is the reason I wake up each day!
I joined in 2014 but could not add products until winter 2017 but am focused on Art and Fashion with my work. Thanks to those who are discovering me and for your positive input and enthusiasm! So appreciated.
Please let me know if you would like a specific item and which art you would like on the item. I do have original art for sale. Please contact me in Conversation area.
Items are sent through Canada Post or UPS to your destination and ship to the address provided. Please make sure the address you provide is where you want the item(s) sent. Delivery time varies by location.
These are custom orders and therefore Refunds or Exchanges are only accepted on a case by case basis with contact within 3 days of receipt of your package. Please contact me if your item is damaged through mailing and provide photos of damage. Also colors on monitors vary and printing on fabric varies depending on the fabric, but have been as accurate as possible.
If you have any problem with your item, please Convo or Email me and I will work with you to clear up the situation the best that I can so we are both happy folks !
Rather than a negative review, let's keep things positive, happy and colorful like my art and work together to make this a great opportunity. And of course, if you are happy, (YAY) please leave a review to let others know I am doing my best and you are pleased with your purchase and the efforts of myself and those involved in the custom work.
I create 7 days a week behind closed doors, creating this stuff for you and your words and communication are so important - I am so grateful to you all. THANK YOU.
Expect production delays at this time.
Holiday Deadlines (Please note these are not guaranteed delivery, but rather guidelines. We cannot guarantee delivery for a certain date.
All of my original paintings, prints, digital images, cards, or any other representation and items made of my art are copyrighted by Claire Bull and may not be used for any purpose without prior written consent.
Thank you for Respecting my art and efforts making it for you.
Welcome Folks!! I am a Canadian Artist working with paints, mixed media and digital photography to make wall art, clothing and gift items. I do this seven days a week and it is the reason I wake up each day!
Recycling items from plain to pretty ! These will be bright and colorful when done, recycled and useful.
I loved coloring as a child and one of my best memories was getting a PEN for best penmanship in grade 4 and being able to use pencil and pen for my work. Most of my jeans were tie dyed or bleached and I would use pens and paint to create flowers and designs on the pockets or legs. Creating and giving back with healing positive art is what I am trying to do now and share the art.
I have taken art classes all of my life for pleasure and distraction and learning and fun and exploring. I see color in everything. I try to recreate that and make the world more colorful with my art. Working with paint and photography, making art with imagination and creativity.
I am offering original art, prints, clothing, fashion accessories and gift items. These are colorful, fun and positive items in a variety of styles and designs. I also enjoy reading, knitting, needlework and nature.
I love experimenting and creating Floral paintings, Landscapes and Digital Art. I have been making art since I was a little girl and now do this full time. Color and inspiration is everywhere. I dream about art. Thanks for your support of my work.
I use a Canadian company to print my work. I love that they source locally to help reduce our carbon footprint. Their paper waste is recycled in the city and excess clothing items or imperfect garments are donated to shelters.
Works with me to produce items with my original art designs.


Everything you need to PLAN & HOST the perfect Holiday gift exchange!
Let's face it, the White Elephant Christmas party is a favorite season tradition! With all the hustle and bustle of the season we bet your Holiday schedule is already starting to fill up! We've taken the stress out of either planning or attending a fabulous white elephant party with your favorite people. Our new exclusive printable pack has everything you need for the ultimate Holiday gift exchange!
Because beautiful Decor + Yummy Food + Hilarious Gifts and Your Favorite People = Amazing Holiday Memories!


Beautiful Japanese wallpaper patterns come alive in a three dimensional object. We have just installed the first prototype of our new Geisha lamp.
I can`t keep my eyes from the ceiling… The first prototype of the Genesis lamp is ready, and it is beautiful! The light is smooth, yet powerful enough to light up the room. It is just perfect.
The EQ sofa has just got a beautiful new wooden frame, with "automatically" folding back supporters. From now if the back is in horizontal position it can support the weight of multiple people if they sit onto it.


Find-A-Pest is now available free on the Apple App Store and Google Play store. It's available for anyone to use during our four month trial period. Install it, take it for a spin, and let us know what you think!
While this Find-A-Pest app is fully functional, our initial focus through February–May will be on testing the app with selected community and industry groups. We'd welcome your feedback too.
The final beta versions of Find-A-Pest were thouroghly tested by a small team of brave people. Thanks again to those who helped us to track down the holes that needed patching.
We'll use all the feedback from our case studies to head back into code and tweak and polish the app so that it's ready for widespread use. All going well, we'll be shouting much louder about Find-A-Pest after that.


text:
/*
 * 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.
 */
package com.facebook.presto.sql.analyzer;

import com.facebook.presto.Session;
import com.facebook.presto.block.BlockEncodingManager;
import com.facebook.presto.metadata.MetadataManager;
import com.facebook.presto.metadata.QualifiedTableName;
import com.facebook.presto.metadata.TableMetadata;
import com.facebook.presto.metadata.TestingMetadata;
import com.facebook.presto.metadata.ViewDefinition;
import com.facebook.presto.spi.ColumnMetadata;
import com.facebook.presto.spi.ConnectorTableMetadata;
import com.facebook.presto.spi.SchemaTableName;
import com.facebook.presto.spi.type.TypeManager;
import com.facebook.presto.split.SplitManager;
import com.facebook.presto.sql.parser.SqlParser;
import com.facebook.presto.sql.tree.Statement;
import com.facebook.presto.type.TypeRegistry;
import com.google.common.collect.ImmutableList;
import io.airlift.json.JsonCodec;
import org.intellij.lang.annotations.Language;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.util.Optional;

import static com.facebook.presto.metadata.ViewDefinition.ViewColumn;
import static com.facebook.presto.spi.type.BigintType.BIGINT;
import static com.facebook.presto.spi.type.TimeZoneKey.UTC_KEY;
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.AMBIGUOUS_ATTRIBUTE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.CANNOT_HAVE_AGGREGATIONS_OR_WINDOWS;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.COLUMN_NAME_NOT_SPECIFIED;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.DUPLICATE_COLUMN_NAME;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.DUPLICATE_RELATION;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_ORDINAL;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_WINDOW_FRAME;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISMATCHED_COLUMN_ALIASES;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISMATCHED_SET_COLUMN_TYPES;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_ATTRIBUTE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_CATALOG;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_SCHEMA;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_TABLE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MUST_BE_AGGREGATE_OR_GROUP_BY;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.NESTED_AGGREGATION;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.NESTED_WINDOW;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.NON_NUMERIC_SAMPLE_PERCENTAGE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.NOT_SUPPORTED;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.ORDER_BY_MUST_BE_IN_SELECT;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.SAMPLE_PERCENTAGE_OUT_OF_RANGE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.TYPE_MISMATCH;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.VIEW_IS_STALE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.WILDCARD_WITHOUT_FROM;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.WINDOW_REQUIRES_OVER;
import static java.lang.String.format;
import static java.util.Locale.ENGLISH;
import static org.testng.Assert.fail;

@Test(singleThreaded = true)
public class TestAnalyzer
{
    public static final Session SESSION = Session.builder()
            .setUser("user")
            .setSource("test")
            .setCatalog("default")
            .setSchema("default")
            .setTimeZoneKey(UTC_KEY)
            .setLocale(ENGLISH)
            .build();

    private static final SqlParser SQL_PARSER = new SqlParser();

    private Analyzer analyzer;
    private Analyzer approximateDisabledAnalyzer;

    @Test
    public void testDuplicateRelation()
            throws Exception
    {
        assertFails(DUPLICATE_RELATION, "SELECT * FROM t1 JOIN t1 USING (a)");
        assertFails(DUPLICATE_RELATION, "SELECT * FROM t1 x JOIN t2 x USING (a)");
    }

    @Test
    public void testNonComparableGroupBy()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT * FROM (SELECT approx_set(1)) GROUP BY 1");
    }

    @Test
    public void testNonComparableWindowPartition()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT row_number() OVER (PARTITION BY t.x) FROM (VALUES(CAST (NULL AS HyperLogLog))) AS t(x)");
    }

    @Test
    public void testNonComparableWindowOrder()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT row_number() OVER (ORDER BY t.x) FROM (VALUES(color('red'))) AS t(x)");
    }

    @Test
    public void testNonComparableDistinctAggregation()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT count(DISTINCT x) FROM (SELECT approx_set(1) x)");
    }

    @Test
    public void testNonComparableDistinct()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT DISTINCT * FROM (SELECT approx_set(1) x)");
        assertFails(TYPE_MISMATCH, "SELECT DISTINCT x FROM (SELECT approx_set(1) x)");
    }

    @Test
    public void testInSubqueryTypes()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT * FROM (VALUES ('a')) t(y) WHERE y IN (VALUES (1))");
    }

    @Test
    public void testScalarSubQueryException()
            throws Exception
    {
        assertFails(NOT_SUPPORTED, "SELECT 'a', (VALUES (1)) GROUP BY 1");
        assertFails(NOT_SUPPORTED, "SELECT 'a', (SELECT (1))");
        assertFails(NOT_SUPPORTED, "SELECT * FROM t1 WHERE (VALUES 1) = 2");
        assertFails(NOT_SUPPORTED, "SELECT * FROM t1 WHERE (VALUES 1) IN (VALUES 1)");
        analyze("SELECT * FROM (SELECT 1) t1(x) WHERE x IN (SELECT 1)");
    }

    @Test
    public void testHavingReferencesOutputAlias()
            throws Exception
    {
        assertFails(MISSING_ATTRIBUTE, "SELECT sum(a) x FROM t1 HAVING x > 5");
    }

    @Test
    public void testWildcardWithInvalidPrefix()
            throws Exception
    {
        assertFails(MISSING_TABLE, "SELECT foo.* FROM t1");
    }

    @Test
    public void testGroupByWithWildcard()
            throws Exception
    {
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT * FROM t1 GROUP BY 1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT u1.*, u2.* FROM (select a, b + 1 from t1) u1 JOIN (select a, b + 2 from t1) u2 USING (a) GROUP BY u1.a, u2.a, 3");
    }

    @Test
    public void testGroupByInvalidOrdinal()
            throws Exception
    {
        assertFails(INVALID_ORDINAL, "SELECT * FROM t1 GROUP BY 10");
        assertFails(INVALID_ORDINAL, "SELECT * FROM t1 GROUP BY 0");
    }

    @Test
    public void testOrderByInvalidOrdinal()
            throws Exception
    {
        assertFails(INVALID_ORDINAL, "SELECT * FROM t1 ORDER BY 10");
        assertFails(INVALID_ORDINAL, "SELECT * FROM t1 ORDER BY 0");
    }

    @Test
    public void testOrderByNonComparable()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT x FROM (SELECT approx_set(1) x) ORDER BY 1");
        assertFails(TYPE_MISMATCH, "SELECT * FROM (SELECT approx_set(1) x) ORDER BY 1");
        assertFails(TYPE_MISMATCH, "SELECT x FROM (SELECT approx_set(1) x) ORDER BY x");
    }

    @Test
    public void testNestedAggregation()
            throws Exception
    {
        assertFails(NESTED_AGGREGATION, "SELECT sum(count(*)) FROM t1");
    }

    @Test
    public void testAggregationsNotAllowed()
            throws Exception
    {
        assertFails(CANNOT_HAVE_AGGREGATIONS_OR_WINDOWS, "SELECT * FROM t1 WHERE sum(a) > 1");
        assertFails(CANNOT_HAVE_AGGREGATIONS_OR_WINDOWS, "SELECT * FROM t1 GROUP BY sum(a)");
        assertFails(CANNOT_HAVE_AGGREGATIONS_OR_WINDOWS, "SELECT * FROM t1 JOIN t2 ON sum(t1.a) = t2.a");
    }

    @Test
    public void testWindowsNotAllowed()
            throws Exception
    {
        assertFails(CANNOT_HAVE_AGGREGATIONS_OR_WINDOWS, "SELECT * FROM t1 WHERE foo() over () > 1");
        assertFails(CANNOT_HAVE_AGGREGATIONS_OR_WINDOWS, "SELECT * FROM t1 GROUP BY rank() over ()");
        assertFails(CANNOT_HAVE_AGGREGATIONS_OR_WINDOWS, "SELECT * FROM t1 JOIN t2 ON sum(t1.a) over () = t2.a");
    }

    @Test
    public void testInvalidTable()
            throws Exception
    {
        assertFails(MISSING_CATALOG, "SELECT * FROM foo.default.t");
        assertFails(MISSING_SCHEMA, "SELECT * FROM foo.t");
        assertFails(MISSING_TABLE, "SELECT * FROM foo");
    }

    @Test
    public void testNonAggregate()
            throws Exception
    {
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT 'a', array[b][1] FROM t1 GROUP BY 1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT a, sum(b) FROM t1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT sum(b) / a FROM t1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT sum(b) / a FROM t1 GROUP BY c");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT sum(b) FROM t1 ORDER BY a + 1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT a, sum(b) FROM t1 GROUP BY a HAVING c > 5");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT count(*) over (PARTITION BY a) FROM t1 GROUP BY b");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT count(*) over (ORDER BY a) FROM t1 GROUP BY b");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT count(*) over (ORDER BY count(*) ROWS a PRECEDING) FROM t1 GROUP BY b");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT count(*) over (ORDER BY count(*) ROWS BETWEEN b PRECEDING AND a PRECEDING) FROM t1 GROUP BY b");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT count(*) over (ORDER BY count(*) ROWS BETWEEN a PRECEDING AND UNBOUNDED PRECEDING) FROM t1 GROUP BY b");
    }

    @Test
    public void testInvalidAttribute()
            throws Exception
    {
        assertFails(MISSING_ATTRIBUTE, "SELECT f FROM t1");
        assertFails(MISSING_ATTRIBUTE, "SELECT * FROM t1 ORDER BY f");
        assertFails(MISSING_ATTRIBUTE, "SELECT count(*) FROM t1 GROUP BY f");
        assertFails(MISSING_ATTRIBUTE, "SELECT * FROM t1 WHERE f > 1");
    }

    @Test
    public void testOrderByMustAppearInSelectWithDistinct()
            throws Exception
    {
        assertFails(ORDER_BY_MUST_BE_IN_SELECT, "SELECT DISTINCT a FROM t1 ORDER BY b");
    }

    @Test
    public void testNonBooleanWhereClause()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT * FROM t1 WHERE a");
    }

    @Test
    public void testApproximateNotEnabled()
            throws Exception
    {
        try {
            Statement statement = SQL_PARSER.createStatement("SELECT AVG(a) FROM t1 APPROXIMATE AT 99.0 CONFIDENCE");
            approximateDisabledAnalyzer.analyze(statement);
            fail(format("Expected error %s, but analysis succeeded", NOT_SUPPORTED));
        }
        catch (SemanticException e) {
            if (e.getCode() != NOT_SUPPORTED) {
                fail(format("Expected error %s, but found %s: %s", NOT_SUPPORTED, e.getCode(), e.getMessage()), e);
            }
        }
    }

    @Test
    public void testApproximateQuery()
            throws Exception
    {
        analyze("SELECT AVG(a) FROM t1 APPROXIMATE AT 99.0 CONFIDENCE");
    }

    @Test
    public void testDistinctAggregations()
            throws Exception
    {
        analyze("SELECT COUNT(DISTINCT a), SUM(a) FROM t1");
    }

    @Test
    public void testMultipleDistinctAggregations()
            throws Exception
    {
        analyze("SELECT COUNT(DISTINCT a), COUNT(DISTINCT b) FROM t1");
    }

    @Test
    public void testOrderByExpressionOnOutputColumn()
            throws Exception
    {
        assertFails(MISSING_ATTRIBUTE, "SELECT a x FROM t1 ORDER BY x + 1");
    }

    @Test
    public void testOrderByExpressionOnOutputColumn2()
            throws Exception
    {
        // TODO: validate output
        analyze("SELECT a x FROM t1 ORDER BY a + 1");
    }

    @Test
    public void testOrderByWithWildcard()
            throws Exception
    {
        // TODO: validate output
        analyze("SELECT a, t1.* FROM t1 ORDER BY a");
    }

    @Test
    public void testMismatchedColumnAliasCount()
            throws Exception
    {
        assertFails(MISMATCHED_COLUMN_ALIASES, "SELECT * FROM t1 u (x, y)");
    }

    @Test
    public void testJoinOnConstantExpression()
            throws Exception
    {
        analyze("SELECT * FROM t1 JOIN t2 ON 1 = 1");
    }

    @Test
    public void testJoinOnNonBooleanExpression()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT * FROM t1 JOIN t2 ON 5");
    }

    @Test
    public void testJoinOnAmbiguousName()
            throws Exception
    {
        assertFails(AMBIGUOUS_ATTRIBUTE, "SELECT * FROM t1 JOIN t2 ON a = a");
    }

    @Test
    public void testNonEquiJoin()
            throws Exception
    {
        assertFails(NOT_SUPPORTED, "SELECT * FROM t1 JOIN t2 ON t1.a + t2.a = 1");
        assertFails(NOT_SUPPORTED, "SELECT * FROM t1 JOIN t2 ON t1.a = t2.a OR t1.b = t2.b");
    }

    @Test
    public void testNonBooleanHaving()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT sum(a) FROM t1 HAVING sum(a)");
    }

    @Test
    public void testAmbiguousReferenceInOrderBy()
            throws Exception
    {
        assertFails(AMBIGUOUS_ATTRIBUTE, "SELECT a x, b x FROM t1 ORDER BY x");
    }

    @Test
    public void testImplicitCrossJoin()
    {
        // TODO: validate output
        analyze("SELECT * FROM t1, t2");
    }

    @Test
    public void testNaturalJoinNotSupported()
            throws Exception
    {
        assertFails(NOT_SUPPORTED, "SELECT * FROM t1 NATURAL JOIN t2");
    }

    @Test
    public void testNestedWindowFunctions()
            throws Exception
    {
        assertFails(NESTED_WINDOW, "SELECT avg(sum(a) OVER ()) FROM t1");
        assertFails(NESTED_WINDOW, "SELECT sum(sum(a) OVER ()) OVER () FROM t1");
        assertFails(NESTED_WINDOW, "SELECT avg(a) OVER (PARTITION BY sum(b) OVER ()) FROM t1");
        assertFails(NESTED_WINDOW, "SELECT avg(a) OVER (ORDER BY sum(b) OVER ()) FROM t1");
    }

    @Test
    public void testWindowFunctionWithoutOverClause()
    {
        assertFails(WINDOW_REQUIRES_OVER, "SELECT row_number()");
        assertFails(WINDOW_REQUIRES_OVER, "SELECT coalesce(lead(a), 0) from (values(0)) t(a)");
    }

    @Test
    public void testInvalidWindowFrame()
            throws Exception
    {
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (ROWS UNBOUNDED FOLLOWING)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (ROWS 2 FOLLOWING)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (ROWS BETWEEN UNBOUNDED FOLLOWING AND CURRENT ROW)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED PRECEDING)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (ROWS BETWEEN CURRENT ROW AND 5 PRECEDING)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (ROWS BETWEEN 2 FOLLOWING AND 5 PRECEDING)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (ROWS BETWEEN 2 FOLLOWING AND CURRENT ROW)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (RANGE 2 PRECEDING)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (RANGE BETWEEN 2 PRECEDING AND CURRENT ROW)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (RANGE BETWEEN CURRENT ROW AND 5 FOLLOWING)");
        assertFails(INVALID_WINDOW_FRAME, "SELECT rank() OVER (RANGE BETWEEN 2 PRECEDING AND 5 FOLLOWING)");

        assertFails(TYPE_MISMATCH, "SELECT rank() OVER (ROWS 0.5 PRECEDING)");
        assertFails(TYPE_MISMATCH, "SELECT rank() OVER (ROWS 'foo' PRECEDING)");
        assertFails(TYPE_MISMATCH, "SELECT rank() OVER (ROWS BETWEEN CURRENT ROW AND 0.5 FOLLOWING)");
        assertFails(TYPE_MISMATCH, "SELECT rank() OVER (ROWS BETWEEN CURRENT ROW AND 'foo' FOLLOWING)");
    }

    @Test
    public void testDistinctInWindowFunctionParameter()
            throws Exception
    {
        assertFails(NOT_SUPPORTED, "SELECT a, count(DISTINCT b) OVER () FROM t1");
    }

    @Test
    public void testGroupByOrdinalsWithWildcard()
            throws Exception
    {
        // TODO: verify output
        analyze("SELECT t1.*, a FROM t1 GROUP BY 1,2,c,d");
    }

    @Test
    public void testGroupByWithQualifiedName()
            throws Exception
    {
        // TODO: verify output
        analyze("SELECT a FROM t1 GROUP BY t1.a");
    }

    @Test
    public void testGroupByWithQualifiedName2()
            throws Exception
    {
        // TODO: verify output
        analyze("SELECT t1.a FROM t1 GROUP BY a");
    }

    @Test
    public void testGroupByWithQualifiedName3()
            throws Exception
    {
        // TODO: verify output
        analyze("SELECT * FROM t1 GROUP BY t1.a, t1.b, t1.c, t1.d");
    }

    @Test
    public void testGroupByWithRowExpression()
            throws Exception
    {
        // TODO: verify output
        analyze("SELECT (a, b) FROM t1 GROUP BY a, b");
    }

    @Test
    public void testHaving()
            throws Exception
    {
        // TODO: verify output
        analyze("SELECT sum(a) FROM t1 HAVING avg(a) - avg(b) > 10");
    }

    @Test
    public void testWithCaseInsensitiveResolution()
            throws Exception
    {
        // TODO: verify output
        analyze("WITH AB AS (SELECT * FROM t1) SELECT * FROM ab");
    }

    @Test
    public void testInsert()
            throws Exception
    {
        analyze("INSERT INTO t1 SELECT * FROM t1");
        analyze("INSERT INTO t3 SELECT * FROM t3");
        analyze("INSERT INTO t3 SELECT a, b FROM t3");
        assertFails(MISMATCHED_SET_COLUMN_TYPES, "INSERT INTO t1 VALUES (1, 2)");

        // ignore t5 hidden column
        analyze("INSERT INTO t5 VALUES (1)");

        // fail if hidden column provided
        assertFails(MISMATCHED_SET_COLUMN_TYPES, "INSERT INTO t5 VALUES (1, 2)");
    }

    @Test
    public void testDuplicateWithQuery()
            throws Exception
    {
        assertFails(DUPLICATE_RELATION,
                "WITH a AS (SELECT * FROM t1)," +
                        "     a AS (SELECT * FROM t1)" +
                        "SELECT * FROM a");
    }

    @Test
    public void testCaseInsensitiveDuplicateWithQuery()
            throws Exception
    {
        assertFails(DUPLICATE_RELATION,
                "WITH a AS (SELECT * FROM t1)," +
                        "     A AS (SELECT * FROM t1)" +
                        "SELECT * FROM a");
    }

    @Test
    public void testWithForwardReference()
            throws Exception
    {
        assertFails(MISSING_TABLE,
                "WITH a AS (SELECT * FROM b)," +
                        "     b AS (SELECT * FROM t1)" +
                        "SELECT * FROM a");
    }

    @Test
    public void testExpressions()
            throws Exception
    {
        // logical not
        assertFails(TYPE_MISMATCH, "SELECT NOT 1 FROM t1");

        // logical and/or
        assertFails(TYPE_MISMATCH, "SELECT 1 AND TRUE FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT TRUE AND 1 FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT 1 OR TRUE FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT TRUE OR 1 FROM t1");

        // comparison
        assertFails(TYPE_MISMATCH, "SELECT 1 = 'a' FROM t1");

        // nullif
        assertFails(TYPE_MISMATCH, "SELECT NULLIF(1, 'a') FROM t1");

        // case
        assertFails(TYPE_MISMATCH, "SELECT CASE WHEN TRUE THEN 'a' ELSE 1 END FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT CASE WHEN '1' THEN 1 ELSE 2 END FROM t1");

        assertFails(TYPE_MISMATCH, "SELECT CASE 1 WHEN 'a' THEN 2 END FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT CASE 1 WHEN 1 THEN 2 ELSE 'a' END FROM t1");

        // coalesce
        assertFails(TYPE_MISMATCH, "SELECT COALESCE(1, 'a') FROM t1");

        // cast
        assertFails(TYPE_MISMATCH, "SELECT CAST(date '2014-01-01' AS bigint)");
        assertFails(TYPE_MISMATCH, "SELECT TRY_CAST(date '2014-01-01' AS bigint)");
        assertFails(TYPE_MISMATCH, "SELECT CAST(null AS UNKNOWN)");

        // arithmetic unary
        assertFails(TYPE_MISMATCH, "SELECT -'a' FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT +'a' FROM t1");

        // arithmetic addition/subtraction
        assertFails(TYPE_MISMATCH, "SELECT 'a' + 1 FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT 1 + 'a'  FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT 'a' - 1 FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT 1 - 'a' FROM t1");

        // like
        assertFails(TYPE_MISMATCH, "SELECT 1 LIKE 'a' FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT 'a' LIKE 1 FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT 'a' LIKE 'b' ESCAPE 1 FROM t1");

        // extract
        assertFails(TYPE_MISMATCH, "SELECT EXTRACT(DAY FROM 'a') FROM t1");

        // between
        assertFails(TYPE_MISMATCH, "SELECT 1 BETWEEN 'a' AND 2 FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT 1 BETWEEN 0 AND 'b' FROM t1");
        assertFails(TYPE_MISMATCH, "SELECT 1 BETWEEN 'a' AND 'b' FROM t1");

        // in
        assertFails(TYPE_MISMATCH, "SELECT * FROM t1 WHERE 1 IN ('a')");
        assertFails(TYPE_MISMATCH, "SELECT * FROM t1 WHERE 'a' IN (1)");
        assertFails(TYPE_MISMATCH, "SELECT * FROM t1 WHERE 'a' IN (1, 'b')");
    }

    @Test(enabled = false) // TODO: need to support widening conversion for numbers
    public void testInWithNumericTypes()
            throws Exception
    {
        analyze("SELECT * FROM t1 WHERE 1 IN (1, 2, 3.5)");
    }

    @Test
    public void testWildcardWithoutFrom()
            throws Exception
    {
        assertFails(WILDCARD_WITHOUT_FROM, "SELECT *");
    }

    @Test
    public void testReferenceWithoutFrom()
            throws Exception
    {
        assertFails(MISSING_ATTRIBUTE, "SELECT dummy");
    }

    @Test
    public void testGroupBy()
            throws Exception
    {
        // TODO: validate output
        analyze("SELECT a, SUM(b) FROM t1 GROUP BY a");
    }

    @Test
    public void testAggregateWithWildcard()
            throws Exception
    {
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT * FROM (SELECT a + 1, b FROM t1) t GROUP BY b ORDER BY 1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT * FROM (SELECT a, b FROM t1) t GROUP BY b ORDER BY 1");

        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT * FROM (SELECT a, b FROM t1) GROUP BY b ORDER BY 1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT * FROM (SELECT a + 1, b FROM t1) GROUP BY b ORDER BY 1");
    }

    @Test
    public void testGroupByCase()
            throws Exception
    {
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT CASE a WHEN 1 THEN 'a' ELSE 'b' END, count(*) FROM t1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT CASE 1 WHEN 2 THEN a ELSE 0 END, count(*) FROM t1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT CASE 1 WHEN 2 THEN 0 ELSE a END, count(*) FROM t1");

        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT CASE WHEN a = 1 THEN 'a' ELSE 'b' END, count(*) FROM t1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT CASE WHEN true THEN a ELSE 0 END, count(*) FROM t1");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT CASE WHEN true THEN 0 ELSE a END, count(*) FROM t1");
    }

    @Test
    public void testMismatchedUnionQueries()
            throws Exception
    {
        assertFails(TYPE_MISMATCH, "SELECT 1 UNION SELECT 'a'");
        assertFails(TYPE_MISMATCH, "SELECT a FROM t1 UNION SELECT 'a'");
        assertFails(TYPE_MISMATCH, "(SELECT 1) UNION SELECT 'a'");
        assertFails(MISMATCHED_SET_COLUMN_TYPES, "SELECT 1, 2 UNION SELECT 1");
        assertFails(MISMATCHED_SET_COLUMN_TYPES, "SELECT 'a' UNION SELECT 'b', 'c'");
        assertFails(MISMATCHED_SET_COLUMN_TYPES, "TABLE t2 UNION SELECT 'a'");
    }

    @Test
    public void testUnionUnmatchedOrderByAttribute()
            throws Exception
    {
        assertFails(MISSING_ATTRIBUTE, "TABLE t2 UNION ALL SELECT c, d FROM t1 ORDER BY c");
    }

    @Test
    public void testGroupByComplexExpressions()
            throws Exception
    {
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT IF(a IS NULL, 1, 0) FROM t1 GROUP BY b");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT IF(a IS NOT NULL, 1, 0) FROM t1 GROUP BY b");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT IF(CAST(a AS VARCHAR) LIKE 'a', 1, 0) FROM t1 GROUP BY b");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT a IN (1, 2, 3) FROM t1 GROUP BY b");
        assertFails(MUST_BE_AGGREGATE_OR_GROUP_BY, "SELECT 1 IN (a, 2, 3) FROM t1 GROUP BY b");
    }

    @Test
    public void testNonNumericTableSamplePercentage()
            throws Exception
    {
        assertFails(NON_NUMERIC_SAMPLE_PERCENTAGE, "SELECT * FROM t1 TABLESAMPLE BERNOULLI ('a')");
        assertFails(NON_NUMERIC_SAMPLE_PERCENTAGE, "SELECT * FROM t1 TABLESAMPLE BERNOULLI (a + 1)");
    }

    @Test
    public void testTableSampleOutOfRange()
            throws Exception
    {
        assertFails(SAMPLE_PERCENTAGE_OUT_OF_RANGE, "SELECT * FROM t1 TABLESAMPLE BERNOULLI (-1)");
        assertFails(SAMPLE_PERCENTAGE_OUT_OF_RANGE, "SELECT * FROM t1 TABLESAMPLE BERNOULLI (-101)");
    }

    @Test
    public void testCreateViewColumns()
            throws Exception
    {
        assertFails(COLUMN_NAME_NOT_SPECIFIED, "CREATE VIEW test AS SELECT 123");
        assertFails(DUPLICATE_COLUMN_NAME, "CREATE VIEW test AS SELECT 1 a, 2 a");
    }

    @Test
    public void testStaleView()
            throws Exception
    {
        assertFails(VIEW_IS_STALE, "SELECT * FROM v2");
    }

    @Test
    public void testStoredViewAnalysisScoping()
            throws Exception
    {
        // the view must not be analyzed using the query context
        analyze("WITH t1 AS (SELECT 123 x) SELECT * FROM v1");
    }

    @Test
    public void testStoredViewResolution()
            throws Exception
    {
        // the view must be analyzed relative to its own catalog/schema
        analyze("SELECT * FROM c3.s3.v3");
    }

    @Test
    public void testUse()
            throws Exception
    {
        assertFails(NOT_SUPPORTED, "USE default");
    }

    @Test
    public void testNotNullInJoinClause()
            throws Exception
    {
        assertFails(NOT_SUPPORTED, "SELECT * FROM (VALUES (1)) a (x) JOIN (VALUES (2)) b ON a.x IS NOT NULL");
    }

    @Test
    public void testIfInJoinClause()
            throws Exception
    {
        assertFails(NOT_SUPPORTED, "SELECT * FROM (VALUES (1)) a (x) JOIN (VALUES (2)) b ON IF(a.x = 1, true, false)");
    }

    @BeforeMethod(alwaysRun = true)
    public void setup()
            throws Exception
    {
        TypeManager typeManager = new TypeRegistry();
        MetadataManager metadata = new MetadataManager(new FeaturesConfig().setExperimentalSyntaxEnabled(true), typeManager, new SplitManager(), new BlockEncodingManager(typeManager));
        metadata.addConnectorMetadata("tpch", "tpch", new TestingMetadata());
        metadata.addConnectorMetadata("c2", "c2", new TestingMetadata());
        metadata.addConnectorMetadata("c3", "c3", new TestingMetadata());

        SchemaTableName table1 = new SchemaTableName("default", "t1");
        metadata.createTable(SESSION, "tpch", new TableMetadata("tpch", new ConnectorTableMetadata(table1,
                ImmutableList.<ColumnMetadata>of(
                        new ColumnMetadata("a", BIGINT, false),
                        new ColumnMetadata("b", BIGINT, false),
                        new ColumnMetadata("c", BIGINT, false),
                        new ColumnMetadata("d", BIGINT, false)))));

        SchemaTableName table2 = new SchemaTableName("default", "t2");
        metadata.createTable(SESSION, "tpch", new TableMetadata("tpch", new ConnectorTableMetadata(table2,
                ImmutableList.<ColumnMetadata>of(
                        new ColumnMetadata("a", BIGINT, false),
                        new ColumnMetadata("b", BIGINT, false)))));

        SchemaTableName table3 = new SchemaTableName("default", "t3");
        metadata.createTable(SESSION, "tpch", new TableMetadata("tpch", new ConnectorTableMetadata(table3,
                ImmutableList.<ColumnMetadata>of(
                        new ColumnMetadata("a", BIGINT, false),
                        new ColumnMetadata("b", BIGINT, false),
                        new ColumnMetadata("x", BIGINT, false, null, true)))));

        // table in different catalog
        SchemaTableName table4 = new SchemaTableName("s2", "t4");
        metadata.createTable(SESSION, "c2", new TableMetadata("tpch", new ConnectorTableMetadata(table4,
                ImmutableList.<ColumnMetadata>of(
                        new ColumnMetadata("a", BIGINT, false)))));

        // table with a hidden column
        SchemaTableName table5 = new SchemaTableName("default", "t5");
        metadata.createTable(SESSION, "tpch", new TableMetadata("tpch", new ConnectorTableMetadata(table5,
                ImmutableList.<ColumnMetadata>of(
                        new ColumnMetadata("a", BIGINT, false),
                        new ColumnMetadata("b", BIGINT, false, null, true)))));

        // valid view referencing table in same schema
        String viewData1 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
                new ViewDefinition("select a from t1", "tpch", "default", ImmutableList.of(
                        new ViewColumn("a", BIGINT))));
        metadata.createView(SESSION, new QualifiedTableName("tpch", "default", "v1"), viewData1, false);

        // stale view (different column type)
        String viewData2 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
                new ViewDefinition("select a from t1", "tpch", "default", ImmutableList.of(
                        new ViewColumn("a", VARCHAR))));
        metadata.createView(SESSION, new QualifiedTableName("tpch", "default", "v2"), viewData2, false);

        // view referencing table in different schema from itself and session
        String viewData3 = JsonCodec.jsonCodec(ViewDefinition.class).toJson(
                new ViewDefinition("select a from t4", "c2", "s2", ImmutableList.of(
                        new ViewColumn("a", BIGINT))));
        metadata.createView(SESSION, new QualifiedTableName("c3", "s3", "v3"), viewData3, false);

        analyzer = new Analyzer(
                Session.builder()
                        .setUser("user")
                        .setSource("test")
                        .setCatalog("tpch")
                        .setSchema("default")
                        .setTimeZoneKey(UTC_KEY)
                        .setLocale(ENGLISH)
                        .build(),
                metadata,
                SQL_PARSER,
                Optional.empty(),
                true);

        approximateDisabledAnalyzer = new Analyzer(
                Session.builder()
                        .setUser("user")
                        .setSource("test")
                        .setCatalog("tpch")
                        .setSchema("default")
                        .setTimeZoneKey(UTC_KEY)
                        .setLocale(ENGLISH)
                        .build(),
                metadata,
                SQL_PARSER,
                Optional.empty(),
                false);
    }

    private void analyze(@Language("SQL") String query)
    {
        Statement statement = SQL_PARSER.createStatement(query);
        analyzer.analyze(statement);
    }

    private void assertFails(SemanticErrorCode error, @Language("SQL") String query)
    {
        try {
            Statement statement = SQL_PARSER.createStatement(query);
            analyzer.analyze(statement);
            fail(format("Expected error %s, but analysis succeeded", error));
        }
        catch (SemanticException e) {
            if (e.getCode() != error) {
                fail(format("Expected error %s, but found %s: %s", error, e.getCode(), e.getMessage()), e);
            }
        }
    }
}