<commit_before>/*
    norx.go
    ------

    This file is part of the Go reference implementation of NORX.

    :copyright: (c) 2014 Philipp Jovanovic <philipp@jovanovic.io>
    :license: BSD (3-Clause), see LICENSE
*/

package aead

const (
    NORX_W = 64              // wordsize
    NORX_R = 4               // number of rounds
    NORX_D = 1               // parallelism degree
    NORX_A = NORX_W * 4      // tag size
    NORX_N = NORX_W * 2      // nonce size
    NORX_K = NORX_W * 4      // key size
    NORX_B = NORX_W * 16     // state size
    NORX_C = NORX_W * 6      // capacity size
    RATE = NORX_B - NORX_C   // rate size
    HEADER_TAG  = 1 << 0
    PAYLOAD_TAG = 1 << 1
    TRAILER_TAG = 1 << 2
    FINAL_TAG   = 1 << 3
    BRANCH_TAG  = 1 << 4
    MERGE_TAG   = 1 << 5
    R0, R1, R2, R3 = 8, 19, 40, 63 // rotation offsets
    u0, u1 = 0x243F6A8885A308D3, 0x13198A2E03707344
    u2, u3 = 0xA4093822299F31D0, 0x082EFA98EC4E6C89
    u4, u5 = 0xAE8858DC339325A1, 0x670A134EE52D7FA6
    u6, u7 = 0xC4316D80CD967541, 0xD21DFBF8B630B762
    u8, u9 = 0x375A18D261E7F892, 0x343D1F187D92285B
)

type state_t struct {
    s [16]uint64
}

func ROTR(x,c uint64) uint64 {
    return (x >> c | x << (NORX_W - c))
}

func H(x,y uint64) uint64 {
    return (x ^ y) ^ ((x & y) << 1)
}

func G(a,b,c,d uint64) (uint64,uint64,uint64,uint64) {

    a = H(a,b)
    d = ROTR(a ^ d, R0)
    c = H(c,d)
    b = ROTR(b ^ c, R1)
    a = H(a,b)
    d = ROTR(a ^ d, R2)
    c = H(c,d)
    b = ROTR(b ^ c, R3)
    return a,b,c,d
}

func F(s []uint64) {
    // Column step
    s[ 0], s[ 4], s[ 8], s[12] = G(s[ 0], s[ 4], s[ 8], s[12])
    s[ 1], s[ 5], s[ 9], s[13] = G(s[ 1], s[ 5], s[ 9], s[13])
    s[ 2], s[ 6], s[10], s[14] = G(s[ 2], s[ 6], s[10], s[14])
    s[ 3], s[ 7], s[11], s[15] = G(s[ 3], s[ 7], s[11], s[15])
    // Diagonal step
    s[ 0], s[ 5], s[10], s[15] = G(s[ 0], s[ 5], s[10], s[15])
    s[ 1], s[ 6], s[11], s[12] = G(s[ 1], s[ 6], s[11], s[12])
    s[ 2], s[ 7], s[ 8], s[13] = G(s[ 2], s[ 7], s[ 8], s[13])
    s[ 3], s[ 4], s[ 9], s[14] = G(s[ 3], s[ 4], s[ 9], s[14])
}

func permute(state *state_t) {
    s := state.s[:]
    for i:=0; i<NORX_R; i++ { F(s) }
}

func setup(state *state_t, k []uint8, n []uint8) {

    s := state.s[:]

    s[ 0] = u0
    s[ 1] = LOAD64(n[ 0: 8])
    s[ 2] = LOAD64(n[ 8:16])
    s[ 3] = u1

    s[ 4] = LOAD64(k[ 0: 8])
    s[ 5] = LOAD64(k[ 8:16])
    s[ 6] = LOAD64(k[16:24])
    s[ 7] = LOAD64(k[24:32])

    s[ 8] = u2
    s[ 9] = u3
    s[10] = u4
    s[11] = u5

    s[12] = u6
    s[13] = u7
    s[14] = u8
    s[15] = u9

    s[14] ^= (NORX_R << 26) | (NORX_D << 18) | (NORX_W << 10) | NORX_A
    permute(state)
}

func process_header(state *state_t, in []uint8, inlen uint64) {

    if inlen > 0 {
        i := uint64(0)
        n := BYTES64(RATE)
        for inlen >= n {
            absorb_block(state, in[n*i:n*(i+1)], HEADER_TAG)
            inlen -= n
            i++
        }
        absorb_lastblock(state, in[n*i:n*i+inlen], inlen, HEADER_TAG)
    }
}

func encrypt_msg(state *state_t, out []uint8, in []uint8, inlen uint64) {

    if inlen > 0 {
        i := uint64(0)
        n := BYTES64(RATE)
        for inlen >= n {
            encrypt_block(state, out[n*i:n*(i+1)], in[n*i:n*(i+1)])
            inlen -= n
            i++
        }
        encrypt_lastblock(state, out[n*i:n*i+inlen], in[n*i:n*i+inlen], inlen)
    }
}

func decrypt_msg(state *state_t, out []uint8, in []uint8, inlen uint64) {

    if inlen > 0 {
        i := uint64(0)
        n := BYTES64(RATE)
        for inlen >= n {
            decrypt_block(state, out[n*i:n*(i+1)], in[n*i:n*(i+1)])
            inlen -= n
            i++
        }
        decrypt_lastblock(state, out[n*i:n*i+inlen], in[n*i:n*i+inlen], inlen)
    }
}

func process_trailer(state *state_t, in []uint8, inlen uint64) {

    if inlen > 0 {
        i := uint64(0)
        n := BYTES64(RATE)
        for inlen >= n {
            absorb_block(state, in[n*i:n*(i+1)], TRAILER_TAG)
            inlen -= n
            i++
        }
        absorb_lastblock(state, in[n*i:n*i+inlen], inlen, TRAILER_TAG)
    }
}

func output_tag(state *state_t, tag []uint8) {

    inject_tag(state, FINAL_TAG)
    permute(state)
    permute(state)

    s := state.s[:]
    lastblock := make([]uint8, BYTES64(RATE))
    b := BYTES64(NORX_W)
    for i:= uint64(0); i < WORDS64(RATE); i++ {
        STORE64(lastblock[b*i:b*(i+1)], s[i])
    }
    copy(tag[:], lastblock[:])
    BURN8(lastblock[:], BYTES64(RATE))
}

func verify_tag(tag1 []uint8, tag2 []uint8) int {

    acc := 0
    for i := uint64(0); i < BYTES64(NORX_A); i++ {
        acc |= int(tag1[i] ^ tag2[i])
    }
    return (((acc - 1) >> 8) & 1) - 1
}

func pad(out []uint8, in []uint8, inlen uint64) {

    copy(out[:],in[:inlen])
    out[inlen] = 0x01
    out[BYTES64(RATE) - 1] |= 0x80
}

func inject_tag(state *state_t, tag uint64) {
    s := state.s[:]
    s[15] ^= tag
}

func absorb_block(state *state_t, in []uint8, tag uint64) {

    inject_tag(state, tag)
    permute(state)

    s := state.s[:]
    b := BYTES64(NORX_W)
    for i:= uint64(0); i < WORDS64(RATE); i++ {
        s[i] ^= LOAD64(in[b*i:b*(i+1)])
    }
}

func absorb_lastblock(state *state_t, in []uint8, inlen uint64, tag uint64) {

    lastblock := make([]uint8, BYTES64(RATE))
    pad(lastblock[:], in[:], inlen)
    absorb_block(state, lastblock[:], tag)
    BURN8(lastblock[:], BYTES64(RATE))
}

func encrypt_block(state *state_t, out []uint8, in []uint8) {

    inject_tag(state, PAYLOAD_TAG)
    permute(state)

    s := state.s[:]
    b := BYTES64(NORX_W)
    for i:= uint64(0); i < WORDS64(RATE); i++ {
        s[i] ^= LOAD64(in[b*i:b*(i+1)])
        STORE64(out[b*i:b*(i+1)], s[i])
    }
}

func encrypt_lastblock(state *state_t, out []uint8, in []uint8, inlen uint64) {

    lastblock := make([]uint8, BYTES64(RATE))
    pad(lastblock[:], in[:], inlen)
    encrypt_block(state, lastblock[:], lastblock[:])
    copy(out[:], lastblock[:])
    BURN8(lastblock[:], BYTES64(RATE))
}

func decrypt_block(state *state_t, out []uint8, in []uint8) {

    inject_tag(state, PAYLOAD_TAG)
    permute(state)

    s := state.s[:]
    b := BYTES64(NORX_W)
    for i:= uint64(0); i < WORDS64(RATE); i++ {
        c := LOAD64(in[b*i:b*(i+1)])
        STORE64(out[b*i:b*(i+1)], s[i] ^ c)
        s[i] = c
    }
}

func decrypt_lastblock(state *state_t, out []uint8, in []uint8, inlen uint64) {

    inject_tag(state, PAYLOAD_TAG)
    permute(state)

    s := state.s[:]
    i := uint64(0)
    n := BYTES64(NORX_W)
    b := make([]uint8, n)

    /* undo padding */
    s[inlen / n] ^= uint64(0x01) << (inlen % n * 8)
    s[WORDS64(RATE) - 1] ^= uint64(0x80) << ((BYTES64(RATE) - 1) % n * 8)

    for inlen >= n {
        c := LOAD64(in[n*i:n*(i+1)])
        STORE64(out[n*i:n*(i+1)], s[i] ^ c)
        s[i] = c
        inlen -= n
        i++
    }

    STORE64(b,s[i])
    for j := uint64(0); j < inlen; j++ {
      c := in[n*i+j]
      out[n*i+j] = b[j] ^ c
      b[j] = c
    }
    s[i] = LOAD64(b)
    BURN8(b,n)
}

func AEAD_encrypt(
    c []uint8, clen *uint64,
    h []uint8, hlen uint64,
    m []uint8, mlen uint64,
    t []uint8, tlen uint64,
    nonce []uint8,
    key []uint8) {

    state := new(state_t)
    setup(state, key, nonce)
    process_header(state, h, hlen)
    encrypt_msg(state, c, m, mlen)
    process_trailer(state, t, tlen)
    output_tag(state, c[ mlen: ])
    *clen = mlen + BYTES64(NORX_A)
    BURN64(state.s[:], WORDS64(NORX_B))
}

func AEAD_decrypt(
    m []uint8, mlen *uint64,
    h []uint8, hlen uint64,
    c []uint8, clen uint64,
    t []uint8, tlen uint64,
    nonce []uint8,
    key []uint8) int {

    if clen < BYTES64(NORX_A) {
      return -1
    }
    result := -1
    tag := make([]uint8, NORX_A)
    state := new(state_t)
    setup(state, key, nonce)
    process_header(state, h, hlen)
    decrypt_msg(state, m, c, clen - BYTES64(NORX_A))
    process_trailer(state, t, tlen)
    output_tag(state, tag)
    *mlen = clen - BYTES64(NORX_A)
    result = verify_tag(c[clen - BYTES64(NORX_A):], tag)
    if result != 0 {
        BURN8(m, clen - BYTES64(NORX_A))
    }
    BURN64(state.s[:], WORDS64(NORX_B))
    return result
}

<commit_msg>process last bytes in decryption word-wise<commit_after>/*
    norx.go
    ------

    This file is part of the Go reference implementation of NORX.

    :copyright: (c) 2014 Philipp Jovanovic <philipp@jovanovic.io>
    :license: BSD (3-Clause), see LICENSE
*/

package aead

const (
    NORX_W = 64              // wordsize
    NORX_R = 4               // number of rounds
    NORX_D = 1               // parallelism degree
    NORX_A = NORX_W * 4      // tag size
    NORX_N = NORX_W * 2      // nonce size
    NORX_K = NORX_W * 4      // key size
    NORX_B = NORX_W * 16     // state size
    NORX_C = NORX_W * 6      // capacity size
    RATE = NORX_B - NORX_C   // rate size
    HEADER_TAG  = 1 << 0
    PAYLOAD_TAG = 1 << 1
    TRAILER_TAG = 1 << 2
    FINAL_TAG   = 1 << 3
    BRANCH_TAG  = 1 << 4
    MERGE_TAG   = 1 << 5
    R0, R1, R2, R3 = 8, 19, 40, 63 // rotation offsets
    u0, u1 = 0x243F6A8885A308D3, 0x13198A2E03707344
    u2, u3 = 0xA4093822299F31D0, 0x082EFA98EC4E6C89
    u4, u5 = 0xAE8858DC339325A1, 0x670A134EE52D7FA6
    u6, u7 = 0xC4316D80CD967541, 0xD21DFBF8B630B762
    u8, u9 = 0x375A18D261E7F892, 0x343D1F187D92285B
)

type state_t struct {
    s [16]uint64
}

func ROTR(x,c uint64) uint64 {
    return (x >> c | x << (NORX_W - c))
}

func H(x,y uint64) uint64 {
    return (x ^ y) ^ ((x & y) << 1)
}

func G(a,b,c,d uint64) (uint64,uint64,uint64,uint64) {

    a = H(a,b)
    d = ROTR(a ^ d, R0)
    c = H(c,d)
    b = ROTR(b ^ c, R1)
    a = H(a,b)
    d = ROTR(a ^ d, R2)
    c = H(c,d)
    b = ROTR(b ^ c, R3)
    return a,b,c,d
}

func F(s []uint64) {

    // Column step
    s[ 0], s[ 4], s[ 8], s[12] = G(s[ 0], s[ 4], s[ 8], s[12])
    s[ 1], s[ 5], s[ 9], s[13] = G(s[ 1], s[ 5], s[ 9], s[13])
    s[ 2], s[ 6], s[10], s[14] = G(s[ 2], s[ 6], s[10], s[14])
    s[ 3], s[ 7], s[11], s[15] = G(s[ 3], s[ 7], s[11], s[15])
    // Diagonal step
    s[ 0], s[ 5], s[10], s[15] = G(s[ 0], s[ 5], s[10], s[15])
    s[ 1], s[ 6], s[11], s[12] = G(s[ 1], s[ 6], s[11], s[12])
    s[ 2], s[ 7], s[ 8], s[13] = G(s[ 2], s[ 7], s[ 8], s[13])
    s[ 3], s[ 4], s[ 9], s[14] = G(s[ 3], s[ 4], s[ 9], s[14])
}

func permute(state *state_t) {

    s := state.s[:]
    for i:=0; i<NORX_R; i++ { F(s) }
}

func setup(state *state_t, k []uint8, n []uint8) {

    s := state.s[:]

    s[ 0] = u0
    s[ 1] = LOAD64(n[ 0: 8])
    s[ 2] = LOAD64(n[ 8:16])
    s[ 3] = u1

    s[ 4] = LOAD64(k[ 0: 8])
    s[ 5] = LOAD64(k[ 8:16])
    s[ 6] = LOAD64(k[16:24])
    s[ 7] = LOAD64(k[24:32])

    s[ 8] = u2
    s[ 9] = u3
    s[10] = u4
    s[11] = u5

    s[12] = u6
    s[13] = u7
    s[14] = u8
    s[15] = u9

    s[14] ^= (NORX_R << 26) | (NORX_D << 18) | (NORX_W << 10) | NORX_A
    permute(state)
}

func process_header(state *state_t, in []uint8, inlen uint64) {

    if inlen > 0 {
        i := uint64(0)
        n := BYTES64(RATE)
        for inlen >= n {
            absorb_block(state, in[n*i:n*(i+1)], HEADER_TAG)
            inlen -= n
            i++
        }
        absorb_lastblock(state, in[n*i:n*i+inlen], inlen, HEADER_TAG)
    }
}

func encrypt_msg(state *state_t, out []uint8, in []uint8, inlen uint64) {

    if inlen > 0 {
        i := uint64(0)
        n := BYTES64(RATE)
        for inlen >= n {
            encrypt_block(state, out[n*i:n*(i+1)], in[n*i:n*(i+1)])
            inlen -= n
            i++
        }
        encrypt_lastblock(state, out[n*i:n*i+inlen], in[n*i:n*i+inlen], inlen)
    }
}

func decrypt_msg(state *state_t, out []uint8, in []uint8, inlen uint64) {

    if inlen > 0 {
        i := uint64(0)
        n := BYTES64(RATE)
        for inlen >= n {
            decrypt_block(state, out[n*i:n*(i+1)], in[n*i:n*(i+1)])
            inlen -= n
            i++
        }
        decrypt_lastblock(state, out[n*i:n*i+inlen], in[n*i:n*i+inlen], inlen)
    }
}

func process_trailer(state *state_t, in []uint8, inlen uint64) {

    if inlen > 0 {
        i := uint64(0)
        n := BYTES64(RATE)
        for inlen >= n {
            absorb_block(state, in[n*i:n*(i+1)], TRAILER_TAG)
            inlen -= n
            i++
        }
        absorb_lastblock(state, in[n*i:n*i+inlen], inlen, TRAILER_TAG)
    }
}

func output_tag(state *state_t, tag []uint8) {

    inject_tag(state, FINAL_TAG)
    permute(state)
    permute(state)

    s := state.s[:]
    lastblock := make([]uint8, BYTES64(RATE))
    b := BYTES64(NORX_W)
    for i:= uint64(0); i < WORDS64(RATE); i++ {
        STORE64(lastblock[b*i:b*(i+1)], s[i])
    }
    copy(tag[:], lastblock[:])
    BURN8(lastblock[:], BYTES64(RATE))
}

func verify_tag(tag1 []uint8, tag2 []uint8) int {

    acc := 0
    for i := uint64(0); i < BYTES64(NORX_A); i++ {
        acc |= int(tag1[i] ^ tag2[i])
    }
    return (((acc - 1) >> 8) & 1) - 1
}

func pad(out []uint8, in []uint8, inlen uint64) {

    copy(out[:],in[:inlen])
    out[inlen] = 0x01
    out[BYTES64(RATE) - 1] |= 0x80
}

func inject_tag(state *state_t, tag uint64) {

    s := state.s[:]
    s[15] ^= tag
}

func absorb_block(state *state_t, in []uint8, tag uint64) {

    inject_tag(state, tag)
    permute(state)

    s := state.s[:]
    b := BYTES64(NORX_W)
    for i:= uint64(0); i < WORDS64(RATE); i++ {
        s[i] ^= LOAD64(in[b*i:b*(i+1)])
    }
}

func absorb_lastblock(state *state_t, in []uint8, inlen uint64, tag uint64) {

    lastblock := make([]uint8, BYTES64(RATE))
    pad(lastblock[:], in[:], inlen)
    absorb_block(state, lastblock[:], tag)
    BURN8(lastblock[:], BYTES64(RATE))
}

func encrypt_block(state *state_t, out []uint8, in []uint8) {

    inject_tag(state, PAYLOAD_TAG)
    permute(state)

    s := state.s[:]
    b := BYTES64(NORX_W)
    for i:= uint64(0); i < WORDS64(RATE); i++ {
        s[i] ^= LOAD64(in[b*i:b*(i+1)])
        STORE64(out[b*i:b*(i+1)], s[i])
    }
}

func encrypt_lastblock(state *state_t, out []uint8, in []uint8, inlen uint64) {

    lastblock := make([]uint8, BYTES64(RATE))
    pad(lastblock[:], in[:], inlen)
    encrypt_block(state, lastblock[:], lastblock[:])
    copy(out[:], lastblock[:])
    BURN8(lastblock[:], BYTES64(RATE))
}

func decrypt_block(state *state_t, out []uint8, in []uint8) {

    inject_tag(state, PAYLOAD_TAG)
    permute(state)

    s := state.s[:]
    b := BYTES64(NORX_W)
    for i:= uint64(0); i < WORDS64(RATE); i++ {
        c := LOAD64(in[b*i:b*(i+1)])
        STORE64(out[b*i:b*(i+1)], s[i] ^ c)
        s[i] = c
    }
}

func decrypt_lastblock(state *state_t, out []uint8, in []uint8, inlen uint64) {

    inject_tag(state, PAYLOAD_TAG)
    permute(state)

    s := state.s[:]
    i := uint64(0)
    n := BYTES64(NORX_W)

    /* undo padding */
    s[inlen / n] ^= uint64(0x01) << (inlen % n * 8)
    s[WORDS64(RATE) - 1] ^= uint64(0x80) << ((BYTES64(RATE) - 1) % n * 8)

    for inlen >= n {
        c := LOAD64(in[n*i:n*(i+1)])
        STORE64(out[n*i:n*(i+1)], s[i] ^ c)
        s[i] = c
        inlen -= n
        i++
    }

    /* decrypt last bytes */
    b := make([]uint8, n)
    copy(b,in[n*i:n*i+inlen])
    x := LOAD64(b)
    STORE64(b, s[i] ^ x)
    copy(out[n*i:n*i+inlen],b)
    s[i] = x
    BURN8(b,n)
}

func AEAD_encrypt(
    c []uint8, clen *uint64,
    h []uint8, hlen uint64,
    m []uint8, mlen uint64,
    t []uint8, tlen uint64,
    nonce []uint8,
    key []uint8) {

    state := new(state_t)
    setup(state, key, nonce)
    process_header(state, h, hlen)
    encrypt_msg(state, c, m, mlen)
    process_trailer(state, t, tlen)
    output_tag(state, c[mlen:])
    *clen = mlen + BYTES64(NORX_A)
    BURN64(state.s[:], WORDS64(NORX_B))
}

func AEAD_decrypt(
    m []uint8, mlen *uint64,
    h []uint8, hlen uint64,
    c []uint8, clen uint64,
    t []uint8, tlen uint64,
    nonce []uint8,
    key []uint8) int {

    if clen < BYTES64(NORX_A) {
      return -1
    }
    result := -1
    tag := make([]uint8, NORX_A)
    state := new(state_t)
    setup(state, key, nonce)
    process_header(state, h, hlen)
    decrypt_msg(state, m, c, clen - BYTES64(NORX_A))
    process_trailer(state, t, tlen)
    output_tag(state, tag)
    *mlen = clen - BYTES64(NORX_A)
    result = verify_tag(c[clen - BYTES64(NORX_A):], tag)
    if result != 0 {
        BURN8(m, clen - BYTES64(NORX_A))
    }
    BURN64(state.s[:], WORDS64(NORX_B))
    return result
}

<|endoftext|>


<commit_before>package stop

import (
	"github.com/spf13/cobra"
	"github.com/BluePecker/JwtAuth/dialog/client"
	"fmt"
)

func NewCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "stop",
		Short: "stop running server",
		RunE: func(cmd *cobra.Command, args []string) error {
			unixSock, err := cmd.Parent().Flags().GetString("unix-sock")
			if err != nil {
				return err
			}
			cli := client.NewClient(unixSock)
			body, err := cli.Get("/v1.0/signal/stop")
			if err != nil {
				return err
			}
			fmt.Println(body)
			return nil
		},
	}

	return cmd
}
<commit_msg>add stop command<commit_after>package stop

import (
	"github.com/spf13/cobra"
	"github.com/BluePecker/JwtAuth/dialog/client"
	"fmt"
)

func NewCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "stop",
		Short: "stop running server",
		RunE: func(cmd *cobra.Command, args []string) error {
			unixSock, err := cmd.Parent().Flags().GetString("unix-sock")
			if err != nil {
				return err
			}
			cli := client.NewClient(unixSock)
			body, err := cli.Get("/v1.0/signal/stop")
			if err != nil {
				return err
			}
			fmt.Printf("result: %s", body)
			return nil
		},
	}

	return cmd
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/pkg/errors"
	"vbom.ml/util/sortorder"

	lxd "github.com/lxc/lxd/client"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/i18n"
	"github.com/lxc/lxd/shared/termios"
)

type stringList [][]string

func (a stringList) Len() int {
	return len(a)
}

func (a stringList) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a stringList) Less(i, j int) bool {
	x := 0
	for x = range a[i] {
		if a[i][x] != a[j][x] {
			break
		}
	}

	if a[i][x] == "" {
		return false
	}

	if a[j][x] == "" {
		return true
	}

	return sortorder.NaturalLess(a[i][x], a[j][x])
}

// Instance name sorting
type byName [][]string

func (a byName) Len() int {
	return len(a)
}

func (a byName) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a byName) Less(i, j int) bool {
	if a[i][0] == "" {
		return false
	}

	if a[j][0] == "" {
		return true
	}

	return sortorder.NaturalLess(a[i][0], a[j][0])
}

// Storage volume sorting
type byNameAndType [][]string

func (a byNameAndType) Len() int {
	return len(a)
}

func (a byNameAndType) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a byNameAndType) Less(i, j int) bool {
	if a[i][0] != a[j][0] {
		return sortorder.NaturalLess(a[i][0], a[j][0])
	}

	if a[i][1] == "" {
		return false
	}

	if a[j][1] == "" {
		return true
	}

	return sortorder.NaturalLess(a[i][1], a[j][1])
}

// Batch operations
type batchResult struct {
	err  error
	name string
}

func runBatch(names []string, action func(name string) error) []batchResult {
	chResult := make(chan batchResult, len(names))

	for _, name := range names {
		go func(name string) {
			chResult <- batchResult{action(name), name}
		}(name)
	}

	results := []batchResult{}
	for range names {
		results = append(results, <-chResult)
	}

	return results
}

// Add a device to an instance
func instanceDeviceAdd(client lxd.InstanceServer, name string, devName string, dev map[string]string) error {
	// Get the instance entry
	inst, etag, err := client.GetInstance(name)
	if err != nil {
		return err
	}

	// Check if the device already exists
	_, ok := inst.Devices[devName]
	if ok {
		return fmt.Errorf(i18n.G("Device already exists: %s"), devName)
	}

	inst.Devices[devName] = dev

	op, err := client.UpdateInstance(name, inst.Writable(), etag)
	if err != nil {
		return err
	}

	return op.Wait()
}

// Add a device to a profile
func profileDeviceAdd(client lxd.InstanceServer, name string, devName string, dev map[string]string) error {
	// Get the profile entry
	profile, profileEtag, err := client.GetProfile(name)
	if err != nil {
		return err
	}

	// Check if the device already exists
	_, ok := profile.Devices[devName]
	if ok {
		return fmt.Errorf(i18n.G("Device already exists: %s"), devName)
	}

	// Add the device to the instance
	profile.Devices[devName] = dev

	err = client.UpdateProfile(name, profile.Writable(), profileEtag)
	if err != nil {
		return err
	}

	return nil
}

// Create the specified image alises, updating those that already exist
func ensureImageAliases(client lxd.InstanceServer, aliases []api.ImageAlias, fingerprint string) error {
	if len(aliases) == 0 {
		return nil
	}

	names := make([]string, len(aliases))
	for i, alias := range aliases {
		names[i] = alias.Name
	}
	sort.Strings(names)

	resp, err := client.GetImageAliases()
	if err != nil {
		return err
	}

	// Delete existing aliases that match provided ones
	for _, alias := range GetExistingAliases(names, resp) {
		err := client.DeleteImageAlias(alias.Name)
		if err != nil {
			fmt.Println(fmt.Sprintf(i18n.G("Failed to remove alias %s"), alias.Name))
		}
	}
	// Create new aliases
	for _, alias := range aliases {
		aliasPost := api.ImageAliasesPost{}
		aliasPost.Name = alias.Name
		aliasPost.Target = fingerprint
		err := client.CreateImageAlias(aliasPost)
		if err != nil {
			fmt.Println(fmt.Sprintf(i18n.G("Failed to create alias %s"), alias.Name))
		}
	}
	return nil
}

// GetExistingAliases returns the intersection between a list of aliases and all the existing ones.
func GetExistingAliases(aliases []string, allAliases []api.ImageAliasesEntry) []api.ImageAliasesEntry {
	existing := []api.ImageAliasesEntry{}
	for _, alias := range allAliases {
		name := alias.Name
		pos := sort.SearchStrings(aliases, name)
		if pos < len(aliases) && aliases[pos] == name {
			existing = append(existing, alias)
		}
	}
	return existing
}

func getConfig(args ...string) (map[string]string, error) {
	if len(args) == 2 && !strings.Contains(args[0], "=") {
		if args[1] == "-" && !termios.IsTerminal(getStdinFd()) {
			buf, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				return nil, errors.Wrap(err, i18n.G("Can't read from stdin: %s"))
			}

			args[1] = string(buf[:])
		}

		return map[string]string{args[0]: args[1]}, nil
	}

	values := map[string]string{}

	for _, arg := range args {
		fields := strings.SplitN(arg, "=", 2)
		if len(fields) != 2 {
			return nil, fmt.Errorf("Invalid key=value configuration: %s", arg)
		}

		if fields[1] == "-" && !termios.IsTerminal(getStdinFd()) {
			buf, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				return nil, fmt.Errorf(i18n.G("Can't read from stdin: %s"), err)
			}

			fields[1] = string(buf[:])
		}

		values[fields[0]] = fields[1]
	}

	return values, nil
}
<commit_msg>lxc: Group snapshot and parent<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/pkg/errors"
	"vbom.ml/util/sortorder"

	lxd "github.com/lxc/lxd/client"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/i18n"
	"github.com/lxc/lxd/shared/termios"
)

type stringList [][]string

func (a stringList) Len() int {
	return len(a)
}

func (a stringList) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a stringList) Less(i, j int) bool {
	x := 0
	for x = range a[i] {
		if a[i][x] != a[j][x] {
			break
		}
	}

	if a[i][x] == "" {
		return false
	}

	if a[j][x] == "" {
		return true
	}

	return sortorder.NaturalLess(a[i][x], a[j][x])
}

// Instance name sorting
type byName [][]string

func (a byName) Len() int {
	return len(a)
}

func (a byName) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a byName) Less(i, j int) bool {
	if a[i][0] == "" {
		return false
	}

	if a[j][0] == "" {
		return true
	}

	return sortorder.NaturalLess(a[i][0], a[j][0])
}

// Storage volume sorting
type byNameAndType [][]string

func (a byNameAndType) Len() int {
	return len(a)
}

func (a byNameAndType) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a byNameAndType) Less(i, j int) bool {
	// Sort snapshot and parent together.
	iType := strings.Split(a[i][0], " ")[0]
	jType := strings.Split(a[j][0], " ")[0]

	if iType != jType {
		return sortorder.NaturalLess(a[i][0], a[j][0])
	}

	if a[i][1] == "" {
		return false
	}

	if a[j][1] == "" {
		return true
	}

	return sortorder.NaturalLess(a[i][1], a[j][1])
}

// Batch operations
type batchResult struct {
	err  error
	name string
}

func runBatch(names []string, action func(name string) error) []batchResult {
	chResult := make(chan batchResult, len(names))

	for _, name := range names {
		go func(name string) {
			chResult <- batchResult{action(name), name}
		}(name)
	}

	results := []batchResult{}
	for range names {
		results = append(results, <-chResult)
	}

	return results
}

// Add a device to an instance
func instanceDeviceAdd(client lxd.InstanceServer, name string, devName string, dev map[string]string) error {
	// Get the instance entry
	inst, etag, err := client.GetInstance(name)
	if err != nil {
		return err
	}

	// Check if the device already exists
	_, ok := inst.Devices[devName]
	if ok {
		return fmt.Errorf(i18n.G("Device already exists: %s"), devName)
	}

	inst.Devices[devName] = dev

	op, err := client.UpdateInstance(name, inst.Writable(), etag)
	if err != nil {
		return err
	}

	return op.Wait()
}

// Add a device to a profile
func profileDeviceAdd(client lxd.InstanceServer, name string, devName string, dev map[string]string) error {
	// Get the profile entry
	profile, profileEtag, err := client.GetProfile(name)
	if err != nil {
		return err
	}

	// Check if the device already exists
	_, ok := profile.Devices[devName]
	if ok {
		return fmt.Errorf(i18n.G("Device already exists: %s"), devName)
	}

	// Add the device to the instance
	profile.Devices[devName] = dev

	err = client.UpdateProfile(name, profile.Writable(), profileEtag)
	if err != nil {
		return err
	}

	return nil
}

// Create the specified image alises, updating those that already exist
func ensureImageAliases(client lxd.InstanceServer, aliases []api.ImageAlias, fingerprint string) error {
	if len(aliases) == 0 {
		return nil
	}

	names := make([]string, len(aliases))
	for i, alias := range aliases {
		names[i] = alias.Name
	}
	sort.Strings(names)

	resp, err := client.GetImageAliases()
	if err != nil {
		return err
	}

	// Delete existing aliases that match provided ones
	for _, alias := range GetExistingAliases(names, resp) {
		err := client.DeleteImageAlias(alias.Name)
		if err != nil {
			fmt.Println(fmt.Sprintf(i18n.G("Failed to remove alias %s"), alias.Name))
		}
	}
	// Create new aliases
	for _, alias := range aliases {
		aliasPost := api.ImageAliasesPost{}
		aliasPost.Name = alias.Name
		aliasPost.Target = fingerprint
		err := client.CreateImageAlias(aliasPost)
		if err != nil {
			fmt.Println(fmt.Sprintf(i18n.G("Failed to create alias %s"), alias.Name))
		}
	}
	return nil
}

// GetExistingAliases returns the intersection between a list of aliases and all the existing ones.
func GetExistingAliases(aliases []string, allAliases []api.ImageAliasesEntry) []api.ImageAliasesEntry {
	existing := []api.ImageAliasesEntry{}
	for _, alias := range allAliases {
		name := alias.Name
		pos := sort.SearchStrings(aliases, name)
		if pos < len(aliases) && aliases[pos] == name {
			existing = append(existing, alias)
		}
	}
	return existing
}

func getConfig(args ...string) (map[string]string, error) {
	if len(args) == 2 && !strings.Contains(args[0], "=") {
		if args[1] == "-" && !termios.IsTerminal(getStdinFd()) {
			buf, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				return nil, errors.Wrap(err, i18n.G("Can't read from stdin: %s"))
			}

			args[1] = string(buf[:])
		}

		return map[string]string{args[0]: args[1]}, nil
	}

	values := map[string]string{}

	for _, arg := range args {
		fields := strings.SplitN(arg, "=", 2)
		if len(fields) != 2 {
			return nil, fmt.Errorf("Invalid key=value configuration: %s", arg)
		}

		if fields[1] == "-" && !termios.IsTerminal(getStdinFd()) {
			buf, err := ioutil.ReadAll(os.Stdin)
			if err != nil {
				return nil, fmt.Errorf(i18n.G("Can't read from stdin: %s"), err)
			}

			fields[1] = string(buf[:])
		}

		values[fields[0]] = fields[1]
	}

	return values, nil
}
<|endoftext|>


<commit_before>// Package ebnf contains the AST and parser for parsing the form of EBNF produced by Participle.
//
// The self-referential EBNF is:
//
//      EBNF = Production* .
//      Production = <ident> "=" Expression "." .
//      Expression = Sequence ("|" Sequence)* .
//      SubExpression = "(" ("?!" | "?=")? Expression ")" .
//      Sequence = Term+ .
//      Term = "!"? (<ident> | <string> | ("<" <ident> ">") | SubExpression) ("*" | "+" | "?" | "!")? .
package ebnf

import (
	"fmt"
	"io"

	"github.com/alecthomas/participle/v2"
)

var parser = participle.MustBuild(&EBNF{})

// Term in the EBNF grammar.
type Term struct {
	Negation bool `@("~")?`

	Name    string         `(   @Ident`
	Literal string         `  | @String`
	Token   string         `  | "<" @Ident ">"`
	Group   *SubExpression `  | @@ )`

	Repetition string `@("*" | "+" | "?" | "!")?`
}

func (t *Term) String() string {
	switch {
	case t.Name != "":
		return t.Name + t.Repetition
	case t.Literal != "":
		return t.Literal + t.Repetition
	case t.Token != "":
		return "<" + t.Token + ">" + t.Repetition
	case t.Group != nil:
		return t.Group.String() + t.Repetition
	default:
		panic("??")
	}
}

// LookaheadAssertion enum.
type LookaheadAssertion rune

func (l *LookaheadAssertion) Capture(tokens []string) error { // nolint
	rn := tokens[0][0]
	switch rn {
	case '!', '=':
		*l = LookaheadAssertion(rn)

	default:
		panic(rn)
	}
	return nil
}

// Lookahead assertion enums.
const (
	LookaheadAssertionNone     LookaheadAssertion = 0
	LookaheadAssertionNegative LookaheadAssertion = '!'
	LookaheadAssertionPositive LookaheadAssertion = '='
)

// SubExpression is an expression inside parentheses ( ... )
type SubExpression struct {
	Lookahead LookaheadAssertion `"(" ("?" @("!" | "="))?`
	Expr      *Expression        `@@ ")"`
}

func (s *SubExpression) String() string {
	out := "("
	if s.Lookahead != LookaheadAssertionNone {
		out += "?" + string(s.Lookahead)
	}
	out += s.Expr.String() + ")"
	return out
}

// A Sequence of terms.
type Sequence struct {
	Terms []*Term `@@+`
}

func (s *Sequence) String() (out string) {
	for i, term := range s.Terms {
		if i > 0 {
			out += " "
		}
		out += term.String()
	}
	return
}

// Expression is a set of alternatives separated by "|" in the EBNF.
type Expression struct {
	Alternatives []*Sequence `@@ ( "|" @@ )*`
}

func (e *Expression) String() (out string) {
	for i, seq := range e.Alternatives {
		if i > 0 {
			out += " | "
		}
		out += seq.String()
	}
	return
}

// Production of the grammar.
type Production struct {
	Production string      `@Ident "="`
	Expression *Expression `@@ "."`
}

// EBNF itself.
type EBNF struct {
	Productions []*Production `@@*`
}

func (e *EBNF) String() (out string) {
	for i, production := range e.Productions {
		out += fmt.Sprintf("%s = %s .", production.Production, production.Expression)
		if i < len(e.Productions)-1 {
			out += "\n"
		}
	}
	return
}

// ParseString string into EBNF.
func ParseString(ebnf string) (*EBNF, error) {
	out := &EBNF{}
	return out, parser.ParseString("", ebnf, out)
}

// Parse io.Reader into EBNF.
func Parse(r io.Reader) (*EBNF, error) {
	out := &EBNF{}
	return out, parser.Parse("", r, out)
}
<commit_msg>Fix comment for new negation ("~")<commit_after>// Package ebnf contains the AST and parser for parsing the form of EBNF produced by Participle.
//
// The self-referential EBNF is:
//
//      EBNF = Production* .
//      Production = <ident> "=" Expression "." .
//      Expression = Sequence ("|" Sequence)* .
//      SubExpression = "(" ("?!" | "?=")? Expression ")" .
//      Sequence = Term+ .
//      Term = "~"? (<ident> | <string> | ("<" <ident> ">") | SubExpression) ("*" | "+" | "?" | "!")? .
package ebnf

import (
	"fmt"
	"io"

	"github.com/alecthomas/participle/v2"
)

var parser = participle.MustBuild(&EBNF{})

// Term in the EBNF grammar.
type Term struct {
	Negation bool `@("~")?`

	Name    string         `(   @Ident`
	Literal string         `  | @String`
	Token   string         `  | "<" @Ident ">"`
	Group   *SubExpression `  | @@ )`

	Repetition string `@("*" | "+" | "?" | "!")?`
}

func (t *Term) String() string {
	switch {
	case t.Name != "":
		return t.Name + t.Repetition
	case t.Literal != "":
		return t.Literal + t.Repetition
	case t.Token != "":
		return "<" + t.Token + ">" + t.Repetition
	case t.Group != nil:
		return t.Group.String() + t.Repetition
	default:
		panic("??")
	}
}

// LookaheadAssertion enum.
type LookaheadAssertion rune

func (l *LookaheadAssertion) Capture(tokens []string) error { // nolint
	rn := tokens[0][0]
	switch rn {
	case '!', '=':
		*l = LookaheadAssertion(rn)

	default:
		panic(rn)
	}
	return nil
}

// Lookahead assertion enums.
const (
	LookaheadAssertionNone     LookaheadAssertion = 0
	LookaheadAssertionNegative LookaheadAssertion = '!'
	LookaheadAssertionPositive LookaheadAssertion = '='
)

// SubExpression is an expression inside parentheses ( ... )
type SubExpression struct {
	Lookahead LookaheadAssertion `"(" ("?" @("!" | "="))?`
	Expr      *Expression        `@@ ")"`
}

func (s *SubExpression) String() string {
	out := "("
	if s.Lookahead != LookaheadAssertionNone {
		out += "?" + string(s.Lookahead)
	}
	out += s.Expr.String() + ")"
	return out
}

// A Sequence of terms.
type Sequence struct {
	Terms []*Term `@@+`
}

func (s *Sequence) String() (out string) {
	for i, term := range s.Terms {
		if i > 0 {
			out += " "
		}
		out += term.String()
	}
	return
}

// Expression is a set of alternatives separated by "|" in the EBNF.
type Expression struct {
	Alternatives []*Sequence `@@ ( "|" @@ )*`
}

func (e *Expression) String() (out string) {
	for i, seq := range e.Alternatives {
		if i > 0 {
			out += " | "
		}
		out += seq.String()
	}
	return
}

// Production of the grammar.
type Production struct {
	Production string      `@Ident "="`
	Expression *Expression `@@ "."`
}

// EBNF itself.
type EBNF struct {
	Productions []*Production `@@*`
}

func (e *EBNF) String() (out string) {
	for i, production := range e.Productions {
		out += fmt.Sprintf("%s = %s .", production.Production, production.Expression)
		if i < len(e.Productions)-1 {
			out += "\n"
		}
	}
	return
}

// ParseString string into EBNF.
func ParseString(ebnf string) (*EBNF, error) {
	out := &EBNF{}
	return out, parser.ParseString("", ebnf, out)
}

// Parse io.Reader into EBNF.
func Parse(r io.Reader) (*EBNF, error) {
	out := &EBNF{}
	return out, parser.Parse("", r, out)
}
<|endoftext|>


<commit_before>package email

import (
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"net/smtp"
	"time"

	"github.com/dockercn/docker-bucket/models"
)

//默认5分钟发一次
func MailService() {
	models.InitDB4Email()
	go func() {
		for {
			//加载模板列表去到prefix的集合，再去prefix对应的message
			tmpl := new(models.TemplateHtml)
			tmpls := tmpl.Query()
			for i, _ := range tmpls {
				msg := new(models.Message)
				msgs := msg.Query(tmpls[i].Prefix)
				for j, _ := range msgs {
					fmt.Printf("%#v\n", msgs[j])
					mailServer := new(models.MailServer)
					server := mailServer.Query(msgs[j].Host)
					isSend, _ := Send(server[0], msgs[j])
					if isSend {
						msgs[j].Update()
					}
				}
			}
			time.Sleep(5 * time.Minute)
		}
	}()
}

//调用发送邮件服务 返回值bool表示是否发送  error表示如果发送是成功还是失败
func Send(mailServer *models.MailServer, msg *models.Message) (bool, error) {
	//判断邮件状态  I待发送 A 已经发送 X 发送失败    发送失败超过10次，停止发送
	if msg.Status == "A" {
		return false, nil
	} else if msg.Status == "X" && msg.Count > 10 {
		return false, nil
	}
	header := make(map[string]string)
	header["From"] = msg.From
	header["To"] = msg.To
	header["Subject"] = msg.Subject
	header["Content-Type"] = msg.ContentType
	content := ""
	for k, v := range header {
		content += fmt.Sprintf("%s: %s\r\n", k, v)
	}
	content += "\r\n" + msg.Body
	auth := smtp.PlainAuth("", mailServer.User, mailServer.Password, mailServer.Host)
	err := sendMailUsingTLS(fmt.Sprintf("%s:%d", mailServer.Host, mailServer.Port), auth, msg.From, []string{msg.To}, []byte(content))
	//判断发送是否成功
	msg.Count = msg.Count + 1
	if err != nil {
		msg.Status = "X"
		return true, err
	}
	msg.Status = "A"
	return true, nil
}

func sendMailUsingTLS(addr string, auth smtp.Auth, from string, to []string, msg []byte) (err error) {
	//create smtp client
	c, err := dial(addr)
	if err != nil {
		log.Println("Create smpt client error:", err)
		return err
	}
	defer c.Close()
	if auth != nil {
		if ok, _ := c.Extension("AUTH"); ok {
			if err = c.Auth(auth); err != nil {
				log.Println("Error during AUTH", err)
				return err
			}
		}
	}
	if err = c.Mail(from); err != nil {
		return err
	}
	for _, addr := range to {
		if err = c.Rcpt(addr); err != nil {
			return err
		}
	}
	w, err := c.Data()
	if err != nil {
		return err
	}
	_, err = w.Write(msg)
	if err != nil {
		return err
	}
	err = w.Close()
	if err != nil {
		return err
	}
	return c.Quit()
}

//return a smtp client
func dial(addr string) (*smtp.Client, error) {
	conn, err := tls.Dial("tcp", addr, nil)
	if err != nil {
		log.Println("Dialing Error:", err)
		return nil, err
	}
	//分解主机端口字符串
	host, _, _ := net.SplitHostPort(addr)
	return smtp.NewClient(conn, host)
}
<commit_msg>review email mouduls<commit_after>package email

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"log"
	"mime/multipart"
	"net"
	"net/mail"
	"net/smtp"
	"net/textproto"
	"strings"
	"time"

	"github.com/dockercn/docker-bucket/models"
)

const (
	maxLineLength = 76
)

//默认5分钟发一次
func MailService() {
	models.InitDb()
	go func() {
		for {
			//加载模板列表去到prefix的集合，再去prefix对应的message
			tmpl := new(models.TemplateHtml)
			tmpls := tmpl.Query()
			for i, _ := range tmpls {
				msg := new(models.Message)
				msgs := msg.Query(tmpls[i].Prefix)
				for j, _ := range msgs {
					fmt.Printf("%#v\n", msgs[j])
					mailServer := new(models.MailServer)
					server := mailServer.Query(msgs[j].Host)
					isSend, err := Send(server[0], msgs[j])
					if isSend {
						msgs[j].Update()
					}
				}
			}
			time.Sleep(5 * time.Minute)
		}
	}()
}

//调用发送邮件服务 返回值bool表示是否发送  error表示如果发送是成功还是失败
func Send(mailServer *models.MailServer, msg *models.Message) (bool, error) {
	//判断邮件状态  I待发送 A 已经发送 X 发送失败    发送失败超过10次，停止发送
	if msg.Status == "A" {
		return false, nil
	} else if msg.Status == "X" && msg.Count > 10 {
		return false, nil
	}
	auth := smtp.PlainAuth("", mailServer.User, mailServer.Password, mailServer.Host)
	to := make([]string, 0, len(msg.Cc)+len(msg.Bcc)+1)
	to = append(append(append(to, msg.To), msg.Cc...), msg.Bcc...)
	// Check to make sure there is at least one recipient and one "From" address
	if msg.From == "" || len(to) == 0 {
		return false, errors.New("Must specify at least one From address and one To address")
	}
	from, err := mail.ParseAddress(msg.From)
	if err != nil {
		return false, err
	}
	raw, err := msg2bytes(msg)
	fmt.Println(string(raw))
	if err != nil {
		return false, err
	}
	//err = SendMail(mailServer.Host+":"+strconv.Itoa(mailServer.Port), auth, from.Address, to, raw)
	address := fmt.Sprintf("%s:%d", mailServer.Host, 465)
	err = sendMailUsingTLS(address, auth, from.Address, to, raw)
	//判断发送是否成功
	msg.Count = msg.Count + 1
	if err != nil {
		msg.Status = "X"
		return true, err
	}
	msg.Status = "A"
	return true, nil
}

func msg2bytes(e *models.Message) ([]byte, error) {
	e.Headers = textproto.MIMEHeader{}
	buff := &bytes.Buffer{}
	w := multipart.NewWriter(buff)
	// Set the appropriate headers (overwriting any conflicts)
	// Leave out Bcc (only included in envelope headers)
	e.Headers.Set("To", e.To)
	if e.Cc != nil {
		e.Headers.Set("Cc", strings.Join(e.Cc, ","))
	}
	e.Headers.Set("From", e.From)
	e.Headers.Set("Subject", e.Subject)
	e.Headers.Set("MIME-Version", "1.0")
	e.Headers.Set("Content-Type", fmt.Sprintf("multipart/mixed;\r\n boundary=%s\r\n", w.Boundary()))
	// Write the envelope headers (including any custom headers)
	if err := headerToBytes(buff, e.Headers); err != nil {
		return nil, fmt.Errorf("Failed to render message headers: %s", err)
	}
	// Start the multipart/mixed part
	fmt.Fprintf(buff, "--%s\r\n", w.Boundary())
	header := textproto.MIMEHeader{}
	// Check to see if there is a Text or HTML field
	if e.Type != "" {
		subWriter := multipart.NewWriter(buff)
		// Create the multipart alternative part
		header.Set("Content-Type", fmt.Sprintf("multipart/alternative;\r\n boundary=%s\r\n", subWriter.Boundary()))
		// Write the header
		if err := headerToBytes(buff, header); err != nil {
			return nil, fmt.Errorf("Failed to render multipart message headers: %s", err)
		}
		// Create the body sections
		if e.Type == "text" {
			header.Set("Content-Type", fmt.Sprintf("text/plain; charset=UTF-8"))
			header.Set("Content-Transfer-Encoding", "quoted-printable")
			if _, err := subWriter.CreatePart(header); err != nil {
				return nil, err
			}
			// Write the text
			if err := quotePrintEncode(buff, e.Body); err != nil {
				return nil, err
			}
		}
		if e.Type == "html" {
			header.Set("Content-Type", fmt.Sprintf("text/html; charset=UTF-8"))
			header.Set("Content-Transfer-Encoding", "quoted-printable")
			if _, err := subWriter.CreatePart(header); err != nil {
				return nil, err
			}
			// Write the text
			if err := quotePrintEncode(buff, e.Body); err != nil {
				return nil, err
			}
		}
		if err := subWriter.Close(); err != nil {
			return nil, err
		}
	}
	// Create attachment part, if necessary
	for _, a := range e.Attachments {
		ap, err := w.CreatePart(a.Header)
		if err != nil {
			return nil, err
		}
		// Write the base64Wrapped content to the part
		base64Wrap(ap, a.Content)
	}
	if err := w.Close(); err != nil {
		return nil, err
	}
	return buff.Bytes(), nil
}

// headerToBytes enumerates the key and values in the header, and writes the results to the IO Writer
func headerToBytes(w io.Writer, t textproto.MIMEHeader) error {
	for k, v := range t {
		// Write the header key
		_, err := fmt.Fprintf(w, "%s:", k)
		if err != nil {
			return err
		}
		// Write each value in the header
		for _, c := range v {
			_, err := fmt.Fprintf(w, " %s\r\n", c)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func quotePrintEncode(w io.Writer, s string) error {
	var buf [3]byte
	mc := 0
	for i := 0; i < len(s); i++ {
		c := s[i]
		// We're assuming Unix style text formats as input (LF line break), and
		// quoted-printble uses CRLF line breaks. (Literal CRs will become
		// "=0D", but probably shouldn't be there to begin with!)
		if c == '\n' {
			io.WriteString(w, "\r\n")
			mc = 0
			continue
		}
		var nextOut []byte
		if isPrintable(c) {
			nextOut = append(buf[:0], c)
		} else {
			nextOut = buf[:]
			qpEscape(nextOut, c)
		}
		// Add a soft line break if the next (encoded) byte would push this line
		// to or past the limit.
		if mc+len(nextOut) >= maxLineLength {
			if _, err := io.WriteString(w, "=\r\n"); err != nil {
				return err
			}
			mc = 0
		}
		if _, err := w.Write(nextOut); err != nil {
			return err
		}
		mc += len(nextOut)
	}
	// No trailing end-of-line?? Soft line break, then. TODO: is this sane?
	if mc > 0 {
		io.WriteString(w, "=\r\n")
	}
	return nil
}

// base64Wrap encodes the attachment content, and wraps it according to RFC 2045 standards (every 76 chars)
// The output is then written to the specified io.Writer
func base64Wrap(w io.Writer, b []byte) {
	// 57 raw bytes per 76-byte base64 line.
	const maxRaw = 57
	// Buffer for each line, including trailing CRLF.
	var buffer [maxLineLength + len("\r\n")]byte
	copy(buffer[maxLineLength:], "\r\n")
	// Process raw chunks until there's no longer enough to fill a line.
	for len(b) >= maxRaw {
		base64.StdEncoding.Encode(buffer[:], b[:maxRaw])
		w.Write(buffer[:])
		b = b[maxRaw:]
	}
	// Handle the last chunk of bytes.
	if len(b) > 0 {
		out := buffer[:base64.StdEncoding.EncodedLen(len(b))]
		base64.StdEncoding.Encode(out, b)
		out = append(out, "\r\n"...)
		w.Write(out)
	}
}

// qpEscape is a helper function for quotePrintEncode which escapes a
// non-printable byte. Expects len(dest) == 3.
func qpEscape(dest []byte, c byte) {
	const nums = "0123456789ABCDEF"
	dest[0] = '='
	dest[1] = nums[(c&0xf0)>>4]
	dest[2] = nums[(c & 0xf)]
}

// isPrintable returns true if the rune given is "printable" according to RFC 2045, false otherwise
func isPrintable(c byte) bool {
	return (c >= '!' && c <= '<') || (c >= '>' && c <= '~') || (c == ' ' || c == '\n' || c == '\t')
}

func sendMailUsingTLS(addr string, auth smtp.Auth, from string, to []string, msg []byte) (err error) {
	//create smtp client
	c, err := dial(addr)
	if err != nil {
		log.Println("Create smpt client error:", err)
		return err
	}
	defer c.Close()
	if auth != nil {
		if ok, _ := c.Extension("AUTH"); ok {
			if err = c.Auth(auth); err != nil {
				log.Println("Error during AUTH", err)
				return err
			}
		}
	}
	if err = c.Mail(from); err != nil {
		return err
	}
	for _, addr := range to {
		if err = c.Rcpt(addr); err != nil {
			return err
		}
	}
	w, err := c.Data()
	if err != nil {
		return err
	}
	_, err = w.Write(msg)
	if err != nil {
		return err
	}
	err = w.Close()
	if err != nil {
		return err
	}
	return c.Quit()
}

func dial(addr string) (*smtp.Client, error) {
	conn, err := tls.Dial("tcp", addr, nil)
	if err != nil {
		log.Println("Dialing Error:", err)
		return nil, err
	}
	//分解主机端口字符串
	host, _, _ := net.SplitHostPort(addr)
	return smtp.NewClient(conn, host)
}
<|endoftext|>


<commit_before>// Package edit provides sam-style editing of rune buffers.
// See sam(1) for an overview: http://swtch.com/plan9port/man/man1/sam.html.
package edit

import (
	"errors"
	"sync"
	"unicode"

	"github.com/eaburns/T/re1"
	"github.com/eaburns/T/runes"
)

// TODO(eaburns): Find a good size.
const blockSize = 1 << 20

// A Buffer is an editable rune buffer.
type Buffer struct {
	runes *runes.Buffer
	lock  sync.Mutex
	eds   []*Editor
}

// NewBuffer returns a new, empty buffer.
func NewBuffer() *Buffer {
	return newBufferRunes(runes.NewBuffer(blockSize))
}

// NewBufferRunes is like NewBuffer, but the buffer uses the given runes.
func newBufferRunes(r *runes.Buffer) *Buffer {
	return &Buffer{runes: r}
}

// Close closes the buffer and all of its editors.
// After Close is called, the buffer is no longer editable.
func (b *Buffer) Close() error {
	b.lock.Lock()
	defer b.lock.Unlock()
	return b.runes.Close()
}

// Size returns the number of runes in the buffer.
// If the rune is out of range it panics.
// If there is an error reading, it panics a RuneReadError containing the error.
//
// The caller must hold b.lock.
func (b *Buffer) size() int64 { return b.runes.Size() }

// Returns the ith rune in the buffer.
//
// The caller must hold b.lock.
func (b *Buffer) rune(i int64) (rune, error) { return b.runes.Rune(i) }

// Change changes the runes in the range.
//
// The caller must hold b.lock.
func (b *Buffer) change(r addr, rs []rune) error {
	if _, err := b.runes.Delete(r.size(), r.from); err != nil {
		return err
	}
	if _, err := b.runes.Insert(rs, r.from); err != nil {
		return err
	}
	for _, e := range b.eds {
		e.update(r, int64(len(rs)))
	}
	return nil
}

// An Editor provides sam-like editing functionality on a buffer of runes.
type Editor struct {
	buf   *Buffer
	marks map[rune]addr
}

// NewEditor returns a new editor that edits the buffer.
func (b *Buffer) NewEditor() *Editor {
	b.lock.Lock()
	defer b.lock.Unlock()

	ed := &Editor{buf: b, marks: make(map[rune]addr, 2)}
	b.eds = append(b.eds, ed)
	return ed
}

// Close closes the editor.
func (ed *Editor) Close() error {
	ed.buf.lock.Lock()
	defer ed.buf.lock.Unlock()

	eds := ed.buf.eds
	for i := range eds {
		if eds[i] == ed {
			ed.buf.eds = append(eds[:i], eds[:i+1]...)
			return nil
		}
	}
	return errors.New("already closed")
}

// Read returns the runes at an address in the buffer
// and sets dot to the address.
func (ed *Editor) Read(a Address) ([]rune, error) {
	ed.buf.lock.Lock()
	defer ed.buf.lock.Unlock()

	r, err := a.addr(ed)
	if err != nil {
		return nil, err
	}
	ed.marks['.'] = r
	rs := make([]rune, r.size())
	if _, err := ed.buf.runes.Read(rs, r.from); err != nil {
		return nil, err
	}
	return rs, nil
}

// Change changes the range to the given runes
// and sets dot to the address of the changed runes.
func (ed *Editor) Change(a Address, rs []rune) error {
	ed.buf.lock.Lock()
	defer ed.buf.lock.Unlock()

	r, err := a.addr(ed)
	if err != nil {
		return err
	}
	if err := ed.buf.change(r, rs); err != nil {
		return err
	}
	ed.marks['.'] = addr{from: r.from, to: r.from + int64(len(rs))}
	return nil
}

// Append inserts the runes after the address
// and sets dot to the address of the appended runes.
func (ed *Editor) Append(ad Address, rs []rune) error {
	return ed.Change(ad.Plus(Rune(0)), rs)
}

// Delete deletes the runes at the address
// and sets dot to the address of the empty string
// where the runes were deleted.
func (ed *Editor) Delete(a Address) error {
	return ed.Change(a, []rune{})
}

// Insert inserts the runes before the address
// and sets dot to the address of the inserted runes.
func (ed *Editor) Insert(ad Address, rs []rune) error {
	return ed.Change(ad.Minus(Rune(0)), rs)
}

// Mark sets a mark to an address.
// The mark must be either a lower-case or upper-case letter or dot: [a-zA-Z.].
// Any other mark is an error.
// If the mark is . then dot is set to the address.
// Otherwise the named mark is set to the address.
func (ed *Editor) Mark(a Address, m rune) error {
	if !isMarkRune(m) && m != '.' {
		return errors.New("bad mark: " + string(m))
	}
	r, err := a.addr(ed)
	if err != nil {
		return err
	}
	ed.marks[m] = r
	return nil
}

// Substitute substitutes text for the first match
// of the regular expression in the addressed range.
// When substituting, a backslash followed by a digit d
// stands for the string that matched the d-th subexpression.
// \n is a literal newline.
// If g is true then all matches in the address range are substituted.
// Dot is set to the modified address.
func (ed *Editor) Substitute(a Address, re *re1.Regexp, sub []rune, g bool) error {
	ed.buf.lock.Lock()
	defer ed.buf.lock.Unlock()

	r, err := a.addr(ed)
	if err != nil {
		return err
	}
	r0 := r

	for {
		d, m, err := ed.sub1(r, re, sub)
		if err != nil {
			return err
		}
		if m == nil {
			break
		}
		r0.to += d
		r.to += d
		r.from = m[0][1] + d
		if !g {
			break
		}
	}
	ed.marks['.'] = r0
	return nil
}

func (ed *Editor) sub1(r addr, re *re1.Regexp, sub []rune) (int64, [][2]int64, error) {
	m, err := ed.subMatch(r, re)
	if err != nil || m == nil {
		return 0, m, err
	}
	repl, err := ed.subText(m, sub)
	if err != nil {
		return 0, nil, err
	}
	if err := ed.buf.change(addr{m[0][0], m[0][1]}, repl); err != nil {
		return 0, nil, err
	}
	return int64(len(repl)) - (m[0][1] - m[0][0]), m, err
}

func (ed *Editor) subText(m [][2]int64, sub []rune) ([]rune, error) {
	var rs []rune
	for i := 0; i < len(sub); i++ {
		d := escDigit(sub[i:])
		if d < 0 {
			rs = append(rs, sub[i])
			continue
		}
		sub, err := ed.subExpr(m, d)
		if err != nil {
			return nil, err
		}
		rs = append(rs, sub...)
		i++
	}
	return rs, nil
}

// EscDigit returns the digit from \[0-9]
// or -1 if the text does not represent an escaped digit.
func escDigit(sub []rune) int {
	if len(sub) >= 2 && sub[0] == '\\' && unicode.IsDigit(sub[1]) {
		return int(sub[1] - '0')
	}
	return -1
}

func (ed *Editor) subExpr(m [][2]int64, n int) ([]rune, error) {
	if n >= len(m) {
		return nil, nil
	}
	rs := make([]rune, m[n][1]-m[n][0])
	if _, err := ed.buf.runes.Read(rs, m[n][0]); err != nil {
		return nil, err
	}
	return rs, nil
}

type runeSlice struct {
	buf *runes.Buffer
	addr
	err error
}

func (rs *runeSlice) Size() int64 { return rs.size() }

func (rs *runeSlice) Rune(i int64) rune {
	switch {
	case i < 0 || i >= rs.size():
		panic("index out of bounds")
	case rs.err != nil:
		return -1
	}
	r, err := rs.buf.Rune(rs.from + i)
	if err != nil {
		rs.err = err
		return -1
	}
	return r
}

func (ed *Editor) subMatch(r addr, re *re1.Regexp) ([][2]int64, error) {
	rs := &runeSlice{buf: ed.buf.runes, addr: r}
	m := re.Match(rs, 0)
	for i := range m {
		m[i][0] += r.from
		m[i][1] += r.from
	}
	return m, rs.err
}

// Edit parses a command and performs its edit on the buffer.
//
// In the following, text surrounded by / represents delimited text.
// The delimiter can be any character, it need not be /.
// Trailing delimiters may be elided, but the opening delimiter must be present.
// In delimited text, \ is an escape; the following character is interpreted literally,
// except \n which represents a literal newline.
// Items in {} are optional.
//
// Commands are:
// 	{addr} a/text/
//	or
//	{addr} a
//	lines of text
//	.	Appends after the addressed text.
//		If an address is not supplied, dot is used.
//	c
//	i	Just like a, but c changes the addressed text
//		and i inserts before the addressed text.
//	{addr} d
//		Deletes the addressed text.
//		If an address is not supplied, dot is used.
//	{addr} m {[a-zA-Z]}
//		Sets the named mark to the address.
//		If an address is not supplied, dot is used.
//		If a mark name is not given, dot is set.
//	{addr} s/regexp/text/
//		Substitute substitutes text for the first match
// 		of the regular expression in the addressed range.
// 		When substituting, a backslash followed by a digit d
// 		stands for the string that matched the d-th subexpression.
//		\n is a literal newline.
// 		If the delimiter after the text is followed by the letter g
//		then all matches in the address range are substituted.
//		If an address is not supplied, dot is used.
func (ed *Editor) Edit(cmd []rune) error {
	addr, n, err := Addr(cmd)
	switch {
	case err != nil:
		return err
	case addr == nil:
		addr = Dot
	case len(cmd) == n:
		return errors.New("missing command")
	default:
		cmd = cmd[n:]
	}
	switch c := cmd[0]; c {
	case 'a':
		return ed.Append(addr, parseText(cmd[1:]))
	case 'c':
		return ed.Change(addr, parseText(cmd[1:]))
	case 'i':
		return ed.Insert(addr, parseText(cmd[1:]))
	case 'd':
		return ed.Delete(addr)
	case 'm':
		return ed.Mark(addr, parseMarkRune(cmd[1:]))
	case 's':
		re, err := re1.Compile(cmd[1:], re1.Options{Delimited: true})
		if err != nil {
			return err
		}
		exp := re.Expression()
		cmd = cmd[1+len(exp):]
		sub := parseDelimited(exp[0], true, cmd)
		g := len(sub) < len(cmd)-1 && cmd[len(sub)+1] == 'g'
		return ed.Substitute(addr, re, sub, g)
	default:
		return errors.New("unknown command: " + string(c))
	}
}

func parseText(cmd []rune) []rune {
	switch {
	case len(cmd) > 0 && cmd[0] == '\n':
		return parseLines(cmd)
	case len(cmd) > 0:
		return parseDelimited(cmd[0], false, cmd[1:])
	default:
		return nil
	}
}

func parseLines(cmd []rune) []rune {
	var rs []rune
	for i := 1; i < len(cmd); i++ {
		rs = append(rs, cmd[i])
		if i < len(cmd)-1 && cmd[i] == '\n' && cmd[i+1] == '.' {
			break
		}
	}
	return rs
}

func parseDelimited(d rune, digits bool, cmd []rune) []rune {
	var rs []rune
	for i := 0; i < len(cmd) && cmd[i] != d; i++ {
		if cmd[i] == '\\' && i < len(cmd)-1 {
			if digits && unicode.IsDigit(cmd[i+1]) {
				rs = append(rs, '\\')
			}
			i++
			if cmd[i] == 'n' {
				cmd[i] = '\n'
			}
		}
		rs = append(rs, cmd[i])
	}
	return rs
}

func parseMarkRune(cmd []rune) rune {
	var i int
	for ; i < len(cmd) && unicode.IsSpace(cmd[i]); i++ {
	}
	if i < len(cmd) && isMarkRune(cmd[i]) {
		return cmd[i]
	}
	return '.'
}

// Update updates the Editor's addresses
// given an addr that changed and its new size.
func (ed *Editor) update(r addr, n int64) {
	for m := range ed.marks {
		ed.marks[m] = ed.marks[m].update(r, n)
	}
}
<commit_msg>Document that dot is set by Edit commands.<commit_after>// Package edit provides sam-style editing of rune buffers.
// See sam(1) for an overview: http://swtch.com/plan9port/man/man1/sam.html.
package edit

import (
	"errors"
	"sync"
	"unicode"

	"github.com/eaburns/T/re1"
	"github.com/eaburns/T/runes"
)

// TODO(eaburns): Find a good size.
const blockSize = 1 << 20

// A Buffer is an editable rune buffer.
type Buffer struct {
	runes *runes.Buffer
	lock  sync.Mutex
	eds   []*Editor
}

// NewBuffer returns a new, empty buffer.
func NewBuffer() *Buffer {
	return newBufferRunes(runes.NewBuffer(blockSize))
}

// NewBufferRunes is like NewBuffer, but the buffer uses the given runes.
func newBufferRunes(r *runes.Buffer) *Buffer {
	return &Buffer{runes: r}
}

// Close closes the buffer and all of its editors.
// After Close is called, the buffer is no longer editable.
func (b *Buffer) Close() error {
	b.lock.Lock()
	defer b.lock.Unlock()
	return b.runes.Close()
}

// Size returns the number of runes in the buffer.
// If the rune is out of range it panics.
// If there is an error reading, it panics a RuneReadError containing the error.
//
// The caller must hold b.lock.
func (b *Buffer) size() int64 { return b.runes.Size() }

// Returns the ith rune in the buffer.
//
// The caller must hold b.lock.
func (b *Buffer) rune(i int64) (rune, error) { return b.runes.Rune(i) }

// Change changes the runes in the range.
//
// The caller must hold b.lock.
func (b *Buffer) change(r addr, rs []rune) error {
	if _, err := b.runes.Delete(r.size(), r.from); err != nil {
		return err
	}
	if _, err := b.runes.Insert(rs, r.from); err != nil {
		return err
	}
	for _, e := range b.eds {
		e.update(r, int64(len(rs)))
	}
	return nil
}

// An Editor provides sam-like editing functionality on a buffer of runes.
type Editor struct {
	buf   *Buffer
	marks map[rune]addr
}

// NewEditor returns a new editor that edits the buffer.
func (b *Buffer) NewEditor() *Editor {
	b.lock.Lock()
	defer b.lock.Unlock()

	ed := &Editor{buf: b, marks: make(map[rune]addr, 2)}
	b.eds = append(b.eds, ed)
	return ed
}

// Close closes the editor.
func (ed *Editor) Close() error {
	ed.buf.lock.Lock()
	defer ed.buf.lock.Unlock()

	eds := ed.buf.eds
	for i := range eds {
		if eds[i] == ed {
			ed.buf.eds = append(eds[:i], eds[:i+1]...)
			return nil
		}
	}
	return errors.New("already closed")
}

// Read returns the runes at an address in the buffer
// and sets dot to the address.
func (ed *Editor) Read(a Address) ([]rune, error) {
	ed.buf.lock.Lock()
	defer ed.buf.lock.Unlock()

	r, err := a.addr(ed)
	if err != nil {
		return nil, err
	}
	ed.marks['.'] = r
	rs := make([]rune, r.size())
	if _, err := ed.buf.runes.Read(rs, r.from); err != nil {
		return nil, err
	}
	return rs, nil
}

// Change changes the range to the given runes
// and sets dot to the address of the changed runes.
func (ed *Editor) Change(a Address, rs []rune) error {
	ed.buf.lock.Lock()
	defer ed.buf.lock.Unlock()

	r, err := a.addr(ed)
	if err != nil {
		return err
	}
	if err := ed.buf.change(r, rs); err != nil {
		return err
	}
	ed.marks['.'] = addr{from: r.from, to: r.from + int64(len(rs))}
	return nil
}

// Append inserts the runes after the address
// and sets dot to the address of the appended runes.
func (ed *Editor) Append(ad Address, rs []rune) error {
	return ed.Change(ad.Plus(Rune(0)), rs)
}

// Delete deletes the runes at the address
// and sets dot to the address of the empty string
// where the runes were deleted.
func (ed *Editor) Delete(a Address) error {
	return ed.Change(a, []rune{})
}

// Insert inserts the runes before the address
// and sets dot to the address of the inserted runes.
func (ed *Editor) Insert(ad Address, rs []rune) error {
	return ed.Change(ad.Minus(Rune(0)), rs)
}

// Mark sets a mark to an address.
// The mark must be either a lower-case or upper-case letter or dot: [a-zA-Z.].
// Any other mark is an error.
// If the mark is . then dot is set to the address.
// Otherwise the named mark is set to the address.
func (ed *Editor) Mark(a Address, m rune) error {
	if !isMarkRune(m) && m != '.' {
		return errors.New("bad mark: " + string(m))
	}
	r, err := a.addr(ed)
	if err != nil {
		return err
	}
	ed.marks[m] = r
	return nil
}

// Substitute substitutes text for the first match
// of the regular expression in the addressed range.
// When substituting, a backslash followed by a digit d
// stands for the string that matched the d-th subexpression.
// \n is a literal newline.
// If g is true then all matches in the address range are substituted.
// Dot is set to the modified address.
func (ed *Editor) Substitute(a Address, re *re1.Regexp, sub []rune, g bool) error {
	ed.buf.lock.Lock()
	defer ed.buf.lock.Unlock()

	r, err := a.addr(ed)
	if err != nil {
		return err
	}
	r0 := r

	for {
		d, m, err := ed.sub1(r, re, sub)
		if err != nil {
			return err
		}
		if m == nil {
			break
		}
		r0.to += d
		r.to += d
		r.from = m[0][1] + d
		if !g {
			break
		}
	}
	ed.marks['.'] = r0
	return nil
}

func (ed *Editor) sub1(r addr, re *re1.Regexp, sub []rune) (int64, [][2]int64, error) {
	m, err := ed.subMatch(r, re)
	if err != nil || m == nil {
		return 0, m, err
	}
	repl, err := ed.subText(m, sub)
	if err != nil {
		return 0, nil, err
	}
	if err := ed.buf.change(addr{m[0][0], m[0][1]}, repl); err != nil {
		return 0, nil, err
	}
	return int64(len(repl)) - (m[0][1] - m[0][0]), m, err
}

func (ed *Editor) subText(m [][2]int64, sub []rune) ([]rune, error) {
	var rs []rune
	for i := 0; i < len(sub); i++ {
		d := escDigit(sub[i:])
		if d < 0 {
			rs = append(rs, sub[i])
			continue
		}
		sub, err := ed.subExpr(m, d)
		if err != nil {
			return nil, err
		}
		rs = append(rs, sub...)
		i++
	}
	return rs, nil
}

// EscDigit returns the digit from \[0-9]
// or -1 if the text does not represent an escaped digit.
func escDigit(sub []rune) int {
	if len(sub) >= 2 && sub[0] == '\\' && unicode.IsDigit(sub[1]) {
		return int(sub[1] - '0')
	}
	return -1
}

func (ed *Editor) subExpr(m [][2]int64, n int) ([]rune, error) {
	if n >= len(m) {
		return nil, nil
	}
	rs := make([]rune, m[n][1]-m[n][0])
	if _, err := ed.buf.runes.Read(rs, m[n][0]); err != nil {
		return nil, err
	}
	return rs, nil
}

type runeSlice struct {
	buf *runes.Buffer
	addr
	err error
}

func (rs *runeSlice) Size() int64 { return rs.size() }

func (rs *runeSlice) Rune(i int64) rune {
	switch {
	case i < 0 || i >= rs.size():
		panic("index out of bounds")
	case rs.err != nil:
		return -1
	}
	r, err := rs.buf.Rune(rs.from + i)
	if err != nil {
		rs.err = err
		return -1
	}
	return r
}

func (ed *Editor) subMatch(r addr, re *re1.Regexp) ([][2]int64, error) {
	rs := &runeSlice{buf: ed.buf.runes, addr: r}
	m := re.Match(rs, 0)
	for i := range m {
		m[i][0] += r.from
		m[i][1] += r.from
	}
	return m, rs.err
}

// Edit parses a command and performs its edit on the buffer.
//
// In the following, text surrounded by / represents delimited text.
// The delimiter can be any character, it need not be /.
// Trailing delimiters may be elided, but the opening delimiter must be present.
// In delimited text, \ is an escape; the following character is interpreted literally,
// except \n which represents a literal newline.
// Items in {} are optional.
//
// Commands are:
// 	{addr} a/text/
//	or
//	{addr} a
//	lines of text
//	.	Appends after the addressed text.
//		If an address is not supplied, dot is used.
//		Dot is set to the address.
//	c
//	i	Just like a, but c changes the addressed text
//		and i inserts before the addressed text.
//		Dot is set to the address.
//	{addr} d
//		Deletes the addressed text.
//		If an address is not supplied, dot is used.
//		Dot is set to the address.
//	{addr} m {[a-zA-Z]}
//		Sets the named mark to the address.
//		If an address is not supplied, dot is used.
//		If a mark name is not given, dot is set.
//		Dot is set to the address.
//	{addr} s/regexp/text/
//		Substitute substitutes text for the first match
// 		of the regular expression in the addressed range.
// 		When substituting, a backslash followed by a digit d
// 		stands for the string that matched the d-th subexpression.
//		\n is a literal newline.
// 		If the delimiter after the text is followed by the letter g
//		then all matches in the address range are substituted.
//		If an address is not supplied, dot is used.
//		Dot is set to the modified address.
func (ed *Editor) Edit(cmd []rune) error {
	addr, n, err := Addr(cmd)
	switch {
	case err != nil:
		return err
	case addr == nil:
		addr = Dot
	case len(cmd) == n:
		return errors.New("missing command")
	default:
		cmd = cmd[n:]
	}
	switch c := cmd[0]; c {
	case 'a':
		return ed.Append(addr, parseText(cmd[1:]))
	case 'c':
		return ed.Change(addr, parseText(cmd[1:]))
	case 'i':
		return ed.Insert(addr, parseText(cmd[1:]))
	case 'd':
		return ed.Delete(addr)
	case 'm':
		return ed.Mark(addr, parseMarkRune(cmd[1:]))
	case 's':
		re, err := re1.Compile(cmd[1:], re1.Options{Delimited: true})
		if err != nil {
			return err
		}
		exp := re.Expression()
		cmd = cmd[1+len(exp):]
		sub := parseDelimited(exp[0], true, cmd)
		g := len(sub) < len(cmd)-1 && cmd[len(sub)+1] == 'g'
		return ed.Substitute(addr, re, sub, g)
	default:
		return errors.New("unknown command: " + string(c))
	}
}

func parseText(cmd []rune) []rune {
	switch {
	case len(cmd) > 0 && cmd[0] == '\n':
		return parseLines(cmd)
	case len(cmd) > 0:
		return parseDelimited(cmd[0], false, cmd[1:])
	default:
		return nil
	}
}

func parseLines(cmd []rune) []rune {
	var rs []rune
	for i := 1; i < len(cmd); i++ {
		rs = append(rs, cmd[i])
		if i < len(cmd)-1 && cmd[i] == '\n' && cmd[i+1] == '.' {
			break
		}
	}
	return rs
}

func parseDelimited(d rune, digits bool, cmd []rune) []rune {
	var rs []rune
	for i := 0; i < len(cmd) && cmd[i] != d; i++ {
		if cmd[i] == '\\' && i < len(cmd)-1 {
			if digits && unicode.IsDigit(cmd[i+1]) {
				rs = append(rs, '\\')
			}
			i++
			if cmd[i] == 'n' {
				cmd[i] = '\n'
			}
		}
		rs = append(rs, cmd[i])
	}
	return rs
}

func parseMarkRune(cmd []rune) rune {
	var i int
	for ; i < len(cmd) && unicode.IsSpace(cmd[i]); i++ {
	}
	if i < len(cmd) && isMarkRune(cmd[i]) {
		return cmd[i]
	}
	return '.'
}

// Update updates the Editor's addresses
// given an addr that changed and its new size.
func (ed *Editor) update(r addr, n int64) {
	for m := range ed.marks {
		ed.marks[m] = ed.marks[m].update(r, n)
	}
}
<|endoftext|>


<commit_before>package analytics

import (
	"io"
	"io/ioutil"

	"bytes"
	"encoding/json"
	"net/http"
	"time"
)

// Version of the client.
const Version = "3.0.0"

// This interface is the main API exposed by the analytics package.
// Values that satsify this interface are returned by the client constructors
// provided by the package and provide a way to send messages via the HTTP API.
type Client interface {
	io.Closer

	// Queues a message to be sent by the client when the conditions for a batch
	// upload are met.
	// This is the main method you'll be using, a typical flow would look like
	// this:
	//
	//	client := analytics.New(writeKey)
	//	...
	//	client.Enqueue(analytics.Track{ ... })
	//	...
	//	client.Close()
	//
	// The method returns an error if the message queue not be queued, which
	// happens if the client was already closed at the time the method was
	// called or if the message was malformed.
	Enqueue(Message) error
}

type client struct {
	Config
	key string

	// This channel is where the `Enqueue` method writes messages so they can be
	// picked up and pushed by the backend goroutine taking care of applying the
	// batching rules.
	msgs chan Message

	// These two channels are used to synchronize the client shutting down when
	// `Close` is called.
	// The first channel is closed to signal the backend goroutine that it has
	// to stop, then the second one is closed by the backend goroutine to signal
	// that it has finished flushing all queued messages.
	quit     chan struct{}
	shutdown chan struct{}

	// This HTTP client is used to send requests to the backend, it uses the
	// HTTP transport provided in the configuration.
	http http.Client
}

// Instantiate a new client that uses the write key passed as first argument to
// send messages to the backend.
// The client is created with the default configuration.
func New(writeKey string) Client {
	// Here we can ignore the error because the default config is always valid.
	c, _ := NewWithConfig(writeKey, Config{})
	return c
}

// Instantiate a new client that uses the write key and configuration passed as
// arguments to send messages to the backend.
// The function will return an error if the configuration contained impossible
// values (like a negative flush interval for example).
// When the function returns an error the returned client will always be nil.
func NewWithConfig(writeKey string, config Config) (cli Client, err error) {
	if err = config.validate(); err != nil {
		return
	}

	c := &client{
		Config:   makeConfig(config),
		key:      writeKey,
		msgs:     make(chan Message, 100),
		quit:     make(chan struct{}),
		shutdown: make(chan struct{}),
		http: http.Client{
			Transport: config.Transport,
		},
	}

	go c.loop()

	cli = c
	return
}

func (c *client) Enqueue(msg Message) (err error) {
	if err = msg.validate(); err != nil {
		return
	}

	var id = c.uid()
	var ts = c.now()

	switch m := msg.(type) {
	case Alias:
		m.Type = "alias"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Group:
		m.Type = "group"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Identify:
		m.Type = "identify"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Page:
		m.Type = "page"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Screen:
		m.Type = "screen"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Track:
		m.Type = "track"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m
	}

	defer func() {
		// When the `msgs` channel is closed writing to it will trigger a panic.
		// To avoid letting the panic propagate to the caller we recover from it
		// and instead report that the client has been closed and shouldn't be
		// used anymore.
		if recover() != nil {
			err = ErrClosed
		}
	}()

	c.msgs <- msg
	return
}

// Close and flush metrics.
func (c *client) Close() (err error) {
	defer func() {
		// Always recover, a panic could be raised if `c`.quit was closed which
		// means the method was called more than once.
		if recover() != nil {
			err = ErrClosed
		}
	}()
	close(c.quit)
	<-c.shutdown
	return
}

// Send batch request.
func (c *client) send(msgs []message) {
	const attempts = 10

	b, err := json.Marshal(batch{
		MessageId: c.uid(),
		SentAt:    c.now(),
		Messages:  msgs,
		Context:   c.DefaultContext,
	})

	if err != nil {
		c.errorf("marshalling mesages - %s", err)
		c.notifyFailure(msgs, err)
		return
	}

	for i := 0; i != attempts; i++ {
		if err = c.upload(b); err == nil {
			c.notifySuccess(msgs)
			return
		}

		// Wait for either a retry timeout or the client to be closed.
		select {
		case <-time.After(c.RetryAfter(i)):
		case <-c.quit:
			c.errorf("%d messages dropped because they failed to be sent and the client was closed", len(msgs))
			c.notifyFailure(msgs, err)
			return
		}
	}

	c.errorf("%d messages dropped because they failed to be sent after %d attempts", len(msgs), attempts)
	c.notifyFailure(msgs, err)
}

// Upload serialized batch message.
func (c *client) upload(b []byte) error {
	url := c.Endpoint + "/v1/batch"
	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
	if err != nil {
		c.errorf("creating request - %s", err)
		return err
	}

	req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Content-Length", string(len(b)))
	req.SetBasicAuth(c.key, "")

	res, err := c.http.Do(req)

	if err != nil {
		c.errorf("sending request - %s", err)
		return err
	}

	defer res.Body.Close()
	c.report(res)

	return nil
}

// Report on response body.
func (c *client) report(res *http.Response) {
	if res.StatusCode < 400 {
		c.debugf("response %s", res.Status)
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		c.errorf("reading response body - %s", err)
		return
	}

	c.logf("response %s: %d – %s", res.Status, res.StatusCode, body)
}

// Batch loop.
func (c *client) loop() {
	defer close(c.shutdown)

	tick := time.NewTicker(c.Interval)
	defer tick.Stop()

	mq := messageQueue{
		maxBatchSize:  c.BatchSize,
		maxBatchBytes: c.maxBatchBytes(),
	}

	for {
		select {
		case msg := <-c.msgs:
			c.push(&mq, msg)

		case <-tick.C:
			c.flush(&mq)

		case <-c.quit:
			c.debugf("exit requested – draining messages")

			// Drain the msg channel, we have to close it first so no more
			// messages can be pushed and otherwise the loop would never end.
			close(c.msgs)
			for msg := range c.msgs {
				c.push(&mq, msg)
			}

			c.flush(&mq)
			c.debugf("exit")
			return
		}
	}
}

func (c *client) push(q *messageQueue, m Message) {
	var msg message
	var err error

	if msg, err = makeMessage(m, maxMessageBytes); err != nil {
		c.errorf("%s - %v", err, m)
		if c.Callback != nil {
			c.Callback.Failure(m, err)
		}
		return
	}

	c.debugf("buffer (%d/%d) %v", len(q.pending), c.BatchSize, m)

	if msgs := q.push(msg); msgs != nil {
		c.debugf("exceeded messages batch limit with batch of %d messages – flushing", len(msgs))
		c.send(msgs)
	}
}

func (c *client) flush(q *messageQueue) {
	if msgs := q.flush(); msgs != nil {
		c.debugf("flushing %d messages", len(msgs))
		c.send(msgs)
	}
}

func (c *client) debugf(format string, args ...interface{}) {
	if c.Verbose {
		c.logf(format, args...)
	}
}

func (c *client) logf(format string, args ...interface{}) {
	c.Logger.Logf(format, args...)
}

func (c *client) errorf(format string, args ...interface{}) {
	c.Logger.Errorf(format, args...)
}

func (c *client) maxBatchBytes() int {
	b, _ := json.Marshal(batch{
		MessageId: c.uid(),
		SentAt:    c.now(),
		Context:   c.DefaultContext,
	})
	return maxBatchBytes - len(b)
}

func (c *client) notifySuccess(msgs []message) {
	if c.Callback != nil {
		for _, m := range msgs {
			c.Callback.Success(m.msg)
		}
	}
}

func (c *client) notifyFailure(msgs []message, err error) {
	if c.Callback != nil {
		for _, m := range msgs {
			c.Callback.Failure(m.msg, err)
		}
	}
}
<commit_msg>async send (#88)<commit_after>package analytics

import (
	"io"
	"io/ioutil"
	"sync"

	"bytes"
	"encoding/json"
	"net/http"
	"time"
)

// Version of the client.
const Version = "3.0.0"

// This interface is the main API exposed by the analytics package.
// Values that satsify this interface are returned by the client constructors
// provided by the package and provide a way to send messages via the HTTP API.
type Client interface {
	io.Closer

	// Queues a message to be sent by the client when the conditions for a batch
	// upload are met.
	// This is the main method you'll be using, a typical flow would look like
	// this:
	//
	//	client := analytics.New(writeKey)
	//	...
	//	client.Enqueue(analytics.Track{ ... })
	//	...
	//	client.Close()
	//
	// The method returns an error if the message queue not be queued, which
	// happens if the client was already closed at the time the method was
	// called or if the message was malformed.
	Enqueue(Message) error
}

type client struct {
	Config
	key string

	// This channel is where the `Enqueue` method writes messages so they can be
	// picked up and pushed by the backend goroutine taking care of applying the
	// batching rules.
	msgs chan Message

	// These two channels are used to synchronize the client shutting down when
	// `Close` is called.
	// The first channel is closed to signal the backend goroutine that it has
	// to stop, then the second one is closed by the backend goroutine to signal
	// that it has finished flushing all queued messages.
	quit     chan struct{}
	shutdown chan struct{}

	// This HTTP client is used to send requests to the backend, it uses the
	// HTTP transport provided in the configuration.
	http http.Client
}

// Instantiate a new client that uses the write key passed as first argument to
// send messages to the backend.
// The client is created with the default configuration.
func New(writeKey string) Client {
	// Here we can ignore the error because the default config is always valid.
	c, _ := NewWithConfig(writeKey, Config{})
	return c
}

// Instantiate a new client that uses the write key and configuration passed as
// arguments to send messages to the backend.
// The function will return an error if the configuration contained impossible
// values (like a negative flush interval for example).
// When the function returns an error the returned client will always be nil.
func NewWithConfig(writeKey string, config Config) (cli Client, err error) {
	if err = config.validate(); err != nil {
		return
	}

	c := &client{
		Config:   makeConfig(config),
		key:      writeKey,
		msgs:     make(chan Message, 100),
		quit:     make(chan struct{}),
		shutdown: make(chan struct{}),
		http: http.Client{
			Transport: config.Transport,
		},
	}

	go c.loop()

	cli = c
	return
}

func (c *client) Enqueue(msg Message) (err error) {
	if err = msg.validate(); err != nil {
		return
	}

	var id = c.uid()
	var ts = c.now()

	switch m := msg.(type) {
	case Alias:
		m.Type = "alias"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Group:
		m.Type = "group"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Identify:
		m.Type = "identify"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Page:
		m.Type = "page"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Screen:
		m.Type = "screen"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m

	case Track:
		m.Type = "track"
		m.MessageId = makeMessageId(m.MessageId, id)
		m.Timestamp = makeTimestamp(m.Timestamp, ts)
		msg = m
	}

	defer func() {
		// When the `msgs` channel is closed writing to it will trigger a panic.
		// To avoid letting the panic propagate to the caller we recover from it
		// and instead report that the client has been closed and shouldn't be
		// used anymore.
		if recover() != nil {
			err = ErrClosed
		}
	}()

	c.msgs <- msg
	return
}

// Close and flush metrics.
func (c *client) Close() (err error) {
	defer func() {
		// Always recover, a panic could be raised if `c`.quit was closed which
		// means the method was called more than once.
		if recover() != nil {
			err = ErrClosed
		}
	}()
	close(c.quit)
	<-c.shutdown
	return
}

// Asychronously send a batched requests.
func (c *client) sendAsync(msgs []message, wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		defer wg.Done()
		defer func() {
			// In case a bug is introduced in the send function that triggers
			// a panic, we don't want this to ever crash the application so we
			// catch it here and log it instead.
			if err := recover(); err != nil {
				c.errorf("panic - %s", err)
			}
		}()
		c.send(msgs)
	}()
}

// Send batch request.
func (c *client) send(msgs []message) {
	const attempts = 10

	b, err := json.Marshal(batch{
		MessageId: c.uid(),
		SentAt:    c.now(),
		Messages:  msgs,
		Context:   c.DefaultContext,
	})

	if err != nil {
		c.errorf("marshalling mesages - %s", err)
		c.notifyFailure(msgs, err)
		return
	}

	for i := 0; i != attempts; i++ {
		if err = c.upload(b); err == nil {
			c.notifySuccess(msgs)
			return
		}

		// Wait for either a retry timeout or the client to be closed.
		select {
		case <-time.After(c.RetryAfter(i)):
		case <-c.quit:
			c.errorf("%d messages dropped because they failed to be sent and the client was closed", len(msgs))
			c.notifyFailure(msgs, err)
			return
		}
	}

	c.errorf("%d messages dropped because they failed to be sent after %d attempts", len(msgs), attempts)
	c.notifyFailure(msgs, err)
}

// Upload serialized batch message.
func (c *client) upload(b []byte) error {
	url := c.Endpoint + "/v1/batch"
	req, err := http.NewRequest("POST", url, bytes.NewReader(b))
	if err != nil {
		c.errorf("creating request - %s", err)
		return err
	}

	req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Content-Length", string(len(b)))
	req.SetBasicAuth(c.key, "")

	res, err := c.http.Do(req)

	if err != nil {
		c.errorf("sending request - %s", err)
		return err
	}

	defer res.Body.Close()
	c.report(res)

	return nil
}

// Report on response body.
func (c *client) report(res *http.Response) {
	if res.StatusCode < 400 {
		c.debugf("response %s", res.Status)
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		c.errorf("reading response body - %s", err)
		return
	}

	c.logf("response %s: %d – %s", res.Status, res.StatusCode, body)
}

// Batch loop.
func (c *client) loop() {
	defer close(c.shutdown)

	wg := &sync.WaitGroup{}
	defer wg.Wait()

	tick := time.NewTicker(c.Interval)
	defer tick.Stop()

	mq := messageQueue{
		maxBatchSize:  c.BatchSize,
		maxBatchBytes: c.maxBatchBytes(),
	}

	for {
		select {
		case msg := <-c.msgs:
			c.push(&mq, msg, wg)

		case <-tick.C:
			c.flush(&mq, wg)

		case <-c.quit:
			c.debugf("exit requested – draining messages")

			// Drain the msg channel, we have to close it first so no more
			// messages can be pushed and otherwise the loop would never end.
			close(c.msgs)
			for msg := range c.msgs {
				c.push(&mq, msg, wg)
			}

			c.flush(&mq, wg)
			c.debugf("exit")
			return
		}
	}
}

func (c *client) push(q *messageQueue, m Message, wg *sync.WaitGroup) {
	var msg message
	var err error

	if msg, err = makeMessage(m, maxMessageBytes); err != nil {
		c.errorf("%s - %v", err, m)
		if c.Callback != nil {
			c.Callback.Failure(m, err)
		}
		return
	}

	c.debugf("buffer (%d/%d) %v", len(q.pending), c.BatchSize, m)

	if msgs := q.push(msg); msgs != nil {
		c.debugf("exceeded messages batch limit with batch of %d messages – flushing", len(msgs))
		c.sendAsync(msgs, wg)
	}
}

func (c *client) flush(q *messageQueue, wg *sync.WaitGroup) {
	if msgs := q.flush(); msgs != nil {
		c.debugf("flushing %d messages", len(msgs))
		c.sendAsync(msgs, wg)
	}
}

func (c *client) debugf(format string, args ...interface{}) {
	if c.Verbose {
		c.logf(format, args...)
	}
}

func (c *client) logf(format string, args ...interface{}) {
	c.Logger.Logf(format, args...)
}

func (c *client) errorf(format string, args ...interface{}) {
	c.Logger.Errorf(format, args...)
}

func (c *client) maxBatchBytes() int {
	b, _ := json.Marshal(batch{
		MessageId: c.uid(),
		SentAt:    c.now(),
		Context:   c.DefaultContext,
	})
	return maxBatchBytes - len(b)
}

func (c *client) notifySuccess(msgs []message) {
	if c.Callback != nil {
		for _, m := range msgs {
			c.Callback.Success(m.msg)
		}
	}
}

func (c *client) notifyFailure(msgs []message, err error) {
	if c.Callback != nil {
		for _, m := range msgs {
			c.Callback.Failure(m.msg, err)
		}
	}
}
<|endoftext|>