text:
import {
  AnchorValue,
  Axis as VgAxis,
  Legend as VgLegend,
  NewSignal,
  Projection as VgProjection,
  Signal,
  SignalRef,
  Title as VgTitle
} from 'vega';
import {
  Channel,
  ExtendedChannel,
  FACET_CHANNELS,
  getPositionScaleChannel,
  isChannel,
  isScaleChannel,
  ScaleChannel,
  SingleDefChannel
} from '../channel';
import {ChannelDef, FieldDef, FieldRefOption, getFieldDef, vgField} from '../channeldef';
import {Config} from '../config';
import {Data, DataSourceType} from '../data';
import {forEach, reduce} from '../encoding';
import {ExprRef, replaceExprRef} from '../expr';
import * as log from '../log';
import {Resolve} from '../resolve';
import {hasDiscreteDomain} from '../scale';
import {isFacetSpec} from '../spec';
import {
  extractCompositionLayout,
  GenericCompositionLayoutWithColumns,
  LayoutSizeMixins,
  SpecType,
  ViewBackground
} from '../spec/base';
import {NormalizedSpec} from '../spec/index';
import {extractTitleConfig, isText, TitleParams} from '../title';
import {normalizeTransform, Transform} from '../transform';
import {contains, Dict, duplicate, isEmpty, keys, varName} from '../util';
import {isVgRangeStep, VgData, VgEncodeEntry, VgLayout, VgMarkGroup} from '../vega.schema';
import {assembleAxes} from './axis/assemble';
import {AxisComponentIndex} from './axis/component';
import {signalOrValueRef} from './common';
import {ConcatModel} from './concat';
import {DataComponent} from './data';
import {FacetModel} from './facet';
import {assembleHeaderGroups, assembleLayoutTitleBand, assembleTitleGroup} from './header/assemble';
import {HEADER_CHANNELS, LayoutHeaderComponent} from './header/component';
import {LayerModel} from './layer';
import {sizeExpr} from './layoutsize/assemble';
import {
  getSizeTypeFromLayoutSizeType,
  LayoutSizeComponent,
  LayoutSizeIndex,
  LayoutSizeType
} from './layoutsize/component';
import {assembleLegends} from './legend/assemble';
import {LegendComponentIndex} from './legend/component';
import {parseLegend} from './legend/parse';
import {assembleProjections} from './projection/assemble';
import {ProjectionComponent} from './projection/component';
import {parseProjection} from './projection/parse';
import {assembleScales} from './scale/assemble';
import {ScaleComponent, ScaleComponentIndex} from './scale/component';
import {assembleDomain, getFieldFromDomain} from './scale/domain';
import {parseScales} from './scale/parse';
import {SelectionComponent} from './selection';
import {Split} from './split';
import {UnitModel} from './unit';

/**
 * Composable Components that are intermediate results of the parsing phase of the
 * compilations. The components represents parts of the specification in a form that
 * can be easily merged (during parsing for composite specs).
 * In addition, these components are easily transformed into Vega specifications
 * during the "assemble" phase, which is the last phase of the compilation step.
 */
export interface Component {
  data: DataComponent;

  layoutSize: LayoutSizeComponent;

  layoutHeaders: {
    row?: LayoutHeaderComponent;
    column?: LayoutHeaderComponent;
    facet?: LayoutHeaderComponent;
  };

  mark: VgMarkGroup[];
  scales: ScaleComponentIndex;
  projection: ProjectionComponent;
  selection: Dict<SelectionComponent>;

  /** Dictionary mapping channel to VgAxis definition */
  axes: AxisComponentIndex;

  /** Dictionary mapping channel to VgLegend definition */
  legends: LegendComponentIndex;

  resolve: Resolve;
}

export interface NameMapInterface {
  rename(oldname: string, newName: string): void;
  has(name: string): boolean;
  get(name: string): string;
}

export class NameMap implements NameMapInterface {
  private nameMap: Dict<string>;

  constructor() {
    this.nameMap = {};
  }

  public rename(oldName: string, newName: string) {
    this.nameMap[oldName] = newName;
  }

  public has(name: string): boolean {
    return this.nameMap[name] !== undefined;
  }

  public get(name: string): string {
    // If the name appears in the _nameMap, we need to read its new name.
    // We have to loop over the dict just in case the new name also gets renamed.
    while (this.nameMap[name] && name !== this.nameMap[name]) {
      name = this.nameMap[name];
    }

    return name;
  }
}

/*
  We use type guards instead of `instanceof` as `instanceof` makes
  different parts of the compiler depend on the actual implementation of
  the model classes, which in turn depend on different parts of the compiler.
  Thus, `instanceof` leads to circular dependency problems.

  On the other hand, type guards only make different parts of the compiler
  depend on the type of the model classes, but not the actual implementation.
*/

export function isUnitModel(model: Model): model is UnitModel {
  return model?.type === 'unit';
}

export function isFacetModel(model: Model): model is FacetModel {
  return model?.type === 'facet';
}

export function isConcatModel(model: Model): model is ConcatModel {
  return model?.type === 'concat';
}

export function isLayerModel(model: Model): model is LayerModel {
  return model?.type === 'layer';
}

export abstract class Model {
  public readonly name: string;

  public size: LayoutSizeMixins;

  public readonly title: TitleParams<SignalRef>;
  public readonly description: string;

  public readonly data: Data | null;
  public readonly transforms: Transform[];
  public readonly layout: GenericCompositionLayoutWithColumns;

  /** Name map for scales, which can be renamed by a model's parent. */
  protected scaleNameMap: NameMapInterface;

  /** Name map for projections, which can be renamed by a model's parent. */
  protected projectionNameMap: NameMapInterface;

  /** Name map for signals, which can be renamed by a model's parent. */
  protected signalNameMap: NameMapInterface;

  public readonly component: Component;

  public readonly view?: ViewBackground<SignalRef>;

  public abstract readonly children: Model[] = [];

  constructor(
    spec: NormalizedSpec,
    public readonly type: SpecType,
    public readonly parent: Model,
    parentGivenName: string,
    public readonly config: Config<SignalRef>,
    resolve: Resolve,
    view?: ViewBackground<ExprRef | SignalRef>
  ) {
    this.parent = parent;
    this.config = config;
    this.view = replaceExprRef(view);

    // If name is not provided, always use parent's givenName to avoid name conflicts.
    this.name = spec.name ?? parentGivenName;
    this.title = isText(spec.title) ? {text: spec.title} : spec.title ? replaceExprRef(spec.title) : undefined;

    // Shared name maps
    this.scaleNameMap = parent ? parent.scaleNameMap : new NameMap();
    this.projectionNameMap = parent ? parent.projectionNameMap : new NameMap();
    this.signalNameMap = parent ? parent.signalNameMap : new NameMap();

    this.data = spec.data;

    this.description = spec.description;
    this.transforms = normalizeTransform(spec.transform ?? []);
    this.layout = type === 'layer' || type === 'unit' ? {} : extractCompositionLayout(spec, type, config);

    this.component = {
      data: {
        sources: parent ? parent.component.data.sources : [],
        outputNodes: parent ? parent.component.data.outputNodes : {},
        outputNodeRefCounts: parent ? parent.component.data.outputNodeRefCounts : {},
        // data is faceted if the spec is a facet spec or the parent has faceted data and data is undefined
        isFaceted: isFacetSpec(spec) || (parent && parent.component.data.isFaceted && spec.data === undefined)
      },
      layoutSize: new Split<LayoutSizeIndex>(),
      layoutHeaders: {row: {}, column: {}, facet: {}},
      mark: null,
      resolve: {
        scale: {},
        axis: {},
        legend: {},
        ...(resolve ? duplicate(resolve) : {})
      },
      selection: null,
      scales: null,
      projection: null,
      axes: {},
      legends: {}
    };
  }

  public get width(): SignalRef {
    return this.getSizeSignalRef('width');
  }

  public get height(): SignalRef {
    return this.getSizeSignalRef('height');
  }

  public parse() {
    this.parseScale();

    this.parseLayoutSize(); // depends on scale
    this.renameTopLevelLayoutSizeSignal();

    this.parseSelections();
    this.parseProjection();
    this.parseData(); // (pathorder) depends on markDef; selection filters depend on parsed selections; depends on projection because some transforms require the finalized projection name.
    this.parseAxesAndHeaders(); // depends on scale and layout size
    this.parseLegends(); // depends on scale, markDef
    this.parseMarkGroup(); // depends on data name, scale, layout size, axisGroup, and children's scale, axis, legend and mark.
  }

  public abstract parseData(): void;

  public abstract parseSelections(): void;

  public parseScale() {
    parseScales(this);
  }

  public parseProjection() {
    parseProjection(this);
  }

  public abstract parseLayoutSize(): void;

  /**
   * Rename top-level spec's size to be just width / height, ignoring model name.
   * This essentially merges the top-level spec's width/height signals with the width/height signals
   * to help us reduce redundant signals declaration.
   */
  private renameTopLevelLayoutSizeSignal() {
    if (this.getName('width') !== 'width') {
      this.renameSignal(this.getName('width'), 'width');
    }
    if (this.getName('height') !== 'height') {
      this.renameSignal(this.getName('height'), 'height');
    }
  }

  public abstract parseMarkGroup(): void;

  public abstract parseAxesAndHeaders(): void;

  public parseLegends() {
    parseLegend(this);
  }

  public abstract assembleSelectionTopLevelSignals(signals: NewSignal[]): NewSignal[];
  public abstract assembleSignals(): NewSignal[];

  public abstract assembleSelectionData(data: readonly VgData[]): readonly VgData[];

  public assembleGroupStyle(): string | string[] {
    if (this.type === 'unit' || this.type === 'layer') {
      return this.view?.style ?? 'cell';
    }
    return undefined;
  }

  private assembleEncodeFromView(view: ViewBackground<SignalRef>): VgEncodeEntry {
    // Exclude "style"
    const {style: _, ...baseView} = view;

    const e: VgEncodeEntry = {};
    for (const property of keys(baseView)) {
      const value = baseView[property];
      if (value !== undefined) {
        e[property] = signalOrValueRef(value);
      }
    }

    return e;
  }

  public assembleGroupEncodeEntry(isTopLevel: boolean): VgEncodeEntry {
    let encodeEntry: VgEncodeEntry = {};
    if (this.view) {
      encodeEntry = this.assembleEncodeFromView(this.view);
    }

    if (!isTopLevel) {
      // Descriptions are already added to the top-level description so we only need to add them to the inner views.
      if (this.description) {
        encodeEntry['description'] = signalOrValueRef(this.description);
      }

      // For top-level spec, we can set the global width and height signal to adjust the group size.
      // For other child specs, we have to manually set width and height in the encode entry.
      if (this.type === 'unit' || this.type === 'layer') {
        return {
          width: this.getSizeSignalRef('width'),
          height: this.getSizeSignalRef('height'),
          ...(encodeEntry ?? {})
        };
      }
    }

    return isEmpty(encodeEntry) ? undefined : encodeEntry;
  }

  public assembleLayout(): VgLayout {
    if (!this.layout) {
      return undefined;
    }

    const {spacing, ...layout} = this.layout;

    const {component, config} = this;
    const titleBand = assembleLayoutTitleBand(component.layoutHeaders, config);

    return {
      padding: spacing,
      ...this.assembleDefaultLayout(),
      ...layout,
      ...(titleBand ? {titleBand} : {})
    };
  }

  protected assembleDefaultLayout(): VgLayout {
    return {};
  }

  public abstract assembleLayoutSignals(): NewSignal[];

  public assembleHeaderMarks(): VgMarkGroup[] {
    const {layoutHeaders} = this.component;
    let headerMarks = [];

    for (const channel of FACET_CHANNELS) {
      if (layoutHeaders[channel].title) {
        headerMarks.push(assembleTitleGroup(this, channel));
      }
    }

    for (const channel of HEADER_CHANNELS) {
      headerMarks = headerMarks.concat(assembleHeaderGroups(this, channel));
    }
    return headerMarks;
  }

  public abstract assembleMarks(): VgMarkGroup[];

  public assembleAxes(): VgAxis[] {
    return assembleAxes(this.component.axes, this.config);
  }

  public assembleLegends(): VgLegend[] {
    return assembleLegends(this);
  }

  public assembleProjections(): VgProjection[] {
    return assembleProjections(this);
  }

  public assembleTitle(): VgTitle {
    const {encoding, ...titleNoEncoding} = this.title ?? ({} as TitleParams<SignalRef>);

    const title: VgTitle = {
      ...extractTitleConfig(this.config.title).nonMark,
      ...titleNoEncoding,
      ...(encoding ? {encode: {update: encoding}} : {})
    };

    if (title.text) {
      if (contains(['unit', 'layer'], this.type)) {
        // Unit/Layer
        if (contains<AnchorValue>(['middle', undefined], title.anchor)) {
          title.frame ??= 'group';
        }
      } else {
        // composition with Vega layout

        // Set title = "start" by default for composition as "middle" does not look nice
        // https://github.com/vega/vega/issues/960#issuecomment-471360328
        title.anchor ??= 'start';
      }

      return isEmpty(title) ? undefined : title;
    }
    return undefined;
  }

  /**
   * Assemble the mark group for this model. We accept optional `signals` so that we can include concat top-level signals with the top-level model's local signals.
   */
  public assembleGroup(signals: Signal[] = []) {
    const group: VgMarkGroup = {};

    signals = signals.concat(this.assembleSignals());

    if (signals.length > 0) {
      group.signals = signals;
    }

    const layout = this.assembleLayout();
    if (layout) {
      group.layout = layout;
    }

    group.marks = [].concat(this.assembleHeaderMarks(), this.assembleMarks());

    // Only include scales if this spec is top-level or if parent is facet.
    // (Otherwise, it will be merged with upper-level's scope.)
    const scales = !this.parent || isFacetModel(this.parent) ? assembleScales(this) : [];
    if (scales.length > 0) {
      group.scales = scales;
    }

    const axes = this.assembleAxes();
    if (axes.length > 0) {
      group.axes = axes;
    }

    const legends = this.assembleLegends();
    if (legends.length > 0) {
      group.legends = legends;
    }

    return group;
  }

  public getName(text: string) {
    return varName((this.name ? `${this.name}_` : '') + text);
  }

  public getDataName(type: DataSourceType) {
    return this.getName(DataSourceType[type].toLowerCase());
  }

  /**
   * Request a data source name for the given data source type and mark that data source as required.
   * This method should be called in parse, so that all used data source can be correctly instantiated in assembleData().
   * You can lookup the correct dataset name in assemble with `lookupDataSource`.
   */
  public requestDataName(name: DataSourceType) {
    const fullName = this.getDataName(name);

    // Increase ref count. This is critical because otherwise we won't create a data source.
    // We also increase the ref counts on OutputNode.getSource() calls.
    const refCounts = this.component.data.outputNodeRefCounts;
    refCounts[fullName] = (refCounts[fullName] || 0) + 1;

    return fullName;
  }

  public getSizeSignalRef(layoutSizeType: LayoutSizeType): SignalRef {
    if (isFacetModel(this.parent)) {
      const sizeType = getSizeTypeFromLayoutSizeType(layoutSizeType);
      const channel = getPositionScaleChannel(sizeType);
      const scaleComponent = this.component.scales[channel];

      if (scaleComponent && !scaleComponent.merged) {
        // independent scale
        const type = scaleComponent.get('type');
        const range = scaleComponent.get('range');

        if (hasDiscreteDomain(type) && isVgRangeStep(range)) {
          const scaleName = scaleComponent.get('name');
          const domain = assembleDomain(this, channel);
          const field = getFieldFromDomain(domain);
          if (field) {
            const fieldRef = vgField({aggregate: 'distinct', field}, {expr: 'datum'});
            return {
              signal: sizeExpr(scaleName, scaleComponent, fieldRef)
            };
          } else {
            log.warn(log.message.unknownField(channel));
            return null;
          }
        }
      }
    }

    return {
      signal: this.signalNameMap.get(this.getName(layoutSizeType))
    };
  }

  /**
   * Lookup the name of the datasource for an output node. You probably want to call this in assemble.
   */
  public lookupDataSource(name: string) {
    const node = this.component.data.outputNodes[name];

    if (!node) {
      // Name not found in map so let's just return what we got.
      // This can happen if we already have the correct name.
      return name;
    }

    return node.getSource();
  }

  public getSignalName(oldSignalName: string): string {
    return this.signalNameMap.get(oldSignalName);
  }

  public renameSignal(oldName: string, newName: string) {
    this.signalNameMap.rename(oldName, newName);
  }

  public renameScale(oldName: string, newName: string) {
    this.scaleNameMap.rename(oldName, newName);
  }

  public renameProjection(oldName: string, newName: string) {
    this.projectionNameMap.rename(oldName, newName);
  }

  /**
   * @return scale name for a given channel after the scale has been parsed and named.
   */
  public scaleName(originalScaleName: ScaleChannel | string, parse?: boolean): string {
    if (parse) {
      // During the parse phase always return a value
      // No need to refer to rename map because a scale can't be renamed
      // before it has the original name.
      return this.getName(originalScaleName);
    }

    // If there is a scale for the channel, it should either
    // be in the scale component or exist in the name map
    if (
      // If there is a scale for the channel, there should be a local scale component for it
      (isChannel(originalScaleName) && isScaleChannel(originalScaleName) && this.component.scales[originalScaleName]) ||
      // in the scale name map (the scale get merged by its parent)
      this.scaleNameMap.has(this.getName(originalScaleName))
    ) {
      return this.scaleNameMap.get(this.getName(originalScaleName));
    }
    return undefined;
  }

  /**
   * @return projection name after the projection has been parsed and named.
   */
  public projectionName(parse?: boolean): string {
    if (parse) {
      // During the parse phase always return a value
      // No need to refer to rename map because a projection can't be renamed
      // before it has the original name.
      return this.getName('projection');
    }

    if (
      (this.component.projection && !this.component.projection.merged) ||
      this.projectionNameMap.has(this.getName('projection'))
    ) {
      return this.projectionNameMap.get(this.getName('projection'));
    }
    return undefined;
  }

  /**
   * Corrects the data references in marks after assemble.
   */
  public correctDataNames = (mark: VgMarkGroup) => {
    // TODO: make this correct

    // for normal data references
    if (mark.from?.data) {
      mark.from.data = this.lookupDataSource(mark.from.data);
    }

    // for access to facet data
    if (mark.from?.facet?.data) {
      mark.from.facet.data = this.lookupDataSource(mark.from.facet.data);
    }

    return mark;
  };

  /**
   * Traverse a model's hierarchy to get the scale component for a particular channel.
   */
  public getScaleComponent(channel: ScaleChannel): ScaleComponent {
    /* istanbul ignore next: This is warning for debugging test */
    if (!this.component.scales) {
      throw new Error(
        'getScaleComponent cannot be called before parseScale(). Make sure you have called parseScale or use parseUnitModelWithScale().'
      );
    }

    const localScaleComponent = this.component.scales[channel];
    if (localScaleComponent && !localScaleComponent.merged) {
      return localScaleComponent;
    }
    return this.parent ? this.parent.getScaleComponent(channel) : undefined;
  }

  /**
   * Traverse a model's hierarchy to get a particular selection component.
   */
  public getSelectionComponent(variableName: string, origName: string): SelectionComponent {
    let sel = this.component.selection[variableName];
    if (!sel && this.parent) {
      sel = this.parent.getSelectionComponent(variableName, origName);
    }
    if (!sel) {
      throw new Error(log.message.selectionNotFound(origName));
    }
    return sel;
  }

  /**
   * Returns true if the model has a signalRef for an axis orient.
   */
  public hasAxisOrientSignalRef() {
    return (
      this.component.axes.x?.some(a => a.hasOrientSignalRef()) ||
      this.component.axes.y?.some(a => a.hasOrientSignalRef())
    );
  }
}

/** Abstract class for UnitModel and FacetModel. Both of which can contain fieldDefs as a part of its own specification. */
export abstract class ModelWithField extends Model {
  public abstract fieldDef(channel: SingleDefChannel): FieldDef<any>;

  /** Get "field" reference for Vega */
  public vgField(channel: SingleDefChannel, opt: FieldRefOption = {}) {
    const fieldDef = this.fieldDef(channel);

    if (!fieldDef) {
      return undefined;
    }

    return vgField(fieldDef, opt);
  }

  protected abstract getMapping(): Partial<Record<ExtendedChannel, any>>;

  public reduceFieldDef<T, U>(f: (acc: U, fd: FieldDef<string>, c: Channel) => U, init: T): T {
    return reduce(
      this.getMapping(),
      (acc: U, cd: ChannelDef, c: Channel) => {
        const fieldDef = getFieldDef(cd);
        if (fieldDef) {
          return f(acc, fieldDef, c);
        }
        return acc;
      },
      init
    );
  }

  public forEachFieldDef(f: (fd: FieldDef<string>, c: ExtendedChannel) => void, t?: any) {
    forEach(
      this.getMapping(),
      (cd, c) => {
        const fieldDef = getFieldDef(cd);
        if (fieldDef) {
          f(fieldDef, c);
        }
      },
      t
    );
  }

  public abstract channelHasField(channel: Channel): boolean;
}


text:
package gc

import (
	"context"
	"sort"
	"sync"
	"time"

	"github.com/globalsign/mgo/bson"
	"github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promauto"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/api/shutdown"
	"github.com/tsuru/tsuru/app"
	"github.com/tsuru/tsuru/app/image"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/log"
	"github.com/tsuru/tsuru/permission"
	"github.com/tsuru/tsuru/registry"
	"github.com/tsuru/tsuru/servicemanager"
	appTypes "github.com/tsuru/tsuru/types/app"
	permTypes "github.com/tsuru/tsuru/types/permission"
)

const (
	imageGCRunInterval = 5 * time.Minute
	promNamespace      = "tsuru"
	promSubsystem      = "gc"
)

var (
	gcExecutionsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "executions_total",
		Help:      "The number of times that gc had runned by phase",
	}, []string{"phase"})

	executionDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "execution_duration_seconds",
		Help:      "How long during the GC process",
		Buckets:   prometheus.ExponentialBuckets(0.1, 2.7, 10),
	}, []string{"phase"})

	versionsMarkedToRemovalTotal = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "versions_marked_to_removal_total",
		Help:      "The number of versions of applications that was marked to removal",
	})

	// just used for dockercluster provisioner
	provisionerPruneTotal = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "provisioner_prune_total",
		Help:      "The number of executions of prune against the provisioner",
	})

	provisionerPruneFailuresTotal = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "provisioner_prune_failures_total",
		Help:      "The number of failures to prune unused images from provisioner",
	})

	provisionerPruneDuration = promauto.NewHistogram(prometheus.HistogramOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "provisioner_prune_duration_seconds",
		Help:      "How long during single prune to provisioner",
		Buckets:   prometheus.ExponentialBuckets(0.005, 4, 10),
	})

	// registry metrics
	registryPruneTotal = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "registry_prune_total",
		Help:      "The number of executions of prune against the registry",
	})

	registryPruneFailuresTotal = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "registry_prune_failures_total",
		Help:      "The number of failures to prune unused images from registry",
	})

	registryPruneDuration = promauto.NewHistogram(prometheus.HistogramOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "registry_prune_duration_seconds",
		Help:      "How long during single prune to registry",
		Buckets:   prometheus.ExponentialBuckets(0.005, 4, 10),
	})

	// database metrics
	storagePruneTotal = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "storage_prune_total",
		Help:      "The number of executions of prune against the storage",
	})

	storagePruneFailuresTotal = promauto.NewCounter(prometheus.CounterOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "storage_prune_failures_total",
		Help:      "The number of failures to prune unused images from storage",
	})

	storagePruneDuration = promauto.NewHistogram(prometheus.HistogramOpts{
		Namespace: promNamespace,
		Subsystem: promSubsystem,
		Name:      "storage_prune_duration_seconds",
		Help:      "How long during single prune to storage",
		Buckets:   prometheus.ExponentialBuckets(0.005, 4, 10),
	})
)

func init() {
	event.SetThrottling(event.ThrottlingSpec{
		TargetType: event.TargetTypeGC,
		KindName:   "gc",
		Time:       imageGCRunInterval,
		Max:        1,
		AllTargets: true,
		WaitFinish: true,
	})
}

func Initialize() error {
	gc := &imgGC{once: &sync.Once{}}
	gc.start()
	shutdown.Register(gc)
	return nil
}

type imgGC struct {
	once   *sync.Once
	stopCh chan struct{}
}

func (g *imgGC) start() {
	g.once.Do(func() {
		g.stopCh = make(chan struct{})
		go g.spin()
	})
}

func (g *imgGC) Shutdown(ctx context.Context) error {
	if g.stopCh == nil {
		return nil
	}
	g.stopCh <- struct{}{}
	g.stopCh = nil
	g.once = &sync.Once{}
	return nil
}

func (g *imgGC) spin() {
	for {
		runPeriodicGC()

		select {
		case <-g.stopCh:
			return
		case <-time.After(imageGCRunInterval):
		}
	}
}

func runPeriodicGC() (err error) {
	evt, err := event.NewInternal(&event.Opts{
		Target:       event.Target{Type: event.TargetTypeGC, Value: "global"},
		InternalKind: "gc",
		Allowed:      event.Allowed(permission.PermAppReadEvents, permission.Context(permTypes.CtxGlobal, "")),
	})
	defer func() {
		if err != nil {
			log.Errorf("[image gc] %v", err)
		}
		if evt == nil {
			return
		}
		if err == nil {
			evt.Abort()
		} else {
			evt.Done(err)
		}
	}()

	if err != nil {
		_, isThrottled := err.(event.ErrThrottled)
		_, isLocked := err.(event.ErrEventLocked)
		if isThrottled || isLocked {
			gcExecutionsTotal.WithLabelValues("suspended").Inc()
			err = nil
			return
		}

		err = errors.Wrap(err, "could not create event")
		return
	}

	multi := tsuruErrors.NewMultiError()
	err = markOldImages()
	if err != nil {
		multi.Add(errors.Wrap(err, "errors running GC mark"))
	}

	dryRun, err := config.GetBool("docker:gc:dry-run")
	if err != nil {
		multi.Add(errors.Wrap(err, "fetch config error"))
	}
	if dryRun {
		err = multi.ToError()
		return
	}

	err = sweepOldImages()
	if err != nil {
		multi.Add(errors.Wrap(err, "errors running GC sweep"))
	}

	err = multi.ToError()
	return
}

func markOldImages() error {
	span, ctx := opentracing.StartSpanFromContext(context.Background(), "GC markOldImages")
	defer span.Finish()

	gcExecutionsTotal.WithLabelValues("mark").Inc()
	timer := prometheus.NewTimer(executionDuration.WithLabelValues("mark"))
	defer timer.ObserveDuration()

	log.Debugf("[image gc] starting gc process to select old images")
	defer log.Debugf("[image gc] finished gc process to select old images")
	allAppVersions, err := servicemanager.AppVersion.AllAppVersions(ctx)
	if err != nil {
		return err
	}
	historySize := image.ImageHistorySize()
	multi := tsuruErrors.NewMultiError()
	for _, appVersions := range allAppVersions {
		if len(appVersions.Versions) == 0 {
			continue
		}

		log.Debugf("[image gc] processing %d versions for app %q", len(appVersions.Versions), appVersions.AppName)
		a, err := app.GetByName(ctx, appVersions.AppName)
		if err != nil && err != appTypes.ErrAppNotFound {
			multi.Add(err)
			continue
		}
		if a == nil {
			log.Debugf("[image gc] app %q not found, mark everything to removal", appVersions.AppName)
			err = servicemanager.AppVersion.MarkToRemoval(ctx, appVersions.AppName, &appTypes.AppVersionWriteOptions{
				PreviousUpdatedHash: appVersions.UpdatedHash,
			})

			if err != nil && err != appTypes.ErrTransactionCancelledByChange {
				multi.Add(err)
			}
			continue
		}

		requireExclusiveLock, err := markOldImagesForAppVersion(ctx, a, appVersions, historySize, false)
		if err != nil {
			multi.Add(err)
			continue
		}
		if !requireExclusiveLock {
			continue
		}

		evt, err := event.NewInternal(&event.Opts{
			Target:       event.Target{Type: event.TargetTypeApp, Value: appVersions.AppName},
			InternalKind: "version gc",
			Allowed:      event.Allowed(permission.PermAppReadEvents, permission.Context(permTypes.CtxApp, appVersions.AppName)),
		})

		if err != nil {
			if _, ok := err.(event.ErrEventLocked); ok {
				continue
			}
			multi.Add(errors.Wrapf(err, "unable to acquire lock of app: %q", appVersions.AppName))
			continue
		}

		_, err = markOldImagesForAppVersion(ctx, a, appVersions, historySize, true)
		if err != nil {
			multi.Add(err)
		}
		evt.Done(err)
	}
	return multi.ToError()
}

func markOldImagesForAppVersion(ctx context.Context, a *app.App, appVersions appTypes.AppVersions, historySize int, exclusiveLockAcquired bool) (requireExclusiveLock bool, err error) {
	deployedVersions, err := a.DeployedVersions()
	if err == app.ErrNoVersionProvisioner {
		deployedVersions = []int{appVersions.LastSuccessfulVersion}
	} else if err != nil {
		return false, errors.Wrapf(err, "Could not get deployed versions of app: %s", appVersions.AppName)
	}

	selection := selectAppVersions(appVersions, deployedVersions, historySize)
	if !exclusiveLockAcquired {
		for _, version := range selection.toPruneFromProvisioner {
			pruneVersionFromProvisioner(a, version)
		}
	}
	if len(selection.toRemove) == 0 && len(selection.unsuccessfulDeploys) == 0 {
		return false, nil
	}
	if !exclusiveLockAcquired {
		return true, nil
	}

	// we can not remove a running deployment version
	// to accomplish that, let's check the every EventID whether is running.
	if len(selection.unsuccessfulDeploys) > 0 {
		var toRemove []appTypes.AppVersionInfo
		toRemove, err = versionsSafeToRemove(selection.unsuccessfulDeploys)
		if err != nil {
			return false, errors.Wrapf(err, "Could not check events running of app: %s", appVersions.AppName)
		}

		selection.toRemove = append(selection.toRemove, toRemove...)
	}

	versionIDs := []int{}
	for _, version := range selection.toRemove {
		versionsMarkedToRemovalTotal.Inc()
		versionIDs = append(versionIDs, version.Version)
	}

	err = servicemanager.AppVersion.MarkVersionsToRemoval(ctx, a.Name, versionIDs, &appTypes.AppVersionWriteOptions{
		PreviousUpdatedHash: appVersions.UpdatedHash,
	})

	if err != nil && err != appTypes.ErrTransactionCancelledByChange {
		return false, errors.Wrapf(err, "Could not mark versions to removal of app: %s", appVersions.AppName)
	}
	return false, nil
}

// versionsSafeToRemove checks whether a version does have a related event running
func versionsSafeToRemove(appVersions []appTypes.AppVersionInfo) ([]appTypes.AppVersionInfo, error) {
	uniqueIds := []bson.ObjectId{}
	mapEventID := map[string]appTypes.AppVersionInfo{}

	for _, v := range appVersions {
		if v.EventID == "" {
			continue
		}
		uniqueIds = append(uniqueIds, bson.ObjectIdHex(v.EventID))
		mapEventID[v.EventID] = v
	}

	events, err := event.List(&event.Filter{
		Raw: bson.M{
			"uniqueid": bson.M{
				"$in": uniqueIds,
			},
		},
	})

	if err != nil {
		return nil, err
	}

	safeVersions := []appTypes.AppVersionInfo{}
	for _, event := range events {
		if event.Running || event.EndTime.IsZero() {
			continue
		}

		version, found := mapEventID[event.UniqueID.Hex()]
		if !found {
			continue
		}
		safeVersions = append(safeVersions, version)
	}

	return safeVersions, nil
}

func sweepOldImages() error {
	span, ctx := opentracing.StartSpanFromContext(context.Background(), "GC sweepOldImages")
	defer span.Finish()

	gcExecutionsTotal.WithLabelValues("sweep").Inc()
	timer := prometheus.NewTimer(executionDuration.WithLabelValues("sweep"))
	defer timer.ObserveDuration()

	log.Debugf("[image gc] starting gc process to sweep old images")
	defer log.Debugf("[image gc] finished gc process to sweep old images")

	allAppVersions, err := servicemanager.AppVersion.AllAppVersions(ctx)
	if err != nil {
		return err
	}

	multi := tsuruErrors.NewMultiError()
	versionsToRemove := map[string][]appTypes.AppVersionInfo{}
	versionsIDsToRemove := map[string][]int{}
	mapAppVersions := map[string]appTypes.AppVersions{}
	for _, appVersions := range allAppVersions {
		if appVersions.MarkedToRemoval {
			err := pruneAllVersionsByApp(ctx, appVersions)
			if err != nil {
				multi.Add(err)
			}
			continue
		}
		for _, version := range appVersions.Versions {
			if !version.MarkedToRemoval {
				continue
			}
			versionsToRemove[appVersions.AppName] = append(versionsToRemove[appVersions.AppName], version)
			versionsIDsToRemove[appVersions.AppName] = append(versionsIDsToRemove[appVersions.AppName], version.Version)
		}
		if len(versionsIDsToRemove[appVersions.AppName]) > 0 {
			mapAppVersions[appVersions.AppName] = appVersions
		}
	}

	for appName, versions := range versionsToRemove {
		a, err := app.GetByName(ctx, appName)
		if err == appTypes.ErrAppNotFound {
			// in the next mark process will be removed
			continue
		}
		if err != nil {
			multi.Add(err)
			continue
		}

		versionsToRemove := []int{}
		for _, version := range versions {
			pruneVersionFromProvisioner(a, version)

			err = pruneVersionFromRegistry(ctx, version)
			if err != nil {
				multi.Add(err)
				continue
			}

			versionsToRemove = append(versionsToRemove, version.Version)
		}

		err = pruneVersionFromStorage(ctx, mapAppVersions[appName], versionsToRemove)
		if err != nil {
			multi.Add(err)
			continue
		}
	}

	return multi.ToError()
}

type appVersionsSelection struct {
	toRemove               []appTypes.AppVersionInfo
	unsuccessfulDeploys    []appTypes.AppVersionInfo
	toPruneFromProvisioner []appTypes.AppVersionInfo
}

func selectAppVersions(versions appTypes.AppVersions, deployedVersions []int, historySize int) *appVersionsSelection {
	var regularVersions, customTagVersions []appTypes.AppVersionInfo
	selection := &appVersionsSelection{}
	for _, v := range versions.Versions {
		if v.MarkedToRemoval {
			continue
		} else if v.CustomBuildTag != "" {
			customTagVersions = append(customTagVersions, v)
		} else if !v.DeploySuccessful {
			// A point to remember: @wpjunior
			// All deploys are created with flag above as a false value
			// It means in the future will turned to true, to avoid a remotion of a running event please check whether v.EventID is running.
			selection.unsuccessfulDeploys = append(selection.unsuccessfulDeploys, v)
		} else {
			regularVersions = append(regularVersions, v)
		}
	}

	sort.Sort(priorizedAppVersions(selection.unsuccessfulDeploys))
	sort.Sort(priorizedAppVersions(regularVersions))
	sort.Sort(priorizedAppVersions(customTagVersions))

	for i, version := range regularVersions {
		// never consider lastSuccessfulversion to garbage collection
		if i == 0 || version.Version == versions.LastSuccessfulVersion || intIn(version.Version, deployedVersions) {
			continue
		}
		if i >= historySize {
			selection.toRemove = append(selection.toRemove, version)
		} else {
			selection.toPruneFromProvisioner = append(selection.toPruneFromProvisioner, version)
		}
	}

	selection.toPruneFromProvisioner = append(selection.toPruneFromProvisioner, customTagVersions...)
	return selection
}

func pruneAllVersionsByApp(ctx context.Context, appVersions appTypes.AppVersions) error {
	multi := tsuruErrors.NewMultiError()

	err := registry.RemoveAppImages(ctx, appVersions.AppName)
	if err != nil {
		multi.Add(errors.Wrapf(err, "could not remove images from registry, app: %q", appVersions.AppName))
	}
	err = servicemanager.AppVersion.DeleteVersions(ctx, appVersions.AppName, &appTypes.AppVersionWriteOptions{
		PreviousUpdatedHash: appVersions.UpdatedHash,
	})
	if err != nil && err != appTypes.ErrTransactionCancelledByChange {
		multi.Add(errors.Wrapf(err, "could not remove versions from storage, app: %q", appVersions.AppName))
	}

	return multi.ToError()
}

func pruneVersionFromRegistry(ctx context.Context, version appTypes.AppVersionInfo) error {
	multi := tsuruErrors.NewMultiError()

	if version.DeployImage != "" {
		err := pruneImageFromRegistry(ctx, version.DeployImage)
		if err != nil {
			multi.Add(err)
		}
	}

	if version.BuildImage != "" {
		err := pruneImageFromRegistry(ctx, version.BuildImage)
		if err != nil {
			multi.Add(err)
		}
	}

	return multi.ToError()
}

func pruneImageFromRegistry(ctx context.Context, image string) error {
	registryPruneTotal.Inc()
	timer := prometheus.NewTimer(registryPruneDuration)
	defer timer.ObserveDuration()

	if err := registry.RemoveImageIgnoreNotFound(ctx, image); err != nil {
		err = errors.Wrapf(err, "error removing old image from registry %q. Image kept on list to retry later.", image)
		log.Errorf("[image gc] %s", err.Error())
		registryPruneFailuresTotal.Inc()
		return err
	}

	return nil
}

func pruneVersionFromProvisioner(a *app.App, version appTypes.AppVersionInfo) error {
	multi := tsuruErrors.NewMultiError()
	if version.DeployImage != "" {
		err := pruneImageFromProvisioner(a, version.DeployImage)
		if err != nil {
			multi.Add(err)
		}
	}
	if version.BuildImage != "" {
		err := pruneImageFromProvisioner(a, version.BuildImage)
		if err != nil {
			multi.Add(err)
		}
	}
	return multi.ToError()
}

func pruneImageFromProvisioner(a *app.App, image string) error {
	provisionerPruneTotal.Inc()
	timer := prometheus.NewTimer(provisionerPruneDuration)
	defer timer.ObserveDuration()

	err := a.CleanImage(image)
	if err != nil {
		err = errors.Wrapf(err, "error removing old image from provisioner for app: %q, image: %s", a.Name, image)
		log.Errorf("[image gc] %s", err.Error())
		provisionerPruneFailuresTotal.Inc()
		return err
	}

	return nil
}

func pruneVersionFromStorage(ctx context.Context, appVersions appTypes.AppVersions, versions []int) error {
	storagePruneTotal.Inc()
	timer := prometheus.NewTimer(storagePruneDuration)
	defer timer.ObserveDuration()

	err := servicemanager.AppVersion.DeleteVersionIDs(ctx, appVersions.AppName, versions, &appTypes.AppVersionWriteOptions{
		PreviousUpdatedHash: appVersions.UpdatedHash,
	})
	if err != nil && err != appTypes.ErrTransactionCancelledByChange {
		err = errors.Wrapf(err, "error removing old versions from database for app: %q", appVersions.AppName)
		log.Errorf("[image gc] %s", err.Error())
		storagePruneFailuresTotal.Inc()
	}
	return nil
}

type priorizedAppVersions []appTypes.AppVersionInfo

func (p priorizedAppVersions) Len() int      { return len(p) }
func (p priorizedAppVersions) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p priorizedAppVersions) Less(i, j int) bool {
	if p[i].UpdatedAt.Equal(p[j].UpdatedAt) {
		return p[i].Version > p[j].Version
	}

	return p[i].UpdatedAt.After(p[j].UpdatedAt)
}

func intIn(n int, slice []int) bool {
	for _, sliceN := range slice {
		if sliceN == n {
			return true
		}
	}
	return false
}

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AppBundle\Validation as AcmeAssert;

/**
 * @ORM\Entity
 * @ORM\Table(name="worked_times")
 * @AcmeAssert\StartBeforeEndConstraint
 */
class WorkedTime {
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    private $user;

    /**
     * @ORM\Column(type="datetime")
     */
    private $start;

    /**
     * @ORM\Column(type="datetime")
     */
    private $end;

    /**
     * @ORM\ManyToOne(targetEntity="Project", inversedBy="times")
     * @ORM\JoinColumn(name="project_id", referencedColumnName="id", onDelete="CASCADE")
     */
    private $project;

    /**
     * @ORM\Column(type="text")
     */
    private $comment;

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set start
     *
     * @param \DateTime $start
     * @return WorkedTime
     */
    public function setStart(\DateTime $start)
    {
        $this->start = $start;

        return $this;
    }

    /**
     * Get start
     *
     * @return \DateTime
     */
    public function getStart()
    {
        return $this->start;
    }

    /**
     * Set end
     *
     * @param \DateTime $end
     * @return WorkedTime
     */
    public function setEnd(\DateTime $end)
    {
        $this->end = $end;

        return $this;
    }

    /**
     * Get end
     *
     * @return \DateTime
     */
    public function getEnd()
    {
        return $this->end;
    }

    /**
     * Set comment
     *
     * @param string $comment
     * @return WorkedTime
     */
    public function setComment($comment)
    {
        $this->comment = $comment;

        return $this;
    }

    /**
     * Get comment
     *
     * @return string
     */
    public function getComment()
    {
        return $this->comment;
    }

    /**
     * Set user
     *
     * @param \AppBundle\Entity\User $user
     * @return WorkedTime
     */
    public function setUser(\AppBundle\Entity\User $user = null)
    {
        $this->user = $user;

        return $this;
    }

    /**
     * Get user
     *
     * @return \AppBundle\Entity\User
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * Set project
     *
     * @param \AppBundle\Entity\Project $project
     * @return WorkedTime
     */
    public function setProject(\AppBundle\Entity\Project $project = null)
    {
        $this->project = $project;

        return $this;
    }

    /**
     * Get project
     *
     * @return \AppBundle\Entity\Project
     */
    public function getProject()
    {
        return $this->project;
    }

    public function getTargets() {
        return self::CLASS_CONSTRAINT;
    }
}


text:
// Provides control sap.m.ProgressIndicator.
sap.ui.define(['jquery.sap.global', './library', 'sap/ui/core/Control', 'sap/ui/core/ValueStateSupport', 'sap/ui/core/library'],
	function(jQuery, library, Control, ValueStateSupport, coreLibrary) {
	"use strict";

	// shortcut for sap.ui.core.TextDirection
	var TextDirection = coreLibrary.TextDirection;

	// shortcut for sap.ui.core.ValueState
	var ValueState = coreLibrary.ValueState;

	/**
	 * Constructor for a new ProgressIndicator.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * Shows the progress of a process in a graphical way. To indicate the progress, the inside of the ProgressIndicator is filled with a color.
	 * Additionally, a user-defined string can be displayed on the ProgressIndicator.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version ${version}
	 *
	 * @constructor
	 * @public
	 * @since 1.13.1
	 * @alias sap.m.ProgressIndicator
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ProgressIndicator = Control.extend("sap.m.ProgressIndicator", /** @lends sap.m.ProgressIndicator.prototype */ { metadata : {

		interfaces : ["sap.ui.core.IFormContent"],
		library : "sap.m",
		properties : {
			/**
			 * Switches enabled state of the control. Disabled fields have different colors, and cannot be focused.
			 */
			enabled : {type : "boolean", group : "Behavior", defaultValue : true},

			/**
			 * Specifies the state of the bar. Enumeration sap.ui.core.ValueState provides Error (red), Warning (yellow), Success (green), None (blue) (default value).
			 */
			state : {type : "sap.ui.core.ValueState", group : "Appearance", defaultValue : ValueState.None},

			/**
			 * Specifies the text value to be displayed in the bar.
			 */
			displayValue : {type : "string", group : "Appearance", defaultValue : null},

			/**
			 * Specifies the numerical value in percent for the length of the progress bar.
			 */
			percentValue : {type : "float", group : "Data", defaultValue : 0},

			/**
			 * Indicates whether the displayValue should be shown in the ProgressIndicator.
			 */
			showValue : {type : "boolean", group : "Appearance", defaultValue : true},

			/**
			 * Specifies the width of the control.
			 */
			width : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : '100%'},

			/**
			 * Specifies the height of the control. The default value depends on the theme. Suggested size for normal use is 2.5rem (40px). Suggested size for small size (like for use in ObjectHeader) is 1.375rem (22px).
			 * @since 1.15.0
			 */
			height : {type : "sap.ui.core.CSSSize", group : "Dimension", defaultValue : null},

			/**
			 * Specifies the element's text directionality with enumerated options (RTL or LTR). By default, the control inherits text direction from the DOM.
			 * @since 1.28.0
			 */
			textDirection : {type : "sap.ui.core.TextDirection", group : "Appearance", defaultValue : TextDirection.Inherit},

			/**
			 * Determines whether the control is in display-only state where the control has different visualization and cannot be focused.
			 * @since 1.50
			 */
			displayOnly : {type : "boolean", group : "Behavior", defaultValue : false}
		}
	}});

	var bUseAnimations = sap.ui.getCore().getConfiguration().getAnimation();

	ProgressIndicator.prototype.setPercentValue = function(fPercentValue) {
		var that = this,
			$progressBar,
			fPercentDiff,
			$progressIndicator = this.$(),
			fAnimationDuration;

		if (!isValidPercentValue(fPercentValue)) {
			fPercentValue = 0;
			jQuery.sap.log.warning(this + ": percentValue (" + fPercentValue + ") is not correct! Setting the default percentValue:0.");
		}

		if (this.getPercentValue() !== fPercentValue) {
			fPercentDiff = this.getPercentValue() - fPercentValue;
			this.setProperty("percentValue", fPercentValue, true);

			if (!$progressIndicator.length) {
				return this;
			}

			["sapMPIValueMax", "sapMPIValueMin", "sapMPIValueNormal", "sapMPIValueGreaterHalf"].forEach(function (sClass){
				$progressIndicator.removeClass(sClass);
			});

			$progressIndicator.addClass(this._getCSSClassByPercentValue(fPercentValue));
			$progressIndicator.addClass("sapMPIAnimate")
				.attr("aria-valuenow", fPercentValue)
				.attr("aria-valuetext", this._getAriaValueText({fPercent: fPercentValue}));

			fAnimationDuration = bUseAnimations ? Math.abs(fPercentDiff) * 20 : 0;
			$progressBar = this.$("bar");
			// Stop currently running animation and start new one.
			// In case of multiple setPercentValue calls all animations will run and it will take some time until the last value is animated,
			// which is the one, actually valuable.
			$progressBar.stop();
			$progressBar.animate({
				"flex-basis" : fPercentValue + "%"
			}, fAnimationDuration, "linear", function() {
				that._setText.apply(that);
				that.$().removeClass("sapMPIAnimate");
			});
		}

		return this;
	};

	ProgressIndicator.prototype._setText = function() {
		this.$().toggleClass("sapMPIValueGreaterHalf", this.getPercentValue() > 50);
		return this;
	};

	ProgressIndicator.prototype.setDisplayValue = function(sDisplayValue) {
		// change of value without rerendering
		this.setProperty("displayValue", sDisplayValue, true);
		var $textLeft = this.$("textLeft");
		var $textRight = this.$("textRight");
		$textLeft.text(sDisplayValue);
		$textRight.text(sDisplayValue);
		this.$().attr("aria-valuetext", this._getAriaValueText({sText: sDisplayValue}));

		return this;
	};

	ProgressIndicator.prototype.setDisplayOnly = function(bDisplayOnly) {
		// change of value without re-rendering
		this.setProperty("displayOnly", bDisplayOnly, true);
		if (this.getDomRef()) {
			this.$().toggleClass("sapMPIDisplayOnly", bDisplayOnly);
		}
		return this;
	};

	/**
	 * Determines the CSS class, which should be applied to the ProgressIndicator
	 * for the given percentValue.
	 * @param {Number} fPercentValue
	 * @return {String} the CSS class
	 * @since 1.44
	 * @private
	 */
	ProgressIndicator.prototype._getCSSClassByPercentValue = function(fPercentValue) {
		if (fPercentValue === 100) {
			return "sapMPIValueMax sapMPIValueGreaterHalf";
		}

		if (fPercentValue === 0) {
			return "sapMPIValueMin";
		}

		if (fPercentValue <= 50) {
			return "sapMPIValueNormal";
		}

		return "sapMPIValueNormal sapMPIValueGreaterHalf";
	};

	ProgressIndicator.prototype._getAriaValueText = function (oParams) {
		oParams.sText = oParams.sText || this.getDisplayValue();
		oParams.fPercent = oParams.fPercent || this.getPercentValue();
		oParams.sStateText = oParams.sStateText || this._getStateText();

		var sAriaValueText = oParams.sText || oParams.fPercent + "%";
		if (oParams.sStateText) {
			sAriaValueText += " " + oParams.sStateText;
		}

		return sAriaValueText;
	};

	ProgressIndicator.prototype._getStateText = function () {
		return ValueStateSupport.getAdditionalText(this.getState());
	};

	/**
	 * Returns the sap.m.ProgressIndicator  accessibility information.
	 *
	 * @see sap.ui.core.Control#getAccessibilityInfo
	 * @protected
	 * @returns {object} The sap.m.ProgressIndicator accessibility information
	 */
	ProgressIndicator.prototype.getAccessibilityInfo = function() {
		var oBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m");
		return {
			role: "progressbar",
			type: oBundle.getText("ACC_CTR_TYPE_PROGRESS"),
			description: oBundle.getText("ACC_CTR_STATE_PROGRESS", [this.getPercentValue()]),
			focusable: this.getEnabled(),
			enabled: this.getEnabled()
		};
	};

	function isValidPercentValue(value) {
		return (typeof (value) === 'number') && !isNaN(value) && value >= 0 && value <= 100;
	}

	return ProgressIndicator;

});


text:
(function () {
	var doc = global.document,
		commonElements = {
			"test": doc.getElementById("test"),
			"start": doc.getElementById("start"),
			"stop": doc.getElementById("stop"),
			"results": doc.getElementById("results")
		},
		childRemoved,
		childrenCleared,
		childNodesCleared;

	function assignValues()
	{
		childRemoved = Utils.node.remove(
			commonElements.test.childNodes[0]
		);
		childrenCleared =
			Utils.traverse.clearChildren(
				commonElements.test
			);
		childNodesCleared =
			Utils.traverse.clearChildNodes(
				commonElements.test
			);
	}

	function createMessage(text)
	{
		var str = String(text);
		if (str === "") {
			str = "[an empty string]";
		}
		return Utils.create.text(
			doc,
			str + "\r\n"
		);
	}

	function addMessage(text)
	{
		var isText =
			Utils.is.text(
				text
			),
			par = commonElements.results;
		if (!isText) {
			text = createMessage(text);
		}
		par.appendChild(text);
	}

	function runTest(evt)
	{
		assignValues();
		addMessage(childRemoved);
		addMessage(childrenCleared);
		addMessage(childNodesCleared);
	}

	function clearTest(evt)
	{
		var par = commonElements.results,
		nodes = par.childNodes;
		while(nodes.length) {
			Utils.node.remove(
				par,
				nodes[0]
			);
		}
	}

	function addHandlers()
	{
		commonElements.start.onclick = runTest;
		commonElements.stop.onclick = clearTest;
	}

	addHandlers();
}());


text:
const Pipeable =require( '../tookit/Pipeable');
const wrapperFnToModule =require( './wrapperFnToModule');
const {replaceWrapFunctionHead, hackCircleDependencies} =require( '../tookit/tookit');

module.exports = function compile({input, ap, depStr = '', file = ''}) {
    const source = replaceWrapFunctionHead(input, matched => {
        return 'function module_exports () {' + '\n' + (depStr || '');
    });

    const pipeable = new Pipeable(source);

    pipeable.pipe(function (source) {
        return wrapperFnToModule(source);
    }).pipe(({type, text = ''}) => {
        // 无 Return ,且有 Auto Return 传参
        if (type === 0 && ap) {
            text = (text||'') + `module.exports = ${ap};`;
        }
        return {
            text,
            type
        }
    }).pipe(({type, text}) => {
        // Nothing
        if (type === 1) {
            text = (text||'') + `;`;
        }
        return {type, text};
    }).pipe(({type, text}) => {
        if (type === 2) {
            text += 'module.exports = module_exports.apply(this);'
        }
        return {type, text};
    }).pipe(({type, text}) => {
        return {
            type,
            text: hackCircleDependencies(file, text)
        };
    });

    return pipeable;
};


text:
package com.googlecode.charts4j;

import static com.googlecode.charts4j.collect.Preconditions.checkArgument;
import static com.googlecode.charts4j.collect.Preconditions.checkNotNull;

/**
 * Type for specifying axis styles.
 *
 * @author Julien Chastang (julien.c.chastang at gmail dot com)
 * @see AxisLabels
 * @see AxisLabelsFactory
 */
public final class AxisStyle implements Kloneable<AxisStyle> {
    /** Axis text color. */
    private final Color             textColor;

    /** Axis text font size. */
    private final int               fontSize;

    /** Axis text alignment relative to tick mark. */
    private final AxisTextAlignment alignment;

    /** Are the tick marks drawn. */
    private Boolean                 areTickMarksDrawn;

    /** The tick mark length. Can be negative. */
    private Integer                 tickMarkLength;

    /** The tick mark color. */
    private Color                   tickMarkColor;

    /**
     * @see #newAxisStyle(Color, int, AxisTextAlignment)
     */
    AxisStyle(final Color textColor, final int fontSize, final AxisTextAlignment alignment) {
        this.textColor = textColor;
        this.fontSize = fontSize;
        this.alignment = alignment;
    }

    /**
     * Copy constructor.
     *
     * @param axisStyle
     *            the axis style
     *
     * @return the axis style
     */
    private AxisStyle (final AxisStyle axisStyle) {
        this(axisStyle.textColor, axisStyle.fontSize, axisStyle.alignment);
        this.areTickMarksDrawn = axisStyle.areTickMarksDrawn;
        this.tickMarkColor = axisStyle.tickMarkColor;
        this.tickMarkLength = axisStyle.tickMarkLength;
    }

    /**
     * {@inheritDoc}
     */
    public AxisStyle klone() {
        return new AxisStyle(this);
    }

    /**
     * Get the text color.
     *
     * @return the text color
     */
    public Color getTextColor() {
        return textColor;
    }

    /**
     * Get the text font size.
     *
     * @return the text fontSize
     */
    public int getFontSize() {
        return fontSize;
    }

    /**
     * Get the text alignment with respect to the tick mark.
     *
     * @return the alignment
     */
    public AxisTextAlignment getAlignment() {
        return alignment;
    }

    /**
     * Are the tick marks drawn?
     *
     * @return are the tick marks displayed? Can be null if it was never set.
     */
    public Boolean drawTickMarks() {
        return areTickMarksDrawn;
    }

    /**
     * The developer can override default tick mark behavior with this method.
     *
     * @param drawTickMarks
     *            Are the tick marks displayed?
     */
    public void setDrawTickMarks(final boolean drawTickMarks) {
        this.areTickMarksDrawn = drawTickMarks;
    }

    /**
     * Get the tick mark length. Can be negative.
     *
     * @return the tickMarkLength
     */
    public Integer getTickMarkLength() {
        return tickMarkLength;
    }

    /**
     * Set the tick mark length. Can be negative. Will also implicitly call
     * {@link #setDrawTickMarks(boolean)} with true.
     *
     * @param tickMarkLength
     *            the tickMarkLength to set
     */
    public void setTickMarkLength(final int tickMarkLength) {
        setDrawTickMarks(true);
        this.tickMarkLength = tickMarkLength;
    }

    /**
     * Get the tick mark color.
     *
     * @return the tickMarkColor
     */
    public Color getTickMarkColor() {
        return tickMarkColor;
    }

    /**
     * Set the tick mark color. Will also implicitly call
     * {@link #setDrawTickMarks(boolean)} with true.
     *
     * @param tickMarkColor
     *            the tickMarkColor to set
     */
    public void setTickMarkColor(final Color tickMarkColor) {
        if (tickMarkColor != null) {
            setDrawTickMarks(true);
            this.tickMarkColor = tickMarkColor;
        }
    }

    /**
     * Define an axis style.
     *
     * @param textColor
     *            color of text displayed along the axis. Cannot be null.
     * @param fontSize
     *            font size of text displayed along the axis. Must be > 0.
     * @param alignment
     *            alignment of text along the axis with respect to the axis tick
     *            marks. Only works for horizontal axes. Cannot be null.
     * @return the new constructed axis style
     */
    public static AxisStyle newAxisStyle(final Color textColor, final int fontSize, final AxisTextAlignment alignment) {
        checkNotNull(textColor, "color must not be null");
        checkArgument(fontSize > 0, "fontsize must be > 0");
        checkNotNull(alignment, "alignment must not be null");
        return new AxisStyle(textColor, fontSize, alignment);
    }

    /**
     * Here is the deal with this very strange copy constructor. There is
     * currently a bug in the Google Chart API where the alignment is reversed
     * with respect to what is specified in the documentation:
     * http://code.google.com/apis/chart/labels.html#axis_styles. This method
     * simply swaps right and left axis text alignment. Note also that the
     * alignments are *correct* for the radar chart's concentric axis labels, so
     * there is no need for this adjustment with radar charts. For more
     * information, see the discussion here:
     *
     * http://groups.google.com/group/google-chart-api/browse_thread/thread/c70760a4437cf945/810fa2ef6dbddd1d?show_docid=810fa2ef6dbddd1d
     *
     * @param axisStyle
     *            the axis style
     *
     * @return the axis style
     */
    static AxisStyle correctAxisStyle(final AxisStyle axisStyle) {
        if (axisStyle == null) {
            return null;
        }

        final AxisStyle as;
        switch (axisStyle.alignment) {
        case RIGHT:
            as = newAxisStyle(axisStyle.textColor, axisStyle.fontSize, AxisTextAlignment.LEFT);
            break;
        case LEFT:
            as = newAxisStyle(axisStyle.textColor, axisStyle.fontSize, AxisTextAlignment.RIGHT);
            break;
        default:
            as = axisStyle.klone();
            break;
        }
        as.areTickMarksDrawn = axisStyle.areTickMarksDrawn;
        as.tickMarkColor = axisStyle.tickMarkColor;
        as.tickMarkLength = axisStyle.tickMarkLength;
        return as;
    }
}


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<title>Python: module atom.mock_http</title>

<big><big>atom.mock_http</big></big>	index
/usr/local/google/home/afshar/src/external-gdata-release/google3/src/atom/mock_http.py

<tt># Copyright (C) 2008 Google Inc.

#

# 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.</tt>

<big>Modules</big>

<tt>      </tt>

atom

<big>Classes</big>

<tt>      </tt>

__builtin__.object

MockRequest

atom.http_interface.GenericHttpClient(__builtin__.object)

MockHttpClient

atom.http_interface.HttpResponse(__builtin__.object)

MockResponse

exceptions.Exception(exceptions.BaseException)

Error

NoRecordingFound

class Error(exceptions.Exception)

<tt>   </tt>

Method resolution order:

Error

exceptions.Exception

exceptions.BaseException

__builtin__.object

Data descriptors defined here:

__weakref__

<tt>list of weak references to the object (if defined)</tt>

Methods inherited from exceptions.Exception:

__init__(...)

<tt>x.__init__(...) initializes x; see help(type(x)) for signature</tt>

Data and other attributes inherited from exceptions.Exception:

__new__ = <built-in method __new__ of type object>
<tt>T.__new__(S, ...) -> a new object with type S, a subtype of T</tt>

Methods inherited from exceptions.BaseException:

__delattr__(...)

<tt>x.__delattr__('name') <==> del x.name</tt>

__getattribute__(...)

<tt>x.__getattribute__('name') <==> x.name</tt>

__getitem__(...)

<tt>x.__getitem__(y) <==> x[y]</tt>

__getslice__(...)

<tt>x.__getslice__(i, j) <==> x[i:j]

Use of negative indices is not supported.</tt>

__reduce__(...)

__repr__(...)

<tt>x.__repr__() <==> repr(x)</tt>

__setattr__(...)

<tt>x.__setattr__('name', value) <==> x.name = value</tt>

__setstate__(...)

__str__(...)

<tt>x.__str__() <==> str(x)</tt>

__unicode__(...)

Data descriptors inherited from exceptions.BaseException:

__dict__

args

message

class MockHttpClient(atom.http_interface.GenericHttpClient)

<tt>   </tt>

Method resolution order:

MockHttpClient

atom.http_interface.GenericHttpClient

__builtin__.object

Methods defined here:

__init__(self, headers=None, recordings=None, real_client=None)

<tt>An HttpClient which responds to request with stored data.

The request-response pairs are stored as tuples in a member list named

recordings.

The MockHttpClient can be switched from replay mode to record mode by

setting the real_client member to an instance of an HttpClient which will

make real HTTP requests and store the server's response in list of

recordings.

Args:

  headers: dict containing HTTP headers which should be included in all

      HTTP requests.

  recordings: The initial recordings to be used for responses. This list

      contains tuples in the form: (MockRequest, MockResponse)

  real_client: An HttpClient which will make a real HTTP request. The

      response will be converted into a MockResponse and stored in

      recordings.</tt>

add_response(self, response, operation, url, data=None, headers=None)

<tt>Adds a request-response pair to the recordings list.

After the recording is added, future matching requests will receive the

response.

Args:

  response: MockResponse

  operation: str

  url: str

  data: str, Currently the data is ignored when looking for matching

      requests.

  headers: dict of strings: Currently the headers are ignored when

      looking for matching requests.</tt>

request(self, operation, url, data=None, headers=None)

<tt>Returns a matching MockResponse from the recordings.

If the real_client is set, the request will be passed along and the

server's response will be added to the recordings and also returned.

If there is no match, a NoRecordingFound error will be raised.</tt>

Methods inherited from atom.http_interface.GenericHttpClient:

delete(self, url, headers=None)

get(self, url, headers=None)

post(self, url, data, headers=None)

put(self, url, data, headers=None)

Data descriptors inherited from atom.http_interface.GenericHttpClient:

__dict__

<tt>dictionary for instance variables (if defined)</tt>

__weakref__

<tt>list of weak references to the object (if defined)</tt>

Data and other attributes inherited from atom.http_interface.GenericHttpClient:

debug = False

class MockRequest(__builtin__.object)

<tt>   </tt>
<tt>Holds parameters of an HTTP request for matching against future requests.
 </tt>

Methods defined here:

__init__(self, operation, url, data=None, headers=None)

Data descriptors defined here:

__dict__

<tt>dictionary for instance variables (if defined)</tt>

__weakref__

<tt>list of weak references to the object (if defined)</tt>

class MockResponse(atom.http_interface.HttpResponse)

<tt>   </tt>
<tt>Simulates an httplib.HTTPResponse object.
 </tt>

Method resolution order:

MockResponse

atom.http_interface.HttpResponse

__builtin__.object

Methods defined here:

__init__(self, body=None, status=None, reason=None, headers=None)

read(self)

Methods inherited from atom.http_interface.HttpResponse:

getheader(self, name, default=None)

Data descriptors inherited from atom.http_interface.HttpResponse:

__dict__

<tt>dictionary for instance variables (if defined)</tt>

__weakref__

<tt>list of weak references to the object (if defined)</tt>

class NoRecordingFound(Error)

<tt>   </tt>

Method resolution order:

NoRecordingFound

Error

exceptions.Exception

exceptions.BaseException

__builtin__.object

Data descriptors inherited from Error:

__weakref__

<tt>list of weak references to the object (if defined)</tt>

Methods inherited from exceptions.Exception:

__init__(...)

<tt>x.__init__(...) initializes x; see help(type(x)) for signature</tt>

Data and other attributes inherited from exceptions.Exception:

__new__ = <built-in method __new__ of type object>
<tt>T.__new__(S, ...) -> a new object with type S, a subtype of T</tt>

Methods inherited from exceptions.BaseException:

__delattr__(...)

<tt>x.__delattr__('name') <==> del x.name</tt>

__getattribute__(...)

<tt>x.__getattribute__('name') <==> x.name</tt>

__getitem__(...)

<tt>x.__getitem__(y) <==> x[y]</tt>

__getslice__(...)

<tt>x.__getslice__(i, j) <==> x[i:j]

Use of negative indices is not supported.</tt>

__reduce__(...)

__repr__(...)

<tt>x.__repr__() <==> repr(x)</tt>

__setattr__(...)

<tt>x.__setattr__('name', value) <==> x.name = value</tt>

__setstate__(...)

__str__(...)

<tt>x.__str__() <==> str(x)</tt>

__unicode__(...)

Data descriptors inherited from exceptions.BaseException:

__dict__

args

message

<big>Data</big>

<tt>      </tt>
__author__ = 'api.jscudder (Jeff Scudder)'

<big>Author</big>

<tt>      </tt>
api.jscudder (Jeff Scudder)


text:
package com.pengrad.telegrambot.request;

import com.pengrad.telegrambot.response.ChatInviteLinkResponse;

/**
 * Stas Parshin
 * 10 March 2021
 */
public class EditChatInviteLink extends BaseRequest<EditChatInviteLink, ChatInviteLinkResponse> {

    public EditChatInviteLink(Object chatId, String inviteLink) {
        super(ChatInviteLinkResponse.class);
        add("chat_id", chatId);
        add("invite_link", inviteLink);
    }

    /**
     *
     * @param name Invite link name; 0-32 characters
     * @return
     */
    public EditChatInviteLink name(String name) {
        return add("name", name);
    }

    public EditChatInviteLink expireDate(Integer expireDate) {
        return add("expire_date", expireDate);
    }

    public EditChatInviteLink memberLimit(Integer memberLimit) {
        return add("member_limit", memberLimit);
    }

    /**
     *
     * @param createsJoinRequest True, if users joining the chat via the link need to be approved by chat administrators. If True, member_limit can't be specified
     * @return
     */
    public EditChatInviteLink createsJoinRequest(Boolean createsJoinRequest) {
        return add("creates_join_request", createsJoinRequest);
    }
}


text:
<?php
// exit if accessed directly
if ( ! defined( 'ABSPATH' ) )
	exit;

new Responsive_Lightbox_Widgets();

/**
 * Responsive Lightbox Widgets class.
 *
 * @class Responsive_Lightbox_Widgets
 */
class Responsive_Lightbox_Widgets {

	public function __construct() {
		// actions
		add_action( 'widgets_init', array( $this, 'register_widgets' ) );
	}

	/**
	 * Register widgets.
	 */
	public function register_widgets() {
		register_widget( 'Responsive_Lightbox_Gallery_Widget' );
		register_widget( 'Responsive_Lightbox_Image_Widget' );
	}
}

/**
 * Responsive Lightbox Gallery Widget class.
 *
 * @class Responsive_Lightbox_Gallery_Widget
 */
class Responsive_Lightbox_Gallery_Widget extends WP_Widget {

	private $rlg_defaults = array();
	private $rlg_orders = array();
	private $rlg_order_types = array();
	private $rlg_image_sizes = array();
	private $rlg_gallery_types  = array();

	public function __construct() {
		parent::__construct(
			'Responsive_Lightbox_Gallery_Widget',
			__( 'Gallery', 'responsive-lightbox' ),
			array(
				'description'	=> __( 'Displays an image gallery.', 'responsive-lightbox' ),
				'classname'		=> 'rl-gallery-widget'
			)
		);

		$this->rlg_defaults = array(
			'title'		=> __( 'Gallery', 'responsive-lightbox' ),
			'orderby'	=> 'menu_order',
			'order'		=> 'asc',
			'columns'	=> 3,
			'size'		=> 'thumbnail',
			'type'		=> 'none',
			'atts'		=> '',
			'ids'		=> ''
		);

		$this->rlg_orders = array(
			'menu_order'	=> __( 'Menu order', 'responsive-lightbox' ),
			'title'			=> __( 'Title', 'responsive-lightbox' ),
			'post_date'		=> __( 'Image date', 'responsive-lightbox' ),
			'ID'			=> __( 'ID', 'responsive-lightbox' ),
			'rand'			=> __( 'Random', 'responsive-lightbox' )
		);

		$this->rlg_order_types = array(
			'asc'	 => __( 'Ascending', 'responsive-lightbox' ),
			'desc'	 => __( 'Descending', 'responsive-lightbox' )
		);

		$gallery_types = apply_filters( 'rl_gallery_types', array() );

		if ( ! empty( $gallery_types ) ) {
			$this->rlg_gallery_types = array_merge(
				array(
					'none'		=> __( 'None', 'responsive-lightbox' ),
					'default'	=> __( 'Default', 'responsive-lightbox' )
				),
				$gallery_types
			);
		}

		$this->rlg_image_sizes = array_merge( array( 'full' ), get_intermediate_image_sizes() );

		sort( $this->rlg_image_sizes, SORT_STRING );
	}

	/**
	 * Display widget.
	 *
	 * @param array $args
	 * @param object $instance
	 * @return void
	 */
	public function widget( $args, $instance ) {
		$instance['title'] = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );

		$html = $args['before_widget'] . $args['before_title'] . ( $instance['title'] !== '' ? $instance['title'] : '' ) . $args['after_title'];
		$html .= do_shortcode( '[gallery link="file" columns="' . $instance['columns'] . '" size="' . $instance['size'] . '" ' . ( $instance['type'] !== 'none' ? 'type="' . $instance['type'] . '"' : '' ) . ' ids="' . ( ! empty( $instance['ids'] ) ? esc_attr( $instance['ids'] ) : '' ) . '" orderby="' . $instance['orderby'] . '" order="' . $instance['order'] . '"' . ( $instance['atts'] !== '' ? ' ' . $instance['atts'] : '' ) . ']' );
		$html .= $args['after_widget'];

		echo apply_filters( 'rl_gallery_widget_html', $html, $instance );
	}

	/** Render widget form.
	 *
	 * @param object $instance
	 * @return void
	 */
	public function form( $instance ) {
		$attachments = ! empty( $instance['ids'] ) ? array_filter( explode( ',', $instance['ids'] ) ) : array();

		$html = '

				get_field_id( 'title' ) . '">' . __( 'Title', 'responsive-lightbox' ) . ':
				<input id="' . $this->get_field_id( 'title' ) . '" class="widefat" name="' . $this->get_field_name( 'title' ) . '" type="text" value="' . esc_attr( isset( $instance['title'] ) ? $instance['title'] : $this->rlg_defaults['title'] ) . '" />

get_field_id( 'gallery' ) . '" class="rl-gallery-widget' . ( ! empty( $attachments ) ? ' has-image' : '' ) . '">
				<input type="hidden" class="rl-gallery-ids" id="' . $this->get_field_id( 'ids' ) . '" name="' . $this->get_field_name( 'ids' ) . '" value="' . ( ! empty( $instance['ids'] ) ? esc_attr( $instance['ids'] ) : '' ) . '">';

			$html .= '
				' . __( 'Select images', 'responsive-lightbox' ) . '

get_field_id( 'gallery-images' ) . '" class="rl-gallery-images">';

			if ( $attachments ) {
				foreach ( $attachments as $attachment_id ) {
					if ( ! $attachment_id || ! wp_attachment_is_image( $attachment_id ) )
						continue;

					$html .= '

' . wp_get_attachment_image( $attachment_id, 'thumbnail' ) . '

';
				}
			}

		$html .= '

';

		if ( ! empty( $this->rlg_gallery_types ) ) {
			$html .= '
				get_field_id( 'type' ) . '">' . __( 'Gallery type', 'responsive-lightbox' ) . ':
				<select id="' . $this->get_field_id( 'type' ) . '" class="widefat" name="' . $this->get_field_name( 'type' ) . '">';

		foreach ( $this->rlg_gallery_types as $id => $type ) {
			$html .= '
					<option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['type'] ) ? $instance['type'] : $this->rlg_defaults['type'] ), false ) . '>' . esc_html( $type ) . '</option>';
		}

		$html .= '
				</select>

';
		}

		$html .= '
				get_field_id( 'orderby' ) . '">' . __( 'Order by', 'responsive-lightbox' ) . ':
				<select id="' . $this->get_field_id( 'orderby' ) . '" class="widefat" name="' . $this->get_field_name( 'orderby' ) . '">';

		foreach ( $this->rlg_orders as $id => $orderby ) {
			$html .= '
					<option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['orderby'] ) ? $instance['orderby'] : $this->rlg_defaults['orderby'] ), false ) . '>' . esc_html( $orderby ) . '</option>';
		}

		$html .= '
				</select>

				get_field_id( 'order' ) . '">' . __( 'Order', 'responsive-lightbox' ) . ':
				<select id="' . $this->get_field_id( 'order' ) . '" class="widefat" name="' . $this->get_field_name( 'order' ) . '">';

		foreach ( $this->rlg_order_types as $id => $order ) {
			$html .= '
					<option value="' . esc_attr( $id ) . '" ' . selected( $id, ( isset( $instance['order'] ) ? $instance['order'] : $this->rlg_defaults['order'] ), false ) . '>' . esc_html( $order ) . '</option>';
		}

		$html .= '
				</select>

				get_field_id( 'size' ) . '">' . __( 'Image size', 'responsive-lightbox' ) . ':
				<select id="' . $this->get_field_id( 'size' ) . '" class="widefat" name="' . $this->get_field_name( 'size' ) . '">';

		foreach ( $this->rlg_image_sizes as $size ) {
			$html .= '
					<option value="' . esc_attr( $size ) . '" ' . selected( $size, ( isset( $instance['size'] ) ? $instance['size'] : $this->rlg_defaults['size'] ), false ) . '>' . esc_html( $size ) . '</option>';
		}

		$html .= '
				</select>

				get_field_id( 'columns' ) . '">' . __( 'Number of columns', 'responsive-lightbox' ) . ':
				<input id="' . $this->get_field_id( 'columns' ) . '" class="small-text" name="' . $this->get_field_name( 'columns' ) . '" type="number" min="0" value="' . esc_attr( isset( $instance['columns'] ) ? $instance['columns'] : $this->rlg_defaults['columns'] ) . '" />

				get_field_id( 'atts' ) . '">' . __( 'Custom attributes', 'responsive-lightbox' ) . ':

				<textarea id="' . $this->get_field_id( 'atts' ) . '" class="widefat" name="' . $this->get_field_name( 'atts' ) . '">' . esc_textarea( isset( $instance['atts'] ) ? $instance['atts'] : $this->rlg_defaults['atts'] ) . '</textarea>' . __( 'Custom gallery shortcode attributes (optional).', 'responsive-lightbox' ) . '

';

		echo $html;
	}

	/**
	 * Save widget form.
	 *
	 * @param array $new_instance
	 * @param array $old_instance
	 * @return array
	 */
	public function update( $new_instance, $old_instance ) {
		// title
		$old_instance['title'] = array_key_exists( 'title', $new_instance ) ? trim( $new_instance['title'] ) : $this->rlg_defaults['title'];

		// order by
		$old_instance['orderby'] = array_key_exists( 'orderby', $new_instance ) && array_key_exists( $new_instance['orderby'], $this->rlg_orders ) ? $new_instance['orderby'] : $this->rlg_defaults['orderby'];

		// order
		$old_instance['order'] = array_key_exists( 'order', $new_instance ) && array_key_exists( $new_instance['order'], $this->rlg_order_types ) ? $new_instance['order'] : $this->rlg_defaults['order'];

		// image size
		$old_instance['size'] = array_key_exists( 'size', $new_instance ) && in_array( $new_instance['size'], $this->rlg_image_sizes, true ) ? $new_instance['size'] : $this->rlg_defaults['size'];

		// gallery type
		$old_instance['type'] = array_key_exists( 'type', $new_instance ) && array_key_exists( $new_instance['type'], $this->rlg_gallery_types ) ? $new_instance['type'] : $this->rlg_defaults['type'];

		// number of columns
		$old_instance['columns'] = array_key_exists( 'columns', $new_instance ) ? ( ( $columns = (int) $new_instance['columns'] ) > 0 ? $columns : $this->rlg_defaults['columns'] ) : $this->rlg_defaults['columns'];

		// image ids
		if ( array_key_exists( 'ids', $new_instance ) && ! empty( $new_instance['ids'] ) ) {
			// get unique and non empty attachment ids only
			$attachment_ids = array_unique( array_filter( array_map( 'intval', explode( ',', $new_instance['ids'] ) ) ) );

			$old_instance['ids'] = implode( ',', $attachment_ids );
		} else
			$old_instance['ids'] = $this->rlg_defaults['ids'];

		// custom attributes
		$atts = preg_replace( '/\s+/', ' ', trim( str_replace( array( "\r\n", "\n\r", "\n", "\r" ), '', array_key_exists( 'atts', $new_instance ) ? $new_instance['atts'] : $this->rlg_defaults['atts'] ) ) );

		$new_atts = array();

		if ( $atts !== '' ) {
			$atts_exp = explode( '" ', $atts );

			if ( ! empty( $atts_exp ) ) {
				end( $atts_exp );

				$last = key( $atts_exp );

				reset( $atts_exp );

				foreach ( $atts_exp as $id => $attribute ) {
					$check = $attribute . ( $last === $id ? '' : '"' );

					if ( preg_match( '/^[a-z0-9_-]+=\"(.+)\"$/', $check ) === 1 )
						$new_atts[] = $check;
				}
			}
		}

		if ( ! empty( $new_atts ) )
			$old_instance['atts'] = implode( ' ', $new_atts );
		else
			$old_instance['atts'] = '';

		return $old_instance;
	}
}

/**
 * Responsive Lightbox Gallery Widget class.
 *
 * @class Responsive_Lightbox_Gallery_Widget
 */
class Responsive_Lightbox_Image_Widget extends WP_Widget {

	private $rli_defaults = array();
	private $rli_text_positions = array();
	private $rli_link_to = array();
	private $rli_aligns = array();
	private $rli_image_sizes = array();

	public function __construct() {
		parent::__construct(
			'Responsive_Lightbox_Image_Widget',
			__( 'Image', 'responsive-lightbox' ),
			array(
				'description'	=> __( 'Displays a single image.', 'responsive-lightbox' ),
				'classname'		=> 'rl-image-widget'
			)
		);

		$this->rli_defaults = array(
			'title'				 => __( 'Image', 'responsive-lightbox' ),
			'image_id'			 => 0,
			'responsive'		 => true,
			'size'				 => 'thumbnail',
			'link_to'			 => 'file',
			'link_custom_url'	 => '',
			'image_align'		 => 'none',
			'text'				 => '',
			'autobr'			 => false,
			'text_position'		 => 'below_image',
			'text_align'		 => 'none',
		);

		$this->rli_text_positions = array(
			'below_image' => __( 'Below the image', 'responsive-lightbox' ),
			'above_image' => __( 'Above the image', 'responsive-lightbox' )
		);

		$this->rli_link_to = array(
			'none'	 => __( 'None', 'responsive-lightbox' ),
			'file'	 => __( 'Media File', 'responsive-lightbox' ),
			'post'	 => __( 'Attachment Page', 'responsive-lightbox' ),
			'custom' => __( 'Custom URL', 'responsive-lightbox' )
		);

		$this->rli_aligns = array(
			'none'		 => __( 'None', 'responsive-lightbox' ),
			'left'		 => __( 'Left', 'responsive-lightbox' ),
			'center'	 => __( 'Center', 'responsive-lightbox' ),
			'right'		 => __( 'Right', 'responsive-lightbox' ),
			'justify'	 => __( 'Justify', 'responsive-lightbox' )
		);

		$this->rli_image_sizes = array_merge( array( 'full' ), get_intermediate_image_sizes() );
		sort( $this->rli_image_sizes, SORT_STRING );
	}

	/**
	 * Display widget.
	 *
	 * @param array $args
	 * @param object $instance
	 * @return void
	 */
	public function widget( $args, $instance ) {
		$instance['title'] = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
		$title = $args['before_widget'] . $args['before_title'] . ( $instance['title'] !== '' ? $instance['title'] : '' ) . $args['after_title'];

		if ( $instance['autobr'] === true ) {
			$text = wpautop( $instance['text'] );
		} else {
			$text = html_entity_decode( $instance['text'], ENT_QUOTES, 'UTF-8' );
		}

		$image = wp_get_attachment_image_src( $instance['image_id'], $instance['size'], false );

		switch ( $instance['link_to'] ) {
			case 'file' :
				$file = wp_get_attachment_image_src( $instance['image_id'], 'full', false );
				$href = $file[0];
				break;

			case 'post' :
				$href = get_permalink( $instance['image_id'] );
				break;

			case 'custom' :
				$href = $instance['link_custom_url'];
				break;

			case 'none' :
			default :
				$href = '';
				break;
		}

		if ( $instance['image_align'] === 'left' )
			$image_align = ' style="float: left;"';
		elseif ( $instance['image_align'] === 'center' )
			$image_align = ' style="margin-left: auto; margin-right: auto; display: block;"';
		elseif ( $instance['image_align'] === 'right' )
			$image_align = ' style="float: right;"';
		else
			$image_align = '';

		if ( $instance['text_align'] === 'left' )
			$text_align = ' style="text-align: left; display: block;"';
		elseif ( $instance['text_align'] === 'center' )
			$text_align = ' style="text-align: center; display: block;"';
		elseif ( $instance['text_align'] === 'right' )
			$text_align = ' style="text-align: right; display: block;"';
		elseif ( $instance['text_align'] === 'justify' )
			$text_align = ' style="text-align: justify; display: block;"';
		else
			$text_align = '';

		$text_position = $instance['text_position'];
		$width = $instance['responsive'] === false ? $image[1] : '100%';
		$height = $instance['responsive'] === false ? $image[2] : 'auto';
		$post = get_post( $instance['image_id'] );
		$image_title = isset( $post->post_title ) ? $post->post_title : '';
		$alt = (string) get_post_meta( $instance['image_id'], '_wp_attachment_image_alt', true );

		$html = $title;

		if ( $text_position === 'below_image' ) {
			$html .= ($href !== '' ? '' : '') . '' . ($href !== '' ? '' : '');
			$html .= '
' . $text . '
';
		} else {
			$html .= '
' . $text . '
';
			$html .= ($href !== '' ? '' : '') . '' . ($href !== '' ? '' : '');
		}
		$html .= $args['after_widget'];

		echo apply_filters( 'rl_image_widget_html', $html, $instance );
	}

	/** Render widget form.
	 *
	 * @param object $instance
	 * @return void
	 */
	public function form( $instance ) {
		$image_id = (int) (isset( $instance['image_id'] ) ? $instance['image_id'] : $this->rli_defaults['image_id']);
		$image = '';

		if ( ! empty( $image_id ) )
			$image = wp_get_attachment_image( $image_id, 'medium', false );

		if ( ! $image )
			$image = wp_get_attachment_image( $image_id, 'full', false );

		$html = '

				get_field_id( 'title' ) . '">' . __( 'Title', 'responsive-lightbox' ) . '
				<input id="' . $this->get_field_id( 'title' ) . '" class="widefat" name="' . $this->get_field_name( 'title' ) . '" type="text" value="' . esc_attr( isset( $instance['title'] ) ? $instance['title'] : $this->rli_defaults['title'] ) . '" />

				<input class="rl-image-widget-image-id" type="hidden" name="' . $this->get_field_name( 'image_id' ) . '" value="' . $image_id . '" />
				' . __( 'Select image', 'responsive-lightbox' ) . '

';
		if ( ! empty( $image ) ) {
			$html .= $image;
		}
		$html .= '

				<input id="' . $this->get_field_id( 'responsive' ) . '" type="checkbox" name="' . $this->get_field_name( 'responsive' ) . '" value="" ' . checked( true, (isset( $instance['responsive'] ) ? $instance['responsive'] : $this->rli_defaults['responsive'] ), false ) . ' /> get_field_id( 'responsive' ) . '">' . __( 'Force responsive', 'responsive-lightbox' ) . '

';

		$html .= '

				get_field_id( 'size' ) . '">' . __( 'Size', 'responsive-lightbox' ) . '
				<select class="rl-image-size-select widefat" id="' . $this->get_field_id( 'size' ) . '" name="' . $this->get_field_name( 'size' ) . '">';

		$size_type = (isset( $instance['size'] ) ? $instance['size'] : $this->rli_defaults['size']);

		foreach ( $this->rli_image_sizes as $size ) {
			$html .= '
					<option value="' . esc_attr( $size ) . '" ' . selected( $size, $size_type, false ) . '>' . $size . '</option>';
		}

		$html .= '
				</select>

				get_field_id( 'link_to' ) . '">' . __( 'Link to', 'responsive-lightbox' ) . '
				<select class="rl-image-link-to widefat" id="' . $this->get_field_id( 'link_to' ) . '" name="' . $this->get_field_name( 'link_to' ) . '">';

		$link_type = (isset( $instance['link_to'] ) ? $instance['link_to'] : $this->rli_defaults['link_to']);

		foreach ( $this->rli_link_to as $id => $type ) {
			$html .= '
					<option value="' . esc_attr( $id ) . '" ' . selected( $id, $link_type, false ) . '>' . $type . '</option>';
		}

		$html .= '
				</select>

				get_field_id( 'link_custom_url' ) . '">' . __( 'URL', 'responsive-lightbox' ) . '
				<input id="' . $this->get_field_id( 'link_custom_url' ) . '" class="widefat" name="' . $this->get_field_name( 'link_custom_url' ) . '" type="text" value="' . esc_attr( isset( $instance['link_custom_url'] ) ? $instance['link_custom_url'] : $this->rli_defaults['link_custom_url'] ) . '" />

';

		$html .= '

				get_field_id( 'image_align' ) . '">' . __( 'Image align', 'responsive-lightbox' ) . '
				<select id="' . $this->get_field_id( 'image_align' ) . '" class="widefat" name="' . $this->get_field_name( 'image_align' ) . '">';

		foreach ( $this->rli_aligns as $id => $image_align ) {
			if ( $id != 'justify' )
				$html .= '
					<option value="' . esc_attr( $id ) . '" ' . selected( $id, (isset( $instance['image_align'] ) ? $instance['image_align'] : $this->rli_defaults['image_align'] ), false ) . '>' . $image_align . '</option>';
		}

		$html .= '
				</select>

				get_field_id( 'text' ) . '">' . __( 'Text', 'responsive-lightbox' ) . '
				<textarea id="' . $this->get_field_id( 'text' ) . '" class="widefat" name="' . $this->get_field_name( 'text' ) . '" rows="4">' . (isset( $instance['text'] ) ? $instance['text'] : $this->rli_defaults['text']) . '</textarea>

				<input id="' . $this->get_field_id( 'autobr' ) . '" type="checkbox" name="' . $this->get_field_name( 'autobr' ) . '" value="" ' . checked( true, (isset( $instance['autobr'] ) ? $instance['autobr'] : $this->rli_defaults['autobr'] ), false ) . ' /> get_field_id( 'autobr' ) . '">' . __( 'Automatically add paragraphs', 'responsive-lightbox' ) . '

';

		$html .=  '

				get_field_id( 'text_position' ) . '">' . __( 'Text position', 'responsive-lightbox' ) . '
				<select id="' . $this->get_field_id( 'text_position' ) . '" class="widefat" name="' . $this->get_field_name( 'text_position' ) . '">';

		foreach ( $this->rli_text_positions as $id => $text_position ) {
			$html .= '
					<option value="' . esc_attr( $id ) . '" ' . selected( $id, (isset( $instance['text_position'] ) ? $instance['text_position'] : $this->rli_defaults['text_position'] ), false ) . '>' . $text_position . '</option>';
		}

		$html .= '
				</select>

			get_field_id( 'text_align' ) . '">' . __( 'Text align', 'responsive-lightbox' ) . '
			<select id="' . $this->get_field_id( 'text_align' ) . '" class="widefat" name="' . $this->get_field_name( 'text_align' ) . '">';

		foreach ( $this->rli_aligns as $id => $text_align ) {
			$html .= '
				<option value="' . esc_attr( $id ) . '" ' . selected( $id, (isset( $instance['text_align'] ) ? $instance['text_align'] : $this->rli_defaults['text_align'] ), false ) . '>' . $text_align . '</option>';
		}

		$html .= '
			</select>

';

		echo $html;
	}

	/**
	 * Save widget form.
	 *
	 * @param array $new_instance
	 * @param array $old_instance
	 * @return array
	 */
	public function update( $new_instance, $old_instance ) {
		$old_instance['title'] = sanitize_text_field( isset( $new_instance['title'] ) ? $new_instance['title'] : $this->rli_defaults['title'] );
		$old_instance['image_id'] = (int) (isset( $new_instance['image_id'] ) ? $new_instance['image_id'] : $this->rli_defaults['image_id']);
		$old_instance['responsive'] = isset( $new_instance['responsive'] ) ? true : false;
		$old_instance['size'] = (isset( $new_instance['size'] ) && in_array( $new_instance['size'], $this->rli_image_sizes, true ) ? $new_instance['size'] : $this->rli_defaults['size']);
		$old_instance['link_to'] = (isset( $new_instance['link_to'] ) && in_array( $new_instance['link_to'], array_keys( $this->rli_link_to ), true ) ? $new_instance['link_to'] : $this->rli_defaults['link_to']);
		$old_instance['link_custom_url'] = esc_url( isset( $new_instance['link_custom_url'] ) ? $new_instance['link_custom_url'] : $this->rli_defaults['link_custom_url'] );
		$old_instance['image_align'] = (isset( $new_instance['image_align'] ) && in_array( $new_instance['image_align'], array_keys( $this->rli_aligns ), true ) ? $new_instance['image_align'] : $this->rli_defaults['image_align']);
		$old_instance['text'] = wp_kses_post( isset( $new_instance['text'] ) ? $new_instance['text'] : $this->rli_defaults['text'] );
		$old_instance['autobr'] = isset( $new_instance['autobr'] ) ? true : false;
		$old_instance['text_position'] = (isset( $new_instance['text_position'] ) && in_array( $new_instance['text_position'], array_keys( $this->rli_text_positions ), true ) ? $new_instance['text_position'] : $this->rli_defaults['text_position']);
		$old_instance['text_align'] = (isset( $new_instance['text_align'] ) && in_array( $new_instance['text_align'], array_keys( $this->rli_aligns ), true ) ? $new_instance['text_align'] : $this->rli_defaults['text_align']);

		return $old_instance;
	}

}


text:
void sema_init(OCSema* sema) {
    assert(sema != NULL && "Null instance error");
    orbit_rcMapInit(&sema->typeTable);

    // Create stack[0], global scope
    sema->stackSize = 1;
    sema->stack[0].parent = NULL;
    orbit_rcMapInit(&sema->stack[0].symbolTable);
}

void sema_deinit(OCSema* sema) {
    assert(sema != NULL && "Null instance error");
    orbit_rcMapDeinit(&sema->typeTable);

    sema->stackSize = 0;
    orbit_rcMapDeinit(&sema->stack[0].symbolTable);
}

OCScope* sema_pushScope(OCSema* sema) {
    assert(sema != NULL && "Null instance error");
    assert(sema->stackSize < ORBIT_SEMA_SCOPESTACK_SIZE && "Sema stack overflow");

    OCScope* scope = &sema->stack[sema->stackSize];
    scope->parent = &sema->stack[sema->stackSize-1];
    orbit_rcMapInit(&scope->symbolTable);
    sema->stackSize += 1;
    return scope;
}

void sema_popScope(OCSema* sema) {
    assert(sema != NULL && "Null instance error");
    assert(sema->stackSize > 1 && "Sema stack underflow");
    sema->stackSize -= 1;

    orbit_rcMapDeinit(&sema->stack[sema->stackSize].symbolTable);
    sema->stack[sema->stackSize].parent = NULL;
}

OrbitAST* sema_lookupSymbolP(OCSema* sema, OCStringID symbol) {
    assert(sema != NULL && "Null instance error");
    if(sema->stackSize == 0) { return NULL; }

    OCScope* scope = &sema->stack[sema->stackSize-1];
    while(scope) {
        OrbitAST* result = orbit_rcMapGetP(&scope->symbolTable, symbol);
        if(result) { return result; }
        scope = scope->parent;
    }
    return NULL;
}

void sema_declareSymbol(OCSema* sema, OCStringID symbol, OrbitAST* type) {
    assert(sema != NULL && "Null instance error");
    assert(type != NULL && "Null type error");
    assert(sema->stackSize > 0 && "Sema no scope error");

    OCScope* scope = &sema->stack[sema->stackSize-1];
    orbit_rcMapInsertP(&scope->symbolTable, symbol, type);
}

void sema_declareType(OCSema* sema, OCStringID name, OrbitAST* declaration) {
    assert(sema != NULL && "Null instance error");
    assert(declaration != NULL && "Null declaration error");

    orbit_rcMapInsertP(&sema->typeTable, name, declaration);
}

OrbitAST* sema_lookupType(OCSema* sema, OCStringID name) {
    assert(sema != NULL && "Null instance error");
    return orbit_rcMapGetP(&sema->typeTable, name);
}


text:
<?php namespace Artesaos\Attacher\Contracts;

interface ImageProcessor
{
    /**
     * Process model
     *
     * @param ModelContract $model
     * @param array         $styles
     * @param               $path
     */
    public function process(ModelContract &$model, array $styles, $path);
}