text:
_Wednesday, December 16th 2015_

### Preface

Probably you already heard such remarks before and probably you are fine with jQuery. So you are asking yourself, why there are crazy people who hate such awesome library and why should I stop use it. You'll be astonished to hear it but it's not about hate. Let's try to clarify the situation.

As many of others I've started with jQuery in bronze age times (2007) when the gap between different browsers was so painful and the lack of common standards was so hateful. JQuery was a source of inspiration and a light ray in the time of darkness, it was revolutionary. I've fallen in love with jQuery when I've started use it. I wrote few handsome plugins with and I also organized few technical talks and team trainings around jQuery. But then, few years ago, I've changed my mind.

Let's see what's wrong with jQuery's usage in modern web development practices and how we could fix it.

#### Uniformization

One of the amazing killer-features of jQuery was an ability to smooth or fill the gap in the case of DOM usage under different browsers and theirs versions. Let's face the truth, a lot of things have changed since these times, especially the appearance of modern standards. Today in the most cases jQuery redirects the function's call to the standard DOM API, or exceptionally it can uses its own implementation of one or another feature. In the modern world we can easily survive without any usage of jQuery's selectors and utilities. We can simply replace following selectors:
```javascript
$('div, span, article');
$('#formId :invalid');
```
by:
```javascript
document.querySelectorAll('div, span, article');
document.querySelectorAll('#formId :invalid');
```
Or utilities like that:
```javascript
$.isArray(array1);
$.each(array, function(i, v) {
  // do something here
});
```
could be replaced by:
```javascript
Array.isArray(array1);
array1.forEach(function(v, i) {
  // do something here
}
```
Personally, I prefer always follow the standards, jQuery isn't one, it's just a library.

#### Wrapper object

As you probably know, after almost all of its manipulations, jQuery returns to you a specially object that wraps a result of its manipulations or the absence of such result. For example *$('span')* will return to you such object. It is not enough that the wrapper object has a plenty of its own, home-brewed methods, also those functions are roughly different from the modern web standards. Nothing guarantees you that such methods are homogeneous enough to use wrapper objects inside. Can you tell us about what will be referenced by *this* inside an event handler or what will be the first argument of such handler or even what value will have its special field *target*? Let's take a look to a small code sample:
```javascript
$('button').bind('click', function(e){
  var el = this; // Is it jQuery "object" or not ? Let's see the doc
  var event = e; // Is it jQuery "object" ? No, it's a special event-wrapper object
  var target = event.target; // Is it jQuery "object" ? Sure not, it's a simple DOM element
});
```
So buddies, sometimes we got a wrapper, sometimes not, but sometimes it could be a "special" wrapper, what a nonsense? Why should we complicate our live at this point?
You could suppose that there is a workaround, what about this silly naming convention to prefix all "special" objects with the dollar sign. Something like that:
```javascript
$('button').bind('click', function(e){
  var $el = $(this);
  var _event = e; // Let's use an another special convention for jQuery's events wrapper, prefix _
  var $event = e; // No, we should be coherent
  var target = $(event.target); // I'm sorry I forgot the dollar, because I'm just a human
  var target2 = $(target); // Oops, but I have to be sure that it's wrapped
  var var1 = someFunc(); // I forgot, this function should return $ or simple NodeList
  $(var1); // Never mind ...
});
```

#### jQuery as a perfect model of web development

How many times I heard such opinion that jQuery is a kind of perfect model for all possible types of web development. If you are web developer you have to use jQuery to achieve your goals and to aim the endless happiness. Probably because jQuery is good, it has balls, and it has a plenty of such awesome plugins. In my opinion it's a full bullshit, maybe it was partially true 5 years ago, but not now. It's the same thing as supposing that if you need to develop modern Windows 8/10 based applications you have to use pure Win32 API.

As I said above, jQuery it's just a library, taking in consideration present day trends, it's a low level library. Such stuff can not be suitable for writing wide, modern web applications. Nothing prevents you from usage of jQuery or pure DOM/API for realization of any kind of low-level task, but write with it an entire web application and then support it, is far to be a piece of cake. I saw a lot of different project becoming a huge plate of spaghetti on their client part, not because jQuery was a root of evil, just because it was too hard to manage tones of code and they ended up being overwhelmed.

How to avoid that? Use more appropriated/adapted solutions for your needs, solutions such as MV* frameworks/libraries for the complex web-application or something else for another needs.

#### Testing

This part is inextricable from previous one. As you know the human being is lazy, it's a nature, and good (automation)programmers are not an exception. Have you ever tested the code that rely on jQuery? Because of chaining methods it becomes non-trivial, tricky task. Especially if we take in consideration the fact that often the project based on pure jQuery can become fat incredibly fast and the developers have not time or cannot rearrange their code. The result is often oppressive. How you can speak about QA when even the author is unable to understand what his own code does.

If we talking about MV* approach, those problems can be simply avoided.

### Summary

If you were convinced by this article and you would like to try live and work without jQuery, you can check following links:

1. [You don't need jQuery](http://blog.garstasio.com/you-dont-need-jquery/) - Detailed blog about how to stop use jQuery
2. [Beyond jQuery](https://leanpub.com/beyondjquery) - The book about how to stop use jQuery
3. [The cost of frameworks](https://aerotwist.com/blog/the-cost-of-frameworks/) - Toughs about how expensive frameworks are and how developer can spare their time
4. [Zepto.js](http://zeptojs.com) - Small jQuery-compatible library, some kind of switch from hard drugs of jQuery to light cannabis Zepto.


text:
import platform
import re
import urllib2
import urlparse

from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_unicode

# These values, if given to validate(), will trigger the self.required check.
EMPTY_VALUES = (None, '', [], (), {})

try:
    from django.conf import settings
    URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
except ImportError:
    # It's OK if Django settings aren't configured.
    URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'

class RegexValidator(object):
    regex = ''
    message = _(u'Enter a valid value.')
    code = 'invalid'

    def __init__(self, regex=None, message=None, code=None):
        if regex is not None:
            self.regex = regex
        if message is not None:
            self.message = message
        if code is not None:
            self.code = code

        if isinstance(self.regex, basestring):
            self.regex = re.compile(regex)

    def __call__(self, value):
        """
        Validates that the input matches the regular expression.
        """
        if not self.regex.search(smart_unicode(value)):
            raise ValidationError(self.message, code=self.code)

class URLValidator(RegexValidator):
    regex = re.compile(
        r'^(?:http|ftp)s?://' # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' #domain...
        r'localhost|' #localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
        r'(?::\d+)?' # optional port
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)

    def __init__(self, verify_exists=False,
                 validator_user_agent=URL_VALIDATOR_USER_AGENT):
        super(URLValidator, self).__init__()
        self.verify_exists = verify_exists
        self.user_agent = validator_user_agent

    def __call__(self, value):
        try:
            super(URLValidator, self).__call__(value)
        except ValidationError, e:
            # Trivial case failed. Try for possible IDN domain
            if value:
                value = smart_unicode(value)
                scheme, netloc, path, query, fragment = urlparse.urlsplit(value)
                try:
                    netloc = netloc.encode('idna') # IDN -> ACE
                except UnicodeError: # invalid domain part
                    raise e
                url = urlparse.urlunsplit((scheme, netloc, path, query, fragment))
                super(URLValidator, self).__call__(url)
            else:
                raise
        else:
            url = value

        #This is deprecated and will be removed in a future release.
        if self.verify_exists:
            headers = {
                "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
                "Accept-Language": "en-us,en;q=0.5",
                "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
                "Connection": "close",
                "User-Agent": self.user_agent,
            }
            url = url.encode('utf-8')
            broken_error = ValidationError(
                _(u'This URL appears to be a broken link.'), code='invalid_link')
            try:
                req = urllib2.Request(url, None, headers)
                req.get_method = lambda: 'HEAD'
                #Create an opener that does not support local file access
                opener = urllib2.OpenerDirector()

                #Don't follow redirects, but don't treat them as errors either
                error_nop = lambda *args, **kwargs: True
                http_error_processor = urllib2.HTTPErrorProcessor()
                http_error_processor.http_error_301 = error_nop
                http_error_processor.http_error_302 = error_nop
                http_error_processor.http_error_307 = error_nop

                handlers = [urllib2.UnknownHandler(),
                            urllib2.HTTPHandler(),
                            urllib2.HTTPDefaultErrorHandler(),
                            urllib2.FTPHandler(),
                            http_error_processor]
                try:
                    import ssl
                    handlers.append(urllib2.HTTPSHandler())
                except:
                    #Python isn't compiled with SSL support
                    pass
                map(opener.add_handler, handlers)
                if platform.python_version_tuple() >= (2, 6):
                    opener.open(req, timeout=10)
                else:
                    opener.open(req)
            except ValueError:
                raise ValidationError(_(u'Enter a valid URL.'), code='invalid')
            except: # urllib2.URLError, httplib.InvalidURL, etc.
                raise broken_error

def validate_integer(value):
    try:
        int(value)
    except (ValueError, TypeError), e:
        raise ValidationError('')

class EmailValidator(RegexValidator):

    def __call__(self, value):
        try:
            super(EmailValidator, self).__call__(value)
        except ValidationError, e:
            # Trivial case failed. Try for possible IDN domain-part
            if value and u'@' in value:
                parts = value.split(u'@')
                domain_part = parts[-1]
                try:
                    parts[-1] = parts[-1].encode('idna')
                except UnicodeError:
                    raise e
                super(EmailValidator, self).__call__(u'@'.join(parts))
            else:
                raise

email_re = re.compile(
    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
    r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain
validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')

slug_re = re.compile(r'^[-\w]+$')
validate_slug = RegexValidator(slug_re, _(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')

ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
validate_ipv4_address = RegexValidator(ipv4_re, _(u'Enter a valid IPv4 address.'), 'invalid')

comma_separated_int_list_re = re.compile('^[\d,]+$')
validate_comma_separated_integer_list = RegexValidator(comma_separated_int_list_re, _(u'Enter only digits separated by commas.'), 'invalid')

class BaseValidator(object):
    compare = lambda self, a, b: a is not b
    clean   = lambda self, x: x
    message = _(u'Ensure this value is %(limit_value)s (it is %(show_value)s).')
    code = 'limit_value'

    def __init__(self, limit_value):
        self.limit_value = limit_value

    def __call__(self, value):
        cleaned = self.clean(value)
        params = {'limit_value': self.limit_value, 'show_value': cleaned}
        if self.compare(cleaned, self.limit_value):
            raise ValidationError(
                self.message % params,
                code=self.code,
                params=params,
            )

class MaxValueValidator(BaseValidator):
    compare = lambda self, a, b: a > b
    message = _(u'Ensure this value is less than or equal to %(limit_value)s.')
    code = 'max_value'

class MinValueValidator(BaseValidator):
    compare = lambda self, a, b: a < b
    message = _(u'Ensure this value is greater than or equal to %(limit_value)s.')
    code = 'min_value'

class MinLengthValidator(BaseValidator):
    compare = lambda self, a, b: a < b
    clean   = lambda self, x: len(x)
    message = _(u'Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).')
    code = 'min_length'

class MaxLengthValidator(BaseValidator):
    compare = lambda self, a, b: a > b
    clean   = lambda self, x: len(x)
    message = _(u'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).')
    code = 'max_length'

redpajama_set_name: RedPajamaGithub


text:
+++

title = "Número 17 - Año II"

date = "1971-07-01"

numero = "017"

artistas = []

colaboradores= ["Daniel Osvaldo Ripoll", "Juan Bernardo Arruabarrena", "Inés Martínez Castañeda", "Mario Alberto Albarracín", "Ana Clara Arveras", "Miguel Gavalas", "Mabel Lernoud", "María Cristina Palanca", "Esteban Szalardi Szegvari", "Ricardo Rodríguez", "María Teresa Gonzalez Llamazares", "María Marta Fernandez", "Margarita Martínez", "Alfredo Álvarez", "Carmen Martínez Castañeda"]

discos = []

poster1 = "Janis Joplin"

+++

**Póster**: Janis Joplin.

**Nota de tapa**:

**Reportajes**:

**Entrevistas**:

**Notas sobre**:

**Secciones**:


text:
SYNONYM

#### According to
Index Fungorum

#### Published in
in Müller Argoviensis, Mém. Soc. Phys. Hist. nat. Genève 16: 403 (1862)

#### Original name
Bilimbia trisepta Hellb.

### Remarks
null


text:
<img align="right" width="120px" src="https://raw.githubusercontent.com/cssivision/looli/master/looli.jpeg">

[![Build Status](https://img.shields.io/travis/cssivision/looli.svg?style=flat-square)](https://travis-ci.org/cssivision/looli)
[![Coverage Status](http://img.shields.io/coveralls/cssivision/looli.svg?style=flat-square)](https://coveralls.io/github/cssivision/looli?branch=master)
[![License](http://img.shields.io/badge/license-mit-blue.svg?style=flat-square)](https://github.com/cssivision/looli/blob/master/LICENSE)

looli is a minimalist web framework for golang.

# Feature

* [Router](#router)
    * [full method support](#using-get-post-put-patch-delete-and-options)
    * [named parameter](#named-parameter)
    * [wildcard pattern](#wildcard-pattern)
    * [trailing slash redirect](#trailing-slash-redirect)
    * [case sensitive](#case-sensitive)
    * [serving static files](#serving-static-files)
* [Context](#context)
    * [query and form](#query-and-form)
    * [header and cookie](#header-and-cookie)
    * [data binding](#data-binding)
    * [string xml json rendering](#string-json-rendering)
    * [html rendering](#html-rendering)
* [Middleware](#middleware)
    * [using middleware](#using-middleware)
    * [builtin middlewares](#builtin-middlewares)
    * [custome middleware](#custome-middleware)

# Installation

```sh
go get github.com/cssivision/looli
```

# Usage

## Router

looli build on the top of [router](https://github.com/cssivision/router) library, which support `Named parameters` `Wildcard parameters` `Trailing slash redirect` `Case sensitive` `Prefix router`, for [detail](https://github.com/cssivision/router).

### Using GET, POST, PUT, PATCH, DELETE and OPTIONS

```go
package main

import (
	"github.com/cssivision/looli"
	"log"
)

func main() {
	router := looli.Default()

	router.Get("/a", func(c *looli.Context) {})
	router.Post("/a", func(c *looli.Context) {})
	router.Put("/a", func(c *looli.Context) {})
	router.Delete("/a", func(c *looli.Context) {})
	router.Patch("/a", func(c *looli.Context) {})
	router.Head("/a", func(c *looli.Context) {})
	router.Options("/a", func(c *looli.Context) {})

	log.Fatal(router.Run(":8080"))
}

```

### Named parameter

Named parameters only match a single path segment:
```
Pattern: /user/:name

 /user/gordon              match
 /user/you                 match
 /user/gordon/profile      no match
 /user/                    no match

Pattern: /:user/:name

 /a/gordon                 match
 /b/you                    match
 /user/gordon/profile      no match
 /user/                    no match
```

```go
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    router.Get("/a/:name", func(c *looli.Context) {
        c.Status(200)
        c.String("hello " + c.Param("name") + "!\n")
    })

    http.ListenAndServe(":8080", router)
}
```

### Wildcard pattern

Match everything, therefore they must always be at the end of the pattern:

```
Pattern: /src/*filepath

 /src/                     match
 /src/somefile.go          match
 /src/subdir/somefile.go   match
```

```go
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    router.Get("/a/*filepath", func(c *looli.Context) {
        c.Status(200)
        c.String("hello " + c.Param("filepath") + "!\n")
    })

    http.ListenAndServe(":8080", router)
}
```

### Trailing slash redirect

By default will redirect, which means if we register path `/a/b`, we can request with `/a/b/`, conversely also success. redirect will work only in the situation that the request can not found, if both define path `/a/b` and `/a/b/`, redirect will not work.

```
/a/b -> /a/b/
/a/b/ -> /a/b
```

```go
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    // default is true, we can forbidden this behavior by set is to false
    // request with /a/ will get 404
    router.SetTrailingSlashRedirect(false)

    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    http.ListenAndServe(":8080", router)
}
```

### Case sensitive

By default is not case sensitive, which means if we register path `/a/b`, request with `/A/B` will get `404 not found`. if we set `true`, request path with `/A/B` will success.

```go
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    // default is false, we can forbidden this behavior by set is to true
    // request with /A/ will success.
    router.SetIgnoreCase(true)

    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    http.ListenAndServe(":8080", router)
}
```

### Prefix router

Group router using prefix

```go
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    v1 := router.Prefix("/v1")
    v1.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world version1\n")
    })

    v2 := router.Prefix("/v2")
    v2.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world version2\n")
    })

    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    http.ListenAndServe(":8080", router)
}
```

### Serving static files

```go
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    // Serve file in the path
    router.StaticFile("/somefile.go", "file/path")

    // Serve files in staic directory
    router.Static("/static", "./static")

    http.ListenAndServe(":8080", router)
}
```

## Context

Context supply some syntactic sugar.

### Query and Form

```go
package main

import (
    "net/http"
    "github.com/cssivision/looli"
)

func main() {
    router := looli.Default()

    router.Get("/query", func(c *looli.Context) {
        id := c.Query("id")
        name := c.DefaultQuery("name", "cssivision")
        c.Status(200)
        c.String("hello %s, %s\n", id, name)
    })

    router.Post("/form", func(c *looli.Context) {
        name := c.DefaultPostForm("name", "somebody")
        age := c.PostForm("age")
        c.Status(200)
        c.JSON(looli.JSON{
            "name": name,
            "age": age,
        })
    })

    http.ListenAndServe(":8080", router)
}
```

query
```sh
curl 'localhost:8080/query?id=1&name=cssivision'
```

form
```sh
curl -d 'age=21&other=haha' 'localhost:8080/form?id=1&name=cssivision'
```

### Header and Cookie

Use method to operate header and cookie

```go
package main

import (
    "fmt"
    "github.com/cssivision/looli"
    "log"
    "net/http"
)

func main() {
    router := looli.Default()

    router.Get("/header", func(c *looli.Context) {
        fmt.Println(c.Header("User-Agent"))
        c.SetHeader("fake-header", "fake")
        c.Status(200)
        c.String("fake header has setted\n")
    })

    router.Get("/cookie", func(c *looli.Context) {
        val, _ := c.Cookie("fake-cookie")
        fmt.Println(val)
        c.SetCookie(&http.Cookie{
            Name: "fake-cookie",
            Value: "fake",
        })
        c.Status(200)
        c.String("fake cookie has setted\n")
    })

    log.Fatal(router.Run(":8080"))
}
```

### Data binding

To bind a request into a type, use data binding, data can from query, post body. currently support binding of JSON, XML and standard form values (x-www-form-urlencoded and multipart/form-data). When using the Bind-method, the binder depending on the Content-Type header.

Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set json:"fieldname".

The Validation of the incoming data show below.

```go
package main

import (
    "fmt"
    "github.com/cssivision/looli"
    "net/http"
)

type Infomation struct {
    Name string`json:"name"`
    Age int`json:"age"`
}

func (i *Infomation) Validate() error {
    // data validate,
    return nil
}

func main() {
    router := looli.Default()

    // curl 'localhost:8080/query?name=cssivision&age=21'
    router.Get("/query", func(c *looli.Context) {
        query := new(Infomation)
        if err := c.Bind(query); err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(query.Name)
        fmt.Println(query.Age)
        c.Status(200)
        c.JSON(query)
    })

    // curl -d "name=cssivision&age=21" 'localhost:8080/form'
    router.Post("/form", func(c *looli.Context) {
        form := new(Infomation)
        if err := c.Bind(form); err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(form.Name)
        fmt.Println(form.Age)
        c.Status(200)
        c.JSON(form)
    })

    // curl  -H "Content-Type: application/json" -X POST -d '{"name":"cssivision","age":21}' localhost:8080/json
    router.Post("/json", func(c *looli.Context) {
        json := new(Infomation)
        if err := c.Bind(json); err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(json.Name)
        fmt.Println(json.Age)
        c.Status(200)
        c.JSON(json)
    })

    http.ListenAndServe(":8080", router)
}
```

### String JSON rendering

```go
package main

import (
    "github.com/cssivision/looli"
    "net/http"
)

func main() {
    router := looli.Default()

    router.Get("/string", func(c *looli.Context) {
        c.String("the response is %s\n", "string")
    })

    router.Get("/json1", func(c *looli.Context) {
        c.JSON(looli.JSON{
            "name": "cssivision",
            "age": 21,
        })
    })

    router.Get("/json2", func(c *looli.Context) {
        var msg struct {
            Name string`json:"name"`
            Age int`json:"age"`
        }

        msg.Name = "cssivision"
        msg.Age = 21

        c.JSON(msg)
    })

    http.ListenAndServe(":8080", router)
}
```

### HTML rendering

```go
package main

import (
    "github.com/cssivision/looli"
    "net/http"
)

func main() {
    router := looli.Default()

    router.LoadHTMLGlob("templates/*")
    router.Get("/html", func(c *looli.Context) {
        c.HTML("index.tmpl", looli.JSON{
            "title": "my site",
        })
    })

    http.ListenAndServe(":8080", router)
}
```

templates/index.tmpl

```html
<html>
    <h1>
        {{ .title }}
    </h1>
</html>
```

## Middleware

`looli.Default()` with middleware `Logger()` `Recover()` by default, without middleware use `looli.New()` instead.

### Using middleware

```go
package main

import (
    "net/http"
    "github.com/cssivision/looli"
    "log"
)

func main() {
    router := looli.New()

    // global middleware
    router.Use(looli.Logger())
    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    // multi handler for specificed path
    router.Get("/b", func(c *looli.Context) {
        c.String("first handler\n")
    }, func(c *looli.Context) {
        c.String("second handler\n")
    })

    v1 := router.Prefix("/v1")

    // recover middleware only work for /v1 prefix router
    v1.Use(looli.Recover())
    v1.Get("/a", func(c *looli.Context) {
        panic("error!")
        c.Status(200)
        c.String("hello world!\n")
    })

    log.Fatal(http.ListenAndServe(":8080", router))
}
```

### Builtin middlewares

* Logger middleware
* Recover middleware
* [Session middleware](https://github.com/cssivision/looli/tree/master/session)
* [Cors middleware](https://github.com/cssivision/looli/tree/master/cors)
* [Csrf middleware](https://github.com/cssivision/looli/tree/master/csrf)

### Custome middleware

```go
package main

import (
    "log"
    "net/http"
    "github.com/cssivision/looli"
    "time"
)

func Logger() looli.HandlerFunc {
    return func(c *looli.Context) {
        t := time.Now()
        // before request
        c.Next()
        // after request
        latency := time.Since(t)
        log.Print(latency)
    }
}

func main() {
    router := looli.New()

    // global middleware
    router.Use(Logger())
    router.Get("/a", func(c *looli.Context) {
        c.Status(200)
        c.String("hello world!\n")
    })

    http.ListenAndServe(":8080", router)
}
```

# Licenses

All source code is licensed under the [MIT License](https://github.com/cssivision/looli/blob/master/LICENSE).

# Todo

* elegant error handle


text:
namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace recalculate
{

template <std::size_t Dimension>
struct recalculate_point
{
    template <typename Point1, typename Point2, typename Strategy>
    static inline void apply(Point1& point1, Point2 const& point2, Strategy const& strategy)
    {
        std::size_t const dim = Dimension - 1;
        geometry::set<dim>(point1, strategy.template apply<dim>(geometry::get<dim>(point2)));
        recalculate_point<dim>::apply(point1, point2, strategy);
    }
};

template <>
struct recalculate_point<0>
{
    template <typename Point1, typename Point2, typename Strategy>
    static inline void apply(Point1&, Point2 const&, Strategy const&)
    {
    }
};

template <std::size_t Dimension>
struct recalculate_indexed
{
    template <typename Geometry1, typename Geometry2, typename Strategy>
    static inline void apply(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
    {
        // Do it for both indices in one dimension
        static std::size_t const dim = Dimension - 1;
        geometry::set<0, dim>(geometry1, strategy.template apply<dim>(geometry::get<0, dim>(geometry2)));
        geometry::set<1, dim>(geometry1, strategy.template apply<dim>(geometry::get<1, dim>(geometry2)));
        recalculate_indexed<dim>::apply(geometry1, geometry2, strategy);
    }
};

template <>
struct recalculate_indexed<0>
{

    template <typename Geometry1, typename Geometry2, typename Strategy>
    static inline void apply(Geometry1& , Geometry2 const& , Strategy const& )
    {
    }
};

struct range_to_range
{
    template
    <
        typename Range1,
        typename Range2,
        typename Strategy
    >
    static inline void apply(Range1& destination, Range2 const& source,
            Strategy const& strategy)
    {
        typedef typename geometry::point_type<Range2>::type point_type;
        typedef recalculate_point<geometry::dimension<point_type>::value> per_point;
        geometry::clear(destination);

        for (typename boost::range_iterator<Range2 const>::type it
                = boost::begin(source);
            it != boost::end(source);
            ++it)
        {
            point_type p;
            per_point::apply(p, *it, strategy);
            geometry::append(destination, p);
        }
    }
};

struct polygon_to_polygon
{
private:
    template
    <
        typename IteratorIn,
        typename IteratorOut,
        typename Strategy
    >
    static inline void iterate(IteratorIn begin, IteratorIn end,
                    IteratorOut it_out,
                    Strategy const& strategy)
    {
        for (IteratorIn it_in = begin; it_in != end;  ++it_in, ++it_out)
        {
            range_to_range::apply(*it_out, *it_in, strategy);
        }
    }

    template
    <
        typename InteriorRingsOut,
        typename InteriorRingsIn,
        typename Strategy
    >
    static inline void apply_interior_rings(
                    InteriorRingsOut& interior_rings_out,
                    InteriorRingsIn const& interior_rings_in,
                    Strategy const& strategy)
    {
        traits::resize<InteriorRingsOut>::apply(interior_rings_out,
            boost::size(interior_rings_in));

        iterate(
            boost::begin(interior_rings_in), boost::end(interior_rings_in),
            boost::begin(interior_rings_out),
            strategy);
    }

public:
    template
    <
        typename Polygon1,
        typename Polygon2,
        typename Strategy
    >
    static inline void apply(Polygon1& destination, Polygon2 const& source,
            Strategy const& strategy)
    {
        range_to_range::apply(geometry::exterior_ring(destination),
            geometry::exterior_ring(source), strategy);

        apply_interior_rings(geometry::interior_rings(destination),
            geometry::interior_rings(source), strategy);
    }
};

}} // namespace detail::recalculate
#endif // DOXYGEN_NO_DETAIL

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

template
<
    typename Geometry1,
    typename Geometry2,
    typename Tag1 = typename geometry::tag<Geometry1>::type,
    typename Tag2 = typename geometry::tag<Geometry2>::type
>
struct recalculate : not_implemented<Tag1, Tag2>
{};

template <typename Point1, typename Point2>
struct recalculate<Point1, Point2, point_tag, point_tag>
    : detail::recalculate::recalculate_point<geometry::dimension<Point1>::value>
{};

template <typename Box1, typename Box2>
struct recalculate<Box1, Box2, box_tag, box_tag>
    : detail::recalculate::recalculate_indexed<geometry::dimension<Box1>::value>
{};

template <typename Segment1, typename Segment2>
struct recalculate<Segment1, Segment2, segment_tag, segment_tag>
    : detail::recalculate::recalculate_indexed<geometry::dimension<Segment1>::value>
{};

template <typename Polygon1, typename Polygon2>
struct recalculate<Polygon1, Polygon2, polygon_tag, polygon_tag>
    : detail::recalculate::polygon_to_polygon
{};

} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

template <typename Geometry1, typename Geometry2, typename Strategy>
inline void recalculate(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
{
    concept::check<Geometry1>();
    concept::check<Geometry2 const>();

    // static assert dimensions (/types) are the same

    dispatch::recalculate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
}

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP


text:
layout: page
title: Peace Silicon Financial Seminar
date: 2016-05-24
author: Dennis Taylor
tags: weekly links, java
status: published
summary: Nam aliquet mi purus, at consectetur quam vulputate eu. Phasellus.
banner: images/banner/office-01.jpg
booking:
  startDate: 02/15/2019
  endDate: 02/18/2019
  ctyhocn: CLTBLHX
  groupCode: PSFS
published: true
---
Donec elementum eleifend nibh non laoreet. Nulla fringilla imperdiet orci, ut volutpat leo viverra sed. Vivamus imperdiet sem eget ornare convallis. Maecenas fermentum erat at dolor sodales lobortis. Vivamus eu diam et tellus ultricies egestas vitae ut quam. Quisque feugiat justo at nisi lobortis, sed euismod lorem finibus. Donec tortor sem, malesuada quis luctus in, hendrerit mattis sapien. Morbi dapibus vel quam nec consectetur. Curabitur non molestie dolor. Curabitur imperdiet lacus quis eros tristique semper in ultricies mi. Integer maximus metus sit amet vestibulum ultrices. Vivamus maximus pulvinar leo. Ut non sem ut libero placerat molestie. Vestibulum laoreet dictum tellus at dapibus.

1 Etiam at lectus ut diam maximus elementum
1 Integer ac sapien vitae quam malesuada pulvinar eget vel purus
1 Donec condimentum ipsum a elit iaculis vehicula.

Donec mollis dapibus libero at interdum. Nunc cursus condimentum velit, at blandit ex. Ut rhoncus, mauris id suscipit pulvinar, lectus mi fringilla mauris, ut placerat odio ex luctus purus. Pellentesque pulvinar id tortor quis porttitor. Nullam viverra nisl quis vehicula mattis. Maecenas mi urna, scelerisque non arcu pharetra, porttitor suscipit ante. Cras non risus mattis felis vulputate lacinia ac in orci.


text:
package swag

import "net/url"

func pathUnescape(path string) (string, error) {
	return url.PathUnescape(path)
}


text:
/*
* tarball.hpp
*
*  Created on: Jul 28, 2010
*      Author: Pierre Lindenbaum PhD
*              plindenbaum@yahoo.fr
*              http://plindenbaum.blogspot.com
*
*
*		Modified by OJ in order to make cross platform
*
*  Updated by Liang Zhang, Sep 18, 2015
*
*    Upgraded to c++11
*    Added features:
*      + add directory to tar
*      + add symlink to tar
*      + extract tar created by this module
*
*/

#ifndef TARBALL_HPP
#define TARBALL_HPP

#include <iostream>
#include <fstream>
#include <exception>
#include <stdexcept>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <ctime>
#include <cstdio>
#include <sstream>
#include <algorithm>

#include <sys/stat.h>
#include <unistd.h>

using std::ios;

namespace tar {

#define TARHEADER static_cast<PosixTarHeader*>(header)
	/* Values used in typeflag field.  */
#define REGTYPE  '0'            /* regular file */
#define AREGTYPE '\0'           /* regular file */
#define LNKTYPE  '1'            /* link */
#define SYMTYPE  '2'            /* reserved */
#define CHRTYPE  '3'            /* character special */
#define BLKTYPE  '4'            /* block special */
#define DIRTYPE  '5'            /* directory */
#define FIFOTYPE '6'            /* FIFO special */
#define CONTTYPE '7'            /* reserved */

	struct PosixTarHeader
	{
		char name[100];
		char mode[8];
		char uid[8];
		char gid[8];
		char size[12];
		char mtime[12];
		char checksum[8];
		char typeflag[1];
		char linkname[100];
		char magic[6];
		char version[2];
		char uname[32];
		char gname[32];
		char devmajor[8];
		char devminor[8];
		char prefix[155];
		char pad[12];
	};

#define	PosixTarHeaderSize 512

	/**
	*  A Tar Archive
	*/

	class Archive
	{
	private:
		bool _finished;
		std::string _user_name;
		void checkSizeOfTagHeader()
		{
			if (sizeof(PosixTarHeader) != PosixTarHeaderSize)
			{
				std::stringstream err;
				err << sizeof(PosixTarHeader);
				throw std::runtime_error(err.str());
			}
		}

	protected:
		std::ostream& out;
		void _init(void* header)
		{
			std::memset(header, 0, sizeof(PosixTarHeader));
			std::snprintf(TARHEADER->magic, sizeof(TARHEADER->magic), "ustar  ");
			std::snprintf(TARHEADER->mtime, sizeof(TARHEADER->mtime), "%011lo", time(NULL));
			// std::snprintf(TARHEADER->mode,sizeof(TARHEADER->mode),"%07o",0644);
			_mode(header, 0644);
			if (!_user_name.empty()) {
				std::snprintf(TARHEADER->uname, sizeof(TARHEADER->uname), "%s", _user_name.c_str());
				// std::snprintf(TARHEADER->gname,sizeof(TARHEADER->gname),"%s","users");
				std::snprintf(TARHEADER->gname, sizeof(TARHEADER->gname), "%s", _user_name.c_str());
			} else {
				// liang: leave uname and gname empty.
			}
		}

		void _checksum(void* header)
		{
			unsigned int sum = 0;
			char *p = (char *) header;
			char *q = p + sizeof(PosixTarHeader);
			while (p < TARHEADER->checksum) sum += *p++ & 0xff;
			for (int i = 0; i < 8; ++i)  {
				sum += ' ';
				++p;
			}
			while (p < q) sum += *p++ & 0xff;

			std::snprintf(TARHEADER->checksum, sizeof(TARHEADER->checksum), "%06o", sum);
		}

		void _size(void* header, unsigned long fileSize)
		{
			std::snprintf(TARHEADER->size, sizeof(TARHEADER->size), "%011llo", (long long unsigned int)fileSize);
		}

		void _mode(void* header, int mode)
		{
			std::snprintf(TARHEADER->mode, sizeof(TARHEADER->mode), "%07o", mode);
		}

		void _filename(void* header, const char* filename)
		{
			if (filename == NULL || filename[0] == 0 || std::strlen(filename) >= 100)
			{
				std::stringstream err;
				err << "invalid archive name \"" << filename << "\"";
				throw std::runtime_error(err.str());
			}
			strcpy(TARHEADER->name, filename);
		}

		void _linkname(void *header, const char *linkname)
		{
			strcpy(TARHEADER->linkname, linkname);
		}

		void _endRecord(std::size_t len)
		{
			char c = '\0';
			while ((len % sizeof(PosixTarHeader)) != 0)
			{
				out.write(&c, sizeof(char));
				++len;
			}
		}

	public:
		Archive(std::ostream & out_, const std::string & user_name) : out(out_)
		{
			checkSizeOfTagHeader();
			if (user_name.length() <= 32)
			{
				_user_name = user_name;
			}
		}

		Archive(std::ostream & out_) : out(out_)
		{
			checkSizeOfTagHeader();
		}

		virtual ~Archive()
		{
			if (!_finished)
			{
				std::cerr << "[warning]tar file was not finished." << std::endl;
			}
		}

		/** writes 2 empty blocks. Should be always called before closing the Tar file */
		void finish()
		{
			_finished = true;
			//The end of the archive is indicated by two blocks filled with binary zeros
			PosixTarHeader header;
			std::memset((void*)&header, 0, sizeof(PosixTarHeader));
			out.write((const char*)&header, sizeof(PosixTarHeader));
			out.write((const char*)&header, sizeof(PosixTarHeader));
			out.flush();
		}

		void put(const char* filename, const std::string & s)
		{
			put(filename, s.c_str(), s.size());
		}

		void put(const char* filename, const char* content)
		{
			put(filename, content, std::strlen(content));
		}

		void put(const char* filename, const char* content, std::size_t len)
		{
			PosixTarHeader header;
			_init((void*)&header);
			_filename((void*)&header, filename);
			header.typeflag[0] = 0;
			_size((void*)&header, len);
			_checksum((void*)&header);
			out.write((const char*)&header, sizeof(PosixTarHeader));
			out.write(content, len);
			_endRecord(len);
		}

		void putFile(const char* filename, const char* nameInArchive)
		{
			char buff[BUFSIZ];
			std::FILE* in = std::fopen(filename, "rb");
			if (in == NULL)
			{
				std::stringstream err;
				err << "Cannot open " << filename << " " << std::strerror(errno);
				throw std::runtime_error(err.str());
			}
			std::fseek(in, 0L, SEEK_END);
			long int len = std::ftell(in);
			std::fseek(in, 0L, SEEK_SET);

			PosixTarHeader header;
			_init((void*)&header);
			_filename((void*)&header, nameInArchive);
			header.typeflag[0] = 0;
			_size((void*)&header, len);
			_checksum((void*)&header);
			out.write((const char*)&header, sizeof(PosixTarHeader));

			std::size_t nRead = 0;
			while ((nRead = std::fread(buff, sizeof(char), BUFSIZ, in)) > 0)
			{
				out.write(buff, nRead);
			}
			std::fclose(in);

			_endRecord(len);
		}

		void putDir(const char* nameInArchive)
		{
			PosixTarHeader header;
			_init((void*)&header);
			_filename((void*)&header, nameInArchive);
			_mode(&header, 0755);
			header.typeflag[0] = DIRTYPE;
			_size((void*)&header, 0);
			_checksum((void*)&header);
			out.write((const char*)&header, sizeof(PosixTarHeader));
		}

		void putSymlink(const char *nameInArchive, const char *linkname)
		{
			PosixTarHeader header;
			_init((void*)&header);
			_filename((void*)&header, nameInArchive);
			_mode(&header, 0777);
			header.typeflag[0] = SYMTYPE; // got this by running gnu tar
			// e.g., tar -cf pico.tar --format=ustar sym
			_linkname(&header, linkname);
			_size((void*)&header, 0);
			_checksum((void*)&header);
			out.write((const char*)&header, sizeof(PosixTarHeader));
		}

		// impl. putSymlink
	};

	class Extractor
	{
	private:
		std::istream& in;

	protected:
		void readBlock(void *block)
		{
			in.read((char*)block, PosixTarHeaderSize); // should be 512
		}

		long int getSize(struct PosixTarHeader *header)
		{
			long int size;
			std::sscanf(header->size, "%011lo", &size);
			return size;
		}

		mode_t getMode(struct PosixTarHeader *header)
		{
			mode_t mode;
			std::sscanf(header->mode, "%07o", &mode);
			return mode;
		}

	public:
		Extractor(std::istream& in) : in(in) {}

		void extract(const char *dest)
		{
			// do not need trailing "/" in dest, e.g., "/path/to/dir"

			char block[PosixTarHeaderSize];
			if (dest == nullptr || dest[0] == 0)
			{
				throw std::runtime_error("invalid destination");
			}

			int numBlankBlock = 0;
			while (!in.eof()) {
				readBlock(block);
				if (block[0] == 0) {
					numBlankBlock ++;
					if (numBlankBlock == 2) {
						return;
					}
					continue;
				}
				struct PosixTarHeader *header = (struct PosixTarHeader *)block;
				char path[100];
				mode_t mode = getMode(header);
				std::snprintf(path, sizeof(path), "%s/%s", dest, header->name);
#ifdef PICO_TRACE
				std::cout<<"Extract "<<header->name<<" to "<<path<<std::endl;
#endif
				long int size = getSize(header);
				switch (header->typeflag[0])
				{
				case AREGTYPE:
				{
					std::ofstream myfile;
					myfile.open (path, ios::out | ios::binary);
					while (size > 0) {
						readBlock(block);
						int len = size > PosixTarHeaderSize ? PosixTarHeaderSize : size;
						myfile.write(block, len);
						size -= PosixTarHeaderSize;
					};
					myfile.close();
					break;
				}
				case DIRTYPE:
				{
					if (mkdir(path, mode) != 0) {
						// ignore if dir exist
						// throw std::runtime_error("fail to make directory");
					}
					break;
				}
				case SYMTYPE:
				{
					if (symlink(header->linkname, path) != 0) {
						// ignore error
					}
					break;
				}
				default:
					char t = header->typeflag[0];
					std::cerr << "Unknown type " << t << " of " << path << std::endl;
				}

			}

		}

	};

}

/* liang: original demo code, see my test_tar.cpp for more.

 * Boost IO streams GZIP Tutorials
 * How to Gzip encode entire folder with Boost IO streams
 * https://code.google.com/p/cloudobserver/wiki/TutorialsBoostIOstreams

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <string>
#include <algorithm>

#include <boost/filesystem.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/stream.hpp>

#include "tarball.hpp"

void is_file( boost::filesystem::path p, lindenb::io::Tar & archive )
{
	std::string file_name_in_archive = p.relative_path().normalize().string();
	std::replace(file_name_in_archive.begin(), file_name_in_archive.end(), '\\', '/');
	file_name_in_archive = file_name_in_archive.substr(2, file_name_in_archive.size());
	archive.putFile(p.string().c_str(), file_name_in_archive.c_str());
}

void is_dir( boost::filesystem::path dir, lindenb::io::Tar & archive )
{
	if (!boost::filesystem::exists(dir))
	{
		return;
	}
	//create_file(dir, old_fs, new_fs);
	if (boost::filesystem::is_directory(dir))
	{
		boost::filesystem::directory_iterator dirIter( dir );
		boost::filesystem::directory_iterator dirIterEnd;

		while ( dirIter != dirIterEnd )
		{
			if ( boost::filesystem::exists( *dirIter ) && !boost::filesystem::is_directory( *dirIter ) )
			{
				try
				{
					is_file((*dirIter), archive);
				}
				catch (std::exception) {}
			}
			else
			{
				try
				{
					is_dir((*dirIter), archive);
				}
				catch (std::exception) {}
			}
			++dirIter;
		}
	}
}

int main(int argc, char** argv)
{
	std::stringstream out("pseudofile");
	lindenb::io::Tar tarball(out);
	is_dir("./myfiles", tarball);
	tarball.finish();
	{
		std::ofstream file( std::string( "hello folder.tar.gz" ).c_str(),  std::ofstream::binary);
		boost::iostreams::filtering_streambuf< boost::iostreams::input> in;
		in.push( boost::iostreams::gzip_compressor());
		in.push(out);
		boost::iostreams::copy(in, file);
	}
	std::cin.get();
	return 0;
}

*/

#endif // TARBALL_HPP


text:
package org.grobid.core.engines.training;

import nu.xom.Attribute;
import nu.xom.Element;
import org.grobid.core.data.Measurement;
import org.grobid.core.data.QuantifiedObject;
import org.grobid.core.data.Quantity;
import org.grobid.core.data.Unit;
import org.grobid.core.utilities.UnitUtilities;

import java.util.List;
import java.util.UUID;

import static org.grobid.core.document.xml.XmlBuilderUtils.teiElement;

public class QuantifiedObjectTrainingFormatter {

    protected Element trainingExtraction(List<Measurement> measurements, String text) {
        Element p = teiElement("p");

        int pos = 0;
        for (Measurement measurement : measurements) {
            Element measure = teiElement("measure");

            int startO = -1;
            int endO = -1;
            final QuantifiedObject quantifiedObject = measurement.getQuantifiedObject();
            Element quantifiedObjectElement = teiElement("quantifiedObject");
            String quantifiedObjectID = null;
            if (quantifiedObject != null) {
                startO = quantifiedObject.getOffsetStart();
                endO = quantifiedObject.getOffsetEnd();

                final String textObject = text.substring(startO, endO);
                quantifiedObjectID = UUID.randomUUID().toString();
                quantifiedObjectElement.appendChild(textObject);
                quantifiedObjectElement.addAttribute(new Attribute("id", quantifiedObjectID));
            }

            if (measurement.getType() == UnitUtilities.Measurement_Type.VALUE) {
                measure.addAttribute(new Attribute("type", "value"));
                Quantity quantity = measurement.getQuantityAtomic();
                if (quantity == null)
                    continue;

                int startQ = quantity.getOffsetStart();
                int endQ = quantity.getOffsetEnd();

                Unit unit = quantity.getRawUnit();
                int endU = -1;
                int startU = -1;

                if (unit != null) {
                    startU = unit.getOffsetStart();
                    endU = unit.getOffsetEnd();
                }

                boolean addedMeasure = false;
                int initPos = pos;

                while (pos < text.length()) {

                    if (pos == startQ) {
                        if (!addedMeasure) {
                            if (quantifiedObject != null) {
                                measure.addAttribute(new Attribute("ptr", "#" + quantifiedObjectID));
                            }
                            p.appendChild(text.substring(initPos, startQ));
                            p.appendChild(measure);
                            addedMeasure = true;
                        } else {
                            measure.appendChild(text.substring(initPos, startQ));
                        }
                        measure.appendChild(text.substring(startQ, endQ));
                        pos = endQ;
                        initPos = pos;
                    }
                    if (pos == startU) {
                        if (!addedMeasure) {
                            if (quantifiedObject != null) {
                                measure.addAttribute(new Attribute("ptr", "#" + quantifiedObjectID));
                            }
                            p.appendChild(text.substring(initPos, startU));
                            p.appendChild(measure);
                            addedMeasure = true;
                        } else {
                            measure.appendChild(text.substring(initPos, startU));
                        }
                        measure.appendChild(text.substring(startU, endU));
                        pos = endU;
                        initPos = pos;

//                        measure.appendChild(text.substring(initPos, startU));
//                        measure.appendChild(text.substring(startU, endU));
//                        pos = endU;
//                        initPos = pos;
                    }
                    if (pos == startO) {
                        p.appendChild(text.substring(initPos, startO));
                        p.appendChild(quantifiedObjectElement);
                        pos = endO;
                        initPos = pos;
                    }

                    if (pos >= endQ && pos >= endU && pos >= endO)
                        break;
                    pos++;
                }
            } else if (measurement.getType() == UnitUtilities.Measurement_Type.INTERVAL_MIN_MAX ||
                    measurement.getType() == UnitUtilities.Measurement_Type.INTERVAL_BASE_RANGE) {
                measure.addAttribute(new Attribute("type", "interval"));

                Quantity quantityLeast = measurement.getQuantityLeast();
                Quantity quantityMost = measurement.getQuantityMost();

                if(measurement.getType() == UnitUtilities.Measurement_Type.INTERVAL_BASE_RANGE) {
                    quantityLeast = measurement.getQuantityBase();
                    quantityMost = measurement.getQuantityRange();
                }

                if (quantityLeast == null && quantityMost == null)
                    continue;

                int startQL = -1;
                int endQL = -1;
                int startUL = -1;
                int endUL = -1;

                if (quantityLeast != null) {
                    startQL = quantityLeast.getOffsetStart();
                    endQL = quantityLeast.getOffsetEnd();

                    Unit unitL = quantityLeast.getRawUnit();
                    if (unitL != null) {
                        startUL = unitL.getOffsetStart();
                        endUL = unitL.getOffsetEnd();
                    }
                }

                int startQM = -1;
                int endQM = -1;
                int startUM = -1;
                int endUM = -1;

                if (quantityMost != null) {
                    startQM = quantityMost.getOffsetStart();
                    endQM = quantityMost.getOffsetEnd();

                    Unit unitM = quantityMost.getRawUnit();
                    if (unitM != null) {
                        startUM = unitM.getOffsetStart();
                        endUM = unitM.getOffsetEnd();
                    }
                }

                boolean addedMeasure = false;
                int initPos = pos;
                while (pos < text.length()) {
                    if (pos == startQL) {
                        if (!addedMeasure) {
                            if (quantifiedObject != null) {
                                measure.addAttribute(new Attribute("ptr", "#" + quantifiedObjectID));
//                                markPosition(measure, quantifiedObject, startQL);
                            }
                            p.appendChild(text.substring(initPos, startQL));
                            p.appendChild(measure);
                            addedMeasure = true;
                        } else {
                            measure.appendChild(text.substring(initPos, startQL));
                        }
                        measure.appendChild(text.substring(startQL, endQL));
                        pos = endQL;
                        initPos = pos;
                    }
                    if (pos == startQM) {
                        if (!addedMeasure) {
                            if (quantifiedObject != null) {
                                measure.addAttribute(new Attribute("ptr", "#" + quantifiedObjectID));
//                                markPosition(measure, quantifiedObject, startQM);
                            }
                            p.appendChild(text.substring(initPos, startQM));
                            p.appendChild(measure);
                            addedMeasure = true;
                        } else {
                            measure.appendChild(text.substring(initPos, startQM));
                        }
                        measure.appendChild(text.substring(startQM, endQM));
                        pos = endQM;
                        initPos = pos;
                    }
                    if (pos == startUL) {
//                            measure.appendChild(text.substring(initPos, endUL));
//
//                            pos = endUL;
//                            initPos = pos;

                        if (!addedMeasure) {
                            if (quantifiedObject != null) {
                                measure.addAttribute(new Attribute("ptr", "#" + quantifiedObjectID));
                            }
                            p.appendChild(text.substring(initPos, startUL));
                            p.appendChild(measure);
                            addedMeasure = true;
                        } else {
                            measure.appendChild(text.substring(initPos, startUL));
                        }
                        measure.appendChild(text.substring(startUL, endUL));
                        pos = endUL;
                        initPos = pos;
                    }
                    if ((pos == startUM) && (startUM != startUL)) {
//                        measure.appendChild(text.substring(initPos, endUM));
//                        pos = endUM;
//                        initPos = pos;

                        if (!addedMeasure) {
                            if (quantifiedObject != null) {
                                measure.addAttribute(new Attribute("ptr", "#" + quantifiedObjectID));
                            }
                            p.appendChild(text.substring(initPos, startUM));
                            p.appendChild(measure);
                            addedMeasure = true;
                        } else {
                            measure.appendChild(text.substring(initPos, startUM));
                        }
                        measure.appendChild(text.substring(startUM, endUM));
                        pos = endUM;
                        initPos = pos;
                    }
                    if (pos == startO) {
                        p.appendChild(text.substring(initPos, startO));
                        p.appendChild(quantifiedObjectElement);
                        pos = endO;
                        initPos = pos;
                    }

                    if ((pos >= endQL) && (pos >= endQM)
                            && (pos >= endUL) && (pos >= endUM)
                            && (pos >= endO))
                        break;
                    pos++;
                }
            } else if (measurement.getType() == UnitUtilities.Measurement_Type.CONJUNCTION) {
                measure.addAttribute(new Attribute("type", "list"));
                List<Quantity> quantities = measurement.getQuantityList();
                int initPos = pos;

                boolean measureAdded = false;
                for (Quantity quantity : quantities) {
                    int startQ = quantity.getOffsetStart();
                    int endQ = quantity.getOffsetEnd();

                    Unit unit = quantity.getRawUnit();
                    int startU = -1;
                    int endU = -1;
                    if (unit != null) {
                        startU = unit.getOffsetStart();
                        endU = unit.getOffsetEnd();
                    }

                    while (pos < text.length()) {
                        if (pos == startQ) {
                            if (!measureAdded) {
                                p.appendChild(text.substring(initPos, startQ));
                            } else {
                                measure.appendChild(text.substring(initPos, startQ));
                            }
                            measure.appendChild(text.substring(startQ, endQ));
                            if (!measureAdded) {
                                if (quantifiedObject != null) {
                                    measure.addAttribute(new Attribute("ptr", "#" + quantifiedObjectID));
//                                    markPosition(measure, quantifiedObject, startQ);
                                }
                                p.appendChild(measure);
                                measureAdded = true;
                            }
                            pos = endQ;
                            initPos = endQ;
                        }
                        if (pos == startU) {
                            measure.appendChild(text.substring(initPos, endU));
                            pos = endU;
                            initPos = endU;
                        }
                        if (pos == startO) {
                            p.appendChild(text.substring(initPos, startO));
                            p.appendChild(quantifiedObjectElement);
                            pos = endO;
                            initPos = pos;
                        }

                        if (pos >= endQ && pos >= endU && pos >= endO) {
                            break;
                        }

                        pos++;
                    }
                }
            }
        }

        p.appendChild(text.substring(pos));

        return p;
    }

    private void markPosition(Element measure, QuantifiedObject quantifiedObject, int startQL) {
        if (quantifiedObject.getOffsetStart() > -1 && quantifiedObject.getOffsetStart() > startQL) {
            measure.addAttribute(new Attribute("pos", "left"));
        } else {
            measure.addAttribute(new Attribute("pos", "right"));
        }
    }
}


text:
import {
  ComplexModel,
  FAIL_MODEL_GSI,
  INDEX_ACTIVE,
  INDEX_ACTIVE_CREATED_AT,
  INDEX_COUNT,
  ModelWithABunchOfIndexes,
  ModelWithDefaultValue,
  ModelWithGSI,
  ModelWithLSI,
  ModelWithoutPartitionKeyModel,
  SimpleWithCompositePartitionKeyModel,
  SimpleWithPartitionKeyModel,
} from '../../../test/models'
import { Metadata } from './metadata'

describe('metadata', () => {
  let metaDataPartitionKey: Metadata<SimpleWithPartitionKeyModel>
  let metaDataNoPartitionKey: Metadata<ModelWithoutPartitionKeyModel>
  let metaDataComposite: Metadata<SimpleWithCompositePartitionKeyModel>
  let metaDataLsi: Metadata<ModelWithLSI>
  let metaDataGsi: Metadata<ModelWithGSI>
  let metaDataIndexes: Metadata<ModelWithABunchOfIndexes>
  let metaDataDefaultValue: Metadata<ModelWithDefaultValue>
  let metaDataComplex: Metadata<ComplexModel>

  beforeEach(() => {
    metaDataPartitionKey = new Metadata(SimpleWithPartitionKeyModel)
    metaDataNoPartitionKey = new Metadata(ModelWithoutPartitionKeyModel)
    metaDataComposite = new Metadata(SimpleWithCompositePartitionKeyModel)
    metaDataLsi = new Metadata(ModelWithLSI)
    metaDataGsi = new Metadata(ModelWithGSI)
    metaDataIndexes = new Metadata(ModelWithABunchOfIndexes)
    metaDataDefaultValue = new Metadata(ModelWithDefaultValue)
    metaDataComplex = new Metadata(ComplexModel)
  })

  it('forProperty', () => {
    const forId = metaDataPartitionKey.forProperty('id')
    expect(forId).toBeDefined()
    expect(forId!.key).toBeDefined()
    expect(forId!.name).toBe('id')
    expect(forId!.typeInfo).toBeDefined()
  })

  it('forProperty [nested object]', () => {
    const nestedObjDateMeta = metaDataComplex.forProperty('nestedObj.date')
    expect(nestedObjDateMeta).toBeDefined()
    expect(nestedObjDateMeta!.name).toEqual('date')
  })

  it('forProperty [property of nested object in list]', () => {
    const nestedObjDateMeta = metaDataComplex.forProperty('sortedComplexSet[0].date')
    expect(nestedObjDateMeta).toBeDefined()
    expect(nestedObjDateMeta!.name).toEqual('date')
  })

  it('forProperty without decorator [nested object in list]', () => {
    const nestedObjDateMeta = metaDataComplex.forProperty('sortedComplexSet[0].id')
    expect(nestedObjDateMeta).toBeUndefined()
  })

  it('getPropertiesWithDefaultValueProvider', () => {
    const props = metaDataDefaultValue.getPropertiesWithDefaultValueProvider()
    expect(props.length).toBe(1)
    expect(props[0].key).toBeDefined()
    expect(props[0].name).toBe('id')
    expect(props[0].defaultValueProvider).toBeDefined()
    expect(props[0].defaultValueProvider!()).toBeDefined()
  })

  it('getPartitionKey', () => {
    expect(metaDataPartitionKey.getPartitionKey()).toEqual('id')
    expect(metaDataGsi.getPartitionKey(INDEX_ACTIVE)).toEqual('active')
    expect(metaDataIndexes.getPartitionKey(INDEX_COUNT)).toEqual('myId')
    expect(metaDataIndexes.getPartitionKey(INDEX_ACTIVE_CREATED_AT)).toEqual('active')
  })

  it('getPartitionKey throws if no partitionKey defined [no index]', () => {
    expect(() => metaDataNoPartitionKey.getPartitionKey()).toThrow()
  })
  it('getPartitionKey throws if no partitionKey defined [GSI]', () => {
    expect(() => metaDataNoPartitionKey.getPartitionKey(FAIL_MODEL_GSI)).toThrow()
  })
  it('getPartitionKey throws if given index is not defined', () => {
    expect(() => metaDataNoPartitionKey.getPartitionKey('not-existing-index')).toThrow()
  })

  it('getSortKey', () => {
    expect(metaDataPartitionKey.getSortKey()).toBe(null)
    expect(metaDataComposite.getSortKey()).toBe('creationDate')
    expect(metaDataLsi.getSortKey(INDEX_ACTIVE)).toBe('active')
    expect(() => metaDataGsi.getSortKey(INDEX_ACTIVE)).toThrow()
    expect(metaDataIndexes.getSortKey(INDEX_ACTIVE_CREATED_AT)).toBe('createdAt')
  })
  it('getSortKey throws if given index is not defined', () => {
    expect(() => metaDataNoPartitionKey.getSortKey('non-existent-index-name')).toThrow()
  })

  it('getIndexes', () => {
    expect(metaDataLsi.getIndexes()).toEqual([{ partitionKey: 'id', sortKey: 'active' }])
    expect(metaDataGsi.getIndexes()).toEqual([{ partitionKey: 'active' }])
    expect(metaDataIndexes.getIndexes()).toEqual([
      { partitionKey: 'active', sortKey: 'createdAt' },
      { partitionKey: 'myId', sortKey: 'count' },
    ])
  })

  it('getIndex', () => {
    expect(metaDataPartitionKey.getIndexes().length).toBe(0)
    expect(metaDataPartitionKey.getIndex('blub')).toBe(null)
    expect(metaDataIndexes.getIndex(INDEX_ACTIVE_CREATED_AT)).toEqual({
      partitionKey: 'active',
      sortKey: 'createdAt',
    })
  })
  it('getIndex returns null if not existent', () => {
    // no indexes at all --> should always be defined
    expect(metaDataNoPartitionKey.modelOptions).toBeDefined()
    expect(metaDataNoPartitionKey.modelOptions.indexes).toBeInstanceOf(Map)
    // no indexes at all
    expect(metaDataPartitionKey.getIndex('non-existent-index')).toBeNull()
    // indexes defined, but not the one requesting
    expect(metaDataIndexes.getIndex('non-existent-index')).toBeNull()
  })
})


text:
<!DOCTYPE html>

		<title>Hueman</title>

		<link rel="stylesheet" href="../css/style.css">
		<link rel="stylesheet" href="../css/animate.css">

		Where are you?

		<canvas id="canvas" width="1000" height="550"></canvas>


text:
import os
import unittest

from cloudify.mocks import MockCloudifyContext
from cloudify.state import current_ctx
from cloudify.workflows import local
from cloudify import ctx
import yaml

from gcp.compute.instance import Instance

class TestPlugin(unittest.TestCase):
    inputs = None

    def setUp(self):  # noqa
        ctx = MockCloudifyContext(node_id='id', node_name='name')
        current_ctx.set(ctx)
        ctx.logger.info('Setting environment')

        # build blueprint path
        blueprint_path = os.path.join(os.path.dirname(__file__),
                                      'blueprint', 'blueprint.yaml')
        with open('inputs_plugin.yaml') as f:
            self.inputs = yaml.safe_load(f)

        # setup local workflow execution environment
        self.env = local.init_env(blueprint_path,
                                  name=self._testMethodName,
                                  inputs=self.inputs)

    def test_create_instance(self):
        config = self.inputs['config']
        instance = Instance(config,
                            ctx.logger,
                            name=ctx.instance.id)
        instances = instance.list()
        base = len(instances.get('items', []))
        ctx.logger.info('Install workflow')
        # execute install workflow
        self.env.execute('install', task_retries=0)

        ctx.logger.info('Check instance number')
        instances = instance.list()
        self.assertEqual(len(instances['items']), base + 1)

        ctx.logger.info('Uninstall workflow')
        self.env.execute('uninstall', task_retries=0)

        ctx.logger.info('Check instance number')
        instances = instance.list()
        self.assertEqual(len(instances.get('items', [])), base)


text:
namespace Aid
{
	class WritingMemory
	{
	public:
		void operator()();

	private:
		static const WORD kForegroundAttrsMask = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
		static const WORD kBackgroundAttrsMask = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;

		static WORD GetForegroundAttributes(const CONSOLE_SCREEN_BUFFER_INFOEX & screen_buffer_info);
		static WORD GetBackgroundAttributes(const CONSOLE_SCREEN_BUFFER_INFOEX & screen_buffer_info);

		static void SetColorAttributes(WORD foreground, WORD background, CONSOLE_SCREEN_BUFFER_INFOEX & screen_buffer_info);
	};
}


text:
title: InfluxDB Enterprise cluster features
aliases:
    - /enterprise/v1.3/features/clustering-features/
menu:
  enterprise_influxdb_1_3:
    weight: 20
    parent: Features
---

## Entitlements

A valid license key is required in order to start `influxd-meta` or `influxd`.
License keys restrict the number of data nodes that can be added to a cluster as well as the number of CPU cores a data node can use.
Without a valid license, the process will abort startup.

## Query management

Query management works cluster wide. Specifically, `SHOW QUERIES` and `KILL QUERY <ID>` on `"<host>"` can be run on any data node. `SHOW QUERIES` will report all queries running across the cluster and the node which is running the query.
`KILL QUERY` can abort queries running on the local node or any other remote data node. For details on using the `SHOW QUERIES` and `KILL QUERY` on InfluxDB Enterprise clusters,
see [Query Management](https://docs.influxdata.com/influxdb/v1.3/troubleshooting/query_management/).

## Subscriptions

Subscriptions used by Kapacitor work in a cluster. Writes to any node will be forwarded to subscribers across all supported subscription protocols.

## Continuous Queries
### Configuration and operational considerations on a cluster

It is important to understand how to configure InfluxDB Enterprise and how this impacts the
Continuous Queries (CQ) engine's behavior:

- **Data Node Configuration** `[continuous queries]`
[run-interval](/enterprise_influxdb/v1.3/administration/configuration#run-interval-1s)
-- The interval at which InfluxDB checks to see if a CQ needs to run. Set this option to the lowest interval
at which your CQs run. For example, if your most frequent CQ runs every minute, set run-interval to 1m.
- **Meta Node Configuration** `[meta]`
[lease-duration](/enterprise_influxdb/v1.3/administration/configuration#lease-duration-1m0s)
-- The default duration of the leases that data nodes acquire from the meta nodes. Leases automatically expire after the
lease-duration is met.  Leases ensure that only one data node is running something at a given time. For example, Continuous
Queries use a lease so that all data nodes aren't running the same CQs at once.
- **Execution time of CQs** – CQs are sequentially executed. Depending on the amount of work that they need to accomplish
in order to complete, the configuration parameters mentioned above can have an impact on the observed behavior of CQs.

The CQ service is running on every node, but only a single node is granted exclusive access to execute CQs at any one time.
However, every time the `run-interval` elapses (and assuming a node isn't currently executing CQs), a node attempts to
acquire the CQ lease. By default the `run-interval` is one second – so the data nodes are aggressively checking to see
if they can acquire the lease. On clusters where all CQs execute in an amount of time less than `lease-duration`
(default is 1m), there's a good chance that the first data node to acquire the lease will still hold the lease when
the `run-interval` elapses. Other nodes will be denied the lease and when the node holding the lease requests it again,
the lease is renewed with the expiration extended to `lease-duration`.  So in a typical situation, we observe that a
single data node acquires the CQ lease and holds on to it. It effectively becomes the executor of CQs until it is
recycled (for any reason).

Now consider the the following case, CQs take longer to execute than the `lease-duration`, so when the lease expires,
~1 second later another data node requests and is granted the lease.  The original holder of the lease is busily working
on sequentially executing the list of CQs it was originally handed and the data node now holding the lease begins
executing CQs from the top of the list.

Based on this scenario, it may appear that CQs are "executing in parallel" because multiple data nodes are
essentially "rolling" sequentially through the registered CQs and the lease is rolling from node to node.
The "long pole" here is effectively your most complex CQ – and it likely means that at some point all nodes
are attempting to execute that same complex CQ (and likely competing for resources as they overwrite points
generated by that query on each node that is executing it --- likely with some phased offset).

To avoid this behavior, and this is desirable because it reduces the overall load on your cluster,
you should set the lease-duration to a value greater than the aggregate execution time for ALL the CQs that you are running.

Based on the current way in which CQs are configured to execute, the way to address parallelism is by using
Kapacitor for the more complex CQs that you are attempting to run.
[See Kapacitor as a continuous query engine](/kapacitor/v1.3/guides/continuous_queries/).
However, you can keep the more simplistic and highly performant CQs within the database –
but ensure that the lease duration is greater than their aggregate execution time to ensure that
"extra" load is not being unnecessarily introduced on your cluster.

## PProf endpoints

Meta nodes expose the /debug/pprof endpoints for profiling and troubleshooting.

## Shard movement

* [Copy Shard](/enterprise_influxdb/v1.3/features/cluster-commands/#copy-shard) support - copy a shard from one node to another
* [Copy Shard Status](/enterprise_influxdb/v1.3/features/cluster-commands/#copy-shard-status) - query the status of a copy shard request
* [Kill Copy Shard](/enterprise_influxdb/v1.3/features/cluster-commands/#kill-copy-shard) - kill a running shard copy
* [Remove Shard](/enterprise_influxdb/v1.3/features/cluster-commands/#remove-shard) - remove a shard from a node (this deletes data)
* [Truncate Shards](/enterprise_influxdb/v1.3/features/cluster-commands/#truncate-shards) - truncate all active shard groups and start new shards immediately (This is useful when adding nodes or changing replication factors.)

This functionality is exposed via an API on the meta service and through [`influxd-ctl` sub-commands](/enterprise_influxdb/v1.3/features/cluster-commands/).

## OSS conversion

Importing a OSS single server as the first data node is supported.

See [OSS to Cluster Migration](/enterprise_influxdb/v1.3/guides/migration/) for
step-by-step instructions.

## Query routing

The query engine skips failed nodes that hold a shard needed for queries.
If there is a replica on another node, it will retry on that node.

## Backup and restore

InfluxDB Enterprise clusters support backup and restore functionality starting with
version 0.7.1.
See [Backup and Restore](/enterprise_influxdb/v1.3/guides/backup-and-restore/) for
more information.