text:
package rkt

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"syscall"
	"time"

	appcschema "github.com/appc/spec/schema"
	appctypes "github.com/appc/spec/schema/types"
	"github.com/coreos/go-systemd/dbus"
	"github.com/coreos/go-systemd/unit"
	"github.com/docker/docker/pkg/parsers"
	docker "github.com/fsouza/go-dockerclient"
	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/record"
	"k8s.io/kubernetes/pkg/credentialprovider"
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
	"k8s.io/kubernetes/pkg/kubelet/prober"
	"k8s.io/kubernetes/pkg/probe"
	"k8s.io/kubernetes/pkg/securitycontext"
	"k8s.io/kubernetes/pkg/types"
)

const (
	acVersion             = "0.6.1"
	rktMinimumVersion     = "0.7.0"
	systemdMinimumVersion = "219"

	systemdServiceDir = "/run/systemd/system"
	rktDataDir        = "/var/lib/rkt"
	rktLocalConfigDir = "/etc/rkt"

	kubernetesUnitPrefix  = "k8s"
	unitKubernetesSection = "X-Kubernetes"
	unitPodName           = "POD"
	unitRktID             = "RktID"

	dockerPrefix = "docker://"

	authDir            = "auth.d"
	dockerAuthTemplate = `{"rktKind":"dockerAuth","rktVersion":"v1","registries":[%q],"credentials":{"user":%q,"password":%q}}`

	// TODO(yifan): Merge with ContainerGCPolicy, i.e., derive
	// the grace period from MinAge in ContainerGCPolicy.
	//
	// Duration to wait before discarding inactive pods from garbage
	defaultGracePeriod = "1m"
	// Duration to wait before expiring prepared pods.
	defaultExpirePrepared = "1m"
)

// runtime implements the Containerruntime for rkt. The implementation
// uses systemd, so in order to run this runtime, systemd must be installed
// on the machine.
type runtime struct {
	systemd *dbus.Conn
	// The absolute path to rkt binary.
	rktBinAbsPath string
	config        *Config
	// TODO(yifan): Refactor this to be generic keyring.
	dockerKeyring credentialprovider.DockerKeyring

	containerRefManager *kubecontainer.RefManager
	generator           kubecontainer.RunContainerOptionsGenerator
	recorder            record.EventRecorder
	prober              prober.Prober
	readinessManager    *kubecontainer.ReadinessManager
	volumeGetter        volumeGetter
}

var _ kubecontainer.Runtime = &runtime{}

// TODO(yifan): Remove this when volumeManager is moved to separate package.
type volumeGetter interface {
	GetVolumes(podUID types.UID) (kubecontainer.VolumeMap, bool)
}

// New creates the rkt container runtime which implements the container runtime interface.
// It will test if the rkt binary is in the $PATH, and whether we can get the
// version of it. If so, creates the rkt container runtime, otherwise returns an error.
func New(config *Config,
	generator kubecontainer.RunContainerOptionsGenerator,
	recorder record.EventRecorder,
	containerRefManager *kubecontainer.RefManager,
	readinessManager *kubecontainer.ReadinessManager,
	volumeGetter volumeGetter) (kubecontainer.Runtime, error) {

	systemdVersion, err := getSystemdVersion()
	if err != nil {
		return nil, err
	}
	result, err := systemdVersion.Compare(systemdMinimumVersion)
	if err != nil {
		return nil, err
	}
	if result < 0 {
		return nil, fmt.Errorf("rkt: systemd version is too old, requires at least %v", systemdMinimumVersion)
	}

	systemd, err := dbus.New()
	if err != nil {
		return nil, fmt.Errorf("cannot connect to dbus: %v", err)
	}

	// Test if rkt binary is in $PATH.
	// TODO(yifan): Use a kubelet flag to read the path.
	rktBinAbsPath, err := exec.LookPath("rkt")
	if err != nil {
		return nil, fmt.Errorf("cannot find rkt binary: %v", err)
	}

	rkt := &runtime{
		systemd:             systemd,
		rktBinAbsPath:       rktBinAbsPath,
		config:              config,
		dockerKeyring:       credentialprovider.NewDockerKeyring(),
		containerRefManager: containerRefManager,
		generator:           generator,
		recorder:            recorder,
		readinessManager:    readinessManager,
		volumeGetter:        volumeGetter,
	}
	rkt.prober = prober.New(rkt, readinessManager, containerRefManager, recorder)

	// Test the rkt version.
	version, err := rkt.Version()
	if err != nil {
		return nil, err
	}
	result, err = version.Compare(rktMinimumVersion)
	if err != nil {
		return nil, err
	}
	if result < 0 {
		return nil, fmt.Errorf("rkt: Version is too old, requires at least %v", rktMinimumVersion)
	}
	return rkt, nil
}

func (r *runtime) buildCommand(args ...string) *exec.Cmd {
	cmd := exec.Command(r.rktBinAbsPath)
	cmd.Args = append(cmd.Args, r.config.buildGlobalOptions()...)
	cmd.Args = append(cmd.Args, args...)
	return cmd
}

// runCommand invokes rkt binary with arguments and returns the result
// from stdout in a list of strings. Each string in the list is a line.
func (r *runtime) runCommand(args ...string) ([]string, error) {
	glog.V(4).Info("rkt: Run command:", args)

	output, err := r.buildCommand(args...).Output()
	if err != nil {
		return nil, err
	}
	return strings.Split(strings.TrimSpace(string(output)), "\n"), nil
}

// makePodServiceFileName constructs the unit file name for a pod using its UID.
func makePodServiceFileName(uid types.UID) string {
	// TODO(yifan): Add name for readability? We need to consider the
	// limit of the length.
	return fmt.Sprintf("%s_%s.service", kubernetesUnitPrefix, uid)
}

type resource struct {
	limit   string
	request string
}

// rawValue converts a string to *json.RawMessage
func rawValue(value string) *json.RawMessage {
	msg := json.RawMessage(value)
	return &msg
}

// rawValue converts the request, limit to *json.RawMessage
func rawRequestLimit(request, limit string) *json.RawMessage {
	if request == "" {
		return rawValue(fmt.Sprintf(`{"limit":%q}`, limit))
	}
	if limit == "" {
		return rawValue(fmt.Sprintf(`{"request":%q}`, request))
	}
	return rawValue(fmt.Sprintf(`{"request":%q,"limit":%q}`, request, limit))
}

// setIsolators overrides the isolators of the pod manifest if necessary.
// TODO need an apply config in security context for rkt
func setIsolators(app *appctypes.App, c *api.Container) error {
	hasCapRequests := securitycontext.HasCapabilitiesRequest(c)
	if hasCapRequests || len(c.Resources.Limits) > 0 || len(c.Resources.Requests) > 0 {
		app.Isolators = []appctypes.Isolator{}
	}

	// Retained capabilities/privileged.
	privileged := false
	if c.SecurityContext != nil && c.SecurityContext.Privileged != nil {
		privileged = *c.SecurityContext.Privileged
	}

	var addCaps string
	if privileged {
		addCaps = getAllCapabilities()
	} else {
		if hasCapRequests {
			addCaps = getCapabilities(c.SecurityContext.Capabilities.Add)
		}
	}
	if len(addCaps) > 0 {
		// TODO(yifan): Replace with constructor, see:
		// https://github.com/appc/spec/issues/268
		isolator := appctypes.Isolator{
			Name:     "os/linux/capabilities-retain-set",
			ValueRaw: rawValue(fmt.Sprintf(`{"set":[%s]}`, addCaps)),
		}
		app.Isolators = append(app.Isolators, isolator)
	}

	// Removed capabilities.
	var dropCaps string
	if hasCapRequests {
		dropCaps = getCapabilities(c.SecurityContext.Capabilities.Drop)
	}
	if len(dropCaps) > 0 {
		// TODO(yifan): Replace with constructor, see:
		// https://github.com/appc/spec/issues/268
		isolator := appctypes.Isolator{
			Name:     "os/linux/capabilities-remove-set",
			ValueRaw: rawValue(fmt.Sprintf(`{"set":[%s]}`, dropCaps)),
		}
		app.Isolators = append(app.Isolators, isolator)
	}

	// Resources.
	resources := make(map[api.ResourceName]resource)
	for name, quantity := range c.Resources.Limits {
		resources[name] = resource{limit: quantity.String()}
	}
	for name, quantity := range c.Resources.Requests {
		r, ok := resources[name]
		if !ok {
			r = resource{}
		}
		r.request = quantity.String()
		resources[name] = r
	}
	var acName appctypes.ACIdentifier
	for name, res := range resources {
		switch name {
		case api.ResourceCPU:
			acName = "resource/cpu"
		case api.ResourceMemory:
			acName = "resource/memory"
		default:
			return fmt.Errorf("resource type not supported: %v", name)
		}
		// TODO(yifan): Replace with constructor, see:
		// https://github.com/appc/spec/issues/268
		isolator := appctypes.Isolator{
			Name:     acName,
			ValueRaw: rawRequestLimit(res.request, res.limit),
		}
		app.Isolators = append(app.Isolators, isolator)
	}
	return nil
}

// setApp overrides the app's fields if any of them are specified in the
// container's spec.
func setApp(app *appctypes.App, c *api.Container, opts *kubecontainer.RunContainerOptions) error {
	// Override the exec.
	// TOOD(yifan): Revisit this for the overriding rule.
	if len(c.Command) > 0 || len(c.Args) > 0 {
		app.Exec = append(c.Command, c.Args...)
	}

	// TODO(yifan): Use non-root user in the future, see:
	// https://github.com/coreos/rkt/issues/820
	app.User, app.Group = "0", "0"

	// Override the working directory.
	if len(c.WorkingDir) > 0 {
		app.WorkingDirectory = c.WorkingDir
	}

	// Override the environment.
	if len(opts.Envs) > 0 {
		app.Environment = []appctypes.EnvironmentVariable{}
	}
	for _, env := range c.Env {
		app.Environment = append(app.Environment, appctypes.EnvironmentVariable{
			Name:  env.Name,
			Value: env.Value,
		})
	}

	// Override the mount points.
	if len(opts.Mounts) > 0 {
		app.MountPoints = []appctypes.MountPoint{}
	}
	for _, m := range opts.Mounts {
		mountPointName, err := appctypes.NewACName(m.Name)
		if err != nil {
			return err
		}
		app.MountPoints = append(app.MountPoints, appctypes.MountPoint{
			Name:     *mountPointName,
			Path:     m.ContainerPath,
			ReadOnly: m.ReadOnly,
		})
	}

	// Override the ports.
	if len(opts.PortMappings) > 0 {
		app.Ports = []appctypes.Port{}
	}
	for _, p := range opts.PortMappings {
		name, err := appctypes.SanitizeACName(p.Name)
		if err != nil {
			return err
		}
		portName := appctypes.MustACName(name)
		app.Ports = append(app.Ports, appctypes.Port{
			Name:     *portName,
			Protocol: string(p.Protocol),
			Port:     uint(p.ContainerPort),
		})
	}

	// Override isolators.
	return setIsolators(app, c)
}

// getImageManifest invokes 'rkt image cat-manifest' to retrive the image manifest
// for the image.
func (r *runtime) getImageManifest(image string) (*appcschema.ImageManifest, error) {
	var manifest appcschema.ImageManifest

	// TODO(yifan): Assume docker images for now.
	output, err := r.runCommand("image", "cat-manifest", "--quiet", dockerPrefix+image)
	if err != nil {
		return nil, err
	}
	if len(output) != 1 {
		return nil, fmt.Errorf("invalid output: %v", output)
	}
	return &manifest, json.Unmarshal([]byte(output[0]), &manifest)
}

// makePodManifest transforms a kubelet pod spec to the rkt pod manifest.
func (r *runtime) makePodManifest(pod *api.Pod) (*appcschema.PodManifest, error) {
	var globalPortMappings []kubecontainer.PortMapping
	manifest := appcschema.BlankPodManifest()

	for _, c := range pod.Spec.Containers {
		imgManifest, err := r.getImageManifest(c.Image)
		if err != nil {
			return nil, err
		}

		if imgManifest.App == nil {
			return nil, fmt.Errorf("no app section in image manifest for image: %q", c.Image)
		}

		img, err := r.getImageByName(c.Image)
		if err != nil {
			return nil, err
		}
		hash, err := appctypes.NewHash(img.id)
		if err != nil {
			return nil, err
		}

		opts, err := r.generator.GenerateRunContainerOptions(pod, &c)
		if err != nil {
			return nil, err
		}

		globalPortMappings = append(globalPortMappings, opts.PortMappings...)

		if err := setApp(imgManifest.App, &c, opts); err != nil {
			return nil, err
		}

		name, err := appctypes.SanitizeACName(c.Name)
		if err != nil {
			return nil, err
		}
		appName := appctypes.MustACName(name)

		manifest.Apps = append(manifest.Apps, appcschema.RuntimeApp{
			Name:  *appName,
			Image: appcschema.RuntimeImage{ID: *hash},
			App:   imgManifest.App,
		})
	}

	volumeMap, ok := r.volumeGetter.GetVolumes(pod.UID)
	if !ok {
		return nil, fmt.Errorf("cannot get the volumes for pod %q", kubecontainer.GetPodFullName(pod))
	}

	// Set global volumes.
	for name, volume := range volumeMap {
		volName, err := appctypes.NewACName(name)
		if err != nil {
			return nil, fmt.Errorf("cannot use the volume's name %q as ACName: %v", name, err)
		}
		manifest.Volumes = append(manifest.Volumes, appctypes.Volume{
			Name:   *volName,
			Kind:   "host",
			Source: volume.GetPath(),
		})
	}

	// Set global ports.
	for _, port := range globalPortMappings {
		name, err := appctypes.SanitizeACName(port.Name)
		if err != nil {
			return nil, fmt.Errorf("cannot use the port's name %q as ACName: %v", port.Name, err)
		}
		portName := appctypes.MustACName(name)
		manifest.Ports = append(manifest.Ports, appctypes.ExposedPort{
			Name:     *portName,
			HostPort: uint(port.HostPort),
		})
	}
	// TODO(yifan): Set pod-level isolators once it's supported in kubernetes.
	return manifest, nil
}

func newUnitOption(section, name, value string) *unit.UnitOption {
	return &unit.UnitOption{Section: section, Name: name, Value: value}
}

func apiPodToruntimePod(uuid string, pod *api.Pod) *kubecontainer.Pod {
	p := &kubecontainer.Pod{
		ID:        pod.UID,
		Name:      pod.Name,
		Namespace: pod.Namespace,
	}
	for i := range pod.Spec.Containers {
		c := &pod.Spec.Containers[i]
		p.Containers = append(p.Containers, &kubecontainer.Container{
			ID:      types.UID(buildContainerID(&containerID{uuid, c.Name})),
			Name:    c.Name,
			Image:   c.Image,
			Hash:    kubecontainer.HashContainer(c),
			Created: time.Now().Unix(),
		})
	}
	return p
}

// preparePod will:
//
// 1. Invoke 'rkt prepare' to prepare the pod, and get the rkt pod uuid.
// 2. Creates the unit file and save it under systemdUnitDir.
//
// On success, it will return a string that represents name of the unit file
// and a boolean that indicates if the unit file needs to be reloaded (whether
// the file is already existed).
func (r *runtime) preparePod(pod *api.Pod) (string, bool, error) {
	cmds := []string{"prepare", "--quiet", "--pod-manifest"}

	// Generate the pod manifest from the pod spec.
	manifest, err := r.makePodManifest(pod)
	if err != nil {
		return "", false, err
	}
	manifestFile, err := ioutil.TempFile("", fmt.Sprintf("manifest-%s-", pod.Name))
	if err != nil {
		return "", false, err
	}
	defer func() {
		manifestFile.Close()
		if err := os.Remove(manifestFile.Name()); err != nil {
			glog.Warningf("rkt: Cannot remove temp manifest file %q: %v", manifestFile.Name(), err)
		}
	}()

	data, err := json.Marshal(manifest)
	if err != nil {
		return "", false, err
	}
	// Since File.Write returns error if the written length is less than len(data),
	// so check error is enough for us.
	if _, err := manifestFile.Write(data); err != nil {
		return "", false, err
	}

	cmds = append(cmds, manifestFile.Name())
	output, err := r.runCommand(cmds...)
	if err != nil {
		return "", false, err
	}
	if len(output) != 1 {
		return "", false, fmt.Errorf("cannot get uuid from 'rkt prepare'")
	}
	uuid := output[0]
	glog.V(4).Infof("'rkt prepare' returns %q", uuid)

	p := apiPodToruntimePod(uuid, pod)
	b, err := json.Marshal(p)
	if err != nil {
		return "", false, err
	}

	var runPrepared string
	if pod.Spec.HostNetwork {
		runPrepared = fmt.Sprintf("%s run-prepared --mds-register=false %s", r.rktBinAbsPath, uuid)
	} else {
		runPrepared = fmt.Sprintf("%s run-prepared --mds-register=false --private-net %s", r.rktBinAbsPath, uuid)
	}

	units := []*unit.UnitOption{
		newUnitOption(unitKubernetesSection, unitRktID, uuid),
		newUnitOption(unitKubernetesSection, unitPodName, string(b)),
		// This makes the service show up for 'systemctl list-units' even if it exits successfully.
		newUnitOption("Service", "RemainAfterExit", "true"),
		newUnitOption("Service", "ExecStart", runPrepared),
	}

	// Save the unit file under systemd's service directory.
	// TODO(yifan) Garbage collect 'dead' service files.
	needReload := false
	unitName := makePodServiceFileName(pod.UID)
	if _, err := os.Stat(path.Join(systemdServiceDir, unitName)); err == nil {
		needReload = true
	}
	unitFile, err := os.Create(path.Join(systemdServiceDir, unitName))
	if err != nil {
		return "", false, err
	}
	defer unitFile.Close()

	_, err = io.Copy(unitFile, unit.Serialize(units))
	if err != nil {
		return "", false, err
	}
	return unitName, needReload, nil
}

// RunPod first creates the unit file for a pod, and then calls
// StartUnit over d-bus.
func (r *runtime) RunPod(pod *api.Pod) error {
	glog.V(4).Infof("Rkt starts to run pod: name %q.", pod.Name)

	name, needReload, err := r.preparePod(pod)
	if err != nil {
		return err
	}
	if needReload {
		// TODO(yifan): More graceful stop. Replace with StopUnit and wait for a timeout.
		r.systemd.KillUnit(name, int32(syscall.SIGKILL))
		if err := r.systemd.Reload(); err != nil {
			return err
		}
	}

	// TODO(yifan): This is the old version of go-systemd. Should update when libcontainer updates
	// its version of go-systemd.
	_, err = r.systemd.StartUnit(name, "replace")
	if err != nil {
		return err
	}
	return nil
}

// makeRuntimePod constructs the container runtime pod. It will:
// 1, Construct the pod by the information stored in the unit file.
// 2, Construct the pod status from pod info.
func (r *runtime) makeRuntimePod(unitName string, podInfos map[string]*podInfo) (*kubecontainer.Pod, error) {
	f, err := os.Open(path.Join(systemdServiceDir, unitName))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var pod kubecontainer.Pod
	opts, err := unit.Deserialize(f)
	if err != nil {
		return nil, err
	}

	var rktID string
	for _, opt := range opts {
		if opt.Section != unitKubernetesSection {
			continue
		}
		switch opt.Name {
		case unitPodName:
			err = json.Unmarshal([]byte(opt.Value), &pod)
			if err != nil {
				return nil, err
			}
		case unitRktID:
			rktID = opt.Value
		default:
			return nil, fmt.Errorf("rkt: Unexpected key: %q", opt.Name)
		}
	}

	if len(rktID) == 0 {
		return nil, fmt.Errorf("rkt: cannot find rkt ID of pod %v, unit file is broken", pod)
	}
	info, found := podInfos[rktID]
	if !found {
		return nil, fmt.Errorf("rkt: cannot find info for pod %q, rkt uuid: %q", pod.Name, rktID)
	}
	pod.Status = info.toPodStatus(&pod)
	return &pod, nil
}

// GetPods runs 'systemctl list-unit' and 'rkt list' to get the list of rkt pods.
// Then it will use the result to construct a list of container runtime pods.
// If all is false, then only running pods will be returned, otherwise all pods will be
// returned.
func (r *runtime) GetPods(all bool) ([]*kubecontainer.Pod, error) {
	glog.V(4).Infof("Rkt getting pods")

	units, err := r.systemd.ListUnits()
	if err != nil {
		return nil, err
	}

	// TODO(yifan): Now we are getting the status of the pod as well.
	// Probably we can leave much of the work to GetPodStatus().
	podInfos, err := r.getPodInfos()
	if err != nil {
		return nil, err
	}

	var pods []*kubecontainer.Pod
	for _, u := range units {
		if strings.HasPrefix(u.Name, kubernetesUnitPrefix) {
			if !all && u.SubState != "running" {
				continue
			}
			pod, err := r.makeRuntimePod(u.Name, podInfos)
			if err != nil {
				glog.Warningf("rkt: Cannot construct pod from unit file: %v.", err)
				continue
			}
			pods = append(pods, pod)
		}
	}
	return pods, nil
}

// KillPod invokes 'systemctl kill' to kill the unit that runs the pod.
func (r *runtime) KillPod(pod kubecontainer.Pod) error {
	glog.V(4).Infof("Rkt is killing pod: name %q.", pod.Name)

	// TODO(yifan): More graceful stop. Replace with StopUnit and wait for a timeout.
	r.systemd.KillUnit(makePodServiceFileName(pod.ID), int32(syscall.SIGKILL))
	return r.systemd.Reload()
}

// GetPodStatus currently invokes GetPods() to return the status.
// TODO(yifan): Split the get status logic from GetPods().
func (r *runtime) GetPodStatus(pod *api.Pod) (*api.PodStatus, error) {
	pods, err := r.GetPods(true)
	if err != nil {
		return nil, err
	}
	p := kubecontainer.Pods(pods).FindPodByID(pod.UID)
	if len(p.Containers) == 0 {
		return nil, fmt.Errorf("cannot find status for pod: %q", kubecontainer.BuildPodFullName(pod.Name, pod.Namespace))
	}
	return &p.Status, nil
}

// Version invokes 'rkt version' to get the version information of the rkt
// runtime on the machine.
// The return values are an int array containers the version number.
//
// Example:
// rkt:0.3.2+git --> []int{0, 3, 2}.
//
func (r *runtime) Version() (kubecontainer.Version, error) {
	output, err := r.runCommand("version")
	if err != nil {
		return nil, err
	}

	// Example output for 'rkt version':
	// rkt version 0.3.2+git
	// appc version 0.3.0+git
	for _, line := range output {
		tuples := strings.Split(strings.TrimSpace(line), " ")
		if len(tuples) != 3 {
			glog.Warningf("rkt: cannot parse the output: %q.", line)
			continue
		}
		if tuples[0] == "rkt" {
			return parseVersion(tuples[2])
		}
	}
	return nil, fmt.Errorf("rkt: cannot determine the version")
}

// writeDockerAuthConfig writes the docker credentials to rkt auth config files.
// This enables rkt to pull docker images from docker registry with credentials.
func (r *runtime) writeDockerAuthConfig(image string, credsSlice []docker.AuthConfiguration) error {
	creds := docker.AuthConfiguration{}
	// TODO handle multiple creds
	if len(credsSlice) >= 1 {
		creds = credsSlice[0]
	}

	registry := "index.docker.io"
	// Image spec: [<registry>/]<repository>/<image>[:<version]
	explicitRegistry := (strings.Count(image, "/") == 2)
	if explicitRegistry {
		registry = strings.Split(image, "/")[0]
	}

	localConfigDir := rktLocalConfigDir
	if r.config.LocalConfigDir != "" {
		localConfigDir = r.config.LocalConfigDir
	}
	authDir := path.Join(localConfigDir, "auth.d")
	if _, err := os.Stat(authDir); os.IsNotExist(err) {
		if err := os.Mkdir(authDir, 0600); err != nil {
			glog.Errorf("rkt: Cannot create auth dir: %v", err)
			return err
		}
	}
	f, err := os.Create(path.Join(localConfigDir, authDir, registry+".json"))
	if err != nil {
		glog.Errorf("rkt: Cannot create docker auth config file: %v", err)
		return err
	}
	defer f.Close()
	config := fmt.Sprintf(dockerAuthTemplate, registry, creds.Username, creds.Password)
	if _, err := f.Write([]byte(config)); err != nil {
		glog.Errorf("rkt: Cannot write docker auth config file: %v", err)
		return err
	}
	return nil
}

// PullImage invokes 'rkt fetch' to download an aci.
// TODO(yifan): Now we only support docker images, this should be changed
// once the format of image is landed, see:
//
// http://issue.k8s.io/7203
//
func (r *runtime) PullImage(image kubecontainer.ImageSpec, pullSecrets []api.Secret) error {
	img := image.Image
	// TODO(yifan): The credential operation is a copy from dockertools package,
	// Need to resolve the code duplication.
	repoToPull, tag := parsers.ParseRepositoryTag(img)
	// If no tag was specified, use the default "latest".
	if len(tag) == 0 {
		tag = "latest"
	}

	keyring, err := credentialprovider.MakeDockerKeyring(pullSecrets, r.dockerKeyring)
	if err != nil {
		return err
	}

	creds, ok := keyring.Lookup(repoToPull)
	if !ok {
		glog.V(1).Infof("Pulling image %s without credentials", img)
	}

	// Let's update a json.
	// TODO(yifan): Find a way to feed this to rkt.
	if err := r.writeDockerAuthConfig(img, creds); err != nil {
		return err
	}

	output, err := r.runCommand("fetch", dockerPrefix+img)
	if err != nil {
		return fmt.Errorf("rkt: Failed to fetch image: %v:", output)
	}
	return nil
}

// IsImagePresent returns true if the image is available on the machine.
// TODO(yifan): 'rkt image' is now landed on master, use that once we bump up
// the rkt version.
func (r *runtime) IsImagePresent(image kubecontainer.ImageSpec) (bool, error) {
	img := image.Image
	if _, err := r.runCommand("prepare", "--local=true", dockerPrefix+img); err != nil {
		return false, nil
	}
	return true, nil
}

func (r *runtime) ListImages() ([]kubecontainer.Image, error) {
	return []kubecontainer.Image{}, fmt.Errorf("rkt: ListImages unimplemented")
}

func (r *runtime) RemoveImage(image kubecontainer.ImageSpec) error {
	return fmt.Errorf("rkt: RemoveImages unimplemented")
}

// SyncPod syncs the running pod to match the specified desired pod.
func (r *runtime) SyncPod(pod *api.Pod, runningPod kubecontainer.Pod, podStatus api.PodStatus, pullSecrets []api.Secret) error {
	podFullName := kubecontainer.GetPodFullName(pod)
	if len(runningPod.Containers) == 0 {
		glog.V(4).Infof("Pod %q is not running, will start it", podFullName)
		return r.RunPod(pod)
	}

	// Add references to all containers.
	unidentifiedContainers := make(map[types.UID]*kubecontainer.Container)
	for _, c := range runningPod.Containers {
		unidentifiedContainers[c.ID] = c
	}

	restartPod := false
	for _, container := range pod.Spec.Containers {
		expectedHash := kubecontainer.HashContainer(&container)

		c := runningPod.FindContainerByName(container.Name)
		if c == nil {
			if kubecontainer.ShouldContainerBeRestarted(&container, pod, &podStatus, r.readinessManager) {
				glog.V(3).Infof("Container %+v is dead, but RestartPolicy says that we should restart it.", container)
				// TODO(yifan): Containers in one pod are fate-sharing at this moment, see:
				// https://github.com/appc/spec/issues/276.
				restartPod = true
				break
			}
			continue
		}

		// TODO: check for non-root image directives.  See ../docker/manager.go#SyncPod

		// TODO(yifan): Take care of host network change.
		containerChanged := c.Hash != 0 && c.Hash != expectedHash
		if containerChanged {
			glog.Infof("Pod %q container %q hash changed (%d vs %d), it will be killed and re-created.", podFullName, container.Name, c.Hash, expectedHash)
			restartPod = true
			break
		}

		result, err := r.prober.Probe(pod, podStatus, container, string(c.ID), c.Created)
		// TODO(vmarmol): examine this logic.
		if err == nil && result != probe.Success {
			glog.Infof("Pod %q container %q is unhealthy (probe result: %v), it will be killed and re-created.", podFullName, container.Name, result)
			restartPod = true
			break
		}

		if err != nil {
			glog.V(2).Infof("Probe container %q failed: %v", container.Name, err)
		}
		delete(unidentifiedContainers, c.ID)
	}

	// If there is any unidentified containers, restart the pod.
	if len(unidentifiedContainers) > 0 {
		restartPod = true
	}

	if restartPod {
		// TODO(yifan): Handle network plugin.
		if err := r.KillPod(runningPod); err != nil {
			return err
		}
		if err := r.RunPod(pod); err != nil {
			return err
		}
	}
	return nil
}

// GetContainerLogs uses journalctl to get the logs of the container.
// By default, it returns a snapshot of the container log. Set |follow| to true to
// stream the log. Set |follow| to false and specify the number of lines (e.g.
// "100" or "all") to tail the log.
// TODO(yifan): Currently, it fetches all the containers' log within a pod. We will
// be able to fetch individual container's log once https://github.com/coreos/rkt/pull/841
// landed.
func (r *runtime) GetContainerLogs(pod *api.Pod, containerID string, tail string, follow bool, stdout, stderr io.Writer) error {
	unitName := makePodServiceFileName(pod.UID)
	cmd := exec.Command("journalctl", "-u", unitName)
	if follow {
		cmd.Args = append(cmd.Args, "-f")
	}
	if tail == "all" {
		cmd.Args = append(cmd.Args, "-a")
	} else {
		_, err := strconv.Atoi(tail)
		if err == nil {
			cmd.Args = append(cmd.Args, "-n", tail)
		}
	}
	cmd.Stdout, cmd.Stderr = stdout, stderr
	return cmd.Start()
}

// GarbageCollect collects the pods/containers. TODO(yifan): Enforce the gc policy.
func (r *runtime) GarbageCollect() error {
	if err := exec.Command("systemctl", "reset-failed").Run(); err != nil {
		glog.Errorf("rkt: Failed to reset failed systemd services: %v", err)
	}
	if _, err := r.runCommand("gc", "--grace-period="+defaultGracePeriod, "--expire-prepared="+defaultExpirePrepared); err != nil {
		glog.Errorf("rkt: Failed to gc: %v", err)
		return err
	}
	return nil
}

// Note: In rkt, the container ID is in the form of "UUID:appName", where
// appName is the container name.
func (r *runtime) RunInContainer(containerID string, cmd []string) ([]byte, error) {
	glog.V(4).Infof("Rkt running in container.")

	id, err := parseContainerID(containerID)
	if err != nil {
		return nil, err
	}
	args := append([]string{}, "enter", fmt.Sprintf("--app=%s", id.appName), id.uuid)
	args = append(args, cmd...)

	result, err := r.runCommand(args...)
	return []byte(strings.Join(result, "\n")), err
}

func (r *runtime) AttachContainer(containerID string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool) error {
	return errors.New("unimplemented")
}

// Note: In rkt, the container ID is in the form of "UUID:appName", where UUID is
// the rkt UUID, and appName is the container name.
func (r *runtime) ExecInContainer(containerID string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool) error {
	glog.V(4).Infof("Rkt execing in container.")

	id, err := parseContainerID(containerID)
	if err != nil {
		return err
	}
	args := append([]string{}, "enter", fmt.Sprintf("--app=%s", id.appName), id.uuid)
	args = append(args, cmd...)
	command := r.buildCommand(args...)

	if tty {
		p, err := kubecontainer.StartPty(command)
		if err != nil {
			return err
		}
		defer p.Close()

		// make sure to close the stdout stream
		defer stdout.Close()

		if stdin != nil {
			go io.Copy(p, stdin)
		}
		if stdout != nil {
			go io.Copy(stdout, p)
		}
		return command.Wait()
	}
	if stdin != nil {
		// Use an os.Pipe here as it returns true *os.File objects.
		// This way, if you run 'kubectl exec <pod> -i bash' (no tty) and type 'exit',
		// the call below to command.Run() can unblock because its Stdin is the read half
		// of the pipe.
		r, w, err := os.Pipe()
		if err != nil {
			return err
		}
		go io.Copy(w, stdin)

		command.Stdin = r
	}
	if stdout != nil {
		command.Stdout = stdout
	}
	if stderr != nil {
		command.Stderr = stderr
	}
	return command.Run()
}

// findRktID returns the rkt uuid for the pod.
// TODO(yifan): This is unefficient which require us to list
// all the unit files.
func (r *runtime) findRktID(pod *kubecontainer.Pod) (string, error) {
	units, err := r.systemd.ListUnits()
	if err != nil {
		return "", err
	}

	unitName := makePodServiceFileName(pod.ID)
	for _, u := range units {
		// u.Name contains file name ext such as .service, .socket, etc.
		if u.Name != unitName {
			continue
		}

		f, err := os.Open(path.Join(systemdServiceDir, u.Name))
		if err != nil {
			return "", err
		}
		defer f.Close()

		opts, err := unit.Deserialize(f)
		if err != nil {
			return "", err
		}

		for _, opt := range opts {
			if opt.Section == unitKubernetesSection && opt.Name == unitRktID {
				return opt.Value, nil
			}
		}
	}
	return "", fmt.Errorf("rkt uuid not found for pod %v", pod)
}

// PortForward executes socat in the pod's network namespace and copies
// data between stream (representing the user's local connection on their
// computer) and the specified port in the container.
//
// TODO:
//  - match cgroups of container
//  - should we support nsenter + socat on the host? (current impl)
//  - should we support nsenter + socat in a container, running with elevated privs and --pid=host?
//
// TODO(yifan): Merge with the same function in dockertools.
func (r *runtime) PortForward(pod *kubecontainer.Pod, port uint16, stream io.ReadWriteCloser) error {
	glog.V(4).Infof("Rkt port forwarding in container.")

	podInfos, err := r.getPodInfos()
	if err != nil {
		return err
	}

	rktID, err := r.findRktID(pod)
	if err != nil {
		return err
	}

	info, ok := podInfos[rktID]
	if !ok {
		return fmt.Errorf("cannot find the pod info for pod %v", pod)
	}
	if info.pid < 0 {
		return fmt.Errorf("cannot get the pid for pod %v", pod)
	}

	_, lookupErr := exec.LookPath("socat")
	if lookupErr != nil {
		return fmt.Errorf("unable to do port forwarding: socat not found.")
	}
	args := []string{"-t", fmt.Sprintf("%d", info.pid), "-n", "socat", "-", fmt.Sprintf("TCP4:localhost:%d", port)}

	_, lookupErr = exec.LookPath("nsenter")
	if lookupErr != nil {
		return fmt.Errorf("unable to do port forwarding: nsenter not found.")
	}
	command := exec.Command("nsenter", args...)
	command.Stdin = stream
	command.Stdout = stream
	return command.Run()
}

// isUUID returns true if the input is a valid rkt UUID,
// e.g. "2372bc17-47cb-43fb-8d78-20b31729feda".
func isUUID(input string) bool {
	if _, err := appctypes.NewUUID(input); err != nil {
		return false
	}
	return true
}

// getPodInfos returns a map of [pod-uuid]:*podInfo
func (r *runtime) getPodInfos() (map[string]*podInfo, error) {
	result := make(map[string]*podInfo)

	output, err := r.runCommand("list", "--no-legend", "--full")
	if err != nil {
		return result, err
	}
	if len(output) == 0 {
		// No pods are running.
		return result, nil
	}

	// Example output of 'rkt list --full' (version == 0.7.0):
	//
	// UUID                                 APP     ACI                STATE      NETWORKS
	// 2372bc17-47cb-43fb-8d78-20b31729feda	foo     coreos.com/etcd    running    default:ip4=172.16.28.3
	//                                      bar     nginx              running
	// 40e2813b-9d5d-4146-a817-0de92646da96 foo     redis              exited
	// 40e2813b-9d5d-4146-a817-0de92646da96 bar     busybox            exited
	//
	// With '--no-legend', the first line is eliminated.
	for _, line := range output {
		tuples := splitLineByTab(line)
		if len(tuples) < 1 {
			continue
		}
		if !isUUID(tuples[0]) {
			continue
		}
		id := tuples[0]
		status, err := r.runCommand("status", id)
		if err != nil {
			glog.Errorf("rkt: Cannot get status for pod (uuid=%q): %v", id, err)
			continue
		}
		info, err := parsePodInfo(status)
		if err != nil {
			glog.Errorf("rkt: Cannot parse status for pod (uuid=%q): %v", id, err)
			continue
		}
		result[id] = info
	}
	return result, nil
}

// listImages lists all the available appc images on the machine by invoking 'rkt images'.
func (r *runtime) listImages() ([]image, error) {
	output, err := r.runCommand("images", "--no-legend=true", "--fields=key,appname")
	if err != nil {
		return nil, err
	}
	if len(output) == 0 {
		return nil, nil
	}

	var images []image
	for _, line := range output {
		var img image
		if err := img.parseString(line); err != nil {
			glog.Warningf("rkt: Cannot parse image info from %q: %v", line, err)
			continue
		}
		images = append(images, img)
	}
	return images, nil
}

// getImageByName tries to find the image info with the given image name.
// TODO(yifan): Replace with 'rkt image cat-manifest'.
func (r *runtime) getImageByName(imageName string) (image, error) {
	// TODO(yifan): Print hash in 'rkt image cat-manifest'?
	images, err := r.listImages()
	if err != nil {
		return image{}, err
	}

	var name, version string
	nameVersion := strings.Split(imageName, ":")

	name, err = appctypes.SanitizeACIdentifier(nameVersion[0])
	if err != nil {
		return image{}, err
	}

	if len(nameVersion) == 2 {
		version = nameVersion[1]
	}

	for _, img := range images {
		if img.name == name {
			if version == "" || img.version == version {
				return img, nil
			}
		}
	}
	return image{}, fmt.Errorf("cannot find the image %q", imageName)
}


text:
#viewScreen, #mirrorScreen, #typeScreen {
    font-size: 16px;
}

#viewScreen, #mirrorScreen {
    /*border-radius: 6px 0px 0px 6px;*/
}

#viewScreen, #typeScreen, #loading, #edit {
    /*box-shadow: 0px 0px 10px 0px #000;*/
}

#typeScreen {
	position: absolute;
    /*border-radius: 0px 6px 6px 0px;*/
	height: 100%;
}

#edit {
	/*background-color: #202328;*/
	background-color: rgb(34, 34, 34);
	overflow: auto;
}

#edit .editContents {
	padding: 60px;
}

/*
#edit #editingLang {
    /color: #0099ff;
}
//*/

#edit .page-header {
	text-shadow: 1px 1px 5px #111;
}

#edit .code-save {
    width: 50%;
}

#edit .progress {
    width: 50%;
}

#edit select {
    width: 50%;
}

#edit #tokenizeProgress > .bar {
    transition-delay: 0s;
    transition-duration: 0.2s;
    transition-property: width;
    transition-timing-function: ease;
}

#edit ol li {
	font-size: 1.3em;
	line-height: 2em;
}

#edit ol li small {
	font-size: 0.7em;
}

.span2 {
	background-color: #202328;
	border-radius: 6px;
}

/* ace-editor control */
.ace_text-layer * {
    /**
    /font-weight: bold !important;
    /**/
}

.ace_dark.typing_view .ace_text-layer * {
    color:#fff !important;
    opacity: 0.7 !important;
    font-weight: normal !important;

}

.typing_view .ace_text-layer * {
    color:#000 !important;
    opacity: 0.7 !important;
    font-weight: normal !important;
}

#viewScreen .ace_hidden-cursors .ace_cursor {
    opacity:1;
}
#viewScreen .ace_cursor, #typeScreen .ace_cursor {
    border-left-width: 2px;
}

#typeScreen .ace_gutter-cell, .typing_view .ace_gutter-cell{
    background-image: none !important;
}
/*
#typeScreen .ace_comment, #viewScreen .ace_comment, #mirrorScreen .ace_comment {
    font-style: normal;
}*/
/* ace-editor control */

redpajama_set_name: RedPajamaGithub


text:
using System;

namespace it.unifi.dsi.stlab.math.algebra.tests
{
	public class ClosureCallbackNotExpectedException : Exception
	{

	}
}


text:
.. _release_howto:

================================
How-To: Release on Maven Central
================================

This page describes the steps to release Phenol on Maven Central. TODO update me

------------------------
Read the following first
------------------------

- http://java.dzone.com/articles/deploy-maven-central
- http://central.sonatype.org/pages/apache-maven.html

------------------------------
Update the ``README.rst`` file
------------------------------

Change the version in the ``README.rst``.

---------------------------------
Update the ``CHANGELOG.rst`` file
---------------------------------

- Update the ``CHANGELOG.rst`` file to reflect the new version.
- Create a new commit with this version.
- Do not create a git tag as this will be done by Maven below.

-------------------------------
Prepare the Release using Maven
-------------------------------

  .. code-block:: shell

    mvn release:prepare

Answer with the default everywhere but use "vMAJOR.MINOR" for giving the
tag name, e.g. "v0.15". Eventually, this will update the versions, create
a tag for the version and also push the tag to Github.

-------------------
Perform the Release
-------------------

  .. code-block:: shell

    mvn release:perform

Create the release and push it to Maven central/Sonatype.

------------------------
Releasing the Deployment
------------------------

Read this:

- http://central.sonatype.org/pages/releasing-the-deployment.html

The publisher backend to Maven Central is here:

- https://oss.sonatype.org/

-----------------------
Update README CHANGELOG
-----------------------

Open README.md and CHANGELOG.md and adjust the files to include the header for the next ``SNAPSHOT`` version.

--------------
Maven comments
--------------

* ``mvn versions:set`` is useful for bumping versions


text:
/* eslint-disable camelcase */

const graphql = require('graphql');

const {
  GraphQLList,
  GraphQLObjectType,
  GraphQLString,
  GraphQLID,
} = graphql;
const Price = require('./price');
const PrimaryImage = require('./primary-image');
const Image = require('./image');
const Agent = require('./agent');
const Location = require('./location');
const Particulars = require('./particulars');
const Status = require('./status');
const Description = require('./description');
const Timestamps = require('./timestamps');
const CategoryEnum = require('./category-enum');
const TypeEnum = require('./type-enum');

module.exports = new GraphQLObjectType({
  name: 'Listing',
  description: 'details of a property',
  fields: () => ({
    id: {
      type: GraphQLID,
      resolve({ listing_id }) {
        return listing_id;
      },
      description: 'the id of the property',
    },
    status: {
      type: Status,
      resolve({ listing_status, status }) {
        return {
          listing_status,
          status,
        };
      },
      description: 'the status of the property',
    },
    category: {
      type: CategoryEnum,
      description: 'the category of the property',
    },
    type: {
      type: TypeEnum,
      resolve({ property_type }) {
        return property_type;
      },
      description: 'the type of property',
    },
    description: {
      type: Description,
      resolve({ description, details_url, short_description }) {
        return {
          description,
          details_url,
          short_description,
        };
      },
      description: 'the description of the property',
    },
    reportUrl: {
      type: GraphQLString,
      resolve({ property_report_url }) {
        return property_report_url;
      },
      description: 'url to the property\'s report',
    },
    price: {
      type: Price,
      resolve({ price, price_change }) {
        return {
          price,
          price_change,
        };
      },
      description: 'the price info of the property',
    },
    timestamps: {
      type: Timestamps,
      resolve({ first_published_date, last_published_date }) {
        return {
          first_published_date,
          last_published_date,
        };
      },
      description: 'the Zoopla timestamps for the property listing',
    },
    primaryImage: {
      type: PrimaryImage,
      resolve({ image_url, image_caption }) {
        return {
          image_url,
          image_caption,
        };
      },
      description: 'the primary image for the property',
    },
    thumbnail: {
      type: GraphQLString,
      resolve({ thumbnail_url }) {
        return thumbnail_url;
      },
      description: 'the url to the thumbnail image of the property',
    },
    images: {
      type: new GraphQLList(Image),
      resolve({
                image_150_113_url,
                image_50_38_url,
                image_645_430_url,
                image_80_60_url,
                image_354_255_url,
              }) {
        return [
          {
            name: 'image_150_113_url',
            url: image_150_113_url,
          },
          {
            name: 'image_50_38_url',
            url: image_50_38_url,
          },
          {
            name: 'image_645_430_url',
            url: image_645_430_url,
          },
          {
            name: 'image_80_60_url',
            url: image_80_60_url,
          },
          {
            name: 'image_354_255_url',
            url: image_354_255_url,
          },
        ];
      },
      description: 'the images of the property',
    },
    agent: {
      type: Agent,
      resolve({ agent_address, agent_name, agent_logo, agent_phone, letting_fees }) {
        return {
          agent_address,
          agent_name,
          agent_logo,
          agent_phone,
          letting_fees,
        };
      },
      description: 'the agent selling the property',
    },
    location: {
      type: Location,
      resolve({
                latitude,
                longitude,
                displayable_address,
                street_name,
                county,
                post_town,
                outcode,
                country,
                country_code,
              }) {
        return {
          latitude,
          longitude,
          displayable_address,
          street_name,
          county,
          post_town,
          outcode,
          country,
          country_code,
        };
      },
      description: 'the location of the property',
    },
    particulars: {
      type: Particulars,
      resolve({ num_floors, num_bedrooms, num_recepts, num_bathrooms, floor_plan }) {
        return {
          num_floors,
          num_bedrooms,
          num_recepts,
          num_bathrooms,
          floor_plan,
        };
      },
      description: 'details of the rooms in the property',
    },
  }),
});


text:
import AssistantToTheTransportManager from './assistant_to_the_transport_manager';
import Transport from "./transport";
import PingDelayOptions from "./ping_delay_options";
import Factory from "../utils/factory";

export interface TransportManagerOptions extends PingDelayOptions {
  lives?: number;
}

/** Keeps track of the number of lives left for a transport.
 *
 * In the beginning of a session, transports may be assigned a number of
 * lives. When an AssistantToTheTransportManager instance reports a transport
 * connection closed uncleanly, the transport loses a life. When the number
 * of lives drops to zero, the transport gets disabled by its manager.
 *
 * @param {Object} options
 */
export default class TransportManager {
  options: TransportManagerOptions;
  livesLeft: number;

  constructor(options : TransportManagerOptions){
    this.options = options || {};
    this.livesLeft = this.options.lives || Infinity;
  }

  /** Creates a assistant for the transport.
   *
   * @param {Transport} transport
   * @returns {AssistantToTheTransportManager}
   */
  getAssistant(transport : Transport) : AssistantToTheTransportManager {
    return Factory.createAssistantToTheTransportManager(this, transport, {
      minPingDelay: this.options.minPingDelay,
      maxPingDelay: this.options.maxPingDelay
    });
  }

  /** Returns whether the transport has any lives left.
   *
   * @returns {Boolean}
   */
  isAlive() : boolean {
    return this.livesLeft > 0;
  }

  /** Takes one life from the transport. */
  reportDeath() {
    this.livesLeft -= 1;
  }
}


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>
org.apache.log4j.xml (Apache Log4j 1.2.17-1 API)
</TITLE>

<META NAME="date" CONTENT="2012-07-10">

<LINK REL ="stylesheet" TYPE="text/css" HREF="../../../../stylesheet.css" TITLE="Style">

org.apache.log4j.xml

Interfaces

UnrecognizedElementHandler

Classes

DOMConfigurator

Log4jEntityResolver

SAXErrorHandler

XMLLayout


text: @include('includes.fortnite.profile.stats_block', ['key' => 'duo'])


text:
'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('prettyugly', 'Minifies and combines css files using prettyugly module.', function() {
    var prettyugly = require('prettyugly');

    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options();

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {

      // Concat specified files.
      var src = f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      });

      //read the source files
      src = src.map(function(filepath) {
        var fileContents = grunt.file.read(filepath);

        if(!fileContents){
          grunt.log.warn("Couldn't read " + filepath + " -- Skiped");
        }
        return fileContents;
      });

      //join the files. Add /*!{SEPARATOR}*/ as a placeholder for the separator later
      src = src.join('/*!{SEPARATOR}*/');

       //uglify the css contents or prettify if the pretty option is set
      if(options.pretty){
        src = prettyugly.pretty(src);
      }else{
        src = prettyugly.ugly(src);
      }

      //replace the separator placeholder with the specified separator in options
      if(options.separator){
        src = src.replace('/*!{SEPARATOR}*/', grunt.util.normalizelf(options.separator));
      }else{
        // replace the separator holder with the added break lines
        if(options.pretty){
          src = src.replace('\n/*!{SEPARATOR}*/\n', '');
        }else{
          // replace in ugly - there are no new lines
          src = src.replace('/*!{SEPARATOR}*/', '');
        }
      }

      //append the banner to our css file
      if(options.banner){
        if(options.pretty){
          // prettifying add the banner with a new line at the top and bottom
          src = '\n' + options.banner + '\n' + src;
        }else{
          // uglifying just add the banner to the css file
          src = options.banner + src;
        }

      }

      // Write the destination file.
      grunt.file.write(f.dest, src);

      // Print a success message.
      grunt.log.writeln('File "' + f.dest + '" created.');
    });
  });

};


text:
import * as path from "path"
import { CachedLinksMap, ContinentLink, NavigationLink, OtherLink } from "./links.types"
import { asiaLinks } from "../asia/asia.links"
import commonEn from "../../../locales/en/common.json"
import commonFr from "../../../locales/fr/common.json"
import { oceaniaLinks } from "../oceania/oceania.links"
import { LivingAbroadWhereCard, MovingAbroadWhyCard } from "../journal/journal.cards"
import { OrangutanCard } from "../animals/animals.cards"

export const isPublished = (element: { published: boolean | Date }) => {
  if (typeof element.published === "boolean") {
    return element.published
  }
  return new Date().getTime() >= element.published.getTime()
}

const getUrl = (object: { url?: string; id: string }): string => object.url || object.id

export const continentLinks: ContinentLink[] = [
  asiaLinks,
  oceaniaLinks,
  {
    id: "africa",
    label: {
      fr: commonFr.continent.africa,
      en: commonEn.continent.africa,
    },
    countries: [],
  },
  {
    id: "south-america",
    label: {
      fr: commonFr.continent["south-america"],
      en: commonEn.continent["south-america"],
    },
    countries: [
      {
        id: "caribbean",
        cities: [],
        others: [],
        label: { fr: "Caraibes", en: "Caraibes" },
      },
    ],
  },
  {
    id: "north-america",
    label: {
      fr: commonFr.continent["north-america"],
      en: commonEn.continent["north-america"],
    },
    countries: [
      {
        id: "united-states",
        others: [
          {
            id: "times-square",
            label: { fr: "Times Square", en: "Times Square" },
            published: false,
          },
        ],
        label: { fr: commonFr.country["united-states"].title, en: commonEn.country["united-states"].title },
        cities: [],
      },
      {
        id: "canada",
        label: { fr: "", en: "" },
        cities: [],
        others: [],
      },
    ],
  },
  {
    id: "europe",
    label: {
      fr: commonFr.continent.europe,
      en: commonEn.continent.europe,
    },
    countries: [
      {
        id: "azores",
        cities: [],
        others: [],
        label: { fr: "Acores", en: "Azores" },
      },
      {
        id: "iceland",
        cities: [],
        others: [],
        label: { fr: "", en: "" },
      },
      {
        id: "russia",
        cities: [],
        others: [],
        label: { fr: "", en: "" },
      },
      {
        id: "france",
        cities: [
          {
            id: "paris",
            highlights: [],
            label: { fr: "", en: "" },
          },
        ],
        others: [],
        label: { fr: "", en: "" },
      },
    ],
  },
  {
    id: "middle-east",
    label: {
      fr: commonFr.continent["middle-east"],
      en: commonEn.continent["middle-east"],
    },
    countries: [],
  },
]

export const menuLinks: NavigationLink[] = [
  {
    id: "organisation",
    label: { fr: "Organisation", en: "Organisation" },
    sections: [
      {
        id: "when-to-go",
        label: { fr: "Quand Partir", en: "When to go" },
        sections: [
          {
            id: "spring",
            label: { fr: "Printemps", en: "Spring" },
            published: true,
            sections: [],
          },
          {
            id: "summer",
            label: { fr: "Été", en: "Summer" },
            published: true,
            sections: [],
          },
          {
            id: "autumn",
            label: { fr: "Automne", en: "Autumn" },
            published: true,
            sections: [],
          },
          {
            id: "winter",
            label: { fr: "Hiver", en: "Winter" },
            published: true,
            sections: [],
          },
        ],
      },
      { id: "prepare", label: { fr: "Prepare", en: "Prepare" }, sections: [] },
    ],
  },
  {
    id: "discovery",
    label: { fr: "Découverte", en: "Discovery" },
    sections: [
      {
        id: "monuments",
        label: { fr: commonFr.link.discovery.monuments, en: commonEn.link.discovery.monuments },
        pointOfInterest: ["monument"],
        published: true,
        sections: [],
      },
      {
        id: "nature",
        label: { fr: commonFr.link.discovery.nature, en: commonEn.link.discovery.nature },
        pointOfInterest: ["nature"],
        published: true,
        sections: [],
      },
      {
        id: "cities",
        label: { fr: commonFr.link.discovery.city, en: commonEn.link.discovery.city },
        pointOfInterest: ["city"],
        published: true,
        sections: [],
      },
      {
        id: "animals",
        label: { fr: commonFr.link.discovery.animals, en: commonEn.link.discovery.animals },
        pointOfInterest: ["animals"],
        published: false,
        sections: [],
      },
      {
        id: "water-activities",
        label: { fr: commonFr.link.discovery["water-activities"], en: commonEn.link.discovery["water-activities"] },
        pointOfInterest: ["water-activities"],
        published: true,
        sections: [],
      },
      {
        id: "winter-activities",
        label: { fr: commonFr.link.discovery["winter-activities"], en: commonEn.link.discovery["winter-activities"] },
        pointOfInterest: ["winter-activities"],
        published: false,
        sections: [],
      },
      {
        id: "beach-holidays",
        label: { fr: "Vacances farniente", en: commonEn.link.discovery.lazy },
        pointOfInterest: ["lazy"],
        published: true,
        sections: [],
      },
    ],
  },
  {
    id: "journal",
    label: { fr: "Journal", en: "Journal" },
    sections: [
      {
        id: "travelling",
        label: { fr: "Voyage", en: "Travelling" },
        sections: [],
      },
      {
        id: "living-abroad",
        label: { fr: commonFr.link.journal["living-abroad"], en: commonEn.link.journal["living-abroad"] },
        sections: [],
        articles: [
          {
            id: "moving-abroad-why",
            label: {
              fr: commonFr.journal["living-abroad"].card["moving-abroad-why"],
              en: commonEn.journal["living-abroad"].card["moving-abroad-why"],
            },
            published: new Date("2021-07-31T17:00:00.000+08:00"),
            card: MovingAbroadWhyCard,
          },
          {
            id: "living-abroad-where",
            label: {
              fr: commonFr.journal["living-abroad"].card["living-abroad-where"],
              en: commonEn.journal["living-abroad"].card["living-abroad-where"],
            },
            published: new Date("2021-08-07T17:00:00.000+08:00"),
            card: LivingAbroadWhereCard,
          },
        ],
      },
      {
        id: "living-singapore",
        label: { fr: "Vivre à Singapour", en: "Living in Singapore" },
        sections: [],
      },
    ],
  },
  {
    id: "about",
    label: { fr: "À propos", en: "About" },
    sections: [
      {
        id: "who",
        label: { fr: commonFr.link.who, en: commonEn.link.who },
        published: true,
        sections: [],
      },
      {
        id: "contact",
        label: { fr: commonFr.link.contact, en: commonEn.link.contact },
        published: true,
        sections: [],
      },
      {
        id: "devices",
        label: { fr: "Notre matériel", en: "Our devices" },
        published: false,
        sections: [],
      },
    ],
  },
]

export const fruitLinks: OtherLink[] = [
  {
    id: "green-pomelo",
    label: { fr: "Green pomelo", en: "Green pomelo" },
    published: false,
  },
  {
    id: "durian",
    label: { fr: "", en: "" },
    published: false,
  },
  {
    id: "rambutan",
    label: { fr: "", en: "" },
    published: false,
  },
  // TODO to move :)
  {
    id: "beef-rendang",
    label: { fr: "", en: "" },
    published: false,
  },
]
export const animalsLinks: OtherLink[] = [
  {
    id: "orangutan",
    label: { fr: commonFr.animals.orangutan, en: commonEn.animals.orangutan },
    card: OrangutanCard,
    additionalTags: ["asia", "malaysia", "indonesia"],
    published: new Date("2021-09-18T17:00:00.000+08:00"),
  },
  {
    id: "proboscis-monkey",
    label: { fr: "", en: "" },
    published: false,
  },
  {
    id: "colugo",
    label: { fr: "", en: "" },
    published: false,
  },
  {
    id: "crab-eating-macaque",
    label: { fr: "", en: "" },
    published: false,
  },
  {
    id: "cassowary",
    label: { fr: "", en: "" },
    published: false,
  },
  {
    id: "koala",
    label: { fr: "", en: "" },
    published: false,
  },
  {
    id: "black-flanked-rock-wallaby",
    label: { fr: "", en: "" },
    published: false,
  },
  {
    id: "quokka",
    label: { fr: "", en: "" },
    published: false,
  },
  {
    id: "wombat",
    label: { fr: "", en: "" },
    published: false,
  },
]

export const noIdeaLinks: NavigationLink[] = [
  {
    id: "home",
    label: { fr: "Accueil", en: "Home" },
    url: "/",
    sections: [],
  },
  {
    id: "articles",
    label: { fr: "Articles", en: "Articles" },
    sections: [],
  },
  {
    id: "404",
    label: { fr: "404", en: "404" },
    sections: [],
  },
]

export const cachedLinks = new Map<string, CachedLinksMap>()
continentLinks.forEach((continent) => {
  continent.countries.forEach((country) => {
    country.others.forEach((other) => {
      cachedLinks.set(other.id, {
        id: other.id,
        label: other.label,
        url: path.join("/", getUrl(continent), getUrl(country), getUrl(other)),
        published: isPublished(other),
        publishedDate: other.published instanceof Date ? other.published : undefined,
        card: other.card,
        tags: [continent.id, country.id, ...(other.additionalTags ?? [])],
        pointOfInterest: [],
        seasons: [],
        country: country.id,
        kind: other.kind ?? "other",
      })
    })
    country.cities.forEach((city) => {
      cachedLinks.set(city.id, {
        id: city.id,
        label: city.label,
        url: path.join("/", getUrl(continent), getUrl(country), getUrl(city)),
        published: city.highlights.some(isPublished),
        tags: [continent.id, country.id],
        pointOfInterest: city.pointOfInterest || [],
        seasons: [],
        country: country.id,
        kind: "city",
      })
      city.highlights.forEach((highlight) => {
        cachedLinks.set(highlight.id, {
          id: highlight.id,
          label: highlight.label,
          url: path.join("/", getUrl(continent), getUrl(country), getUrl(city), getUrl(highlight)),
          published: isPublished(highlight),
          publishedDate: highlight.published instanceof Date ? highlight.published : undefined,
          card: highlight.card,
          tags: [continent.id, country.id, city.id],
          seasons: [],
          pointOfInterest: [],
          country: country.id,
          kind: "highlight",
        })
      })
    })

    cachedLinks.set(country.id, {
      id: country.id,
      label: country.label,
      url: path.join("/", getUrl(continent), getUrl(country)),
      published:
        country.others.some((o) => cachedLinks.get(o.id)?.published) ||
        country.cities.some((c) => cachedLinks.get(c.id)?.published),
      tags: [continent.id],
      pointOfInterest: country.pointOfInterest || [],
      seasons: country.seasons || [],
      country: country.id,
      imageProps: country.imageProps,
      kind: "country",
    })
  })
  cachedLinks.set(continent.id, {
    id: continent.id,
    label: continent.label,
    url: path.join("/", getUrl(continent)),
    published: continent.countries.some((country) => cachedLinks.get(country.id)?.published),
    tags: [],
    pointOfInterest: [],
    seasons: [],
    kind: "continent",
  })
})

menuLinks.forEach((menu) => {
  menu.sections.forEach((submenu) => {
    submenu.sections.forEach((subsubmenu) => {
      cachedLinks.set(subsubmenu.id, {
        id: subsubmenu.id,
        label: subsubmenu.label,
        url: path.join("/", getUrl(menu), getUrl(submenu), getUrl(subsubmenu)),
        published: !!subsubmenu.published,
        tags: [],
        pointOfInterest: [],
        seasons: [],
        kind: "menu",
      })
    })
    submenu.articles?.forEach((article) => {
      cachedLinks.set(article.id, {
        id: article.id,
        label: article.label,
        url: path.join("/", getUrl(menu), getUrl(submenu), getUrl(article)),
        published: isPublished(article),
        publishedDate: article.published instanceof Date ? article.published : undefined,
        card: article.card,
        // as of today, I didn't add menu.id for articles in living-abroad. Indeed I don't want the journal ta to be displayed
        // if it needs to be changed, be careful on the living abroad articles
        tags: [submenu.id],
        pointOfInterest: [],
        seasons: [],
        kind: "other",
      })
    })

    cachedLinks.set(submenu.id, {
      id: submenu.id,
      label: submenu.label,
      url: path.join("/", getUrl(menu), getUrl(submenu)),
      published:
        submenu.sections.some((subsubmenu) => cachedLinks.get(subsubmenu.id)?.published) ||
        submenu.articles?.some((article) => cachedLinks.get(article.id)?.published) ||
        !!submenu.published,
      tags: [],
      pointOfInterest: submenu.pointOfInterest ?? [],
      seasons: [],
      kind: "menu",
    })
  })
  cachedLinks.set(menu.id, {
    id: menu.id,
    label: menu.label,
    url: path.join("/", getUrl(menu)),
    published: menu.sections.some((submenu) => cachedLinks.get(submenu.id)?.published) || !!menu.published,
    tags: [],
    pointOfInterest: [],
    seasons: [],
    kind: "menu",
  })
})

noIdeaLinks.forEach((link) => {
  cachedLinks.set(link.id, {
    id: link.id,
    label: link.label,
    url: path.join("/", getUrl(link)),
    published: true,
    tags: [],
    pointOfInterest: [],
    seasons: [],
    kind: "noIdea",
  })
})

fruitLinks.forEach((link) => {
  cachedLinks.set(link.id, {
    id: link.id,
    label: link.label,
    url: path.join("/", getUrl(link)),
    published: isPublished(link),
    publishedDate: link.published instanceof Date ? link.published : undefined,
    card: link.card,
    tags: [...(link.additionalTags || [])],
    pointOfInterest: [],
    seasons: [],
    kind: "fruit",
  })
})

animalsLinks.forEach((link) => {
  cachedLinks.set(link.id, {
    id: link.id,
    label: link.label,
    url: path.join("/animals", getUrl(link)),
    published: isPublished(link),
    publishedDate: link.published instanceof Date ? link.published : undefined,
    card: link.card,
    tags: [...(link.additionalTags || [])],
    pointOfInterest: [],
    seasons: [],
    kind: "animal",
  })
})


text:
import React from "react";
import ReactDOM from "react-dom";

const render = () => {
    // tslint:disable-next-line:no-require-imports
    const {default: App} = require("./App");
    ReactDOM.render(<App />, document.getElementById("root"));
};

render();

if (process.env.NODE_ENV !== "production") {
    (module as any).hot.accept(render);
}


text:
class CMissileDefense : public CDigitanksWeapon
{
	REGISTER_ENTITY_CLASS(CMissileDefense, CDigitanksWeapon);

public:
	void						SetTarget(class CProjectile* pTarget);

	virtual const TVector		GetGlobalOrigin() const;

	virtual void				Think();

	virtual bool				ShouldRender() const { return true; };
	virtual void				OnRender(class CGameRenderingContext* pContext);

	virtual weapon_t			GetWeaponType() { return WEAPON_MISSILEDEFENSE; }
	virtual float				ExplosionRadius() { return 4.0f; };
	virtual bool				MakesSounds() { return true; };

	virtual bool				CreatesCraters() { return false; };
	virtual float				PushRadius() { return 0.0f; };

	virtual float				InterceptTime() const { return 0.7f; };

protected:
	CEntityHandle<CProjectile>	m_hTarget;
};

#endif


text:
using UnityEngine;
using System.Collections;

namespace HolojamEngine {
  public class DestroyAllMorphStrokes : MonoBehaviour {

    void OnEnable() {
      foreach(MorphStroke s in GameObject.FindObjectsOfType<MorphStroke>()) {
        Destroy(s.gameObject);
      }
    }
  }
}


text:
import os
import sys
sys.path.insert(0, os.path.abspath('../'))

# Use the readthedocs.org theme if installed
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'

if not on_rtd:  # only import and set the theme if we're building docs locally
    try:
        import sphinx_rtd_theme
        html_theme = 'sphinx_rtd_theme'
        html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
    except ImportError:
        html_theme = 'default'

# -- Project information -----------------------------------------------------

project = u'Python Control Systems Library'
copyright = u'2020, python-control.org'
author = u'Python Control Developers'

# Version information - read from the source code
import re
import control

# The short X.Y.Z version
version = re.sub(r'(\d+\.\d+\.\d+)(.*)', r'\1', control.__version__)

# The full version, including alpha/beta/rc tags
release = control.__version__
print("version %s, release %s" % (version, release))

# -- General configuration ---------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#
needs_sphinx = '3.1'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.napoleon',
    'sphinx.ext.intersphinx', 'sphinx.ext.imgmath',
    'sphinx.ext.autosummary', 'nbsphinx',
]

# scan documents for autosummary directives and generate stub pages for each.
autosummary_generate = True

# list of autodoc directive flags that should be automatically applied
# to all autodoc directives.
autodoc_default_options = {
    'members': True,
    'inherited-members': True,
    'exclude-members': '__init__, __weakref__, __repr__, __str__'
}

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'

# The master toctree document.
master_doc = 'index'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path .
exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store',
                    '*.ipynb_checkpoints']

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# This config value contains the locations and names of other projects that
# should be linked to in this documentation.
intersphinx_mapping = \
    {'scipy': ('https://docs.scipy.org/doc/scipy/reference', None),
     'numpy': ('https://numpy.org/doc/stable', None),
     'matplotlib': ('https://matplotlib.org/', None),
     }

# If this is True, todo and todolist produce output, else they produce nothing.
# The default is False.
todo_include_todos = True

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself.  Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}

# -- Options for HTMLHelp output ---------------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = 'PythonControlLibrarydoc'

# -- Options for LaTeX output ------------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',

    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',

    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
    (master_doc, 'PythonControlLibrary.tex', u'Python Control Library Documentation',
     u'RMM', 'manual'),
]

# -- Options for manual page output ------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    (master_doc, 'pythoncontrollibrary', u'Python Control Library Documentation',
     [author], 1)
]

# -- Options for Texinfo output ----------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    (master_doc, 'PythonControlLibrary', u'Python Control Library Documentation',
     author, 'PythonControlLibrary', 'One line description of project.',
     'Miscellaneous'),
]


text:
'use strict';

const Base = require('../base/Base');

module.exports = class Job extends Base {

    execute () {
        // place code here
    }

    isCanceled () {
        return this._canceled;
    }

    cancel () {
        this._canceled = true;
    }

    async start () {
        if (this._started) {
            throw new Error('Job has already started');
        }
        this._started = true;
        await PromiseHelper.setImmediate();
        await this.execute();
    }

    log () {
        this.task.log(...arguments);
    }
};

const PromiseHelper = require('../helper/PromiseHelper');


text:
<?php

/**
 * Points hook reaction condition DOM element class.
 *
 * @package WordPoints_Dev_Lib
 * @since 2.5.0
 */

namespace WordPoints\Tests\Codeception\Element;

use WordPoints\Tests\Codeception\AcceptanceTester;
use WordPoints\Tests\Codeception\Element;

/**
 * Represents the element for a points hook reaction condition in the DOM.
 *
 * @since 2.5.0
 */
class ReactionCondition extends Element {

	/**
	 * Construct the element with its parent reaction element.
	 *
	 * @since 2.5.0
	 *
	 * @param AcceptanceTester $actor    The actor object.
	 * @param Reaction         $reaction The reaction element object.
	 */
	public function __construct( AcceptanceTester $actor, Reaction $reaction ) {

		$this->setActor( $actor );

		$this->selector = $reaction . '.condition ';
	}

	/**
	 * Delete the condition.
	 *
	 * @since 2.5.0
	 */
	public function delete() {
		$I = $this->actor;
		$I->click( 'Remove Condition', $this->selector );
	}
}

// EOF


text:
import unittest2
import sys

if __name__ == '__main__':

    count = 0
    errors = 0
    fails = 0

    runner = unittest2.TextTestRunner()
    loader = unittest2.TestLoader()
    suites = loader.discover('./ztest', pattern='zt_*.py')
    for suite in suites:
        result = runner.run(suite)
        errors += len(result.errors)
        fails += len(result.failures)
        count += suite.countTestCases()

    runner.stream.writeln('%s tests, %s errors %s fails' % (count, errors,
                                                            fails))

    if errors or fails:
        sys.exit(1)


text:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="bc.css">

### Roadmap, Rebar Curves, Wizard Zip and More

I returned from my vacation and Buddhist retreat in France, on the Atlantic coast and in the countryside around Bordeaux.

I am going off on vacation again next week, though, in the French Jura, so this is just a short break in between vacations  :-)

Here are my topics for this week:

- [Revit public roadmap – July 2019](#2)
- [Rebar curves](#3)
- [Built-in zip utility for add-in wizard](#4)
- [Only detail section views can be used for top view direction](#5)
- [Displaying an RFA family instance in DA4R](#6)
- [Revit 2020 alters the TEMP file system variable](#7)
- [Lattice multiplication](#8)

#### Revit Public Roadmap – July 2019

Sasha Crotty and The Factory published
an [update to the *Revit Public Roadmap – July 2019*](https://blogs.autodesk.com/revit/2019/07/21/revit-public-roadmap-july-2019).

I urge you to check it out to see where Revit is headed.

If you wish to get involved, submit your own ideas and requests, please do so in
the [Revit Idea Station](http://www.autodesk.com/RevitIdeas).

#### Rebar Curves

I recently implemented
a new [external command `CmdRebarCurves`](https://github.com/jeremytammik/the_building_coder_samples/blob/master/BuildingCoder/BuildingCoder/CmdRebarCurves.cs)
in [The Building Coder samples](https://github.com/jeremytammik/the_building_coder_samples).

It was originally intended to be used to simplify and minimise models for Forge processing.

However, it seems that may no longer be required, since
Michael [@micbeale](https://twitter.com/micbeale) [@wallabyway](https://github.com/wallabyway) Beale lists
some alternative options as well:

>    - Avoid Revit solids due to 'triangle explosion', i.e., too many triangles in SVF, making downstream processing extremely problematic and expensive.
>    - Jeremy looked into using the Revit API, prototyping a Revit API plugin solution to be piped through DA4R to extract the Revit primitive information about the rebar centre lines that can avoid the triangle explosion problem.
>    - We are now investigating a new 'rebar-lines' solution that includes enough meta-data information to avoid needing Jeremy's add-in.

> The latter is the winning solution, since it avoids the triangle explosion, because rebar-lines use low bytes compared to the heavily tessellated rebar-solids, and we can create 'unit-mesh' cylinder primitives during Forge processing, thus outputting highly optimised rebar solids in a future  updated Forge Viewer.

Therefore, I see no need to enhance the current `CmdRebarCurves` implementation at this point.

I still hope that it will remain useful in its current state for answering questions such as the following one from
the [Revit API discussion forum](http://forums.autodesk.com/t5/revit-api-forum/bd-p/160) thread
on [getting rebar centreline curves using `GetCenterlineCurves`](https://forums.autodesk.com/t5/revit-api-forum/cannot-get-rebar-centerline-curve-using-getcenterlinecurves/m-p/8910986):

**Question:** I am using the Revit 2019 API and I want to get the centre line curve of the first and the last rebars in a rebar set.
I tried using the following method:

  Rebar.GetCenterlineCurves(
    bool adjustForSelfIntersection,
    bool suppressHooks,
    bool suppressBendRadius,
    MultiplanarOption multiplanarOption,
    int barPositionIndex);

However, it seems that the parameter `barPositionIndex` has no effect at all.

No matter what valid position index of the rebar set I input, the curve list I receive is the curves of the first bar – the same as the result of calling `RebarShapeDriveAccessor.ComputeDrivingCurve`.

How is this possible? Is there anything I missed in the document?

P.S. I found another way to achieve what I want by translating the first rebar curves along the direction of rebar set.

**Answer:** Congratulations on solving the problem as described in your post scriptum.

Take a look at the
new [external command `CmdRebarCurves`](https://github.com/jeremytammik/the_building_coder_samples/blob/master/BuildingCoder/BuildingCoder/CmdRebarCurves.cs)
in [The Building Coder samples](https://github.com/jeremytammik/the_building_coder_samples).

It seems to be using the very same approach you describe.

Manuel Solís López of [SOFiSTiK AG](https://www.sofistik.com) explains:

`Rebar.GetCenterlineCurves(... , i )` will return the curves of the Rebar at the i-th position.

However, You must distinguish three different cases, depending on the `DistributionType`:

- `Uniform` – The rebar curves will be equal at all valid positions.
- `VaryingLength` – According to the rebar constraints, the rebar curves may vary along the distribution path. For example, a set of straight rebar in a triangular slab.
- `IsRebarFreeForm()` == `true` – The Rebar curves of FreeFormRebar at each position will be defined by the given constraints, but also by the specific RebarUpdateServer to which the Rebar is subscribed, for instance using SurfaceDistribution or AlignedDistribution.

The Rebar curves at each i-th position could vary or not, but in case of non-FreeFormRebar (Rebar.IsRebarFreeForm() == false), you would have to apply the corresponding Transformation in order to obtain the actual location in 3D Space:

  Rebar.GetShapeDrivenAccessor()
    .GetBarPositionTransform(i);

Many thanks to Manuel for his helpful explanation!

#### Built-In Zip Utility for Add-In Wizard

The [Visual Studio Revit add-in wizards](https://thebuildingcoder.typepad.com/blog/about-the-author.html#5.20) provide
Visual Studio templates for generating C# and VB .NET Revit add-ins.
They enable the instantaneous automatic generation, installation and debugging of a new Revit add-in skeleton with one single click.

The current version of the wizards now includes a built-in zip utility.

It was added by Brandon [@ProjectBarks](https://github.com/ProjectBarks) Barker
in his [pull request #9 providing Visual Studio version support and an integrated zip utility](https://github.com/jeremytammik/VisualStudioRevitAddinWizard/pull/9).

The most up-to-date version today
is [VisualStudioRevitAddinWizard release 2020.0.0.1](https://github.com/jeremytammik/VisualStudioRevitAddinWizard/releases/tag/2020.0.0.1).

Many thanks to Brandon for this useful contribution!

#### Only Detail Section Views can be Used for Top View Direction

In another case, an add-in developer wishes to create a section view with a top view direction:

- 15565451 *试用 SectionView创建俯视图。– try `SectionView` to create a top view*

**Question:** When passing the `BoundingBoxXYZ` parameter, what is the requirement for the corresponding base(i) vector?
What is the specific logic?

I tried it myself, and it seems that the logic of `BoundingBoxXYZ` is different when generating an inside view and generating a top view.

Do any special rules apply when using the `ViewSection` creation methods to generate a top view, i.e., view direction equal to (0,0,-1)?

**Answer:** Looking at the Revit API documentation, the `ViewSection` class covers sections, details, elevations, and callouts, all in their reference and non-reference variations. Its creation methods can be used to specify the view direction:

- CreateCallout Creates a new callout view.
- CreateDetail Returns a new detail ViewSection.
- CreateReferenceCallout Creates a new reference callout.
- CreateReferenceSection Creates a new reference section.
- CreateSection Returns a new section ViewSection.

In the last of these,
[CreateSection](https://www.revitapidocs.com/2020/d6228f68-3643-8aaf-72bb-f9a0b4125886.htm),
the notes explain:

> Create a section whose view volume corresponds geometrically with the specified sectionBox.
The view direction of the resulting section will be sectionBox.Transform.BasisZ and the up direction will be sectionBox.Transform.BasisY.
The right-hand direction will be computed so that (right, up, view direction) form a left handed coordinate system.
The resulting view will be cropped, and far clipping will be active.
The crop region will correspond to the projections of BoundingBoxXYZ.Min and BoundingBoxXYZ.Max onto the view's cut plane.
The far clip distance will be equal to the difference of the z-coordinates of BoundingBoxXYZ.Min and BoundingBoxXYZ.Max.
The new section ViewSection will receive a unique view name.

The development team clarifies:

For most section views, the UI does not allow this, and therefore the API does not do so either.

Sections created in elevation views must be vertical.

For instance, `ViewSection.CreateSection` restricts the view direction to be horizontal, i.e., the view plane to be vertical.

However, `ViewSection.CreateDetail` has no restrictions on the view direction and can therefore be used to create a section view parallel to a plan view.

So, you should be able to use a detail view to achieve what you require.

#### Displaying an RFA Family Instance in DA4R

[Forge Design Automation for Revit or DA4R](https://thebuildingcoder.typepad.com/blog/about-the-author.html#5.55) supports RVT file processing, but not RFA.

This begs the question:

**Question:** I came across an AU class recording showing a customer with WS Atkins & Partners demoing their Revit IO apps.

One thing it showed was extracting Revit families using Revit IO and displaying them on the web using the Forge derivative service and viewer.

However, I don't believe the derivative service supports the RFA file type.

Do you know how they managed to show 3D models of Revit families on the web?

**Answer:** The workaround is to place a family instance in an empty project and have it translated.

So, the source files are actually RVT, not RFA.

#### Revit 2020 Alters the TEMP File System Variable

Many add-in make use of the Windows `TEMP` system variable to define a path for outputting a temporary file.

Revit 2020 apparently alters the value of that variable, affecting the add-in behaviour as well.

I ran into this issue myself, prompting me to discover the StackOverflow discussion
on [`Path.GetTempPath` method returning `UserTempPath` with GUID added in Revit 2020](https://stackoverflow.com/questions/56984043/path-gettemppath-method-returns-usertemppath-with-guid-in-the-end-when-using-r).

The answers there explain:

- Since Revit 2020, the requested temp path contains an additional GUID at the end of the path that changes after every restart of Revit, i.e.,  *C:\Users\USERNAME\AppData\Local\Temp\84ae8c0d-197b-4b44-b8d3-8823fabbba4f*.
- That's probably due to Revit defining its own %TMP/TEMP% environment variable
- [Revit 2020 temp path changes every session](https://forums.autodesk.com/t5/revit-api-forum/revit-2020-temp-path-changes-every-session/td-p/8759058)

Apparently, Revit changes the temp path for the scope of the application.

I chose the easy solution in my add-in, using a constant `"C:/tmp"` instead.

Other possible solutions include:

- Searching for "Temp" and dropping the GUID sub-folder
- Using

      Environment.GetFolderPath(
        Environment.SpecialFolder.ApplicationData )
          + @"\AppData\Local\Temp\"

- Using

      Path.Combine(
        System.Environment.GetEnvironmentVariable(
          "LOCALAPPDATA" ),
            "Temp")

#### Lattice Multiplication

Let us round this off with an interesting little mathematical non-Revit-API observation:

I ran across several neat demonstrations of an ancient and well-known multiplication method previously unknown to me,
[lattice multiplication](https://en.wikipedia.org/wiki/Lattice_multiplication), e.g. this
three-minute video on [multiplying numbers by drawing lines](https://youtu.be/bbKjXKV9QNA):


text:
using System;

using Microsoft.FSharp.Core;

namespace Amazon.SimpleWorkflow.Extensions.Builders
{
    internal sealed class ActivityBuilderImpl<TInput, TOutput> : IActivityBuilder<TInput, TOutput>
    {
        public ActivityBuilderImpl(
            string name,
            Func<TInput, TOutput> processor,
            int taskHeartbeatTimeout,
            int taskScheduleToStartTimeout,
            int taskStartToCloseTimeout,
            int taskScheduleToCloseTimeout)
        {
            Name = name;
            Processor = processor;
            TaskHeartbeatTimeout = taskHeartbeatTimeout;
            TaskScheduleToStartTimeout = taskScheduleToStartTimeout;
            TaskStartToCloseTimeout = taskStartToCloseTimeout;
            TaskScheduleToCloseTimeout = taskScheduleToCloseTimeout;
        }

        public string Name { get; private set; }

        public string Description { get; private set; }

        public string Version { get; private set; }

        public string TaskList { get; private set; }

        public Func<TInput, TOutput> Processor { get; private set; }

        public int TaskHeartbeatTimeout { get; private set; }

        public int TaskScheduleToStartTimeout { get; private set; }

        public int TaskStartToCloseTimeout { get; private set; }

        public int TaskScheduleToCloseTimeout { get; private set; }

        public int? MaxAttempts { get; private set; }

        public IActivityBuilder<TInput, TOutput> WithVersion(string version)
        {
            Version = version;
            return this;
        }

        public IActivityBuilder<TInput, TOutput> WithDescription(string description)
        {
            Description = description;
            return this;
        }

        public IActivityBuilder<TInput, TOutput> WithTaskList(string taskList)
        {
            TaskList = taskList;
            return this;
        }

        public IActivityBuilder<TInput, TOutput> WithMaxAttempts(int maxAttempts)
        {
            MaxAttempts = maxAttempts;
            return this;
        }

        public IActivity Complete()
        {
            var processor = FuncConvert.ToFSharpFunc(new Converter<TInput, TOutput>(Processor));

            return new Activity<TInput, TOutput>(
                            Name,
                            Description,
                            processor,
                            TaskHeartbeatTimeout,
                            TaskScheduleToStartTimeout,
                            TaskStartToCloseTimeout,
                            TaskScheduleToCloseTimeout,
                            Version.AsOption(string.IsNullOrWhiteSpace),
                            TaskList.AsOption(string.IsNullOrWhiteSpace),
                            MaxAttempts.AsOption());
        }
    }
}


text:
Add Signature:

    <form id="sigAddForm" class="form-inline" action="system/signatures/add" method="post">
        {% csrf_token %}
        {% for field in form %}
            {% if field.errors %}

{{field.errors}}

            {% endif %}
            {{field.label_tag}} {{field}} &nbsp
        {% endfor %}
        <input class="btn btn-primary" type="submit" value="Add Sig" />
    </form>