<commit_before>package create

const eventTmpl = `name: "{{ .Year}}-{{ .City}}" # The name of the event. Four digit year with the city name in lower-case, with no spaces.
year: "{{ .Year}}" # The year of the event. Make sure it is in quotes.
city: "{{ .City}}" # The displayed city name of the event. Capitalize it.
event_twitter: "{{ .Twitter}}" # Change this to the twitter handle for your event such as devopsdayschi or devopsdaysmsp
description: "Devopsdays is coming to {{ .City}}!" # Edit this to suit your preferences
ga_tracking_id: "{{ .GoogleAnalytics}}" # If you have your own Google Analytics tracking ID, enter it here. Example: "UA-74738648-1"

# All dates are in unquoted YYYY-MM-DD, like this:   variable: 2016-01-05
startdate: {{ .StartDate}} # The start date of your event. Leave blank if you don't have a venue reserved yet.
enddate: {{ .StartDate}} # The end date of your event. Leave blank if you don't have a venue reserved yet.

# Leave CFP dates blank if you don't know yet, or set all three at once.
cfp_date_start: {{ .CFPDateStart}} # start accepting talk proposals.
cfp_date_end: {{ .CFPDateEnd}} # close your call for proposals.
cfp_date_announce: {{ .CFPDateAnnounce}} # inform proposers of status

cfp_open: "{{ .CFPOpen}}"
cfp_link: "{{ .CFPLink}}" #if you have a custom link for submitting proposals, add it here. This will control the Propose menu item as well as the "Propose" button.

registration_date_start: {{ .RegistrationDateStart}} # start accepting registration. Leave blank if registration is not open yet
registration_date_end: {{ .RegistrationDateEnd}} # close registration. Leave blank if registration is not open yet.

registration_closed: "{{ .RegistrationClosed }}" # set this to true if you need to manually close registration before your registration end date
registration_link: "{{ .RegistrationLink }}" # If you have a custom registration link, enter it here. This will control the Registration menu item as well as the "Register" button.

masthead_background: "{{ .MastheadBackground }}"

# Location
#
coordinates: "{{ .Coordinates }}" # The coordinates of your city. Get Latitude and Longitude of a Point: http://itouchmap.com/latlong.html
location: "{{ .Location }}" # Defaults to city, but you can make it the venue name.
#
location_address: "{{ .LocationAddress }}" #Optional - use the street address of your venue. This will show up on the welcome page if set.

nav_elements: # List of pages you want to show up in the navigation of your page.
 # - name: propose
 # - name: location
 # - name: registration
 # - name: program
 # - name: speakers
  - name: sponsor
  - name: contact
  - name: conduct
# - name: example
#   icon: "map-o" # This is a font-awesome icon that will display on small screens. Choose at http://fontawesome.io/icons/
#   url: http://mycfp.com # The url setting is optional, and only if you want the navigation to link off-site

# These are the same people you have on the mailing list and Slack channel.
team_members: # Name is the only required field for team members.
  - name: "John Doe"
  - name: "Jane Smith"
    twitter: "devopsdays"
  - name: "Sally Fields"
    employer: "Acme Anvil Co."
    github: "devopsdays"
    facebook: "https://www.facebook.com/sally.fields"
    linkedin: "https://www.linkedin.com/in/sallyfields"
    website: "https://mattstratton.com"
    image: "sally-fields.jpg"
organizer_email: "{{ .OrganizerEmail }}" # Put your organizer email address here
proposal_email: "{{ .ProposalEmail }}" # Put your proposal email address here

# List all of your sponsors here along with what level of sponsorship they have.
# Check data/sponsors/ to use sponsors already added by others.
sponsors:
  - id: samplesponsorname
    level: gold
 #  url: http://mysponsor.com/?campaign=me # Use this if you need to over-ride a sponsor URL.
  - id: arresteddevops
    level: community

sponsors_accepted : "{{ .SponsorsAccepted }}" # Whether you want "Become a XXX Sponsor!" link

# In this section, list the level of sponsorships and the label to use.
# You may optionally include a "max" attribute to limit the number of sponsors per level. For
# unlimited sponsors, omit the max attribute or set it to 0. If you want to prevent all
# sponsorship for a specific level, it is best to remove the level.
sponsor_levels:
  - id: gold
    label: Gold
#    max: 10
  - id: silver
    label: Silver
    max: 0 # This is the same as omitting the max limit.
  - id: bronze
    label: Bronze
  - id: community
    label: Community
    `

const speakerTmpl = `+++
Title = "{{ .Title }}"
type = "speaker"
{{ with .Website }}website = "{{ . }}"{{ end }}
{{ with .Twitter }}twitter = "{{ . }}"{{ end }}
{{ with .Facebook }}facebook = "{{ . }}"{{ end }}
{{ with .Linkedin }}linkedin = "{{ . }}"{{ end }}
{{ with .Github }}github = "{{ . }}"{{ end }}
{{ with .Gitlab }}gitlab = "{{ . }}"{{ end }}
{{ with .ImagePath }}image = "{{ . }}"{{ end }}
+++
{{ with .Bio }}{{.}}{{ end }}
`
<commit_msg>Fix twitter field in event template<commit_after>package create

const eventTmpl = `name: "{{ .Year}}-{{ .City}}" # The name of the event. Four digit year with the city name in lower-case, with no spaces.
year: "{{ .Year}}" # The year of the event. Make sure it is in quotes.
city: "{{ .City}}" # The displayed city name of the event. Capitalize it.
event_twitter: "{{ .EventTwitter}}" # Change this to the twitter handle for your event such as devopsdayschi or devopsdaysmsp
description: "Devopsdays is coming to {{ .City}}!" # Edit this to suit your preferences
ga_tracking_id: "{{ .GoogleAnalytics}}" # If you have your own Google Analytics tracking ID, enter it here. Example: "UA-74738648-1"

# All dates are in unquoted YYYY-MM-DD, like this:   variable: 2016-01-05
startdate: {{ .StartDate}} # The start date of your event. Leave blank if you don't have a venue reserved yet.
enddate: {{ .StartDate}} # The end date of your event. Leave blank if you don't have a venue reserved yet.

# Leave CFP dates blank if you don't know yet, or set all three at once.
cfp_date_start: {{ .CFPDateStart}} # start accepting talk proposals.
cfp_date_end: {{ .CFPDateEnd}} # close your call for proposals.
cfp_date_announce: {{ .CFPDateAnnounce}} # inform proposers of status

cfp_open: "{{ .CFPOpen}}"
cfp_link: "{{ .CFPLink}}" #if you have a custom link for submitting proposals, add it here. This will control the Propose menu item as well as the "Propose" button.

registration_date_start: {{ .RegistrationDateStart}} # start accepting registration. Leave blank if registration is not open yet
registration_date_end: {{ .RegistrationDateEnd}} # close registration. Leave blank if registration is not open yet.

registration_closed: "{{ .RegistrationClosed }}" # set this to true if you need to manually close registration before your registration end date
registration_link: "{{ .RegistrationLink }}" # If you have a custom registration link, enter it here. This will control the Registration menu item as well as the "Register" button.

masthead_background: "{{ .MastheadBackground }}"

# Location
#
coordinates: "{{ .Coordinates }}" # The coordinates of your city. Get Latitude and Longitude of a Point: http://itouchmap.com/latlong.html
location: "{{ .Location }}" # Defaults to city, but you can make it the venue name.
#
location_address: "{{ .LocationAddress }}" #Optional - use the street address of your venue. This will show up on the welcome page if set.

nav_elements: # List of pages you want to show up in the navigation of your page.
 # - name: propose
 # - name: location
 # - name: registration
 # - name: program
 # - name: speakers
  - name: sponsor
  - name: contact
  - name: conduct
# - name: example
#   icon: "map-o" # This is a font-awesome icon that will display on small screens. Choose at http://fontawesome.io/icons/
#   url: http://mycfp.com # The url setting is optional, and only if you want the navigation to link off-site

# These are the same people you have on the mailing list and Slack channel.
team_members: # Name is the only required field for team members.
  - name: "John Doe"
  - name: "Jane Smith"
    twitter: "devopsdays"
  - name: "Sally Fields"
    employer: "Acme Anvil Co."
    github: "devopsdays"
    facebook: "https://www.facebook.com/sally.fields"
    linkedin: "https://www.linkedin.com/in/sallyfields"
    website: "https://mattstratton.com"
    image: "sally-fields.jpg"
organizer_email: "{{ .OrganizerEmail }}" # Put your organizer email address here
proposal_email: "{{ .ProposalEmail }}" # Put your proposal email address here

# List all of your sponsors here along with what level of sponsorship they have.
# Check data/sponsors/ to use sponsors already added by others.
sponsors:
  - id: samplesponsorname
    level: gold
 #  url: http://mysponsor.com/?campaign=me # Use this if you need to over-ride a sponsor URL.
  - id: arresteddevops
    level: community

sponsors_accepted : "{{ .SponsorsAccepted }}" # Whether you want "Become a XXX Sponsor!" link

# In this section, list the level of sponsorships and the label to use.
# You may optionally include a "max" attribute to limit the number of sponsors per level. For
# unlimited sponsors, omit the max attribute or set it to 0. If you want to prevent all
# sponsorship for a specific level, it is best to remove the level.
sponsor_levels:
  - id: gold
    label: Gold
#    max: 10
  - id: silver
    label: Silver
    max: 0 # This is the same as omitting the max limit.
  - id: bronze
    label: Bronze
  - id: community
    label: Community
    `

const speakerTmpl = `+++
Title = "{{ .Title }}"
type = "speaker"
{{ with .Website }}website = "{{ . }}"{{ end }}
{{ with .Twitter }}twitter = "{{ . }}"{{ end }}
{{ with .Facebook }}facebook = "{{ . }}"{{ end }}
{{ with .Linkedin }}linkedin = "{{ . }}"{{ end }}
{{ with .Github }}github = "{{ . }}"{{ end }}
{{ with .Gitlab }}gitlab = "{{ . }}"{{ end }}
{{ with .ImagePath }}image = "{{ . }}"{{ end }}
+++
{{ with .Bio }}{{.}}{{ end }}
`
<|endoftext|>


<commit_before>// Copyright 2017 The go-xdgbasedir Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin

package xdgbasedir

import (
	"os"
	"path/filepath"
	"strconv"

	home "github.com/zchee/go-xdgbasedir/home"
)

var (
	defaultDataHome   string
	defaultConfigHome string
	defaultDataDirs   string
	defaultConfigDirs string
	defaultCacheHome  string
	defaultRuntimeDir string
)

func initDir() {
	initOnce.Do(func() {
		switch Mode {
		case Unix:
			defaultDataHome = filepath.Join(home.Dir(), ".local", "share")
			defaultConfigHome = filepath.Join(home.Dir(), ".config")
			defaultDataDirs = filepath.Join("/usr", "local", "share") + string(filepath.ListSeparator) + filepath.Join("/usr", "share")
			defaultConfigDirs = filepath.Join("/etc", "xdg")
			defaultCacheHome = filepath.Join(home.Dir(), ".cache")
			defaultRuntimeDir = filepath.Join("/run", "user", strconv.Itoa(os.Getuid()))
		case Native:
			// ref: https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html
			defaultDataHome = filepath.Join(home.Dir(), "Library", "Application Support")
			defaultConfigHome = filepath.Join(home.Dir(), "Library", "Preferences")
			defaultDataDirs = defaultDataHome
			defaultConfigDirs = defaultConfigHome
			defaultCacheHome = filepath.Join(home.Dir(), "Library", "Caches")
			defaultRuntimeDir = defaultDataHome
		}
	})
}

func dataHome() string {
	initDir()
	return defaultDataHome
}

func configHome() string {
	initDir()
	return defaultConfigHome
}

func dataDirs() string {
	initDir()
	return defaultDataDirs
}

func configDirs() string {
	initDir()
	return defaultConfigDirs
}

func cacheHome() string {
	initDir()
	return defaultCacheHome
}

func runtimeDir() string {
	initDir()
	return defaultRuntimeDir
}
<commit_msg>xdgbasedir: remove unnecessary import alias<commit_after>// Copyright 2017 The go-xdgbasedir Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin

package xdgbasedir

import (
	"os"
	"path/filepath"
	"strconv"

	"github.com/zchee/go-xdgbasedir/home"
)

var (
	defaultDataHome   string
	defaultConfigHome string
	defaultDataDirs   string
	defaultConfigDirs string
	defaultCacheHome  string
	defaultRuntimeDir string
)

func initDir() {
	initOnce.Do(func() {
		switch Mode {
		case Unix:
			defaultDataHome = filepath.Join(home.Dir(), ".local", "share")
			defaultConfigHome = filepath.Join(home.Dir(), ".config")
			defaultDataDirs = filepath.Join("/usr", "local", "share") + string(filepath.ListSeparator) + filepath.Join("/usr", "share")
			defaultConfigDirs = filepath.Join("/etc", "xdg")
			defaultCacheHome = filepath.Join(home.Dir(), ".cache")
			defaultRuntimeDir = filepath.Join("/run", "user", strconv.Itoa(os.Getuid()))
		case Native:
			// ref: https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html
			defaultDataHome = filepath.Join(home.Dir(), "Library", "Application Support")
			defaultConfigHome = filepath.Join(home.Dir(), "Library", "Preferences")
			defaultDataDirs = defaultDataHome
			defaultConfigDirs = defaultConfigHome
			defaultCacheHome = filepath.Join(home.Dir(), "Library", "Caches")
			defaultRuntimeDir = defaultDataHome
		}
	})
}

func dataHome() string {
	initDir()
	return defaultDataHome
}

func configHome() string {
	initDir()
	return defaultConfigHome
}

func dataDirs() string {
	initDir()
	return defaultDataDirs
}

func configDirs() string {
	initDir()
	return defaultConfigDirs
}

func cacheHome() string {
	initDir()
	return defaultCacheHome
}

func runtimeDir() string {
	initDir()
	return defaultRuntimeDir
}
<|endoftext|>


<commit_before>// Copyright 2017 Ole Krüger.
// Licensed under the MIT license which can be found in the LICENSE file.

package dpt

import (
	"fmt"
)

// A DatapointValue is a value of a datapoint.
type DatapointValue interface {
	// Pack the datapoint to a byte array.
	Pack() []byte

	// Unpack a the datapoint value from a byte array.
	Unpack(data []byte) error
}

// DatapointMeta gives meta information about a datapoint type.
type DatapointMeta interface {
	// Unit returns the unit of this datapoint type or empty string if it doesn't have a unit.
	Unit() string
}

// DPT_5001 represents DPT 5.001 / Scaling.
type DPT_5001 float32

func (d DPT_5001) Pack() []byte {
	if d <= 0 {
		return packU8(0)
	} else if d >= 100 {
		return packU8(255)
	} else {
		return packU8(uint8(d * 2.55))
	}
}

func (d *DPT_5001) Unpack(data []byte) error {
	var value uint8
	if err := unpackU8(data, &value); err != nil {
		return err
	}

	*d = DPT_5001(value) / 2.55

	return nil
}

func (d DPT_5001) Unit() string {
	return "%"
}

func (d DPT_5001) String() string {
	return fmt.Sprintf("%.2f%%", float32(d))
}

// DPT_5003 represents DPT 5.003 / Angle.
type DPT_5003 float32

func (d DPT_5003) Pack() []byte {
	if d <= 0 {
		return packU8(0)
	} else if d >= 360 {
		return packU8(255)
	} else {
		return packU8(uint8(d * 255 / 360))
	}
}

func (d *DPT_5003) Unpack(data []byte) error {
	var value uint8
	if err := unpackU8(data, &value); err != nil {
		return err
	}

	*d = DPT_5003(value) * 360 / 255

	return nil
}

func (d DPT_5003) Unit() string {
	return "°"
}

func (d DPT_5003) String() string {
	return fmt.Sprintf("%.2f°", float32(d))
}

// DPT_5004 represents DPT 5.004 / Percent_U8.
type DPT_5004 uint8

func (d DPT_5004) Pack() []byte {
	return packU8(uint8(d))
}

func (d *DPT_5004) Unpack(data []byte) error {
	return unpackU8(data, (*uint8)(d))
}

func (d DPT_5004) Unit() string {
	return "%"
}

func (d DPT_5004) String() string {
	return fmt.Sprintf("%.2f%%", float32(d))
}

// DPT_12001 represents DPT 12.001 / Unsigned counter.
type DPT_12001 uint32

func (d DPT_12001) Pack() []byte {
	return packU32(uint32(d))
}

func (d *DPT_12001) Unpack(data []byte) error {
	return unpackU32(data, (*uint32)(d))
}

func (d DPT_12001) Unit() string {
	return "pulses"
}

func (d DPT_12001) String() string {
	return fmt.Sprintf("%d pulses", uint32(d))
}

// DPT_17001 represents DPT 17.001 / Scene Number.
type DPT_17001 uint8

func (d DPT_17001) Pack() []byte {
	if d > 63 {
		return packU8(63)
	} else {
		return packU8(uint8(d))
	}
}

func (d *DPT_17001) Unpack(data []byte) error {
	var value uint8

	if err := unpackU8(data, &value); err != nil {
		return err
	}

	if value <= 63 {
		*d = DPT_17001(value)
		return nil
	} else {
		*d = DPT_17001(63)
		return nil
	}
}

func (d DPT_17001) Unit() string {
	return ""
}

func (d DPT_17001) String() string {
	return fmt.Sprintf("%d", uint8(d))
}

// DPT_18001 represents DPT 18.001 / Scene Control.
type DPT_18001 uint8

func (d DPT_18001) Pack() []byte {
	if d <= 63 || (d >= 128 && d <= 191) {
		return packU8(uint8(d))
	} else {
		return packU8(63)
	}
}

func (d *DPT_18001) Unpack(data []byte) error {
	var value uint8

	if err := unpackU8(data, &value); err != nil {
		return err
	}

	if *d <= 63 || (*d >= 128 && *d <= 191) {
		*d = DPT_18001(value)
		return nil
	} else {
		*d = DPT_18001(63)
		return nil
	}
}

func (d DPT_18001) Unit() string {
	return ""
}

// KNX Association recommends to display the scene numbers [1..64].
// See note 6 of the KNX Specifications v2.1.
func (d DPT_18001) String() string {
	return fmt.Sprintf("%d", uint8(d))
}
<commit_msg>Fix bounds check for DPT 18.001<commit_after>// Copyright 2017 Ole Krüger.
// Licensed under the MIT license which can be found in the LICENSE file.

package dpt

import (
	"fmt"
)

// A DatapointValue is a value of a datapoint.
type DatapointValue interface {
	// Pack the datapoint to a byte array.
	Pack() []byte

	// Unpack a the datapoint value from a byte array.
	Unpack(data []byte) error
}

// DatapointMeta gives meta information about a datapoint type.
type DatapointMeta interface {
	// Unit returns the unit of this datapoint type or empty string if it doesn't have a unit.
	Unit() string
}

// DPT_5001 represents DPT 5.001 / Scaling.
type DPT_5001 float32

func (d DPT_5001) Pack() []byte {
	if d <= 0 {
		return packU8(0)
	} else if d >= 100 {
		return packU8(255)
	} else {
		return packU8(uint8(d * 2.55))
	}
}

func (d *DPT_5001) Unpack(data []byte) error {
	var value uint8
	if err := unpackU8(data, &value); err != nil {
		return err
	}

	*d = DPT_5001(value) / 2.55

	return nil
}

func (d DPT_5001) Unit() string {
	return "%"
}

func (d DPT_5001) String() string {
	return fmt.Sprintf("%.2f%%", float32(d))
}

// DPT_5003 represents DPT 5.003 / Angle.
type DPT_5003 float32

func (d DPT_5003) Pack() []byte {
	if d <= 0 {
		return packU8(0)
	} else if d >= 360 {
		return packU8(255)
	} else {
		return packU8(uint8(d * 255 / 360))
	}
}

func (d *DPT_5003) Unpack(data []byte) error {
	var value uint8
	if err := unpackU8(data, &value); err != nil {
		return err
	}

	*d = DPT_5003(value) * 360 / 255

	return nil
}

func (d DPT_5003) Unit() string {
	return "°"
}

func (d DPT_5003) String() string {
	return fmt.Sprintf("%.2f°", float32(d))
}

// DPT_5004 represents DPT 5.004 / Percent_U8.
type DPT_5004 uint8

func (d DPT_5004) Pack() []byte {
	return packU8(uint8(d))
}

func (d *DPT_5004) Unpack(data []byte) error {
	return unpackU8(data, (*uint8)(d))
}

func (d DPT_5004) Unit() string {
	return "%"
}

func (d DPT_5004) String() string {
	return fmt.Sprintf("%.2f%%", float32(d))
}

// DPT_12001 represents DPT 12.001 / Unsigned counter.
type DPT_12001 uint32

func (d DPT_12001) Pack() []byte {
	return packU32(uint32(d))
}

func (d *DPT_12001) Unpack(data []byte) error {
	return unpackU32(data, (*uint32)(d))
}

func (d DPT_12001) Unit() string {
	return "pulses"
}

func (d DPT_12001) String() string {
	return fmt.Sprintf("%d pulses", uint32(d))
}

// DPT_17001 represents DPT 17.001 / Scene Number.
type DPT_17001 uint8

func (d DPT_17001) Pack() []byte {
	if d > 63 {
		return packU8(63)
	} else {
		return packU8(uint8(d))
	}
}

func (d *DPT_17001) Unpack(data []byte) error {
	var value uint8

	if err := unpackU8(data, &value); err != nil {
		return err
	}

	if value <= 63 {
		*d = DPT_17001(value)
		return nil
	} else {
		*d = DPT_17001(63)
		return nil
	}
}

func (d DPT_17001) Unit() string {
	return ""
}

func (d DPT_17001) String() string {
	return fmt.Sprintf("%d", uint8(d))
}

// DPT_18001 represents DPT 18.001 / Scene Control.
type DPT_18001 uint8

func (d DPT_18001) Pack() []byte {
	if d <= 63 || (d >= 128 && d <= 191) {
		return packU8(uint8(d))
	} else {
		return packU8(63)
	}
}

func (d *DPT_18001) Unpack(data []byte) error {
	var value uint8

	if err := unpackU8(data, &value); err != nil {
		return err
	}

	if value <= 63 || (value >= 128 && value <= 191) {
		*d = DPT_18001(value)
		return nil
	} else {
		*d = DPT_18001(63)
		return nil
	}
}

func (d DPT_18001) Unit() string {
	return ""
}

// KNX Association recommends to display the scene numbers [1..64].
// See note 6 of the KNX Specifications v2.1.
func (d DPT_18001) String() string {
	return fmt.Sprintf("%d", uint8(d))
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"time"
)

type bashDeployer struct {
	clusterIPRange *string
}

var _ deployer = &bashDeployer{}

func newBash(clusterIPRange *string) *bashDeployer {
	b := &bashDeployer{clusterIPRange}
	return b
}

func (b *bashDeployer) Up() error {
	if b.clusterIPRange == nil || *b.clusterIPRange == "" {
		if numNodes, err := strconv.Atoi(os.Getenv("NUM_NODES")); err == nil {
			*b.clusterIPRange = getClusterIPRange(numNodes)
		}
	}
	if *b.clusterIPRange != "" {
		pop, err := pushEnv("CLUSTER_IP_RANGE", *b.clusterIPRange)
		if err != nil {
			return err
		}
		defer pop()
	}

	// TODO(shashidharatd): Remove below logic of choosing the scripts to run from federation
	// repo once the k8s deployment in federation jobs moves to kubernetes-anywhere
	var cmd string
	if useFederationRepo() {
		cmd = "../federation/hack/e2e-internal/e2e-up.sh"
	} else {
		cmd = "./hack/e2e-internal/e2e-up.sh"
	}
	return finishRunning(exec.Command(cmd))
}

func (b *bashDeployer) IsUp() error {
	var cmd string
	if useFederationRepo() {
		cmd = "../federation/hack/e2e-internal/e2e-status.sh"
	} else {
		cmd = "./hack/e2e-internal/e2e-status.sh"
	}
	return finishRunning(exec.Command(cmd))
}

func (b *bashDeployer) DumpClusterLogs(localPath, gcsPath string) error {
	return defaultDumpClusterLogs(localPath, gcsPath)
}

func (b *bashDeployer) TestSetup() error {
	return nil
}

func (b *bashDeployer) Down() error {
	var cmd string
	if useFederationRepo() {
		cmd = "../federation/hack/e2e-internal/e2e-down.sh"
	} else {
		cmd = "./hack/e2e-internal/e2e-down.sh"
	}
	return finishRunning(exec.Command(cmd))
}

func (b *bashDeployer) GetClusterCreated(gcpProject string) (time.Time, error) {
	res, err := output(exec.Command(
		"gcloud",
		"compute",
		"instance-groups",
		"list",
		"--project="+gcpProject,
		"--format=json(name,creationTimestamp)"))
	if err != nil {
		return time.Time{}, fmt.Errorf("list instance-group failed : %v", err)
	}

	created, err := getLatestClusterUpTime(string(res))
	if err != nil {
		return time.Time{}, fmt.Errorf("parse time failed : got gcloud res %s, err %v", string(res), err)
	}
	return created, nil
}

// Calculates the cluster IP range based on the no. of nodes in the cluster.
// Note: This mimics the function get-cluster-ip-range used by kube-up script.
func getClusterIPRange(numNodes int) string {
	suggestedRange := "10.64.0.0/14"
	if numNodes > 1000 {
		suggestedRange = "10.64.0.0/13"
	}
	if numNodes > 2000 {
		suggestedRange = "10.64.0.0/12"
	}
	if numNodes > 4000 {
		suggestedRange = "10.64.0.0/11"
	}
	return suggestedRange
}
<commit_msg>Set clusterIPRange param as part of creating kubetest bash deployer<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package main

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"time"
)

type bashDeployer struct {
	clusterIPRange string
}

var _ deployer = &bashDeployer{}

func newBash(clusterIPRange *string) *bashDeployer {
	if *clusterIPRange == "" {
		if numNodes, err := strconv.Atoi(os.Getenv("NUM_NODES")); err == nil {
			*clusterIPRange = getClusterIPRange(numNodes)
		}
	}
	b := &bashDeployer{*clusterIPRange}
	return b
}

func (b *bashDeployer) Up() error {
	// TODO(shashidharatd): Remove below logic of choosing the scripts to run from federation
	// repo once the k8s deployment in federation jobs moves to kubernetes-anywhere
	var script string
	if useFederationRepo() {
		script = "../federation/hack/e2e-internal/e2e-up.sh"
	} else {
		script = "./hack/e2e-internal/e2e-up.sh"
	}
	cmd := exec.Command(script)
	cmd.Env = os.Environ()
	cmd.Env = append(cmd.Env, fmt.Sprintf("CLUSTER_IP_RANGE=%s", b.clusterIPRange))
	return finishRunning(cmd)
}

func (b *bashDeployer) IsUp() error {
	var cmd string
	if useFederationRepo() {
		cmd = "../federation/hack/e2e-internal/e2e-status.sh"
	} else {
		cmd = "./hack/e2e-internal/e2e-status.sh"
	}
	return finishRunning(exec.Command(cmd))
}

func (b *bashDeployer) DumpClusterLogs(localPath, gcsPath string) error {
	return defaultDumpClusterLogs(localPath, gcsPath)
}

func (b *bashDeployer) TestSetup() error {
	return nil
}

func (b *bashDeployer) Down() error {
	var cmd string
	if useFederationRepo() {
		cmd = "../federation/hack/e2e-internal/e2e-down.sh"
	} else {
		cmd = "./hack/e2e-internal/e2e-down.sh"
	}
	return finishRunning(exec.Command(cmd))
}

func (b *bashDeployer) GetClusterCreated(gcpProject string) (time.Time, error) {
	res, err := output(exec.Command(
		"gcloud",
		"compute",
		"instance-groups",
		"list",
		"--project="+gcpProject,
		"--format=json(name,creationTimestamp)"))
	if err != nil {
		return time.Time{}, fmt.Errorf("list instance-group failed : %v", err)
	}

	created, err := getLatestClusterUpTime(string(res))
	if err != nil {
		return time.Time{}, fmt.Errorf("parse time failed : got gcloud res %s, err %v", string(res), err)
	}
	return created, nil
}

// Calculates the cluster IP range based on the no. of nodes in the cluster.
// Note: This mimics the function get-cluster-ip-range used by kube-up script.
func getClusterIPRange(numNodes int) string {
	suggestedRange := "10.64.0.0/14"
	if numNodes > 1000 {
		suggestedRange = "10.64.0.0/13"
	}
	if numNodes > 2000 {
		suggestedRange = "10.64.0.0/12"
	}
	if numNodes > 4000 {
		suggestedRange = "10.64.0.0/11"
	}
	return suggestedRange
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

func main() {
	address := os.Args[1]
	concurrencycount, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Printf("ERROR %s\n", err)
		return
	}
	requestcount, err := strconv.Atoi(os.Args[3])
	if err != nil {
		fmt.Printf("ERROR %s\n", err)
		return
	}
	fmt.Printf("Will spawn %d workers each making %d requests to %s\n", concurrencycount, requestcount, address)
	runLoadTest(address, requestcount, concurrencycount)
}

func runLoadTest(url string, requestcount int, concurrencycount int) {
	totalRequests := requestcount * concurrencycount
	ch := make(chan string, totalRequests)
	var wg sync.WaitGroup
	for i := 0; i < concurrencycount; i++ {
		wg.Add(1)
		go fetch(url, requestcount, ch, &wg)
	}
	fmt.Println("Waiting for results…")

	completedRequests := 0
	for completedRequests < totalRequests {
		_ = <-ch
		completedRequests++
		fmt.Printf("\r%.2f%% done (%d requests out of %d)", (float64(completedRequests)/float64(totalRequests))*100.0, completedRequests, totalRequests)
	}
	wg.Wait()
	fmt.Printf("\nYay🎈\n")

}

func fetch(address string, requestcount int, ch chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	fmt.Printf("Fetching %s %d times\n", address, requestcount)
	for i := 0; i < requestcount; i++ {
		start := time.Now()
		response, err := http.Get(address)
		if err != nil {
			fmt.Printf("ERROR %s\n", err)
			return
		}
		_, err = ioutil.ReadAll(response.Body)
		if err != nil {
			fmt.Printf("ERROR %s\n", err)
			return
		}
		//fmt.Printf("%s\n", string(contents))
		elapsed := time.Since(start)
		ch <- fmt.Sprintf("%d", elapsed.Nanoseconds())
	}

}
<commit_msg>store results in a struct<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

func main() {
	address := os.Args[1]
	concurrencycount, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Printf("ERROR %s\n", err)
		return
	}
	requestcount, err := strconv.Atoi(os.Args[3])
	if err != nil {
		fmt.Printf("ERROR %s\n", err)
		return
	}
	fmt.Printf("Will spawn %d workers each making %d requests to %s\n", concurrencycount, requestcount, address)
	runLoadTest(address, requestcount, concurrencycount)
}

type RequestResult struct {
	Elapsed int64
}

func runLoadTest(url string, requestcount int, concurrencycount int) {
	totalRequests := requestcount * concurrencycount
	ch := make(chan RequestResult, totalRequests)
	var wg sync.WaitGroup
	for i := 0; i < concurrencycount; i++ {
		wg.Add(1)
		go fetch(url, requestcount, ch, &wg)
	}
	fmt.Println("Waiting for results…")

	completedRequests := 0
	for completedRequests < totalRequests {
		_ = <-ch
		completedRequests++
		fmt.Printf("\r%.2f%% done (%d requests out of %d)", (float64(completedRequests)/float64(totalRequests))*100.0, completedRequests, totalRequests)
	}
	wg.Wait()
	fmt.Printf("\nYay🎈\n")

}

func fetch(address string, requestcount int, ch chan RequestResult, wg *sync.WaitGroup) {
	defer wg.Done()
	fmt.Printf("Fetching %s %d times\n", address, requestcount)
	for i := 0; i < requestcount; i++ {
		start := time.Now()
		response, err := http.Get(address)
		if err != nil {
			fmt.Printf("ERROR %s\n", err)
			return
		}
		_, err = ioutil.ReadAll(response.Body)
		if err != nil {
			fmt.Printf("ERROR %s\n", err)
			return
		}
		//fmt.Printf("%s\n", string(contents))
		elapsed := time.Since(start)
		var result RequestResult
		result.Elapsed = elapsed.Nanoseconds()
		ch <- result
	}

}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package encoding defines an interface for character encodings, such as Shift
// JIS and Windows 1252, that can convert to and from UTF-8.
//
// Encoding implementations are provided in other packages, such as
// golang.org/x/text/encoding/charmap and
// golang.org/x/text/encoding/japanese.
package encoding // import "golang.org/x/text/encoding"

import (
	"errors"
	"io"
	"strconv"
	"unicode/utf8"

	"golang.org/x/text/encoding/internal/identifier"
	"golang.org/x/text/transform"
)

// TODO:
// - There seems to be some inconsistency in when decoders return errors
//   and when not. Also documentation seems to suggest they shouldn't return
//   errors at all (except for UTF-16).
// - Encoders seem to rely on or at least benefit from the input being in NFC
//   normal form. Perhaps add an example how users could prepare their output.

// Encoding is a character set encoding that can be transformed to and from
// UTF-8.
type Encoding interface {
	// NewDecoder returns a Decoder.
	NewDecoder() *Decoder

	// NewEncoder returns an Encoder.
	NewEncoder() *Encoder
}

// A Decoder converts bytes to UTF-8. It implements transform.Transformer.
//
// Transforming source bytes that are not of that encoding will not result in an
// error per se. Each byte that cannot be transcoded will be represented in the
// output by the UTF-8 encoding of '\uFFFD', the replacement rune.
type Decoder struct {
	transform.Transformer

	// This forces external creators of Decoders to use names in struct
	// initializers, allowing for future extendibility without having to break
	// code.
	_ struct{}
}

// Bytes converts the given encoded bytes to UTF-8. It returns the converted
// bytes or 0, err if any error occurred.
func (d *Decoder) Bytes(b []byte) ([]byte, error) {
	b, _, err := transform.Bytes(d, b)
	if err != nil {
		return nil, err
	}
	return b, nil
}

// String converts the given encoded string to UTF-8. It returns the converted
// string or 0, err if any error occurred.
func (d *Decoder) String(s string) (string, error) {
	s, _, err := transform.String(d, s)
	if err != nil {
		return "", err
	}
	return s, nil
}

// Reader wraps another Reader to decode its bytes.
//
// The Decoder may not be used for any other operation as long as the returned
// Reader is in use.
func (d *Decoder) Reader(r io.Reader) io.Reader {
	return transform.NewReader(r, d)
}

// An Encoder converts bytes from UTF-8. It implements transform.Transformer.
//
// Each rune that cannot be transcoded will result in an error. In this case,
// the transform will consume all source byte up to, not including the offending
// rune. Transforming source bytes that are not valid UTF-8 will be replaced by
// `\uFFFD`. To return early with an error instead, use transform.Chain to
// preprocess the data with a UTF8Validator.
type Encoder struct {
	transform.Transformer

	// This forces external creators of Encoders to use names in struct
	// initializers, allowing for future extendibility without having to break
	// code.
	_ struct{}
}

// Bytes converts bytes from UTF-8. It returns the converted bytes or 0, err if
// any error occurred.
func (e *Encoder) Bytes(b []byte) ([]byte, error) {
	b, _, err := transform.Bytes(e, b)
	if err != nil {
		return nil, err
	}
	return b, nil
}

// String converts a string from UTF-8. It returns the converted string or
// 0, err if any error occurred.
func (e *Encoder) String(s string) (string, error) {
	s, _, err := transform.String(e, s)
	if err != nil {
		return "", err
	}
	return s, nil
}

// Writer wraps another Writer to encode its UTF-8 output.
//
// The Encoder may not be used for any other operation as long as the returned
// Writer is in use.
func (e *Encoder) Writer(w io.Writer) io.Writer {
	return transform.NewWriter(w, e)
}

// ASCIISub is the ASCII substitute character, as recommended by
// http://unicode.org/reports/tr36/#Text_Comparison
const ASCIISub = '\x1a'

// Nop is the nop encoding. Its transformed bytes are the same as the source
// bytes; it does not replace invalid UTF-8 sequences.
var Nop Encoding = nop{}

type nop struct{}

func (nop) NewDecoder() *Decoder {
	return &Decoder{Transformer: transform.Nop}
}
func (nop) NewEncoder() *Encoder {
	return &Encoder{Transformer: transform.Nop}
}

// Replacement is the replacement encoding. Decoding from the replacement
// encoding yields a single '\uFFFD' replacement rune. Encoding from UTF-8 to
// the replacement encoding yields the same as the source bytes except that
// invalid UTF-8 is converted to '\uFFFD'.
//
// It is defined at http://encoding.spec.whatwg.org/#replacement
var Replacement Encoding = replacement{}

type replacement struct{}

func (replacement) NewDecoder() *Decoder {
	return &Decoder{Transformer: replacementDecoder{}}
}

func (replacement) NewEncoder() *Encoder {
	return &Encoder{Transformer: replacementEncoder{}}
}

func (replacement) ID() (mib identifier.MIB, other string) {
	return identifier.Replacement, ""
}

type replacementDecoder struct{ transform.NopResetter }

func (replacementDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	if len(dst) < 3 {
		return 0, 0, transform.ErrShortDst
	}
	if atEOF {
		const fffd = "\ufffd"
		dst[0] = fffd[0]
		dst[1] = fffd[1]
		dst[2] = fffd[2]
		nDst = 3
	}
	return nDst, len(src), nil
}

type replacementEncoder struct{ transform.NopResetter }

func (replacementEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	r, size := rune(0), 0

	for ; nSrc < len(src); nSrc += size {
		r = rune(src[nSrc])

		// Decode a 1-byte rune.
		if r < utf8.RuneSelf {
			size = 1

		} else {
			// Decode a multi-byte rune.
			r, size = utf8.DecodeRune(src[nSrc:])
			if size == 1 {
				// All valid runes of size 1 (those below utf8.RuneSelf) were
				// handled above. We have invalid UTF-8 or we haven't seen the
				// full character yet.
				if !atEOF && !utf8.FullRune(src[nSrc:]) {
					err = transform.ErrShortSrc
					break
				}
				r = '\ufffd'
			}
		}

		if nDst+utf8.RuneLen(r) > len(dst) {
			err = transform.ErrShortDst
			break
		}
		nDst += utf8.EncodeRune(dst[nDst:], r)
	}
	return nDst, nSrc, err
}

// HTMLEscapeUnsupported wraps encoders to replace source runes outside the
// repertoire of the destination encoding with HTML escape sequences.
//
// This wrapper exists to comply to URL and HTML forms requiring a
// non-terminating legacy encoder. The produced sequences may lead to data
// loss as they are indistinguishable from legitimate input. To avoid this
// issue, use UTF-8 encodings whenever possible.
func HTMLEscapeUnsupported(e *Encoder) *Encoder {
	return &Encoder{Transformer: &errorHandler{e, errorToHTML}}
}

// ReplaceUnsupported wraps encoders to replace source runes outside the
// repertoire of the destination encoding with an encoding-specific
// replacement.
//
// This wrapper is only provided for backwards compatibility and legacy
// handling. Its use is strongly discouraged. Use UTF-8 whenever possible.
func ReplaceUnsupported(e *Encoder) *Encoder {
	return &Encoder{Transformer: &errorHandler{e, errorToReplacement}}
}

type errorHandler struct {
	*Encoder
	handler func(dst []byte, r rune, err repertoireError) (n int, ok bool)
}

// TODO: consider making this error public in some form.
type repertoireError interface {
	Replacement() byte
}

func (h errorHandler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	nDst, nSrc, err = h.Transformer.Transform(dst, src, atEOF)
	for err != nil {
		rerr, ok := err.(repertoireError)
		if !ok {
			return nDst, nSrc, err
		}
		r, sz := utf8.DecodeRune(src[nSrc:])
		n, ok := h.handler(dst[nDst:], r, rerr)
		if !ok {
			return nDst, nSrc, transform.ErrShortDst
		}
		err = nil
		nDst += n
		if nSrc += sz; nSrc < len(src) {
			var dn, sn int
			dn, sn, err = h.Transformer.Transform(dst[nDst:], src[nSrc:], atEOF)
			nDst += dn
			nSrc += sn
		}
	}
	return nDst, nSrc, err
}

func errorToHTML(dst []byte, r rune, err repertoireError) (n int, ok bool) {
	buf := [8]byte{}
	b := strconv.AppendUint(buf[:0], uint64(r), 10)
	if n = len(b) + len("&#;"); n >= len(dst) {
		return 0, false
	}
	dst[0] = '&'
	dst[1] = '#'
	dst[copy(dst[2:], b)+2] = ';'
	return n, true
}

func errorToReplacement(dst []byte, r rune, err repertoireError) (n int, ok bool) {
	if len(dst) == 0 {
		return 0, false
	}
	dst[0] = err.Replacement()
	return 1, true
}

// ErrInvalidUTF8 means that a transformer encountered invalid UTF-8.
var ErrInvalidUTF8 = errors.New("encoding: invalid UTF-8")

// UTF8Validator is a transformer that returns ErrInvalidUTF8 on the first
// input byte that is not valid UTF-8.
var UTF8Validator transform.Transformer = utf8Validator{}

type utf8Validator struct{ transform.NopResetter }

func (utf8Validator) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	n := len(src)
	if n > len(dst) {
		n = len(dst)
	}
	for i := 0; i < n; {
		if c := src[i]; c < utf8.RuneSelf {
			dst[i] = c
			i++
			continue
		}
		_, size := utf8.DecodeRune(src[i:])
		if size == 1 {
			// All valid runes of size 1 (those below utf8.RuneSelf) were
			// handled above. We have invalid UTF-8 or we haven't seen the
			// full character yet.
			err = ErrInvalidUTF8
			if !atEOF && !utf8.FullRune(src[i:]) {
				err = transform.ErrShortSrc
			}
			return i, i, err
		}
		if i+size > len(dst) {
			return i, i, transform.ErrShortDst
		}
		for ; size > 0; size-- {
			dst[i] = src[i]
			i++
		}
	}
	if len(src) > len(dst) {
		err = transform.ErrShortDst
	}
	return n, n, err
}
<commit_msg>encoding: be clear what is returned in error cases<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package encoding defines an interface for character encodings, such as Shift
// JIS and Windows 1252, that can convert to and from UTF-8.
//
// Encoding implementations are provided in other packages, such as
// golang.org/x/text/encoding/charmap and
// golang.org/x/text/encoding/japanese.
package encoding // import "golang.org/x/text/encoding"

import (
	"errors"
	"io"
	"strconv"
	"unicode/utf8"

	"golang.org/x/text/encoding/internal/identifier"
	"golang.org/x/text/transform"
)

// TODO:
// - There seems to be some inconsistency in when decoders return errors
//   and when not. Also documentation seems to suggest they shouldn't return
//   errors at all (except for UTF-16).
// - Encoders seem to rely on or at least benefit from the input being in NFC
//   normal form. Perhaps add an example how users could prepare their output.

// Encoding is a character set encoding that can be transformed to and from
// UTF-8.
type Encoding interface {
	// NewDecoder returns a Decoder.
	NewDecoder() *Decoder

	// NewEncoder returns an Encoder.
	NewEncoder() *Encoder
}

// A Decoder converts bytes to UTF-8. It implements transform.Transformer.
//
// Transforming source bytes that are not of that encoding will not result in an
// error per se. Each byte that cannot be transcoded will be represented in the
// output by the UTF-8 encoding of '\uFFFD', the replacement rune.
type Decoder struct {
	transform.Transformer

	// This forces external creators of Decoders to use names in struct
	// initializers, allowing for future extendibility without having to break
	// code.
	_ struct{}
}

// Bytes converts the given encoded bytes to UTF-8. It returns the converted
// bytes or nil, err if any error occurred.
func (d *Decoder) Bytes(b []byte) ([]byte, error) {
	b, _, err := transform.Bytes(d, b)
	if err != nil {
		return nil, err
	}
	return b, nil
}

// String converts the given encoded string to UTF-8. It returns the converted
// string or "", err if any error occurred.
func (d *Decoder) String(s string) (string, error) {
	s, _, err := transform.String(d, s)
	if err != nil {
		return "", err
	}
	return s, nil
}

// Reader wraps another Reader to decode its bytes.
//
// The Decoder may not be used for any other operation as long as the returned
// Reader is in use.
func (d *Decoder) Reader(r io.Reader) io.Reader {
	return transform.NewReader(r, d)
}

// An Encoder converts bytes from UTF-8. It implements transform.Transformer.
//
// Each rune that cannot be transcoded will result in an error. In this case,
// the transform will consume all source byte up to, not including the offending
// rune. Transforming source bytes that are not valid UTF-8 will be replaced by
// `\uFFFD`. To return early with an error instead, use transform.Chain to
// preprocess the data with a UTF8Validator.
type Encoder struct {
	transform.Transformer

	// This forces external creators of Encoders to use names in struct
	// initializers, allowing for future extendibility without having to break
	// code.
	_ struct{}
}

// Bytes converts bytes from UTF-8. It returns the converted bytes or nil, err if
// any error occurred.
func (e *Encoder) Bytes(b []byte) ([]byte, error) {
	b, _, err := transform.Bytes(e, b)
	if err != nil {
		return nil, err
	}
	return b, nil
}

// String converts a string from UTF-8. It returns the converted string or
// "", err if any error occurred.
func (e *Encoder) String(s string) (string, error) {
	s, _, err := transform.String(e, s)
	if err != nil {
		return "", err
	}
	return s, nil
}

// Writer wraps another Writer to encode its UTF-8 output.
//
// The Encoder may not be used for any other operation as long as the returned
// Writer is in use.
func (e *Encoder) Writer(w io.Writer) io.Writer {
	return transform.NewWriter(w, e)
}

// ASCIISub is the ASCII substitute character, as recommended by
// http://unicode.org/reports/tr36/#Text_Comparison
const ASCIISub = '\x1a'

// Nop is the nop encoding. Its transformed bytes are the same as the source
// bytes; it does not replace invalid UTF-8 sequences.
var Nop Encoding = nop{}

type nop struct{}

func (nop) NewDecoder() *Decoder {
	return &Decoder{Transformer: transform.Nop}
}
func (nop) NewEncoder() *Encoder {
	return &Encoder{Transformer: transform.Nop}
}

// Replacement is the replacement encoding. Decoding from the replacement
// encoding yields a single '\uFFFD' replacement rune. Encoding from UTF-8 to
// the replacement encoding yields the same as the source bytes except that
// invalid UTF-8 is converted to '\uFFFD'.
//
// It is defined at http://encoding.spec.whatwg.org/#replacement
var Replacement Encoding = replacement{}

type replacement struct{}

func (replacement) NewDecoder() *Decoder {
	return &Decoder{Transformer: replacementDecoder{}}
}

func (replacement) NewEncoder() *Encoder {
	return &Encoder{Transformer: replacementEncoder{}}
}

func (replacement) ID() (mib identifier.MIB, other string) {
	return identifier.Replacement, ""
}

type replacementDecoder struct{ transform.NopResetter }

func (replacementDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	if len(dst) < 3 {
		return 0, 0, transform.ErrShortDst
	}
	if atEOF {
		const fffd = "\ufffd"
		dst[0] = fffd[0]
		dst[1] = fffd[1]
		dst[2] = fffd[2]
		nDst = 3
	}
	return nDst, len(src), nil
}

type replacementEncoder struct{ transform.NopResetter }

func (replacementEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	r, size := rune(0), 0

	for ; nSrc < len(src); nSrc += size {
		r = rune(src[nSrc])

		// Decode a 1-byte rune.
		if r < utf8.RuneSelf {
			size = 1

		} else {
			// Decode a multi-byte rune.
			r, size = utf8.DecodeRune(src[nSrc:])
			if size == 1 {
				// All valid runes of size 1 (those below utf8.RuneSelf) were
				// handled above. We have invalid UTF-8 or we haven't seen the
				// full character yet.
				if !atEOF && !utf8.FullRune(src[nSrc:]) {
					err = transform.ErrShortSrc
					break
				}
				r = '\ufffd'
			}
		}

		if nDst+utf8.RuneLen(r) > len(dst) {
			err = transform.ErrShortDst
			break
		}
		nDst += utf8.EncodeRune(dst[nDst:], r)
	}
	return nDst, nSrc, err
}

// HTMLEscapeUnsupported wraps encoders to replace source runes outside the
// repertoire of the destination encoding with HTML escape sequences.
//
// This wrapper exists to comply to URL and HTML forms requiring a
// non-terminating legacy encoder. The produced sequences may lead to data
// loss as they are indistinguishable from legitimate input. To avoid this
// issue, use UTF-8 encodings whenever possible.
func HTMLEscapeUnsupported(e *Encoder) *Encoder {
	return &Encoder{Transformer: &errorHandler{e, errorToHTML}}
}

// ReplaceUnsupported wraps encoders to replace source runes outside the
// repertoire of the destination encoding with an encoding-specific
// replacement.
//
// This wrapper is only provided for backwards compatibility and legacy
// handling. Its use is strongly discouraged. Use UTF-8 whenever possible.
func ReplaceUnsupported(e *Encoder) *Encoder {
	return &Encoder{Transformer: &errorHandler{e, errorToReplacement}}
}

type errorHandler struct {
	*Encoder
	handler func(dst []byte, r rune, err repertoireError) (n int, ok bool)
}

// TODO: consider making this error public in some form.
type repertoireError interface {
	Replacement() byte
}

func (h errorHandler) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	nDst, nSrc, err = h.Transformer.Transform(dst, src, atEOF)
	for err != nil {
		rerr, ok := err.(repertoireError)
		if !ok {
			return nDst, nSrc, err
		}
		r, sz := utf8.DecodeRune(src[nSrc:])
		n, ok := h.handler(dst[nDst:], r, rerr)
		if !ok {
			return nDst, nSrc, transform.ErrShortDst
		}
		err = nil
		nDst += n
		if nSrc += sz; nSrc < len(src) {
			var dn, sn int
			dn, sn, err = h.Transformer.Transform(dst[nDst:], src[nSrc:], atEOF)
			nDst += dn
			nSrc += sn
		}
	}
	return nDst, nSrc, err
}

func errorToHTML(dst []byte, r rune, err repertoireError) (n int, ok bool) {
	buf := [8]byte{}
	b := strconv.AppendUint(buf[:0], uint64(r), 10)
	if n = len(b) + len("&#;"); n >= len(dst) {
		return 0, false
	}
	dst[0] = '&'
	dst[1] = '#'
	dst[copy(dst[2:], b)+2] = ';'
	return n, true
}

func errorToReplacement(dst []byte, r rune, err repertoireError) (n int, ok bool) {
	if len(dst) == 0 {
		return 0, false
	}
	dst[0] = err.Replacement()
	return 1, true
}

// ErrInvalidUTF8 means that a transformer encountered invalid UTF-8.
var ErrInvalidUTF8 = errors.New("encoding: invalid UTF-8")

// UTF8Validator is a transformer that returns ErrInvalidUTF8 on the first
// input byte that is not valid UTF-8.
var UTF8Validator transform.Transformer = utf8Validator{}

type utf8Validator struct{ transform.NopResetter }

func (utf8Validator) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	n := len(src)
	if n > len(dst) {
		n = len(dst)
	}
	for i := 0; i < n; {
		if c := src[i]; c < utf8.RuneSelf {
			dst[i] = c
			i++
			continue
		}
		_, size := utf8.DecodeRune(src[i:])
		if size == 1 {
			// All valid runes of size 1 (those below utf8.RuneSelf) were
			// handled above. We have invalid UTF-8 or we haven't seen the
			// full character yet.
			err = ErrInvalidUTF8
			if !atEOF && !utf8.FullRune(src[i:]) {
				err = transform.ErrShortSrc
			}
			return i, i, err
		}
		if i+size > len(dst) {
			return i, i, transform.ErrShortDst
		}
		for ; size > 0; size-- {
			dst[i] = src[i]
			i++
		}
	}
	if len(src) > len(dst) {
		err = transform.ErrShortDst
	}
	return n, n, err
}
<|endoftext|>


<commit_before>package osm

import (
	"fmt"

	"github.com/ctessum/geom"
	"github.com/ctessum/geom/op"
	"github.com/qedus/osmpbf"
)

// GeomTags holds a geometry object and the tags that apply to it.
type GeomTags struct {
	geom.Geom
	Tags map[string]string
}

// Geom converts the OSM data to geometry objects, keeping the tag information.
func (o *Data) Geom() ([]*GeomTags, error) {

	items := make([]*GeomTags, 0, len(o.Ways))
	for _, r := range o.Relations {
		if _, ok := o.dependentRelations[r.ID]; !ok {
			g, err := relationToGeom(r, o.Relations, o.Ways, o.Nodes)
			if err != nil {
				return nil, err
			}
			items = append(items, &GeomTags{
				Geom: g,
				Tags: r.Tags,
			})
		}
	}
	for _, w := range o.Ways {
		if _, ok := o.dependentWays[w.ID]; !ok {
			items = append(items, &GeomTags{
				Geom: wayToGeom(w, o.Nodes),
				Tags: w.Tags,
			})
		}
	}
	for _, n := range o.Nodes {
		if _, ok := o.dependentNodes[n.ID]; !ok {
			items = append(items, &GeomTags{
				Geom: nodeToPoint(n),
				Tags: n.Tags,
			})
		}
	}
	return items, nil
}

func nodeToPoint(n *osmpbf.Node) geom.Point {
	return geom.Point{X: n.Lon, Y: n.Lat}
}

func wayToGeom(way *osmpbf.Way, nodes map[int64]*osmpbf.Node) geom.Geom {
	if wayIsClosed(way) {
		return wayToPolygon(way, nodes)
	}
	return wayToLineString(way, nodes)
}

// wayIsClosed determines whether a way represents a polygon.
func wayIsClosed(way *osmpbf.Way) bool {
	return way.NodeIDs[0] == way.NodeIDs[len(way.NodeIDs)-1]
}

// wayToPolygon converts a way to a polygon
func wayToPolygon(way *osmpbf.Way, nodes map[int64]*osmpbf.Node) geom.Polygon {
	p := make(geom.Polygon, 1)
	for _, nid := range way.NodeIDs {
		p[0] = append(p[0], nodeToPoint(nodes[nid]))
	}
	return p
}

// wayToLineString converts a way to a LineString
func wayToLineString(way *osmpbf.Way, nodes map[int64]*osmpbf.Node) geom.LineString {
	var p geom.LineString
	for _, nid := range way.NodeIDs {
		p = append(p, nodeToPoint(nodes[nid]))
	}
	return p
}

// relationToGeom converts a relation to a geometry object.
func relationToGeom(relation *osmpbf.Relation,
	relations map[int64]*osmpbf.Relation, ways map[int64]*osmpbf.Way,
	nodes map[int64]*osmpbf.Node) (geom.Geom, error) {

	var nNodes, nLines, nPolygons int
	for _, m := range relation.Members {
		switch m.Type {
		case osmpbf.WayType:
			if wayIsClosed(ways[m.ID]) {
				nPolygons++
			} else {
				nLines++
			}
		case osmpbf.NodeType:
			nNodes++
		}
	}
	if nPolygons == len(relation.Members) {
		return relationToPolygon(relation, ways, nodes)
	}
	if nLines == len(relation.Members) {
		return relationToMultiLineString(relation, ways, nodes), nil
	}
	if nNodes == len(relation.Members) {
		return relationToMultiPoint(relation, nodes), nil
	}
	return relationToGeometryCollection(relation, relations, ways, nodes)
}

// relationToMultiPoint converts a relation to a MultiPoint
func relationToMultiPoint(relation *osmpbf.Relation,
	nodes map[int64]*osmpbf.Node) geom.MultiPoint {

	p := make(geom.MultiPoint, len(relation.Members))
	for i, m := range relation.Members {
		switch m.Type {
		case osmpbf.NodeType:
			p[i] = nodeToPoint(nodes[m.ID])
		default:
			panic(fmt.Errorf("unsupported relation type %v", m.Type))
		}
	}
	return p
}

// relationToPolygon converts a relation to a polygon
func relationToPolygon(relation *osmpbf.Relation, ways map[int64]*osmpbf.Way,
	nodes map[int64]*osmpbf.Node) (geom.Polygon, error) {
	var p geom.Polygon
	for _, m := range relation.Members {
		switch m.Type {
		case osmpbf.WayType:
			p = append(p, wayToPolygon(ways[m.ID], nodes)[0])
		default:
			panic(fmt.Errorf("unsupported relation type %v", m.Type))
		}
	}
	if err := op.FixOrientation(p); err != nil {
		return nil, err
	}
	return p, nil
}

// relationToMultiLineString converts a relation to a MultiLineString,
// deleting its contained elements from 'ways' and 'nodes'.
func relationToMultiLineString(relation *osmpbf.Relation, ways map[int64]*osmpbf.Way,
	nodes map[int64]*osmpbf.Node) geom.MultiLineString {
	var p geom.MultiLineString
	for _, m := range relation.Members {
		switch m.Type {
		case osmpbf.WayType:
			p = append(p, wayToLineString(ways[m.ID], nodes))
		default:
			panic(fmt.Errorf("unsupported relation type %v", m.Type))
		}
	}
	return p
}

func relationToGeometryCollection(relation *osmpbf.Relation,
	relations map[int64]*osmpbf.Relation, ways map[int64]*osmpbf.Way,
	nodes map[int64]*osmpbf.Node) (geom.Geom, error) {

	p := make(geom.GeometryCollection, len(relation.Members))
	for i, m := range relation.Members {
		switch m.Type {
		case osmpbf.WayType:
			p[i] = wayToGeom(ways[m.ID], nodes)
		case osmpbf.NodeType:
			p[i] = nodeToPoint(nodes[m.ID])
		case osmpbf.RelationType:
			var err error
			p[i], err = relationToGeom(relations[m.ID], relations, ways, nodes)
			if err != nil {
				return nil, err
			}
		default:
			panic(fmt.Errorf("unsupported relation type %v", m.Type))
		}
	}
	return p, nil
}

type GeomType int

const (
	Point GeomType = iota
	Line
	Poly
	Collection
)

// DominantType returns the most frequently occurring type among the
// given features.
func DominantType(gt []*GeomTags) (GeomType, error) {
	var points, lines, polys, collections int
	for _, g := range gt {
		switch g.Geom.(type) {
		case geom.Point:
			points++
		case geom.MultiPoint:
			points++
		case geom.LineString:
			lines++
		case geom.Polygon:
			polys++
		case geom.GeometryCollection:
			collections++
			continue
		default:
			return -1, fmt.Errorf("invalid geometry type %#v", g.Geom)
		}
	}
	fmt.Println(points, lines, polys)
	if points >= lines && points >= polys && points >= collections {
		return Point, nil
	}
	if lines > points && lines >= polys && lines >= collections {
		return Line, nil
	}
	if polys > points && polys > lines && polys >= collections {
		return Poly, nil
	}
	return Collection, nil
}
<commit_msg>Remove print statement<commit_after>package osm

import (
	"fmt"

	"github.com/ctessum/geom"
	"github.com/ctessum/geom/op"
	"github.com/qedus/osmpbf"
)

// GeomTags holds a geometry object and the tags that apply to it.
type GeomTags struct {
	geom.Geom
	Tags map[string]string
}

// Geom converts the OSM data to geometry objects, keeping the tag information.
func (o *Data) Geom() ([]*GeomTags, error) {

	items := make([]*GeomTags, 0, len(o.Ways))
	for _, r := range o.Relations {
		if _, ok := o.dependentRelations[r.ID]; !ok {
			g, err := relationToGeom(r, o.Relations, o.Ways, o.Nodes)
			if err != nil {
				return nil, err
			}
			items = append(items, &GeomTags{
				Geom: g,
				Tags: r.Tags,
			})
		}
	}
	for _, w := range o.Ways {
		if _, ok := o.dependentWays[w.ID]; !ok {
			items = append(items, &GeomTags{
				Geom: wayToGeom(w, o.Nodes),
				Tags: w.Tags,
			})
		}
	}
	for _, n := range o.Nodes {
		if _, ok := o.dependentNodes[n.ID]; !ok {
			items = append(items, &GeomTags{
				Geom: nodeToPoint(n),
				Tags: n.Tags,
			})
		}
	}
	return items, nil
}

func nodeToPoint(n *osmpbf.Node) geom.Point {
	return geom.Point{X: n.Lon, Y: n.Lat}
}

func wayToGeom(way *osmpbf.Way, nodes map[int64]*osmpbf.Node) geom.Geom {
	if wayIsClosed(way) {
		return wayToPolygon(way, nodes)
	}
	return wayToLineString(way, nodes)
}

// wayIsClosed determines whether a way represents a polygon.
func wayIsClosed(way *osmpbf.Way) bool {
	return way.NodeIDs[0] == way.NodeIDs[len(way.NodeIDs)-1]
}

// wayToPolygon converts a way to a polygon
func wayToPolygon(way *osmpbf.Way, nodes map[int64]*osmpbf.Node) geom.Polygon {
	p := make(geom.Polygon, 1)
	for _, nid := range way.NodeIDs {
		p[0] = append(p[0], nodeToPoint(nodes[nid]))
	}
	return p
}

// wayToLineString converts a way to a LineString
func wayToLineString(way *osmpbf.Way, nodes map[int64]*osmpbf.Node) geom.LineString {
	var p geom.LineString
	for _, nid := range way.NodeIDs {
		p = append(p, nodeToPoint(nodes[nid]))
	}
	return p
}

// relationToGeom converts a relation to a geometry object.
func relationToGeom(relation *osmpbf.Relation,
	relations map[int64]*osmpbf.Relation, ways map[int64]*osmpbf.Way,
	nodes map[int64]*osmpbf.Node) (geom.Geom, error) {

	var nNodes, nLines, nPolygons int
	for _, m := range relation.Members {
		switch m.Type {
		case osmpbf.WayType:
			if wayIsClosed(ways[m.ID]) {
				nPolygons++
			} else {
				nLines++
			}
		case osmpbf.NodeType:
			nNodes++
		}
	}
	if nPolygons == len(relation.Members) {
		return relationToPolygon(relation, ways, nodes)
	}
	if nLines == len(relation.Members) {
		return relationToMultiLineString(relation, ways, nodes), nil
	}
	if nNodes == len(relation.Members) {
		return relationToMultiPoint(relation, nodes), nil
	}
	return relationToGeometryCollection(relation, relations, ways, nodes)
}

// relationToMultiPoint converts a relation to a MultiPoint
func relationToMultiPoint(relation *osmpbf.Relation,
	nodes map[int64]*osmpbf.Node) geom.MultiPoint {

	p := make(geom.MultiPoint, len(relation.Members))
	for i, m := range relation.Members {
		switch m.Type {
		case osmpbf.NodeType:
			p[i] = nodeToPoint(nodes[m.ID])
		default:
			panic(fmt.Errorf("unsupported relation type %v", m.Type))
		}
	}
	return p
}

// relationToPolygon converts a relation to a polygon
func relationToPolygon(relation *osmpbf.Relation, ways map[int64]*osmpbf.Way,
	nodes map[int64]*osmpbf.Node) (geom.Polygon, error) {
	var p geom.Polygon
	for _, m := range relation.Members {
		switch m.Type {
		case osmpbf.WayType:
			p = append(p, wayToPolygon(ways[m.ID], nodes)[0])
		default:
			panic(fmt.Errorf("unsupported relation type %v", m.Type))
		}
	}
	if err := op.FixOrientation(p); err != nil {
		return nil, err
	}
	return p, nil
}

// relationToMultiLineString converts a relation to a MultiLineString,
// deleting its contained elements from 'ways' and 'nodes'.
func relationToMultiLineString(relation *osmpbf.Relation, ways map[int64]*osmpbf.Way,
	nodes map[int64]*osmpbf.Node) geom.MultiLineString {
	var p geom.MultiLineString
	for _, m := range relation.Members {
		switch m.Type {
		case osmpbf.WayType:
			p = append(p, wayToLineString(ways[m.ID], nodes))
		default:
			panic(fmt.Errorf("unsupported relation type %v", m.Type))
		}
	}
	return p
}

func relationToGeometryCollection(relation *osmpbf.Relation,
	relations map[int64]*osmpbf.Relation, ways map[int64]*osmpbf.Way,
	nodes map[int64]*osmpbf.Node) (geom.Geom, error) {

	p := make(geom.GeometryCollection, len(relation.Members))
	for i, m := range relation.Members {
		switch m.Type {
		case osmpbf.WayType:
			p[i] = wayToGeom(ways[m.ID], nodes)
		case osmpbf.NodeType:
			p[i] = nodeToPoint(nodes[m.ID])
		case osmpbf.RelationType:
			var err error
			p[i], err = relationToGeom(relations[m.ID], relations, ways, nodes)
			if err != nil {
				return nil, err
			}
		default:
			panic(fmt.Errorf("unsupported relation type %v", m.Type))
		}
	}
	return p, nil
}

type GeomType int

const (
	Point GeomType = iota
	Line
	Poly
	Collection
)

// DominantType returns the most frequently occurring type among the
// given features.
func DominantType(gt []*GeomTags) (GeomType, error) {
	var points, lines, polys, collections int
	for _, g := range gt {
		switch g.Geom.(type) {
		case geom.Point:
			points++
		case geom.MultiPoint:
			points++
		case geom.LineString:
			lines++
		case geom.Polygon:
			polys++
		case geom.GeometryCollection:
			collections++
			continue
		default:
			return -1, fmt.Errorf("invalid geometry type %#v", g.Geom)
		}
	}
	if points >= lines && points >= polys && points >= collections {
		return Point, nil
	}
	if lines > points && lines >= polys && lines >= collections {
		return Line, nil
	}
	if polys > points && polys > lines && polys >= collections {
		return Poly, nil
	}
	return Collection, nil
}
<|endoftext|>


<commit_before>package entities

import (
	"regexp"
	"strconv"

	"github.com/pkg/errors"
)

type Project struct {
	ID            ProjectID
	Title         string
	Link          string
	Description   string
	IssueTypes    []TypeID
	ActivityTypes []TypeID
}

type Tracker struct {
	ID          int64
	URL         string
	Type        string
	Credentials Credentials
}

type Credentials struct {
	Login    string
	Password string
}

type TypeID struct {
	ID   int64
	Name string
}

type Issue struct {
	ID          IssueID
	ProjectID   ProjectID `json:"-"`
	Type        TypeID
	Title       string
	Description string
	Estimate    int64
	DueDate     int64
	Done        Progress
	Spent       int64
	URL         string
}

type NewIssue struct {
	Issue
	// Be carefule with NewIssue type
	// Type field inside Issue will be empty
	// We have only id of Type with NewIssue
	Type int64
}

type User struct {
	ID   int64
	Name string
	Mail string
}

type Report struct {
	IssueID    int64
	ActivityID int64
	Comments   string
	Duration   int64 //In seconds
	Started    int64
}

type Pagination struct {
	Offset int
	Limit  int
}

type ProjectID int64
type IssueID int64
type Progress int

type IssueURL string

var issueIDRegexp = regexp.MustCompile(`/issues/([0-9]+)`)

func (u IssueURL) IssueID() (IssueID, error) {
	strID := issueIDRegexp.FindStringSubmatch(string(u))
	if strID == nil {
		return 0, errors.Wrapf(ErrIssueURL, "invalid issue URL %s", u)
	}
	id, err := strconv.ParseInt(strID[1], 10, 0)
	if err != nil {
		return 0, errors.Wrapf(ErrIssueURL, "failed to parse id from URL %s", u)
	}
	return IssueID(id), nil
}
<commit_msg>Remove unused parsing<commit_after>package entities

type Project struct {
	ID            ProjectID
	Title         string
	Link          string
	Description   string
	IssueTypes    []TypeID
	ActivityTypes []TypeID
}

type Tracker struct {
	ID          int64
	URL         string
	Type        string
	Credentials Credentials
}

type Credentials struct {
	Login    string
	Password string
}

type TypeID struct {
	ID   int64
	Name string
}

type Issue struct {
	ID          IssueID
	ProjectID   ProjectID `json:"-"`
	Type        TypeID
	Title       string
	Description string
	Estimate    int64
	DueDate     int64
	Done        Progress
	Spent       int64
	URL         string
}

type NewIssue struct {
	Issue
	// Be carefule with NewIssue type
	// Type field inside Issue will be empty
	// We have only id of Type with NewIssue
	Type int64
}

type User struct {
	ID   int64
	Name string
	Mail string
}

type Report struct {
	IssueID    int64
	ActivityID int64
	Comments   string
	Duration   int64 //In seconds
	Started    int64
}

type Pagination struct {
	Offset int
	Limit  int
}

type ProjectID int64
type IssueID int64
type Progress int
type IssueURL string
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/network"
)

func TestNetworkConnectError(t *testing.T) {
	client := &Client{
		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
	}

	err := client.NetworkConnect(context.Background(), "network_id", "container_id", nil)
	if err == nil || err.Error() != "Error response from daemon: Server error" {
		t.Fatalf("expected a Server Error, got %v", err)
	}
}

func TestNetworkConnectEmptyNilEndpointSettings(t *testing.T) {
	expectedURL := "/networks/network_id/connect"

	client := &Client{
		client: newMockClient(func(req *http.Request) (*http.Response, error) {
			if !strings.HasPrefix(req.URL.Path, expectedURL) {
				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
			}

			if req.Method != "POST" {
				return nil, fmt.Errorf("expected POST method, got %s", req.Method)
			}

			var connect types.NetworkConnect
			if err := json.NewDecoder(req.Body).Decode(&connect); err != nil {
				return nil, err
			}

			if connect.Container != "container_id" {
				return nil, fmt.Errorf("expected 'container_id', got %s", connect.Container)
			}

			if connect.EndpointConfig != nil {
				return nil, fmt.Errorf("expected connect.EndpointConfig to be nil, got %v", connect.EndpointConfig)
			}

			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       ioutil.NopCloser(bytes.NewReader([]byte(""))),
			}, nil
		}),
	}

	err := client.NetworkConnect(context.Background(), "network_id", "container_id", nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestNetworkConnect(t *testing.T) {
	expectedURL := "/networks/network_id/connect"

	client := &Client{
		client: newMockClient(func(req *http.Request) (*http.Response, error) {
			if !strings.HasPrefix(req.URL.Path, expectedURL) {
				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
			}

			if req.Method != "POST" {
				return nil, fmt.Errorf("expected POST method, got %s", req.Method)
			}

			var connect types.NetworkConnect
			if err := json.NewDecoder(req.Body).Decode(&connect); err != nil {
				return nil, err
			}

			if connect.Container != "container_id" {
				return nil, fmt.Errorf("expected 'container_id', got %s", connect.Container)
			}

			if connect.EndpointConfig.NetworkID != "NetworkID" {
				return nil, fmt.Errorf("expected 'NetworkID', got %s", connect.EndpointConfig.NetworkID)
			}

			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       ioutil.NopCloser(bytes.NewReader([]byte(""))),
			}, nil
		}),
	}

	err := client.NetworkConnect(context.Background(), "network_id", "container_id", &network.EndpointSettings{
		NetworkID: "NetworkID",
	})
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>add test case check connect.EndpointConfig not nil<commit_after>package client

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"testing"

	"golang.org/x/net/context"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/network"
)

func TestNetworkConnectError(t *testing.T) {
	client := &Client{
		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
	}

	err := client.NetworkConnect(context.Background(), "network_id", "container_id", nil)
	if err == nil || err.Error() != "Error response from daemon: Server error" {
		t.Fatalf("expected a Server Error, got %v", err)
	}
}

func TestNetworkConnectEmptyNilEndpointSettings(t *testing.T) {
	expectedURL := "/networks/network_id/connect"

	client := &Client{
		client: newMockClient(func(req *http.Request) (*http.Response, error) {
			if !strings.HasPrefix(req.URL.Path, expectedURL) {
				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
			}

			if req.Method != "POST" {
				return nil, fmt.Errorf("expected POST method, got %s", req.Method)
			}

			var connect types.NetworkConnect
			if err := json.NewDecoder(req.Body).Decode(&connect); err != nil {
				return nil, err
			}

			if connect.Container != "container_id" {
				return nil, fmt.Errorf("expected 'container_id', got %s", connect.Container)
			}

			if connect.EndpointConfig != nil {
				return nil, fmt.Errorf("expected connect.EndpointConfig to be nil, got %v", connect.EndpointConfig)
			}

			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       ioutil.NopCloser(bytes.NewReader([]byte(""))),
			}, nil
		}),
	}

	err := client.NetworkConnect(context.Background(), "network_id", "container_id", nil)
	if err != nil {
		t.Fatal(err)
	}
}

func TestNetworkConnect(t *testing.T) {
	expectedURL := "/networks/network_id/connect"

	client := &Client{
		client: newMockClient(func(req *http.Request) (*http.Response, error) {
			if !strings.HasPrefix(req.URL.Path, expectedURL) {
				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
			}

			if req.Method != "POST" {
				return nil, fmt.Errorf("expected POST method, got %s", req.Method)
			}

			var connect types.NetworkConnect
			if err := json.NewDecoder(req.Body).Decode(&connect); err != nil {
				return nil, err
			}

			if connect.Container != "container_id" {
				return nil, fmt.Errorf("expected 'container_id', got %s", connect.Container)
			}

			if connect.EndpointConfig == nil {
				return nil, fmt.Errorf("expected connect.EndpointConfig to be not nil, got %v", connect.EndpointConfig)
			}

			if connect.EndpointConfig.NetworkID != "NetworkID" {
				return nil, fmt.Errorf("expected 'NetworkID', got %s", connect.EndpointConfig.NetworkID)
			}

			return &http.Response{
				StatusCode: http.StatusOK,
				Body:       ioutil.NopCloser(bytes.NewReader([]byte(""))),
			}, nil
		}),
	}

	err := client.NetworkConnect(context.Background(), "network_id", "container_id", &network.EndpointSettings{
		NetworkID: "NetworkID",
	})
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package scanner

import (
	"fmt"
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"
)

// tokenType identifies the type of lexical tokens.
type tokenType int

// String returns a string representation of the token type.
func (t tokenType) String() string {
	return tokenNames[t]
}

// Token represents a token and the corresponding string.
type Token struct {
	Type   tokenType
	Value  string
	Line   int
	Column int
}

// String returns a string representation of the token.
func (t *Token) String() string {
	if len(t.Value) > 10 {
		return fmt.Sprintf("%s (line: %d, column: %d): %.10q...",
			t.Type, t.Line, t.Column, t.Value)
	}
	return fmt.Sprintf("%s (line: %d, column: %d): %q",
		t.Type, t.Line, t.Column, t.Value)
}

// All tokens -----------------------------------------------------------------

// The complete list of tokens in CSS3.
const (
	// Scanner flags.
	TokenError tokenType = iota
	TokenEOF
	// From now on, only tokens from the CSS specification.
	TokenIdent
	TokenAtKeyword
	TokenString
	TokenHash
	TokenNumber
	TokenPercentage
	TokenDimension
	TokenURI
	TokenUnicodeRange
	TokenCDO
	TokenCDC
	TokenS
	TokenComment
	TokenFunction
	TokenIncludes
	TokenDashMatch
	TokenPrefixMatch
	TokenSuffixMatch
	TokenSubstringMatch
	TokenChar
	TokenBOM
)

// tokenNames maps tokenType's to their names. Used for conversion to string.
var tokenNames = map[tokenType]string{
	TokenError:          "error",
	TokenEOF:            "EOF",
	TokenIdent:          "IDENT",
	TokenAtKeyword:      "ATKEYWORD",
	TokenString:         "STRING",
	TokenHash:           "HASH",
	TokenNumber:         "NUMBER",
	TokenPercentage:     "PERCENTAGE",
	TokenDimension:      "DIMENSION",
	TokenURI:            "URI",
	TokenUnicodeRange:   "UNICODE-RANGE",
	TokenCDO:            "CDO",
	TokenCDC:            "CDC",
	TokenS:              "S",
	TokenComment:        "COMMENT",
	TokenFunction:       "FUNCTION",
	TokenIncludes:       "INCLUDES",
	TokenDashMatch:      "DASHMATCH",
	TokenPrefixMatch:    "PREFIXMATCH",
	TokenSuffixMatch:    "SUFFIXMATCH",
	TokenSubstringMatch: "SUBSTRINGMATCH",
	TokenChar:           "CHAR",
	TokenBOM:            "BOM",
}

// Macros and productions -----------------------------------------------------
// http://www.w3.org/TR/css3-syntax/#tokenization

var macroRegexp = regexp.MustCompile(`\{[a-z]+\}`)

// macros maps macro names to patterns to be expanded.
var macros = map[string]string{
	// must be escaped: `\.+*?()|[]{}^$`
	"ident":      `-?{nmstart}{nmchar}*`,
	"name":       `{nmchar}+`,
	"nmstart":    `[a-zA-Z_]|{nonascii}|{escape}`,
	"nonascii":   "[\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]",
	"unicode":    `\\[0-9a-fA-F]{1,6}{wc}?`,
	"escape":     "{unicode}|\\[\u0020-\u007E\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]",
	"nmchar":     `[a-zA-Z0-9_-]|{nonascii}|{escape}`,
	"num":        `[0-9]+|[0-9]*\.[0-9]+`,
	"string":     `"(?:{stringchar}|')*"|'(?:{stringchar}|")*'`,
	"stringchar": `{urlchar}|[ ]|\\{nl}`,
	"urlchar":    "[\u0009\u0021\u0023-\u0026\u0027-\u007E]|{nonascii}|{escape}",
	"nl":         `[\n\r\f]|\r\n`,
	"w":          `{wc}*`,
	"wc":         `[\t\n\f\r ]`,
}

// productions maps the list of tokens to patterns to be expanded.
var productions = map[tokenType]string{
	// Unused regexps (matched using other methods) are commented out.
	TokenIdent:        `{ident}`,
	TokenAtKeyword:    `@{ident}`,
	TokenString:       `{string}`,
	TokenHash:         `#{name}`,
	TokenNumber:       `{num}`,
	TokenPercentage:   `{num}%`,
	TokenDimension:    `{num}{ident}`,
	TokenURI:          `url\({w}(?:{string}|{urlchar}*){w}\)`,
	TokenUnicodeRange: `U\+[0-9A-F\?]{1,6}(?:-[0-9A-F]{1,6})?`,
	//TokenCDO:            `<!--`,
	TokenCDC:      `-->`,
	TokenS:        `{wc}+`,
	TokenComment:  `/\*[^\*]*[\*]+(?:[^/][^\*]*[\*]+)*/`,
	TokenFunction: `{ident}\(`,
	//TokenIncludes:       `~=`,
	//TokenDashMatch:      `\|=`,
	//TokenPrefixMatch:    `\^=`,
	//TokenSuffixMatch:    `\$=`,
	//TokenSubstringMatch: `\*=`,
	//TokenChar:           `[^"']`,
	//TokenBOM:            "\uFEFF",
}

// matchers maps the list of tokens to compiled regular expressions.
//
// The map is filled on init() using the macros and productions defined in
// the CSS specification.
var matchers = map[tokenType]*regexp.Regexp{}

// matchOrder is the order to test regexps when first-char shortcuts
// can't be used.
var matchOrder = []tokenType{
	TokenURI,
	TokenFunction,
	TokenUnicodeRange,
	TokenIdent,
	TokenDimension,
	TokenPercentage,
	TokenNumber,
	TokenCDC,
}

func init() {
	// replace macros and compile regexps for productions.
	replaceMacro := func(s string) string {
		return "(?:" + macros[s[1:len(s)-1]] + ")"
	}
	for t, s := range productions {
		for macroRegexp.MatchString(s) {
			s = macroRegexp.ReplaceAllStringFunc(s, replaceMacro)
		}
		matchers[t] = regexp.MustCompile("^(?:" + s + ")")
	}
}

// Scanner --------------------------------------------------------------------

// New returns a new CSS scanner for the given input.
func New(input string) *Scanner {
	// Normalize newlines.
	input = strings.Replace(input, "\r\n", "\n", -1)
	return &Scanner{
		input: input,
		row:   1,
		col:   1,
	}
}

// Scanner scans an input and emits tokens following the CSS3 specification.
type Scanner struct {
	input string
	pos   int
	row   int
	col   int
	err   *Token
}

// Next returns the next token from the input.
//
// At the end of the input the token type is TokenEOF.
//
// If the input can't be tokenized the token type is TokenError. This occurs
// in case of unclosed quotation marks or comments.
func (s *Scanner) Next() *Token {
	if s.err != nil {
		return s.err
	}
	if s.pos >= len(s.input) {
		s.err = &Token{TokenEOF, "", s.row, s.col}
		return s.err
	}
	if s.pos == 0 {
		// Test BOM only once, at the beginning of the file.
		if strings.HasPrefix(s.input, "\uFEFF") {
			return s.emitSimple(TokenBOM, "\uFEFF")
		}
	}
	// There's a lot we can guess based on the first byte so we'll take a
	// shortcut before testing multiple regexps.
	input := s.input[s.pos:]
	switch input[0] {
	case '\t', '\n', '\f', '\r', ' ':
		// Whitespace.
		return s.emitToken(TokenS, matchers[TokenS].FindString(input))
	case '.':
		// Dot is too common to not have a quick check.
		// We'll test if this is a Char; if it is followed by a number it is a
		// dimension/percentage/number, and this will be matched later.
		if len(input) > 1 && !unicode.IsDigit(rune(input[1])) {
			return s.emitSimple(TokenChar, ".")
		}
	case '#':
		// Another common one: Hash or Char.
		if match := matchers[TokenHash].FindString(input); match != "" {
			return s.emitSimple(TokenHash, match)
		}
		return s.emitSimple(TokenChar, "#")
	case '@':
		// Another common one: AtKeyword or Char.
		if match := matchers[TokenAtKeyword].FindString(input); match != "" {
			return s.emitSimple(TokenAtKeyword, match)
		}
		return s.emitSimple(TokenChar, "@")
	case ':', ',', ';', '%', '&', '+', '=', '>', '(', ')', '[', ']', '{', '}':
		// More common chars.
		return s.emitSimple(TokenChar, string(input[0]))
	case '"', '\'':
		// String or error.
		match := matchers[TokenString].FindString(input)
		if match != "" {
			return s.emitToken(TokenString, match)
		} else {
			s.err = &Token{TokenError, "unclosed quotation mark", s.row, s.col}
			return s.err
		}
	case '/':
		// Comment, error or Char.
		if len(input) > 1 && input[1] == '*' {
			match := matchers[TokenComment].FindString(input)
			if match != "" {
				return s.emitToken(TokenComment, match)
			} else {
				s.err = &Token{TokenError, "unclosed comment", s.row, s.col}
				return s.err
			}
		}
		return s.emitSimple(TokenChar, "/")
	case '~':
		// Includes or Char.
		return s.emitPrefixOrChar(TokenIncludes, "~=")
	case '|':
		// DashMatch or Char.
		return s.emitPrefixOrChar(TokenDashMatch, "|=")
	case '^':
		// PrefixMatch or Char.
		return s.emitPrefixOrChar(TokenPrefixMatch, "^=")
	case '$':
		// SuffixMatch or Char.
		return s.emitPrefixOrChar(TokenSuffixMatch, "$=")
	case '*':
		// SubstringMatch or Char.
		return s.emitPrefixOrChar(TokenSubstringMatch, "*=")
	case '<':
		// CDO or Char.
		return s.emitPrefixOrChar(TokenCDO, "<!--")
	}
	// Test all regexps, in order.
	for _, token := range matchOrder {
		if match := matchers[token].FindString(input); match != "" {
			return s.emitToken(token, match)
		}
	}
	// We already handled unclosed quotation marks and comments,
	// so this can only be a Char.
	r, width := utf8.DecodeRuneInString(input)
	token := &Token{TokenChar, string(r), s.row, s.col}
	s.col += width
	s.pos += width
	return token
}

// updatePosition updates input coordinates based on the consumed text.
func (s *Scanner) updatePosition(text string) {
	width := utf8.RuneCountInString(text)
	lines := strings.Count(text, "\n")
	s.row += lines
	if lines == 0 {
		s.col += width
	} else {
		s.col = utf8.RuneCountInString(text[strings.LastIndex(text, "\n"):])
	}
	s.pos += width
}

// emitToken returns a Token for the string v and updates the scanner position.
func (s *Scanner) emitToken(t tokenType, v string) *Token {
	token := &Token{t, v, s.row, s.col}
	s.updatePosition(v)
	return token
}

// emitSimple returns a Token for the string v and updates the scanner
// position in a simplified manner.
//
// The string is known to have only ASCII characters and to not have a newline.
func (s *Scanner) emitSimple(t tokenType, v string) *Token {
	token := &Token{t, v, s.row, s.col}
	s.col += len(v)
	s.pos += len(v)
	return token
}

// emitPrefixOrChar returns a Token for type t if the current position
// matches the given prefix. Otherwise it returns a Char token using the
// first character from the prefix.
//
// The prefix is known to have only ASCII characters and to not have a newline.
func (s *Scanner) emitPrefixOrChar(t tokenType, prefix string) *Token {
	if strings.HasPrefix(s.input[s.pos:], prefix) {
		return s.emitSimple(t, prefix)
	}
	return s.emitSimple(TokenChar, string(prefix[0]))
}
<commit_msg>escape regexp didn't handle \ properly in regex rule<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package scanner

import (
	"fmt"
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"
)

// tokenType identifies the type of lexical tokens.
type tokenType int

// String returns a string representation of the token type.
func (t tokenType) String() string {
	return tokenNames[t]
}

// Token represents a token and the corresponding string.
type Token struct {
	Type   tokenType
	Value  string
	Line   int
	Column int
}

// String returns a string representation of the token.
func (t *Token) String() string {
	if len(t.Value) > 10 {
		return fmt.Sprintf("%s (line: %d, column: %d): %.10q...",
			t.Type, t.Line, t.Column, t.Value)
	}
	return fmt.Sprintf("%s (line: %d, column: %d): %q",
		t.Type, t.Line, t.Column, t.Value)
}

// All tokens -----------------------------------------------------------------

// The complete list of tokens in CSS3.
const (
	// Scanner flags.
	TokenError tokenType = iota
	TokenEOF
	// From now on, only tokens from the CSS specification.
	TokenIdent
	TokenAtKeyword
	TokenString
	TokenHash
	TokenNumber
	TokenPercentage
	TokenDimension
	TokenURI
	TokenUnicodeRange
	TokenCDO
	TokenCDC
	TokenS
	TokenComment
	TokenFunction
	TokenIncludes
	TokenDashMatch
	TokenPrefixMatch
	TokenSuffixMatch
	TokenSubstringMatch
	TokenChar
	TokenBOM
)

// tokenNames maps tokenType's to their names. Used for conversion to string.
var tokenNames = map[tokenType]string{
	TokenError:          "error",
	TokenEOF:            "EOF",
	TokenIdent:          "IDENT",
	TokenAtKeyword:      "ATKEYWORD",
	TokenString:         "STRING",
	TokenHash:           "HASH",
	TokenNumber:         "NUMBER",
	TokenPercentage:     "PERCENTAGE",
	TokenDimension:      "DIMENSION",
	TokenURI:            "URI",
	TokenUnicodeRange:   "UNICODE-RANGE",
	TokenCDO:            "CDO",
	TokenCDC:            "CDC",
	TokenS:              "S",
	TokenComment:        "COMMENT",
	TokenFunction:       "FUNCTION",
	TokenIncludes:       "INCLUDES",
	TokenDashMatch:      "DASHMATCH",
	TokenPrefixMatch:    "PREFIXMATCH",
	TokenSuffixMatch:    "SUFFIXMATCH",
	TokenSubstringMatch: "SUBSTRINGMATCH",
	TokenChar:           "CHAR",
	TokenBOM:            "BOM",
}

// Macros and productions -----------------------------------------------------
// http://www.w3.org/TR/css3-syntax/#tokenization

var macroRegexp = regexp.MustCompile(`\{[a-z]+\}`)

// macros maps macro names to patterns to be expanded.
var macros = map[string]string{
	// must be escaped: `\.+*?()|[]{}^$`
	"ident":      `-?{nmstart}{nmchar}*`,
	"name":       `{nmchar}+`,
	"nmstart":    `[a-zA-Z_]|{nonascii}|{escape}`,
	"nonascii":   "[\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]",
	"unicode":    `\\[0-9a-fA-F]{1,6}{wc}?`,
	"escape":     "{unicode}|\\\\[\u0020-\u007E\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]",
	"nmchar":     `[a-zA-Z0-9_-]|{nonascii}|{escape}`,
	"num":        `[0-9]+|[0-9]*\.[0-9]+`,
	"string":     `"(?:{stringchar}|')*"|'(?:{stringchar}|")*'`,
	"stringchar": `{urlchar}|[ ]|\\{nl}`,
	"urlchar":    "[\u0009\u0021\u0023-\u0026\u0027-\u007E]|{nonascii}|{escape}",
	"nl":         `[\n\r\f]|\r\n`,
	"w":          `{wc}*`,
	"wc":         `[\t\n\f\r ]`,
}

// productions maps the list of tokens to patterns to be expanded.
var productions = map[tokenType]string{
	// Unused regexps (matched using other methods) are commented out.
	TokenIdent:        `{ident}`,
	TokenAtKeyword:    `@{ident}`,
	TokenString:       `{string}`,
	TokenHash:         `#{name}`,
	TokenNumber:       `{num}`,
	TokenPercentage:   `{num}%`,
	TokenDimension:    `{num}{ident}`,
	TokenURI:          `url\({w}(?:{string}|{urlchar}*){w}\)`,
	TokenUnicodeRange: `U\+[0-9A-F\?]{1,6}(?:-[0-9A-F]{1,6})?`,
	//TokenCDO:            `<!--`,
	TokenCDC:      `-->`,
	TokenS:        `{wc}+`,
	TokenComment:  `/\*[^\*]*[\*]+(?:[^/][^\*]*[\*]+)*/`,
	TokenFunction: `{ident}\(`,
	//TokenIncludes:       `~=`,
	//TokenDashMatch:      `\|=`,
	//TokenPrefixMatch:    `\^=`,
	//TokenSuffixMatch:    `\$=`,
	//TokenSubstringMatch: `\*=`,
	//TokenChar:           `[^"']`,
	//TokenBOM:            "\uFEFF",
}

// matchers maps the list of tokens to compiled regular expressions.
//
// The map is filled on init() using the macros and productions defined in
// the CSS specification.
var matchers = map[tokenType]*regexp.Regexp{}

// matchOrder is the order to test regexps when first-char shortcuts
// can't be used.
var matchOrder = []tokenType{
	TokenURI,
	TokenFunction,
	TokenUnicodeRange,
	TokenIdent,
	TokenDimension,
	TokenPercentage,
	TokenNumber,
	TokenCDC,
}

func init() {
	// replace macros and compile regexps for productions.
	replaceMacro := func(s string) string {
		return "(?:" + macros[s[1:len(s)-1]] + ")"
	}
	for t, s := range productions {
		for macroRegexp.MatchString(s) {
			s = macroRegexp.ReplaceAllStringFunc(s, replaceMacro)
		}
		matchers[t] = regexp.MustCompile("^(?:" + s + ")")
	}
}

// Scanner --------------------------------------------------------------------

// New returns a new CSS scanner for the given input.
func New(input string) *Scanner {
	// Normalize newlines.
	input = strings.Replace(input, "\r\n", "\n", -1)
	return &Scanner{
		input: input,
		row:   1,
		col:   1,
	}
}

// Scanner scans an input and emits tokens following the CSS3 specification.
type Scanner struct {
	input string
	pos   int
	row   int
	col   int
	err   *Token
}

// Next returns the next token from the input.
//
// At the end of the input the token type is TokenEOF.
//
// If the input can't be tokenized the token type is TokenError. This occurs
// in case of unclosed quotation marks or comments.
func (s *Scanner) Next() *Token {
	if s.err != nil {
		return s.err
	}
	if s.pos >= len(s.input) {
		s.err = &Token{TokenEOF, "", s.row, s.col}
		return s.err
	}
	if s.pos == 0 {
		// Test BOM only once, at the beginning of the file.
		if strings.HasPrefix(s.input, "\uFEFF") {
			return s.emitSimple(TokenBOM, "\uFEFF")
		}
	}
	// There's a lot we can guess based on the first byte so we'll take a
	// shortcut before testing multiple regexps.
	input := s.input[s.pos:]
	switch input[0] {
	case '\t', '\n', '\f', '\r', ' ':
		// Whitespace.
		return s.emitToken(TokenS, matchers[TokenS].FindString(input))
	case '.':
		// Dot is too common to not have a quick check.
		// We'll test if this is a Char; if it is followed by a number it is a
		// dimension/percentage/number, and this will be matched later.
		if len(input) > 1 && !unicode.IsDigit(rune(input[1])) {
			return s.emitSimple(TokenChar, ".")
		}
	case '#':
		// Another common one: Hash or Char.
		if match := matchers[TokenHash].FindString(input); match != "" {
			return s.emitSimple(TokenHash, match)
		}
		return s.emitSimple(TokenChar, "#")
	case '@':
		// Another common one: AtKeyword or Char.
		if match := matchers[TokenAtKeyword].FindString(input); match != "" {
			return s.emitSimple(TokenAtKeyword, match)
		}
		return s.emitSimple(TokenChar, "@")
	case ':', ',', ';', '%', '&', '+', '=', '>', '(', ')', '[', ']', '{', '}':
		// More common chars.
		return s.emitSimple(TokenChar, string(input[0]))
	case '"', '\'':
		// String or error.
		match := matchers[TokenString].FindString(input)
		if match != "" {
			return s.emitToken(TokenString, match)
		} else {
			s.err = &Token{TokenError, "unclosed quotation mark", s.row, s.col}
			return s.err
		}
	case '/':
		// Comment, error or Char.
		if len(input) > 1 && input[1] == '*' {
			match := matchers[TokenComment].FindString(input)
			if match != "" {
				return s.emitToken(TokenComment, match)
			} else {
				s.err = &Token{TokenError, "unclosed comment", s.row, s.col}
				return s.err
			}
		}
		return s.emitSimple(TokenChar, "/")
	case '~':
		// Includes or Char.
		return s.emitPrefixOrChar(TokenIncludes, "~=")
	case '|':
		// DashMatch or Char.
		return s.emitPrefixOrChar(TokenDashMatch, "|=")
	case '^':
		// PrefixMatch or Char.
		return s.emitPrefixOrChar(TokenPrefixMatch, "^=")
	case '$':
		// SuffixMatch or Char.
		return s.emitPrefixOrChar(TokenSuffixMatch, "$=")
	case '*':
		// SubstringMatch or Char.
		return s.emitPrefixOrChar(TokenSubstringMatch, "*=")
	case '<':
		// CDO or Char.
		return s.emitPrefixOrChar(TokenCDO, "<!--")
	}
	// Test all regexps, in order.
	for _, token := range matchOrder {
		if match := matchers[token].FindString(input); match != "" {
			return s.emitToken(token, match)
		}
	}
	// We already handled unclosed quotation marks and comments,
	// so this can only be a Char.
	r, width := utf8.DecodeRuneInString(input)
	token := &Token{TokenChar, string(r), s.row, s.col}
	s.col += width
	s.pos += width
	return token
}

// updatePosition updates input coordinates based on the consumed text.
func (s *Scanner) updatePosition(text string) {
	width := utf8.RuneCountInString(text)
	lines := strings.Count(text, "\n")
	s.row += lines
	if lines == 0 {
		s.col += width
	} else {
		s.col = utf8.RuneCountInString(text[strings.LastIndex(text, "\n"):])
	}
	s.pos += width
}

// emitToken returns a Token for the string v and updates the scanner position.
func (s *Scanner) emitToken(t tokenType, v string) *Token {
	token := &Token{t, v, s.row, s.col}
	s.updatePosition(v)
	return token
}

// emitSimple returns a Token for the string v and updates the scanner
// position in a simplified manner.
//
// The string is known to have only ASCII characters and to not have a newline.
func (s *Scanner) emitSimple(t tokenType, v string) *Token {
	token := &Token{t, v, s.row, s.col}
	s.col += len(v)
	s.pos += len(v)
	return token
}

// emitPrefixOrChar returns a Token for type t if the current position
// matches the given prefix. Otherwise it returns a Char token using the
// first character from the prefix.
//
// The prefix is known to have only ASCII characters and to not have a newline.
func (s *Scanner) emitPrefixOrChar(t tokenType, prefix string) *Token {
	if strings.HasPrefix(s.input[s.pos:], prefix) {
		return s.emitSimple(t, prefix)
	}
	return s.emitSimple(TokenChar, string(prefix[0]))
}
<|endoftext|>