<select>
	<option value="FR">Française</option>
	<option value="CH">Suisse</option>
	<option value="BE">Belge</option>
	<option value="DE">Allemande</option>
	<option value="IT">Italienne</option>
	<option value="AF">Afghane</option>
	<option value="AL">Albanaise</option>
	<option value="DZ">Algerienne</option>
	<option value="US">Americaine</option>
	<option value="AD">Andorrane</option>
	<option value="AO">Angolaise</option>
	<option value="AG">Antiguaise et barbudienne</option>
	<option value="AR">Argentine</option>
	<option value="AM">Armenienne</option>
	<option value="AU">Australienne</option>
	<option value="AT">Autrichienne</option>
	<option value="AZ">Azerbaïdjanaise</option>
	<option value="BS">Bahamienne</option>
	<option value="BH">Bahreinienne</option>
	<option value="BD">Bangladaise</option>
	<option value="BB">Barbadienne</option>
	<option value="BZ">Belizienne</option>
	<option value="BJ">Beninoise</option>
	<option value="BT">Bhoutanaise</option>
	<option value="BY">Bielorusse</option>
	<option value="MM">Birmane</option>
	<option value="GW">Bissau-Guinéenne</option>
	<option value="BO">Bolivienne</option>
	<option value="BA">Bosnienne</option>
	<option value="BW">Botswanaise</option>
	<option value="BR">Bresilienne</option>
	<option value="GB">Britannique</option>
	<option value="BN">Bruneienne</option>
	<option value="BG">Bulgare</option>
	<option value="BF">Burkinabe</option>
	<option value="BI">Burundaise</option>
	<option value="KH">Cambodgienne</option>
	<option value="CM">Camerounaise</option>
	<option value="CA">Canadienne</option>
	<option value="CV">Cap-verdienne</option>
	<option value="CF">Centrafricaine</option>
	<option value="CL">Chilienne</option>
	<option value="CN">Chinoise</option>
	<option value="CY">Chypriote</option>
	<option value="CO">Colombienne</option>
	<option value="KM">Comorienne</option>
	<option value="CG">Congolaise</option>
	<option value="CR">Costaricaine</option>
	<option value="HR">Croate</option>
	<option value="CU">Cubaine</option>
	<option value="DK">Danoise</option>
	<option value="DJ">Djiboutienne</option>
	<option value="DO">Dominicaine</option>
	<option value="DM">Dominiquaise</option>
	<option value="EG">Egyptienne</option>
	<option value="AE">Emirienne</option>
	<option value="GQ">Equato-guineenne</option>
	<option value="EC">Equatorienne</option>
	<option value="ER">Erythreenne</option>
	<option value="ES">Espagnole</option>
	<option value="TL">Est-timoraise</option>
	<option value="EE">Estonienne</option>
	<option value="ET">Ethiopienne</option>
	<option value="FJ">Fidjienne</option>
	<option value="FI">Finlandaise</option>
	<option value="GA">Gabonaise</option>
	<option value="GM">Gambienne</option>
	<option value="GE">Georgienne</option>
	<option value="GH">Ghaneenne</option>
	<option value="GD">Grenadienne</option>
	<option value="GT">Guatemalteque</option>
	<option value="GN">Guineenne</option>
	<option value="GF">Guyanienne</option>
	<option value="HT">Haïtienne</option>
	<option value="GR">Hellenique</option>
	<option value="HN">Hondurienne</option>
	<option value="HU">Hongroise</option>
	<option value="IN">Indienne</option>
	<option value="ID">Indonesienne</option>
	<option value="IQ">Irakienne</option>
	<option value="IE">Irlandaise</option>
	<option value="IS">Islandaise</option>
	<option value="IL">Israélienne</option>
	<option value="CI">Ivoirienne</option>
	<option value="JM">Jamaïcaine</option>
	<option value="JP">Japonaise</option>
	<option value="JO">Jordanienne</option>
	<option value="KZ">Kazakhstanaise</option>
	<option value="KE">Kenyane</option>
	<option value="KG">Kirghize</option>
	<option value="KI">Kiribatienne</option>
	<option value="KN">Kittitienne-et-nevicienne</option>
	<option value="KW">Koweitienne</option>
	<option value="LA">Laotienne</option>
	<option value="LS">Lesothane</option>
	<option value="LV">Lettone</option>
	<option value="LB">Libanaise</option>
	<option value="LR">Liberienne</option>
	<option value="LY">Libyenne</option>
	<option value="LI">Liechtensteinoise</option>
	<option value="LT">Lituanienne</option>
	<option value="LU">Luxembourgeoise</option>
	<option value="MK">Macedonienne</option>
	<option value="MY">Malaisienne</option>
	<option value="MW">Malawienne</option>
	<option value="MV">Maldivienne</option>
	<option value="MG">Malgache</option>
	<option value="ML">Malienne</option>
	<option value="MT">Maltaise</option>
	<option value="MA">Marocaine</option>
	<option value="MH">Marshallaise</option>
	<option value="MU">Mauricienne</option>
	<option value="MR">Mauritanienne</option>
	<option value="MX">Mexicaine</option>
	<option value="FM">Micronesienne</option>
	<option value="MD">Moldave</option>
	<option value="MC">Monegasque</option>
	<option value="MN">Mongole</option>
	<option value="ME">Montenegrine</option>
	<option value="MZ">Mozambicaine</option>
	<option value="NA">Namibienne</option>
	<option value="NR">Nauruane</option>
	<option value="NL">Neerlandaise</option>
	<option value="NZ">Neo-zelandaise</option>
	<option value="NP">Nepalaise</option>
	<option value="NI">Nicaraguayenne</option>
	<option value="NG">Nigeriane</option>
	<option value="NE">Nigerienne</option>
	<option value="KP">Nord-coréenne</option>
	<option value="NO">Norvegienne</option>
	<option value="OM">Omanaise</option>
	<option value="UG">Ougandaise</option>
	<option value="UZ">Ouzbeke</option>
	<option value="PK">Pakistanaise</option>
	<option value="PW">Palau</option>
	<option value="PS">Palestinienne</option>
	<option value="PA">Panameenne</option>
	<option value="PG">Papouane-neoguineenne</option>
	<option value="PY">Paraguayenne</option>
	<option value="PE">Peruvienne</option>
	<option value="PH">Philippine</option>
	<option value="PL">Polonaise</option>
	<option value="PR">Portoricaine</option>
	<option value="PT">Portugaise</option>
	<option value="QA">Qatarienne</option>
	<option value="RO">Roumaine</option>
	<option value="RU">Russe</option>
	<option value="RW">Rwandaise</option>
	<option value="LC">Saint-Lucienne</option>
	<option value="SM">Saint-Marinaise</option>
	<option value="VC">Saint-Vincentaise-et-Grenadine</option>
	<option value="SB">Salomonaise</option>
	<option value="SV">Salvadorienne</option>
	<option value="WS">Samoane</option>
	<option value="ST">Santomeenne</option>
	<option value="SA">Saoudienne</option>
	<option value="SN">Senegalaise</option>
	<option value="RS">Serbe</option>
	<option value="SC">Seychelloise</option>
	<option value="SL">Sierra-leonaise</option>
	<option value="SG">Singapourienne</option>
	<option value="SK">Slovaque</option>
	<option value="SI">Slovene</option>
	<option value="SO">Somalienne</option>
	<option value="SD">Soudanaise</option>
	<option value="LK">Sri-lankaise</option>
	<option value="ZA">Sud-africaine</option>
	<option value="KR">Sud-coréenne</option>
	<option value="SE">Suedoise</option>
	<option value="SR">Surinamaise</option>
	<option value="SZ">Swazie</option>
	<option value="SY">Syrienne</option>
	<option value="TJ">Tadjike</option>
	<option value="TW">Taiwanaise</option>
	<option value="TZ">Tanzanienne</option>
	<option value="TD">Tchadienne</option>
	<option value="CZ">Tcheque</option>
	<option value="TH">Thaïlandaise</option>
	<option value="TG">Tonguienne</option>
	<option value="TT">Trinidadienne</option>
	<option value="TN">Tunisienne</option>
	<option value="TM">Turkmene</option>
	<option value="TR">Turque</option>
	<option value="TV">Tuvaluane</option>
	<option value="UA">Ukrainienne</option>
	<option value="UY">Uruguayenne</option>
	<option value="VU">Vanuatuane</option>
	<option value="VE">Venezuelienne</option>
	<option value="VN">Vietnamienne</option>
	<option value="YE">Yemenite</option>
	<option value="ZM">Zambienne</option>
	<option value="ZW">Zimbabweenne</option>
</select>


package com.june.dto.back.demo;

import java.io.Serializable;
import java.util.List;

import com.june.common.PageDTO;

public class TreeGridDto extends PageDTO<TreeGridDto> implements Serializable{
	/**
	 * long serialVersionUID
	 */
	private static final long serialVersionUID = 4936747688639597710L;
	private String id; //节点id
    private String pid;//父节点id
	private String name;
	private String persons;
	private String begin;
	private String end;
	private List<TreeGridDto> children;
	private String iconCls;//节点的图标
	private String state; //节点的状态，展开(open)还是闭合(closed)，
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPersons() {
		return persons;
	}
	public void setPersons(String persons) {
		this.persons = persons;
	}
	public String getBegin() {
		return begin;
	}
	public void setBegin(String begin) {
		this.begin = begin;
	}
	public String getEnd() {
		return end;
	}
	public void setEnd(String end) {
		this.end = end;
	}
	public List<TreeGridDto> getChildren() {
		return children;
	}
	public void setChildren(List<TreeGridDto> children) {
		this.children = children;
	}
	public String getIconCls() {
		return iconCls;
	}
	public void setIconCls(String iconCls) {
		this.iconCls = iconCls;
	}
	public String getState() {
		return state;
	}
	public void setState(String state) {
		this.state = state;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPid() {
		return pid;
	}
	public void setPid(String pid) {
		this.pid = pid;
	}
	@Override
	protected String getDtoName() {
		return "TreeGridDto";
	}
}


@implementation MoodMessageCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{

    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {

        self.tagImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
        //self.tagImageView.backgroundColor = [UIColor redColor];
        [self.contentView addSubview:self.tagImageView];

        self.backImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
        [self.contentView addSubview:self.backImageView];

        self.emptyImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
        [self.contentView addSubview:self.emptyImageView];

        self.tagLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        self.tagLabel.textColor = [UIColor whiteColor];
        [self.contentView addSubview:self.tagLabel];

        self.descriptionLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        self.descriptionLabel.numberOfLines = 0;
        self.descriptionLabel.textColor = [UIColor colorWithWhite:0.510 alpha:1.000];
        [self.contentView addSubview:self.descriptionLabel];

        self.timeThread = [[UIImageView alloc] initWithFrame:CGRectZero];
        self.timeThread.backgroundColor = [UIColor grayColor];
        [self.contentView addSubview:self.timeThread];

    }

    return self;
}

- (void)setValueWithModel:(dayModel *)model{

    //标记图片
    self.tagImageView.frame = CGRectMake(15, 2, 20, 20);
    self.tagImageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld", model.moodDay]];

    //标记背景
    self.backImageView.frame = CGRectMake(CGRectGetMaxX(self.tagImageView.frame), self.tagImageView.frame.origin.y, jjScreenWidth - 70, 100);
    //背景图片处理
    UIImage *backImage = [UIImage imageNamed:@"background"];
    UIEdgeInsets edgeInsets = UIEdgeInsetsMake(5, 15, 0, 5);
    // 拉伸图片
    UIImage *newImage = [backImage resizableImageWithCapInsets:edgeInsets resizingMode:UIImageResizingModeStretch];
    self.backImageView.image = newImage;

    //标记内容
    self.tagLabel.frame = CGRectMake(self.backImageView.frame.origin.x+15, self.backImageView.frame.origin.y + 8, self.backImageView.frame.size.width - 5, 30);
    self.tagLabel.font = [UIFont systemFontOfSize:17 weight:10];
    self.tagLabel.text = [NSString getTagStringTag:model.tagDay];

    //记录内容
    self.descriptionLabel.text = [NSString stringWithFormat:@"%@\n%@",[NSString getDateStringFromDate:model.dateDay],model.content];
    self.descriptionLabel.font = [UIFont systemFontOfSize:14];

    CGFloat labelHeight = [GetHeightTool getHeightForText:self.descriptionLabel.text font:[UIFont systemFontOfSize:14] width:jjScreenWidth - 100];
    self.descriptionLabel.frame = CGRectMake(CGRectGetMinX(self.backImageView.frame) + 15, CGRectGetMaxY(self.tagLabel.frame)+ 5, self.backImageView.frame.size.width - 20, labelHeight);
    self.emptyImageView.frame = CGRectMake(self.backImageView.frame.origin.x + 7, CGRectGetMaxY(self.tagLabel.frame), self.backImageView.frame.size.width - 8, self.descriptionLabel.frame.size.height + 10);

    //背景图片处理
    UIImage *image = [UIImage imageNamed:@"empty"];
    //上, 左, 下, 右部分不可拉伸的区域
    UIEdgeInsets edgeInsets1 = UIEdgeInsetsMake(0, 10, 10, 10);
    UIImage *newimage = [image resizableImageWithCapInsets:edgeInsets1 resizingMode:UIImageResizingModeStretch];
    self.emptyImageView.image = newimage;

    //时间轴
    self.timeThread.frame = CGRectMake(self.tagImageView.center.x - 1, CGRectGetMaxY(self.tagImageView.frame)+1, 2, self.descriptionLabel.frame.size.height + 33);

}

- (void)awakeFromNib {
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end


package org.eclipse.rdf4j.rio.hdt;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.CheckedInputStream;

import org.eclipse.rdf4j.common.io.UncloseableInputStream;

/**
 * Log64
 *
 * It contains the data part of the {@link HDTArray}, followed by the 32-bit CRC calculated over this data.
 *
 * Data structure:
 *
 *

 * ...+---------+-------+
 *    | entries | CRC32 |
 * ...+---------+-------+
 *

 *
 * Entries are stored little-endian, with each entry using nrbits bits
 *
 * @author Bart Hanssens
 */
class HDTArrayLog64 extends HDTArray {
	private byte buffer[];

	@Override
	protected int getType() {
		return HDTArray.Type.LOG64.getValue();
	}

	@Override
	protected int get(int i) {
		// start byte of the value, and start bit in that start byte
		int bytePos = (i * nrbits) / 8;
		int bitPos = (i * nrbits) % 8;

		// value bits may be encoded across boundaries of bytes
		int tmplen = (bitPos + nrbits + 7) / 8;

		long val = 0L;
		// little-endian to big-endian
		for (int j = 0; j < tmplen; j++) {
			val |= (buffer[bytePos + j] & 0xFFL) << (j * 8);
		}

		val >>= bitPos;
		val &= 0xFFFFFFFFFFFFFFFFL >>> (64 - nrbits);

		return (int) val;
	}

	@Override
	protected void parse(InputStream is) throws IOException {
		super.parse(is);

		// don't close CheckedInputStream, as it will close the underlying inputstream
		try (UncloseableInputStream uis = new UncloseableInputStream(is);
				CheckedInputStream cis = new CheckedInputStream(uis, new CRC32())) {
			// read bytes, minimum 1
			long bytes = (nrbits * entries + 7) / 8;
			if (bytes > Integer.MAX_VALUE) {
				throw new UnsupportedOperationException("Maximum number of bytes in array exceeded: " + bytes);
			}

			buffer = new byte[(int) bytes];
			cis.read(buffer);

			checkCRC(cis, is, 4);
		}
	}
}


package com.thoughtworks.go.util;

import com.thoughtworks.go.agent.ServerUrlGenerator;
import com.thoughtworks.go.domain.JobIdentifier;
import org.springframework.stereotype.Component;

import java.net.URI;
import java.net.URISyntaxException;

import static java.lang.String.format;

@Component
public class URLService implements ServerUrlGenerator{
    private String baseRemotingURL;

    public URLService() {
        String url = new SystemEnvironment().getServiceUrl();
        if (url.endsWith("/")) {
            url = url.substring(0, url.length() - 1);
        }
        baseRemotingURL = url;
    }

    public URLService(String baseRemotingURL) {
        this.baseRemotingURL = baseRemotingURL;
    }

    public String baseRemoteURL() {
        return baseRemotingURL;
    }

    public String getBuildRepositoryURL() {
        return baseRemotingURL + "/remoting/remoteBuildRepository";
    }

    public String getAgentRegistrationURL() {
        return baseRemotingURL + "/admin/agent";
    }

    public String getAgentLatestStatusUrl() {
        return baseRemotingURL + "/admin/latest-agent.status";
    }

    public String getUploadUrlOfAgent(JobIdentifier jobIdentifier, String filePath) {
        return getUploadUrlOfAgent(jobIdentifier, filePath, 1);
    }

    public String getComponentVersionsOnServerUrl() {
        return String.format("%s/%s", baseRemotingURL, "admin/component-versions-on-server");
    }

    // TODO - keep buildId for now because currently we do not support 'jobcounter'
    // and therefore cannot locate job correctly when it is rescheduled
    public String getUploadUrlOfAgent(JobIdentifier jobIdentifier, String filePath, int attempt) {
        return format("%s/%s/%s/%s?attempt=%d&buildId=%d", baseRemotingURL, "remoting", "files", jobIdentifier.artifactLocator(filePath), attempt, jobIdentifier.getBuildId());
    }

    /*
     * Server will use this method, the base url is in the request.
     */
    public String getRestfulArtifactUrl(JobIdentifier jobIdentifier, String filePath) {
        return format("/%s/%s", "files", jobIdentifier.artifactLocator(filePath));
    }

    public String getUploadBaseUrlOfAgent(JobIdentifier jobIdentifier) {
        return format("%s/%s/%s/%s", baseRemotingURL, "remoting", "files", jobIdentifier.artifactLocator(""));
    }

    /*
    * Agent will use this method, the baseUrl will be injected from config xml in agent side.
    *   This is used to fix security issues with the agent uploading artifacts when security is enabled.
    */
    public String getPropertiesUrl(JobIdentifier jobIdentifier, String propertyName) {
        return format("%s/%s/%s/%s",
                baseRemotingURL, "remoting", "properties", jobIdentifier.propertyLocator(propertyName));
    }

    public String serverUrlFor(String subPath) {
        return format("%s/%s", baseRemotingURL, subPath);
    }

    public String serverSslBaseUrl(int serverHttpsPort) {
        return baseRemotingURL;
    }

    public String getAgentRemoteWebSocketUrl() {
        return format("%s/%s", getWebSocketBaseUrl(), "agent-websocket");
    }
    public String getWebSocketBaseUrl() {
        try {
            URI uri = new URI(baseRemotingURL);
            StringBuffer ret = new StringBuffer("wss://");
            ret.append(uri.getHost()).append(":").append(uri.getPort());
            if (uri.getPath() != null) {
                ret.append(uri.getPath());
            }
            return ret.toString();
        } catch (URISyntaxException e) {
            throw new RuntimeException("Invalid Go Server url", e);
        }
    }

    public String prefixPartialUrl(String url) {
        if(url.startsWith("/")) {
            return format("%s%s", baseRemoteURL(), url);
        }
        return url;
    }
}


'use strict';

module.exports = function () {
  this.alert = function () {
    throw 'Doh! You used a real notifier rather than a test double!';
  };
};


package rest

import (
	"fmt"
	"time"

	"github.com/golang/glog"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/rest"
	"k8s.io/kubernetes/pkg/apis/extensions"
	extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
	extensionsclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion"
	"k8s.io/kubernetes/pkg/genericapiserver"
	horizontalpodautoscaleretcd "k8s.io/kubernetes/pkg/registry/autoscaling/horizontalpodautoscaler/etcd"
	jobetcd "k8s.io/kubernetes/pkg/registry/batch/job/etcd"
	expcontrolleretcd "k8s.io/kubernetes/pkg/registry/extensions/controller/etcd"
	daemonetcd "k8s.io/kubernetes/pkg/registry/extensions/daemonset/etcd"
	deploymentetcd "k8s.io/kubernetes/pkg/registry/extensions/deployment/etcd"
	ingressetcd "k8s.io/kubernetes/pkg/registry/extensions/ingress/etcd"
	networkpolicyetcd "k8s.io/kubernetes/pkg/registry/extensions/networkpolicy/etcd"
	pspetcd "k8s.io/kubernetes/pkg/registry/extensions/podsecuritypolicy/etcd"
	replicasetetcd "k8s.io/kubernetes/pkg/registry/extensions/replicaset/etcd"
	thirdpartyresourceetcd "k8s.io/kubernetes/pkg/registry/extensions/thirdpartyresource/etcd"
	utilruntime "k8s.io/kubernetes/pkg/util/runtime"
	"k8s.io/kubernetes/pkg/util/wait"
)

type RESTStorageProvider struct {
	ResourceInterface ResourceInterface
}

var _ genericapiserver.RESTStorageProvider = &RESTStorageProvider{}

func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource genericapiserver.APIResourceConfigSource, restOptionsGetter genericapiserver.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool) {
	apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(extensions.GroupName)

	if apiResourceConfigSource.AnyResourcesForVersionEnabled(extensionsapiv1beta1.SchemeGroupVersion) {
		apiGroupInfo.VersionedResourcesStorageMap[extensionsapiv1beta1.SchemeGroupVersion.Version] = p.v1beta1Storage(apiResourceConfigSource, restOptionsGetter)
		apiGroupInfo.GroupMeta.GroupVersion = extensionsapiv1beta1.SchemeGroupVersion
	}

	return apiGroupInfo, true
}

func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource genericapiserver.APIResourceConfigSource, restOptionsGetter genericapiserver.RESTOptionsGetter) map[string]rest.Storage {
	version := extensionsapiv1beta1.SchemeGroupVersion

	storage := map[string]rest.Storage{}

	if apiResourceConfigSource.ResourceEnabled(version.WithResource("horizontalpodautoscalers")) {
		hpaStorage, hpaStatusStorage := horizontalpodautoscaleretcd.NewREST(restOptionsGetter(extensions.Resource("horizontalpodautoscalers")))
		storage["horizontalpodautoscalers"] = hpaStorage
		storage["horizontalpodautoscalers/status"] = hpaStatusStorage

		controllerStorage := expcontrolleretcd.NewStorage(restOptionsGetter(api.Resource("replicationControllers")))
		storage["replicationcontrollers"] = controllerStorage.ReplicationController
		storage["replicationcontrollers/scale"] = controllerStorage.Scale
	}
	if apiResourceConfigSource.ResourceEnabled(version.WithResource("thirdpartyresources")) {
		thirdPartyResourceStorage := thirdpartyresourceetcd.NewREST(restOptionsGetter(extensions.Resource("thirdpartyresources")))
		storage["thirdpartyresources"] = thirdPartyResourceStorage
	}

	if apiResourceConfigSource.ResourceEnabled(version.WithResource("daemonsets")) {
		daemonSetStorage, daemonSetStatusStorage := daemonetcd.NewREST(restOptionsGetter(extensions.Resource("daemonsets")))
		storage["daemonsets"] = daemonSetStorage
		storage["daemonsets/status"] = daemonSetStatusStorage
	}
	if apiResourceConfigSource.ResourceEnabled(version.WithResource("deployments")) {
		deploymentStorage := deploymentetcd.NewStorage(restOptionsGetter(extensions.Resource("deployments")))
		storage["deployments"] = deploymentStorage.Deployment
		storage["deployments/status"] = deploymentStorage.Status
		storage["deployments/rollback"] = deploymentStorage.Rollback
		storage["deployments/scale"] = deploymentStorage.Scale
	}
	if apiResourceConfigSource.ResourceEnabled(version.WithResource("jobs")) {
		jobsStorage, jobsStatusStorage := jobetcd.NewREST(restOptionsGetter(extensions.Resource("jobs")))
		storage["jobs"] = jobsStorage
		storage["jobs/status"] = jobsStatusStorage
	}
	if apiResourceConfigSource.ResourceEnabled(version.WithResource("ingresses")) {
		ingressStorage, ingressStatusStorage := ingressetcd.NewREST(restOptionsGetter(extensions.Resource("ingresses")))
		storage["ingresses"] = ingressStorage
		storage["ingresses/status"] = ingressStatusStorage
	}
	if apiResourceConfigSource.ResourceEnabled(version.WithResource("podsecuritypolicy")) {
		podSecurityExtensionsStorage := pspetcd.NewREST(restOptionsGetter(extensions.Resource("podsecuritypolicy")))
		storage["podSecurityPolicies"] = podSecurityExtensionsStorage
	}
	if apiResourceConfigSource.ResourceEnabled(version.WithResource("replicasets")) {
		replicaSetStorage := replicasetetcd.NewStorage(restOptionsGetter(extensions.Resource("replicasets")))
		storage["replicasets"] = replicaSetStorage.ReplicaSet
		storage["replicasets/status"] = replicaSetStorage.Status
		storage["replicasets/scale"] = replicaSetStorage.Scale
	}
	if apiResourceConfigSource.ResourceEnabled(version.WithResource("networkpolicies")) {
		networkExtensionsStorage := networkpolicyetcd.NewREST(restOptionsGetter(extensions.Resource("networkpolicies")))
		storage["networkpolicies"] = networkExtensionsStorage
	}

	return storage
}

func (p RESTStorageProvider) PostStartHook() (string, genericapiserver.PostStartHookFunc, error) {
	return "extensions/third-party-resources", p.postStartHookFunc, nil
}
func (p RESTStorageProvider) postStartHookFunc(hookContext genericapiserver.PostStartHookContext) error {
	clientset, err := extensionsclient.NewForConfig(hookContext.LoopbackClientConfig)
	if err != nil {
		utilruntime.HandleError(fmt.Errorf("unable to initialize clusterroles: %v", err))
		return nil
	}

	thirdPartyControl := ThirdPartyController{
		master: p.ResourceInterface,
		client: clientset,
	}
	go wait.Forever(func() {
		if err := thirdPartyControl.SyncResources(); err != nil {
			glog.Warningf("third party resource sync failed: %v", err)
		}
	}, 10*time.Second)

	return nil
}


/*
 * Copyright 2005 Jenia org.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.fckfaces.util;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author srecinto
 */
public class Servlet extends HttpServlet {

	private static final long serialVersionUID = 7260045528613530636L;

	private static final String modify=calcModify();

	private volatile String customResourcePath;

	private static final String calcModify() {
		Date mod = new Date(System.currentTimeMillis());
		SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z",Locale.ENGLISH);
		sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
		return sdf.format(mod);
	}

	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		setCustomResourcePath(config.getInitParameter("customResourcePath"));
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // search the resource in classloader
        ClassLoader cl = this.getClass().getClassLoader();
        String uri = request.getRequestURI();
        String path = uri.substring(uri.indexOf(Util.FCK_FACES_RESOURCE_PREFIX)+Util.FCK_FACES_RESOURCE_PREFIX.length()+1);

        if(getCustomResourcePath() != null) { //Use custom path to FCKeditor
        	this.getServletContext().getRequestDispatcher(getCustomResourcePath() + path).forward(request,response);
        } else {  //Use default FCKeditor bundled up in the jar
        	if (uri.endsWith(".jsf") || uri.endsWith(".html")) {
	        	response.setContentType("text/html;charset=UTF-8");
	        } else {
	            response.setHeader("Cache-Control", "public");
	            response.setHeader("Last-Modified", modify);
	        }
	        if (uri.endsWith(".css")) {
	        	response.setContentType("text/css;charset=UTF-8");
	        } else if (uri.endsWith(".js")) {
	        	response.setContentType("text/javascript;charset=UTF-8");
	        } else if (uri.endsWith(".gif")) {
	        	response.setContentType("image/gif;");
	        } else if (uri.endsWith(".xml")) {
	        	response.setContentType("text/xml;charset=UTF-8");
	        }

	        InputStream is = cl.getResourceAsStream(path);
	        // if no resource found in classloader return nothing
	        if (is==null) return;
	        // resource found, copying on output stream
	        OutputStream out = response.getOutputStream();
	        byte[] buffer = new byte[2048];
	        BufferedInputStream bis = new BufferedInputStream(is);
	        try {
	        	int read = 0;
	        	read = bis.read(buffer);
	        	while (read!=-1) {
	        		out.write(buffer,0,read);
	        		read = bis.read(buffer);
	        	}
	        } finally {
	        	bis.close();
	        }
	        out.flush();
	        out.close();
        }
    }

	public String getCustomResourcePath() {
		return customResourcePath;
	}

	public void setCustomResourcePath(String customResourcePath) {
		synchronized (this) {
			this.customResourcePath = customResourcePath;
		}
	}

}


namespace performance_manager {

NodeAttachedData::NodeAttachedData() = default;

NodeAttachedData::~NodeAttachedData() = default;

// static
void NodeAttachedDataMapHelper::AttachInMap(
    const Node* node,
    std::unique_ptr<NodeAttachedData> data) {
  GraphImpl* graph = GraphImpl::FromGraph(node->GetGraph());
  DCHECK_CALLED_ON_VALID_SEQUENCE(graph->sequence_checker_);
  const NodeBase* node_base = NodeBase::FromNode(node);
  DCHECK(graph->NodeInGraph(node_base));
  GraphImpl::NodeAttachedDataKey data_key =
      std::make_pair(node, data->GetKey());
  auto& map = graph->node_attached_data_map_;
  DCHECK(!base::Contains(map, data_key));
  map[data_key] = std::move(data);
}

// static
NodeAttachedData* NodeAttachedDataMapHelper::GetFromMap(const Node* node,
                                                        const void* key) {
  GraphImpl* graph = GraphImpl::FromGraph(node->GetGraph());
  DCHECK_CALLED_ON_VALID_SEQUENCE(graph->sequence_checker_);
  const NodeBase* node_base = NodeBase::FromNode(node);
  DCHECK(graph->NodeInGraph(node_base));
  GraphImpl::NodeAttachedDataKey data_key = std::make_pair(node, key);
  auto& map = graph->node_attached_data_map_;
  auto it = map.find(data_key);
  if (it == map.end())
    return nullptr;
  DCHECK_EQ(key, it->second->GetKey());
  return it->second.get();
}

// static
std::unique_ptr<NodeAttachedData> NodeAttachedDataMapHelper::DetachFromMap(
    const Node* node,
    const void* key) {
  GraphImpl* graph = GraphImpl::FromGraph(node->GetGraph());
  DCHECK_CALLED_ON_VALID_SEQUENCE(graph->sequence_checker_);
  const NodeBase* node_base = NodeBase::FromNode(node);
  DCHECK(graph->NodeInGraph(node_base));
  GraphImpl::NodeAttachedDataKey data_key = std::make_pair(node, key);
  auto& map = graph->node_attached_data_map_;
  auto it = map.find(data_key);

  std::unique_ptr<NodeAttachedData> data;
  if (it != map.end()) {
    data = std::move(it->second);
    map.erase(it);
  }

  return data;
}

}  // namespace performance_manager


import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-comp-4914',
  templateUrl: './comp-4914.component.html',
  styleUrls: ['./comp-4914.component.css']
})
export class Comp4914Component implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}


package org.apache.flink.runtime.webmonitor;

import org.apache.flink.api.common.JobID;
import org.apache.flink.api.common.time.Time;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.runtime.checkpoint.CompletedCheckpoint;
import org.apache.flink.runtime.clusterframework.types.ResourceID;
import org.apache.flink.runtime.executiongraph.AccessExecutionGraph;
import org.apache.flink.runtime.jobgraph.JobStatus;
import org.apache.flink.runtime.jobgraph.JobVertexID;
import org.apache.flink.runtime.jobmaster.JobResult;
import org.apache.flink.runtime.jobmaster.RescalingBehaviour;
import org.apache.flink.runtime.messages.Acknowledge;
import org.apache.flink.runtime.messages.FlinkJobNotFoundException;
import org.apache.flink.runtime.messages.webmonitor.ClusterOverview;
import org.apache.flink.runtime.messages.webmonitor.MultipleJobsDetails;
import org.apache.flink.runtime.metrics.dump.MetricQueryService;
import org.apache.flink.runtime.rest.handler.legacy.backpressure.OperatorBackPressureStatsResponse;
import org.apache.flink.runtime.rpc.RpcEndpoint;
import org.apache.flink.runtime.rpc.RpcGateway;
import org.apache.flink.runtime.rpc.RpcTimeout;

import java.util.Collection;
import java.util.concurrent.CompletableFuture;

/**
 * Gateway for restful endpoints.
 *
 * <p>Gateways which implement this method run a REST endpoint which is reachable
 * under the returned address.
 */
public interface RestfulGateway extends RpcGateway {

	/**
	 * Cancel the given job.
	 *
	 * @param jobId identifying the job to cancel
	 * @param timeout of the operation
	 * @return A future acknowledge if the cancellation succeeded
	 */
	CompletableFuture<Acknowledge> cancelJob(JobID jobId, @RpcTimeout Time timeout);

	/**
	 * Stop the given job.
	 *
	 * @param jobId identifying the job to stop
	 * @param timeout of the operation
	 * @return A future acknowledge if the stopping succeeded
	 */
	CompletableFuture<Acknowledge> stopJob(JobID jobId, @RpcTimeout Time timeout);

	/**
	 * Requests the REST address of this {@link RpcEndpoint}.
	 *
	 * @param timeout for this operation
	 * @return Future REST endpoint address
	 */
	CompletableFuture<String> requestRestAddress(@RpcTimeout  Time timeout);

	/**
	 * Requests the {@link AccessExecutionGraph} for the given jobId. If there is no such graph, then
	 * the future is completed with a {@link FlinkJobNotFoundException}.
	 *
	 * @param jobId identifying the job whose AccessExecutionGraph is requested
	 * @param timeout for the asynchronous operation
	 * @return Future containing the AccessExecutionGraph for the given jobId, otherwise {@link FlinkJobNotFoundException}
	 */
	CompletableFuture<? extends AccessExecutionGraph> requestJob(JobID jobId, @RpcTimeout Time timeout);

	/**
	 * Requests the {@link JobResult} of a job specified by the given jobId.
	 *
	 * @param jobId identifying the job for which to retrieve the {@link JobResult}.
	 * @param timeout for the asynchronous operation
	 * @return Future which is completed with the job's {@link JobResult} once the job has finished
	 */
	CompletableFuture<JobResult> requestJobResult(JobID jobId, @RpcTimeout Time timeout);

	/**
	 * Requests job details currently being executed on the Flink cluster.
	 *
	 * @param timeout for the asynchronous operation
	 * @return Future containing the job details
	 */
	CompletableFuture<MultipleJobsDetails> requestMultipleJobDetails(
		@RpcTimeout Time timeout);

	/**
	 * Requests the cluster status overview.
	 *
	 * @param timeout for the asynchronous operation
	 * @return Future containing the status overview
	 */
	CompletableFuture<ClusterOverview> requestClusterOverview(@RpcTimeout Time timeout);

	/**
	 * Requests the paths for the {@link MetricQueryService} to query.
	 *
	 * @param timeout for the asynchronous operation
	 * @return Future containing the collection of metric query service paths to query
	 */
	CompletableFuture<Collection<String>> requestMetricQueryServicePaths(@RpcTimeout Time timeout);

	/**
	 * Requests the paths for the TaskManager's {@link MetricQueryService} to query.
	 *
	 * @param timeout for the asynchronous operation
	 * @return Future containing the collection of instance ids and the corresponding metric query service path
	 */
	CompletableFuture<Collection<Tuple2<ResourceID, String>>> requestTaskManagerMetricQueryServicePaths(@RpcTimeout Time timeout);

	/**
	 * Triggers a savepoint with the given savepoint directory as a target.
	 *
	 * @param jobId           ID of the job for which the savepoint should be triggered.
	 * @param targetDirectory Target directory for the savepoint.
	 * @param timeout         Timeout for the asynchronous operation
	 * @return A future to the {@link CompletedCheckpoint#getExternalPointer() external pointer} of
	 * the savepoint.
	 */
	default CompletableFuture<String> triggerSavepoint(
			JobID jobId,
			String targetDirectory,
			boolean cancelJob,
			@RpcTimeout Time timeout) {
		throw new UnsupportedOperationException();
	}

	/**
	 * Dispose the given savepoint.
	 *
	 * @param savepointPath identifying the savepoint to dispose
	 * @param timeout RPC timeout
	 * @return A future acknowledge if the disposal succeeded
	 */
	default CompletableFuture<Acknowledge> disposeSavepoint(
			final String savepointPath,
			@RpcTimeout final Time timeout) {
		throw new UnsupportedOperationException();
	}

	/**
	 * Request the {@link JobStatus} of the given job.
	 *
	 * @param jobId identifying the job for which to retrieve the JobStatus
	 * @param timeout for the asynchronous operation
	 * @return A future to the {@link JobStatus} of the given job
	 */
	default CompletableFuture<JobStatus> requestJobStatus(
			JobID jobId,
			@RpcTimeout Time timeout) {
		throw new UnsupportedOperationException();
	}

	/**
	 * Requests the statistics on operator back pressure.
	 *
	 * @param jobId       Job for which the stats are requested.
	 * @param jobVertexId JobVertex for which the stats are requested.
	 * @return A Future to the {@link OperatorBackPressureStatsResponse} or {@code null} if the stats are
	 * not available (yet).
	 */
	default CompletableFuture<OperatorBackPressureStatsResponse> requestOperatorBackPressureStats(
			JobID jobId,
			JobVertexID jobVertexId) {
		throw new UnsupportedOperationException();
	}

	/**
	 * Trigger rescaling of the given job.
	 *
	 * @param jobId specifying the job to rescale
	 * @param newParallelism new parallelism of the job
	 * @param rescalingBehaviour defining how strict the rescaling has to be executed
	 * @param timeout of this operation
	 * @return Future which is completed with {@link Acknowledge} once the rescaling was successful
	 */
	default CompletableFuture<Acknowledge> rescaleJob(
			JobID jobId,
			int newParallelism,
			RescalingBehaviour rescalingBehaviour,
			@RpcTimeout Time timeout) {
		throw new UnsupportedOperationException();
	}

	default CompletableFuture<Acknowledge> shutDownCluster() {
		throw new UnsupportedOperationException();
	}
}


# Kinvey GeoTag
This is a Kinvey sample app, to location-based search, 3rd-Party location services, Push notifications, and Business Logic with Collection Hooks and Custom Endpoints.

In particular in addition to showing location-based data, this app allows user actions to trigger push notifications to other users that are near new notes and are interested in certain tags.

For more details about location, see the blog post at http://goo.gl/9dyMm.
For more details about business logic, see http://devcenter.kinvey.com/ios/guides/business-logic.

## Using the App
The app shows a map highlighting the user's current location. The map is annotated with nearby hotels (from the 3rd-paty location service) as well as yours and other user's notes that match your selected tags.

Tap the "page curl" button to see a list of nearby tags. Selecting a tag will cause the user to subscribe to be notified for new notes with that tag as well as display those notes on the map.

To enter a new note, type in the text field. Any word preceded by a `#` will be added as a tag.

## Set-up

### Set up the App in Xcode

Also, you have to update `app-key` and `app-secret` in the file `KGAAppDelegate.m` to your app-key and app-secret from the Kinvey console.

To enable push, you need a push certificate from the Apple developer portal. Upload to Kinvey (under the push configuration) and enter the `Push Key` and `Push Secret` in the file `KGAAppDelegate.m.

### Set up Locations services

To enable Data Integration with this app, just

* Go to the **Locations** Add-On and select a provider. For example, choose "FourSquare" ![Enable Data Integration](https://github.com/KinveyApps/GeoTag-iOS/raw/master/Screenshots/Enable.png "Enable Data Integration")
* Name the endpoint `hotels` and enter your foursquare credentials. Then press `Create Configuration`. ![Enter Credentials](https://github.com/KinveyApps/GeoTag-iOS/raw/master/Screenshots/Active.png "Enter Credentials")

### Set up Collection Hook To Automatically Push to Nearby users
1. From the `Addons` -> `Data & Storage` -> `Data Store` menu, add a new collection and call it `mapNotes`.
2. From the `Addons` -> `Business Logic` -> `Collection Hooks` menu, select the `mapNotes` collection in the left menu.
3. Select __`After` every `Save` run this function__ from the javascript area.
4. Enter the code from [`after_save_mapnotes.js`](https://github.com/KinveyApps/GeoTag-iOS/raw/master/after_save_mapnotes.js) in the code window:

```
function onPostSave(request, response, modules){
  var push = modules.push, collectionAccess = modules.collectionAccess, logger = modules.logger;
  var userCollection = collectionAccess.collection('user');
  var body = request.body;
  if (body.tags && body._geoloc) {
    logger.info("added map note with tags: " + body.tags +", location: "+ body._geoloc);
    var distanceInMiles = 5.0 /*5 mi radius*/ / 3963.192;
    var query = {"tags": {"$in":body.tags}, "_geoloc":{"$nearSphere": body._geoloc,"$maxDistance":distanceInMiles}};
    userCollection.find(query, function (err, userColl) {
      logger.info("got " + userColl.length + " users with matching tags.");
      if (err) {
        logger.error('Query failed: '+ err);
      } else {
        userColl.forEach(function (user) {
          logger.info('Pushing message to ' + user.username);
          push.send(user, "New notes for tag(s): " + body.tags);
        });
      }
      response.continue();
    });
 } else {
   logger.info("no tags in " + body);
   response.continue();
 }
}
```

This code does the following:

1. Extracts any tags and location from the just saved `MapNote` object.
2. Searches the user collection for users that are (a) last within 5 miles of the note, and (b) have subscribed at least of the new note's tags in it's `tags` field.
3. For each of the users that satisfy these requirements, send a push notification letting them know a new note is available for those tags.
4. __Next Step:__ An even better form of the push notification would be include the note's `_id` and just reload that note. Right now the app just displays an alert and reloads all the notes.

### Set up Custom Endpoint
1. From the `Addons` -> `Business Logic` -> `Custom Endpoints` menu, create a new endpoint called `tagsNearMe`.
2. Enter the code from [`tagsNearMe.js`](https://github.com/KinveyApps/GeoTag-iOS/raw/master/tagsNearMe.js) in the code window:

```
function getTags(request,response,modules,user) {
  var headers = {"Authorization":request.headers.authorization}; //re-use the current user's ACLs rather than master secret
  var loc = user._geoloc;
  var qs = '{"_geoloc":{"$nearSphere":['+loc+'],"$maxDistance":"10"}}'; //find notes within 10 miles
  var uri = 'https://' + request.headers.host + '/appdata/'+request.appKey+'/mapNotes/?query='+qs; //build the request
  modules.request.get({uri: uri, headers: headers}, function(error, res, body){
	if (error){
	  modules.logger.error(error);
	  response.body = {error: error.message};
      response.complete(res.status);
	} else {
	  //iterate through all the notes and count the tags
	  var elements = JSON.parse(body);
	  var tags = {};
	  elements.forEach(function(doc){
		doc.tags.forEach(function(tagar) {
		  if (tags[tagar]) {
			tags[tagar]++;
		  } else {
			tags[tagar] = 1;
		  }
		});
	  });
	  response.body = tags; //return all the tags with their count, could create a count threshold in the future
	  response.complete(200);
	}
});
}

function onRequest(request, response, modules){
  var collectionAccess = modules.collectionAccess;
  //find the current user in the user collection
  collectionAccess.collection('user').find({"username": request.username}, function (err, userColl) {
     if (err) {
         response.body = {error: error.message};
         response.complete(434);
     } else {
         getTags(request,response,modules,userColl[0]);
     }
  });
}
```

This code does the following:

1. The `onRequest` method is called when the request comes in.
2. This method looks up the user using `collectionAccess`. The user object is needed to obtain the user's location.
3. In `getTags()` a call is made "as the user" using the user's `Authorization` header to `mapNotes` collection. This is done in order to respect the user's ACLs (as collectionAccess is done as the "master secret"). For GeoTag, this should not make a difference since `mapNotes` is globally readable by default.
4. If the response is successful, it will be an array of `MapNotes` objects. This array is iterated over and the each of the tags is counted in a running total.
5. After all the notes are counted, the totals object is returned to the app.
6. __Next Step:__ A good next step is to limit the tags to the 20 most popular, or only display tags that have been used 5 or more times in order to limit the noisiness of the data.

__NOTE:__ it is important to `complete()` the response in all terminal branches, or the client will timeout waiting for a response.

## System Requirements
* Xcode 4.5+
* iPad/iPhone/iPod Touch
* iOS 6+
* KinveyKit 1.17.0+

## Contact
Website: [www.kinvey.com](http://www.kinvey.com)

Support: [support@kinvey.com](http://docs.kinvey.com/mailto:support@kinvey.com)

## License

Copyright (c) 2013 Kinvey, 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.


#ifndef __parserclass__
#define __parserclass__

#include <pelet/LexicalAnalyzerClass.h>
#include <pelet/TokenClass.h>
#include <pelet/ParserTypeClass.h>
#include <unicode/unistr.h>
#include <pelet/Api.h>

/**
\mainpage pelet: Php Easy LanguagE Toolkit. A C++ library for analyzing PHP source code
\section Overview
This doc briefly describes the major design of the pelet parser library.

pelet has the folowing major components:

- Parser
- Lexer
- Parser Implementation

\section Parser
The pelet::ParserClass, along with pelet::ClassObserverClass, pelet::ClassMemberObserverClass,
pelet::FunctionObserverClass, pelet::VariableObserverClass, and pelet::ExpressionObserverClass, make up
the "driver" (or main entry point) to pelet. ParserClass takes as input a string (or file) of PHP source code and
extracts artifacts from it (classes, functions, methods, etc..).

To use the parser, a user will create a class that defines the callbacks for each PHP artifact (class, function,
method, etc). The user will register these callbacks with the parser. When pelet::ParserClass::ScanFile is called,
the bison parser rules start looking for syntax rules. The parser will ask the lexer for tokens.  As soon as a
specific rule is hit, then the proper parser observer callback gets called. For example, when the parser hits
the "class" rule (ie "class MyClass {") then the class observer will get called; and the observer will get the
identifer ("MyClass") along with other info (signature, comment).

The important thing to note here is that the callbacks happen while ParserClass::ScanFile still has control.
ParserClass::ScanFile does not return control until the entire file has been parsed; multiple callbacks will have
been called before ParserClass::ScanFile returns.  For this reason, it is important that ParserClass::ScanFile
should not be called within any of the observers.

A word on concurrency: The pelet parser does not keep global state (it is a "pure" bison parser), but the pelet
parser is not thread-safe.  If pelet is used on a multi-threaded app, each thread should have its own instance
of pelet::ParserClass.

\section Lexer
The pelet::LexicalAnalyzerClass is used to tokenize the source code (turn strings into tokens). The
details of the implementation can be found in the \ref LexerDetailsPage page.

\section ParserImplementation Parser Implementation
This is a parser generated with the help of Bison. This used to follow the PHP rules;
for example after "function" comes the function name; after "if" comes a "(" and so on...)
When the syntax rules hit an artifact (for example a class) the syntax rules will call the proper observer.
The details of the implementation can be found in the \ref ParserImplementationDetailsPage page.
*/
namespace pelet {

/**
 * Holds the results of the lint check.  Currently lint check will stop when
 * the first error is encountered.
 */
class PELET_API LintResultsClass {
public:

	/**
	 * A short description of the error; this is generated by the bison parser and is
	 * not the most user-friendly but it is exactly what PHP displays; might as well
	 * keep it consistant.
	 */
	UnicodeString Error;

	/**
	 * Path to the file in which the error ocurred.
	 * This is what was given to the LintFile() method or ScanFile(std::string, LintResultsClass&) method.
	 * For LintString() results this will be the empty string.
	 */
	std::string File;

	/**
	 * Path to the file in which the error ocurred.
	 * This is what was given to the LintFile() or ScanFile(FILE*, UnicodeString, LintResultsClass&) method.
	 * For LintString() results this will be the empty string.
	 */
	UnicodeString UnicodeFilename;

	/**
	 * If the parser encountered a syntax error, then this object will be filled with
	 * the last known class/method/function where the error occurred.
	 */
	pelet::ScopeClass Scope;

	/**
	 * The line in which the error ocurred. This is 1-based.
	 */
	int LineNumber;

	/**
	 * The character offset in which the error ocurred (with regargs to the start of
	 * the file). This is 0-based.
	 */
	int CharacterPosition;

	LintResultsClass();

	/**
	 * copy the attributes from src to this object.
	 */
	void Copy(const LintResultsClass& src);

	/**
	 * remove any error string
	 */
	void Clear();
};

/**
 * The parser class is designed in a way that can utilized by different pieces of code.  The parser will analyze
 * given code and make calls to the different registered observers.  There are observers for classes, functions, and
 * methods. Not all observers have to be set; for example if a FunctionObserverClass is never registered then the
 * parser will not notify when a function has been found in a piece of code.
 *
 * @code
 *   class EchoAndObserverClass : public ClassObserverClass {
 *
 *     virtual void ClassFound(const UnicodeString& className, const UnicodeString& signature,
 *          const UnicodeString& comment) {
 *       printf("Found Class %s\n", (const char*)className.ToUTF8());
 *     }
 *   }
 *
 *   EchoAndObserverClass echoObserver;
 *   ParserClass parser;
 *   parser.SetClassObserver(&echoObserver);
 *   wxString someFileName = wxT("/some/file.php");
 *   if (!parser.ScanFile(someFileName)) {
 *     puts("Could not find file to parse!");
 *   }
 * @endcode
 *
 * Observers follow the PHP parsing rules to the letter.  If source code is not valid; then observers may not
 * get called.
 *
 * Lint functionality
 *
 * The parser class has the ability to check PHP code for syntax errors. This is done via the LintXXX() methods.
 *
 * @code
 *   ParserClass parser;
 *   std::string file = "/path/to/phpfile.php";
 *   LintResultsClass lintResults;
 *   if (parser.LintFile(file, parserResults)) {
 *     printf("No syntax errors in file %s", (const char*)file.c_str());
 *   }
 *   else {
 *     printf("%s. Error found in file %s on line %d.\n", parserResults.Error, file.c_str(), parserResults.LineNumber);
 *   }
 * @endcode
 */
class PELET_API ParserClass {

public:

	ParserClass();

	/**
	 * Opens and scans the given file; This function will return once the entire
	 * file has been parsed; it will call the proper observers when it encounters
	 * a class, function, or variable declaration. This means that this
	 * parser should not be modified in the observer calls.
	 *
	 * This is a convenience method, it does no handle unicode file names. For that,
	 * see ScanFile(FILE*, UnicodeString, LintResultsClass)
	 *
	 * @param file the file to parse.  Must be a full path.
	 * @param LintResultsClass& results any error message will be populated here
	 * @return bool if file was found and could be parsed successfully
	 */
	bool ScanFile(const std::string& file, LintResultsClass& results);

	/**
	 * Opens and scans the given file; This function will return once the entire
	 * file has been parsed; it will call the proper observers when it encounters
	 * a class, function, or variable declaration. This means that this
	 * parser should not be modified in the observer calls.
	 * This method is given a file pointer, it is useful for example when a file
	 * with a unicode filename is opened by the caller.
	 *
	 * @param file the file to parse, this class will NOT own the file pointer
	 * @param fileName this is the name that will be set in  results.UnicodeFilename when an error happens
	 * @param LintResultsClass& results any error message will be populated here
	 * @return bool if file was found and could be parsed successfully
	 */
	bool ScanFile(FILE* file, const UnicodeString& fileName, LintResultsClass& results);

	/**
	 * Scans the given string. This function will return once the entire
	 * string has been parsed; it will call the proper observers when it encounters
	 * a class, function, or variable declaration. This means that this
	 * parser should not be modified in the observer calls.
	 *
	 * @param const UnicodeString& code the code to parse.
	 * @param LintResultsClass& results any error message will be populated here
	 * @return bool if string could be parsed successfully
	 */
	bool ScanString(const UnicodeString& code, LintResultsClass& results);

	/**
	 * Change the version that this parser can handle. This needs to be called BEFORE ScanFile() or
	 * ScanString()
	 */
	void SetVersion(Versions version);

	/**
	 * Set the class observer.  The observer will get notified when a class is encountered.
	 * Memory management of this pointer should be done by the caller.
	 *
	 * @param ClassObserverClass* observer the object to sent notifications to
	 */
	void SetClassObserver(ClassObserverClass* observer);

	/**
	 * Set the class member observer.  The observer will get notified when a class member is encountered.
	 * Memory management of this pointer should be done by the caller.
	 *
	 * @param ClassMemberObserverClass* observer the object to sent notifications to
	 */
	void SetClassMemberObserver(ClassMemberObserverClass* observer);

	/**
	 * Set the function observer.  The observer will get notified when a function is encountered.
	 * Memory management of this pointer should be done by the caller.
	 *
	 * @param FunctionObserverClass* observer the object to sent notifications to
	 */
	void SetFunctionObserver(FunctionObserverClass* observer);

	/**
	 * Set the variable observer.  The observer will get notified when a new variable has been created.
	 * Memory management of this pointer should be done by the caller.
	 *
	 * There are performance implications if you call this method; if you want to be notified
	 * of variables then the full PHP parser is used; and parsing a file can be memory intensive.
	 *
	 * @param VariableObserverClass* observer the object to sent notifications to
	 */
	void SetVariableObserver(VariableObserverClass* observer);

	/**
	 * Set the expression observer.  The observer will get notified when a new expression has been created.
	 * Memory management of this pointer should be done by the caller.
	 *
	 * There are performance implications if you call this method; if you want to be notified
	 * of expressions then the full PHP parser is used; and parsing a file can be memory intensive.
	 *
	 * @param ExpressionObserverClass* observer the object to sent notifications to
	 */
	void SetExpressionObserver(ExpressionObserverClass* expressionObserver);

	/**
	 * Perform a TRUE PHP syntax check on the entire file. This syntax check is based on PHP 5.3
	 * or PHP 5.4 depending on whether SetVersion() was called.
	 *
	 * Note that this is not entirely the same as 'php -l' command; the PHP lint command detects
	 * duplicate function  / class names where as this lint check method does not.
	 *
	 * Returns true if the file had no syntax errors. Note that a file that does not have
	 * any PHP code will be considered a good file (a PHP file that has only HTML is
	 * considered good and true will be returned).
	 *
	 * This is a convenience method; unicode filenames are not handled.
	 *
	 * @param file the file to parse.  Must be a full path.
	 * @param LintResultsClass& results any error message will be populated here
	 * @return bool true if file was found and had no syntax errors.
	 */
	bool LintFile(const std::string& file, LintResultsClass& results);

	/**
	 * Perform a TRUE PHP syntax check on the entire file. This syntax check is based on PHP 5.3
	 * or PHP 5.4 depending on whether SetVersion() was called.
	 *
	 * Note that this is not entirely the same as 'php -l' command; the PHP lint command detects
	 * duplicate function  / class names where as this lint check method does not.
	 *
	 * Returns true if the file had no syntax errors. Note that a file that does not have
	 * any PHP code will be considered a good file (a PHP file that has only HTML is
	 * considered good and true will be returned).
	 *
	 * @param FILE* file the file to parse.  Must be an opened file pointer, this class will NOT own the file pointer
	 * @param fileName this is the name that will be set in  results.UnicodeFilename when an error happens
	 * @param LintResultsClass& results any error message will be populated here
	 * @return bool true if file was found and had no syntax errors.
	 */
	bool LintFile(FILE* file, const UnicodeString& filename, LintResultsClass& results);

	/**
	 * Perform a syntax check on the given source code. Source code is assumed to be
	 * all code (HTML will not be skipped, and will result in syntax errors). The PHP
	 * open tag is optional.
	 * Returns true if the code had no syntax errors.
	 *
	 * @param const UnicodeString& code the actual code to parse.
	 * @param LintResultsClass& results any error message will be populated here
	 * @return bool true if the code has no syntax errors.
	 */
	bool LintString(const UnicodeString& code, LintResultsClass& results);

	/**
	 * @return the character position where the parser is currently parsing. This can be called
	 * inside an observer callback; in which case the character position is right PAST the
	 * current token.
	 */
	int GetCharacterPosition() const;

	/**
	 * Parses a given PHP expression.  This method will parse the given expression into a list of
	 * of "chained" calls.
	 *
	 * A PHP expression is
	 *  - a variable  ($obj)
	 *  - a function call (myFunc())
	 *  - an object operation ("$obj->prop")
	 *  - a static object operation ("MyClass::Prop")
	 *
	 * Object operations can be chained; like "$obj->prop->anotherFunc()". While indirect variables are allowed
	 * in PHP (ie $this->$prop)  this method will not handle them as it is nearly impossible to resolve them at parse time.
	 *
	 * The most extreme example is this expression: "$obj->prop->anotherFunc()"
	 * This method will parse the expression into
	 * $obj
	 * ->prop
	 * ->anotherFunc()

	 * For example, if sourceCode represented this string:
	 *
	 *   @code
	 *     UnicodeString sourceCode = UNICODE_STRING_SIMPLE("
	 *       class UserClass {
	 *         private $name;
	 *
	 *         function getName() {
	 *           return $this->
	 *     ");
	 *   @endcode
	 *  then the following C++ code can be used to find a variable's type
	 *
	 *   @code
	 *     ParserClass parser;
	 *     UnicodeString expression = UNICODE_STRING_SIMPLE("$this->");
	 *     pelet::SymbolClass exprResult;
	 *     if (parser.ParseExpression(expression, exprResult)) {
	 *     	// if successful, symbol.Lexeme will be set to "$this"
	 *     }
	 *   @endcode
	 *
	 *
	 * @param expression the code string of the expression to resolve. This must be the code for a single expression.
	 *        Examples:
	 *        $anObject
	 *        $this->prop
	 *        $this->work()->another
	 *        $this->
	 *		  work()->another
	 *		  work()
	 *        self::prop
	 *        self::prop::
	 *        self::func()->prop
	 *        parent::prop
	 *        parent::fun()->prop
	 *        aFunction
	 *        An expression can have whitespace like this
	 *        $anObject
	 *			->method1()
	 *			->method2()
	 *			->method3()
	 *
	 * A special case that happens when the given expression ends with the object operator:
	 *        $this->
	 *        MyClass::
	 * In this case, the operator will be added the chain list; this way the client code can determine that
	 * the variable name actually ended.
	 * @param expression the expression's name and "chain" list. The  properties of this object will be reset every call.
	 */
	void ParseExpression(UnicodeString expressionString, pelet::VariableClass& variable);

private:

	/**
	 * Clean up any resources after parsing a file. This is also very important if the
	 * parser opens a string; without closing the string will not be released (if it's a
	 * long string).
	 */
	void Close();

	/**
	 * Used to tokenize code
	 */
	LexicalAnalyzerClass Lexer;

	/**
	 * Notify the ClassObserver when a class has been found. Memory management of this pointer should be
	 * done by the caller.
	 */
	ClassObserverClass* ClassObserver;

	/**
	 * Notify the ClassMemberObserver when a class member has been found. Memory management of this pointer should be
	 * done by the caller.
	 */
	ClassMemberObserverClass* ClassMemberObserver;

	/**
	 * Notify the FunctionObserver when a function has been found. Memory management of this pointer should be
	 * done by the caller.
	 */
	FunctionObserverClass* FunctionObserver;

	/**
	 * Notify the VariableObserver when a variable has been created. Memory management of this pointer should be
	 * done by the caller.
	 */
	VariableObserverClass* VariableObserver;

	/**
	 * Notify the ExpressionObserver when an expressionhas been found. Memory management of this pointer should be
	 * done by the caller.
	 */
	ExpressionObserverClass* ExpressionObserver;

	/**
	 * The PHP version to handle
	 */
	Versions Version;
};

}
#endif // __parserclass__