text:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <glib.h>
#include <dbus/dbus.h>

#include "lib/bluetooth.h"
#include "lib/sdp.h"

#include "gdbus/gdbus.h"

#include "log.h"
#include "error.h"
#include "hcid.h"
#include "dbus-common.h"
#include "adapter.h"
#include "device.h"
#include "agent.h"
#include "shared/queue.h"

#define IO_CAPABILITY_DISPLAYONLY	0x00
#define IO_CAPABILITY_DISPLAYYESNO	0x01
#define IO_CAPABILITY_KEYBOARDONLY	0x02
#define IO_CAPABILITY_NOINPUTNOOUTPUT	0x03
#define IO_CAPABILITY_KEYBOARDDISPLAY	0x04
#define IO_CAPABILITY_INVALID		0xFF

#define REQUEST_TIMEOUT (60 * 1000)		/* 60 seconds */
#define AGENT_INTERFACE "org.bluez.Agent1"

static GHashTable *agent_list;
struct queue *default_agents = NULL;

typedef enum {
	AGENT_REQUEST_PASSKEY,
	AGENT_REQUEST_CONFIRMATION,
	AGENT_REQUEST_AUTHORIZATION,
	AGENT_REQUEST_PINCODE,
	AGENT_REQUEST_AUTHORIZE_SERVICE,
	AGENT_REQUEST_DISPLAY_PINCODE,
} agent_request_type_t;

struct agent {
	int ref;
	char *owner;
	char *path;
	uint8_t capability;
	struct agent_request *request;
	guint watch;
};

struct agent_request {
	agent_request_type_t type;
	struct agent *agent;
	DBusMessage *msg;
	DBusPendingCall *call;
	void *cb;
	void *user_data;
	GDestroyNotify destroy;
};

static void agent_release(struct agent *agent)
{
	DBusMessage *message;

	DBG("Releasing agent %s, %s", agent->owner, agent->path);

	if (agent->request)
		agent_cancel(agent);

	message = dbus_message_new_method_call(agent->owner, agent->path,
						AGENT_INTERFACE, "Release");
	if (message == NULL) {
		error("Couldn't allocate D-Bus message");
		return;
	}

	g_dbus_send_message(btd_get_dbus_connection(), message);
}

static int send_cancel_request(struct agent_request *req)
{
	DBusMessage *message;

	DBG("Sending Cancel request to %s, %s", req->agent->owner,
							req->agent->path);

	message = dbus_message_new_method_call(req->agent->owner, req->agent->path,
						AGENT_INTERFACE, "Cancel");
	if (message == NULL) {
		error("Couldn't allocate D-Bus message");
		return -ENOMEM;
	}

	g_dbus_send_message(btd_get_dbus_connection(), message);

	return 0;
}

static void agent_request_free(struct agent_request *req, gboolean destroy)
{
	if (req->msg)
		dbus_message_unref(req->msg);
	if (req->call)
		dbus_pending_call_unref(req->call);
	if (req->agent && req->agent->request)
		req->agent->request = NULL;
	if (destroy && req->destroy)
		req->destroy(req->user_data);
	g_free(req);
}

static void set_io_cap(struct btd_adapter *adapter, gpointer user_data)
{
	struct agent *agent = user_data;
	uint8_t io_cap;

	if (agent)
		io_cap = agent->capability;
	else
		io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT;

	adapter_set_io_capability(adapter, io_cap);
}

static bool add_default_agent(struct agent *agent)
{
	if (queue_peek_head(default_agents) == agent)
		return true;

	queue_remove(default_agents, agent);

	if (!queue_push_head(default_agents, agent))
		return false;

	DBG("Default agent set to %s %s", agent->owner, agent->path);

	adapter_foreach(set_io_cap, agent);

	return true;
}

static void remove_default_agent(struct agent *agent)
{
	if (queue_peek_head(default_agents) != agent) {
		queue_remove(default_agents, agent);
		return;
	}

	queue_remove(default_agents, agent);

	agent = queue_peek_head(default_agents);
	if (agent)
		DBG("Default agent set to %s %s", agent->owner, agent->path);
	else
		DBG("Default agent cleared");

	adapter_foreach(set_io_cap, agent);
}

static void agent_disconnect(DBusConnection *conn, void *user_data)
{
	struct agent *agent = user_data;

	DBG("Agent %s disconnected", agent->owner);

	if (agent->watch > 0) {
		g_dbus_remove_watch(conn, agent->watch);
		agent->watch = 0;
	}

	remove_default_agent(agent);

	g_hash_table_remove(agent_list, agent->owner);
}

struct agent *agent_ref(struct agent *agent)
{
	agent->ref++;

	DBG("%p: ref=%d", agent, agent->ref);

	return agent;
}

void agent_unref(struct agent *agent)
{
	agent->ref--;

	DBG("%p: ref=%d", agent, agent->ref);

	if (agent->ref > 0)
		return;

	if (agent->request) {
		DBusError err;
		agent_pincode_cb pincode_cb;
		agent_passkey_cb passkey_cb;
		agent_cb cb;

		dbus_error_init(&err);
		dbus_set_error_const(&err, ERROR_INTERFACE ".Failed",
								"Canceled");

		switch (agent->request->type) {
		case AGENT_REQUEST_PINCODE:
			pincode_cb = agent->request->cb;
			pincode_cb(agent, &err, NULL, agent->request->user_data);
			break;
		case AGENT_REQUEST_PASSKEY:
			passkey_cb = agent->request->cb;
			passkey_cb(agent, &err, 0, agent->request->user_data);
			break;
		case AGENT_REQUEST_CONFIRMATION:
		case AGENT_REQUEST_AUTHORIZATION:
		case AGENT_REQUEST_AUTHORIZE_SERVICE:
		case AGENT_REQUEST_DISPLAY_PINCODE:
		default:
			cb = agent->request->cb;
			cb(agent, &err, agent->request->user_data);
		}

		dbus_error_free(&err);

		agent_cancel(agent);
	}

	g_free(agent->owner);
	g_free(agent->path);

	g_free(agent);
}

struct agent *agent_get(const char *owner)
{
	struct agent *agent;

	if (owner) {
		agent = g_hash_table_lookup(agent_list, owner);
		if (agent)
			return agent_ref(agent);
	}

	if (!queue_isempty(default_agents))
		return agent_ref(queue_peek_head(default_agents));

	return NULL;
}

static struct agent *agent_create( const char *name, const char *path,
							uint8_t capability)
{
	struct agent *agent;

	agent = g_new0(struct agent, 1);

	agent->owner = g_strdup(name);
	agent->path = g_strdup(path);
	agent->capability = capability;

	agent->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
							name, agent_disconnect,
							agent, NULL);

	return agent_ref(agent);
}

static struct agent_request *agent_request_new(struct agent *agent,
						agent_request_type_t type,
						void *cb,
						void *user_data,
						GDestroyNotify destroy)
{
	struct agent_request *req;

	req = g_new0(struct agent_request, 1);

	req->agent = agent;
	req->type = type;
	req->cb = cb;
	req->user_data = user_data;
	req->destroy = destroy;

	return req;
}

int agent_cancel(struct agent *agent)
{
	if (!agent->request)
		return -EINVAL;

	if (agent->request->call) {
		dbus_pending_call_cancel(agent->request->call);
		send_cancel_request(agent->request);
	}

	agent_request_free(agent->request, TRUE);
	agent->request = NULL;

	return 0;
}

static void simple_agent_reply(DBusPendingCall *call, void *user_data)
{
	struct agent_request *req = user_data;
	struct agent *agent = req->agent;
	DBusMessage *message;
	DBusError err;
	agent_cb cb = req->cb;

	/* steal_reply will always return non-NULL since the callback
	 * is only called after a reply has been received */
	message = dbus_pending_call_steal_reply(call);

	/* Protect from the callback freeing the agent */
	agent_ref(agent);

	dbus_error_init(&err);
	if (dbus_set_error_from_message(&err, message)) {
		DBG("agent error reply: %s, %s", err.name, err.message);

		cb(agent, &err, req->user_data);

		if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
			error("Timed out waiting for reply from agent");
			agent_cancel(agent);
			dbus_message_unref(message);
			dbus_error_free(&err);
			agent_unref(agent);
			return;
		}

		dbus_error_free(&err);
		goto done;
	}

	if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
		error("Wrong reply signature: %s", err.message);
		cb(agent, &err, req->user_data);
		dbus_error_free(&err);
		goto done;
	}

	cb(agent, NULL, req->user_data);
done:
	dbus_message_unref(message);

	agent->request = NULL;
	agent_request_free(req, TRUE);
	agent_unref(agent);
}

static int agent_call_authorize_service(struct agent_request *req,
						const char *device_path,
						const char *uuid)
{
	struct agent *agent = req->agent;

	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
					AGENT_INTERFACE, "AuthorizeService");
	if (!req->msg) {
		error("Couldn't allocate D-Bus message");
		return -ENOMEM;
	}

	dbus_message_append_args(req->msg,
				DBUS_TYPE_OBJECT_PATH, &device_path,
				DBUS_TYPE_STRING, &uuid,
				DBUS_TYPE_INVALID);

	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(),
						req->msg, &req->call,
						REQUEST_TIMEOUT) == FALSE) {
		error("D-Bus send failed");
		return -EIO;
	}

	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
	return 0;
}

int agent_authorize_service(struct agent *agent, const char *path,
				const char *uuid, agent_cb cb,
				void *user_data, GDestroyNotify destroy)
{
	struct agent_request *req;
	int err;

	if (agent->request)
		return -EBUSY;

	req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE_SERVICE, cb,
							user_data, destroy);

	err = agent_call_authorize_service(req, path, uuid);
	if (err < 0) {
		agent_request_free(req, FALSE);
		return -ENOMEM;
	}

	agent->request = req;

	DBG("authorize service request was sent for %s", path);

	return 0;
}

static void pincode_reply(DBusPendingCall *call, void *user_data)
{
	struct agent_request *req = user_data;
	struct agent *agent = req->agent;
	agent_pincode_cb cb = req->cb;
	DBusMessage *message;
	DBusError err;
	size_t len;
	char *pin;

	/* steal_reply will always return non-NULL since the callback
	 * is only called after a reply has been received */
	message = dbus_pending_call_steal_reply(call);

	/* Protect from the callback freeing the agent */
	agent_ref(agent);

	dbus_error_init(&err);
	if (dbus_set_error_from_message(&err, message)) {
		error("Agent %s replied with an error: %s, %s",
				agent->path, err.name, err.message);

		cb(agent, &err, NULL, req->user_data);
		dbus_error_free(&err);
		goto done;
	}

	if (!dbus_message_get_args(message, &err,
				DBUS_TYPE_STRING, &pin,
				DBUS_TYPE_INVALID)) {
		error("Wrong passkey reply signature: %s", err.message);
		cb(agent, &err, NULL, req->user_data);
		dbus_error_free(&err);
		goto done;
	}

	len = strlen(pin);

	if (len > 16 || len < 1) {
		error("Invalid PIN length (%zu) from agent", len);
		dbus_set_error_const(&err, ERROR_INTERFACE ".InvalidArgs",
					"Invalid passkey length");
		cb(agent, &err, NULL, req->user_data);
		dbus_error_free(&err);
		goto done;
	}

	cb(agent, NULL, pin, req->user_data);

done:
	if (message)
		dbus_message_unref(message);

	dbus_pending_call_cancel(req->call);
	agent->request = NULL;
	agent_request_free(req, TRUE);
	agent_unref(agent);
}

static int pincode_request_new(struct agent_request *req, const char *device_path,
				dbus_bool_t secure)
{
	struct agent *agent = req->agent;

	/* TODO: Add a new method or a new param to Agent interface to request
		secure pin. */

	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
					AGENT_INTERFACE, "RequestPinCode");
	if (req->msg == NULL) {
		error("Couldn't allocate D-Bus message");
		return -ENOMEM;
	}

	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
					DBUS_TYPE_INVALID);

	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
					&req->call, REQUEST_TIMEOUT) == FALSE) {
		error("D-Bus send failed");
		return -EIO;
	}

	dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL);
	return 0;
}

int agent_request_pincode(struct agent *agent, struct btd_device *device,
				agent_pincode_cb cb, gboolean secure,
				void *user_data, GDestroyNotify destroy)
{
	struct agent_request *req;
	const char *dev_path = device_get_path(device);
	int err;

	if (agent->request)
		return -EBUSY;

	req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb,
							user_data, destroy);

	err = pincode_request_new(req, dev_path, secure);
	if (err < 0)
		goto failed;

	agent->request = req;

	return 0;

failed:
	agent_request_free(req, FALSE);
	return err;
}

static void passkey_reply(DBusPendingCall *call, void *user_data)
{
	struct agent_request *req = user_data;
	struct agent *agent = req->agent;
	agent_passkey_cb cb = req->cb;
	DBusMessage *message;
	DBusError err;
	uint32_t passkey;

	/* steal_reply will always return non-NULL since the callback
	 * is only called after a reply has been received */
	message = dbus_pending_call_steal_reply(call);

	dbus_error_init(&err);
	if (dbus_set_error_from_message(&err, message)) {
		error("Agent replied with an error: %s, %s",
						err.name, err.message);
		cb(agent, &err, 0, req->user_data);
		dbus_error_free(&err);
		goto done;
	}

	if (!dbus_message_get_args(message, &err,
				DBUS_TYPE_UINT32, &passkey,
				DBUS_TYPE_INVALID)) {
		error("Wrong passkey reply signature: %s", err.message);
		cb(agent, &err, 0, req->user_data);
		dbus_error_free(&err);
		goto done;
	}

	cb(agent, NULL, passkey, req->user_data);

done:
	if (message)
		dbus_message_unref(message);

	dbus_pending_call_cancel(req->call);
	agent->request = NULL;
	agent_request_free(req, TRUE);
}

static int passkey_request_new(struct agent_request *req,
				const char *device_path)
{
	struct agent *agent = req->agent;

	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
					AGENT_INTERFACE, "RequestPasskey");
	if (req->msg == NULL) {
		error("Couldn't allocate D-Bus message");
		return -ENOMEM;
	}

	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
					DBUS_TYPE_INVALID);

	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
					&req->call, REQUEST_TIMEOUT) == FALSE) {
		error("D-Bus send failed");
		return -EIO;
	}

	dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL);
	return 0;
}

int agent_request_passkey(struct agent *agent, struct btd_device *device,
				agent_passkey_cb cb, void *user_data,
				GDestroyNotify destroy)
{
	struct agent_request *req;
	const char *dev_path = device_get_path(device);
	int err;

	if (agent->request)
		return -EBUSY;

	DBG("Calling Agent.RequestPasskey: name=%s, path=%s",
			agent->owner, agent->path);

	req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb,
							user_data, destroy);

	err = passkey_request_new(req, dev_path);
	if (err < 0)
		goto failed;

	agent->request = req;

	return 0;

failed:
	agent_request_free(req, FALSE);
	return err;
}

static int confirmation_request_new(struct agent_request *req,
					const char *device_path,
					uint32_t passkey)
{
	struct agent *agent = req->agent;

	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
				AGENT_INTERFACE, "RequestConfirmation");
	if (req->msg == NULL) {
		error("Couldn't allocate D-Bus message");
		return -ENOMEM;
	}

	dbus_message_append_args(req->msg,
				DBUS_TYPE_OBJECT_PATH, &device_path,
				DBUS_TYPE_UINT32, &passkey,
				DBUS_TYPE_INVALID);

	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
				&req->call, REQUEST_TIMEOUT) == FALSE) {
		error("D-Bus send failed");
		return -EIO;
	}

	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);

	return 0;
}

int agent_request_confirmation(struct agent *agent, struct btd_device *device,
				uint32_t passkey, agent_cb cb,
				void *user_data, GDestroyNotify destroy)
{
	struct agent_request *req;
	const char *dev_path = device_get_path(device);
	int err;

	if (agent->request)
		return -EBUSY;

	DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
			agent->owner, agent->path, passkey);

	req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
				user_data, destroy);

	err = confirmation_request_new(req, dev_path, passkey);
	if (err < 0)
		goto failed;

	agent->request = req;

	return 0;

failed:
	agent_request_free(req, FALSE);
	return err;
}

static int authorization_request_new(struct agent_request *req,
						const char *device_path)
{
	struct agent *agent = req->agent;

	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
				AGENT_INTERFACE, "RequestAuthorization");
	if (req->msg == NULL) {
		error("Couldn't allocate D-Bus message");
		return -ENOMEM;
	}

	dbus_message_append_args(req->msg,
				DBUS_TYPE_OBJECT_PATH, &device_path,
				DBUS_TYPE_INVALID);

	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
				&req->call, REQUEST_TIMEOUT) == FALSE) {
		error("D-Bus send failed");
		return -EIO;
	}

	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);

	return 0;
}

int agent_request_authorization(struct agent *agent, struct btd_device *device,
						agent_cb cb, void *user_data,
						GDestroyNotify destroy)
{
	struct agent_request *req;
	const char *dev_path = device_get_path(device);
	int err;

	if (agent->request)
		return -EBUSY;

	DBG("Calling Agent.RequestAuthorization: name=%s, path=%s",
						agent->owner, agent->path);

	req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZATION, cb,
				user_data, destroy);

	err = authorization_request_new(req, dev_path);
	if (err < 0)
		goto failed;

	agent->request = req;

	return 0;

failed:
	agent_request_free(req, FALSE);
	return err;
}

int agent_display_passkey(struct agent *agent, struct btd_device *device,
				uint32_t passkey, uint16_t entered)
{
	DBusMessage *message;
	const char *dev_path = device_get_path(device);

	message = dbus_message_new_method_call(agent->owner, agent->path,
					AGENT_INTERFACE, "DisplayPasskey");
	if (!message) {
		error("Couldn't allocate D-Bus message");
		return -1;
	}

	dbus_message_append_args(message,
				DBUS_TYPE_OBJECT_PATH, &dev_path,
				DBUS_TYPE_UINT32, &passkey,
				DBUS_TYPE_UINT16, &entered,
				DBUS_TYPE_INVALID);

	if (!g_dbus_send_message(btd_get_dbus_connection(), message)) {
		error("D-Bus send failed");
		return -1;
	}

	return 0;
}

static void display_pincode_reply(DBusPendingCall *call, void *user_data)
{
	struct agent_request *req = user_data;
	struct agent *agent = req->agent;
	DBusMessage *message;
	DBusError err;
	agent_cb cb = req->cb;

	/* clear agent->request early; our callback will likely try
	 * another request */
	agent->request = NULL;

	/* steal_reply will always return non-NULL since the callback
	 * is only called after a reply has been received */
	message = dbus_pending_call_steal_reply(call);

	dbus_error_init(&err);
	if (dbus_set_error_from_message(&err, message)) {
		error("Agent replied with an error: %s, %s",
						err.name, err.message);

		cb(agent, &err, req->user_data);

		if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
			agent_cancel(agent);
			dbus_message_unref(message);
			dbus_error_free(&err);
			return;
		}

		dbus_error_free(&err);
		goto done;
	}

	if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) {
		error("Wrong reply signature: %s", err.message);
		cb(agent, &err, req->user_data);
		dbus_error_free(&err);
		goto done;
	}

	cb(agent, NULL, req->user_data);
done:
	dbus_message_unref(message);

	agent_request_free(req, TRUE);
}

static int display_pincode_request_new(struct agent_request *req,
					const char *device_path,
					const char *pincode)
{
	struct agent *agent = req->agent;

	req->msg = dbus_message_new_method_call(agent->owner, agent->path,
					AGENT_INTERFACE, "DisplayPinCode");
	if (req->msg == NULL) {
		error("Couldn't allocate D-Bus message");
		return -ENOMEM;
	}

	dbus_message_append_args(req->msg,
					DBUS_TYPE_OBJECT_PATH, &device_path,
					DBUS_TYPE_STRING, &pincode,
					DBUS_TYPE_INVALID);

	if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
				&req->call, REQUEST_TIMEOUT) == FALSE) {
		error("D-Bus send failed");
		return -EIO;
	}

	dbus_pending_call_set_notify(req->call, display_pincode_reply,
								req, NULL);

	return 0;
}

int agent_display_pincode(struct agent *agent, struct btd_device *device,
				const char *pincode, agent_cb cb,
				void *user_data, GDestroyNotify destroy)
{
	struct agent_request *req;
	const char *dev_path = device_get_path(device);
	int err;

	if (agent->request)
		return -EBUSY;

	DBG("Calling Agent.DisplayPinCode: name=%s, path=%s, pincode=%s",
					agent->owner, agent->path, pincode);

	req = agent_request_new(agent, AGENT_REQUEST_DISPLAY_PINCODE, cb,
							user_data, destroy);

	err = display_pincode_request_new(req, dev_path, pincode);
	if (err < 0)
		goto failed;

	agent->request = req;

	return 0;

failed:
	agent_request_free(req, FALSE);
	return err;
}

uint8_t agent_get_io_capability(struct agent *agent)
{
	return agent->capability;
}

static void agent_destroy(gpointer data)
{
	struct agent *agent = data;

	DBG("agent %s", agent->owner);

	if (agent->watch > 0) {
		g_dbus_remove_watch(btd_get_dbus_connection(), agent->watch);
		agent->watch = 0;
		agent_release(agent);
	}

	remove_default_agent(agent);

	agent_unref(agent);
}

static uint8_t parse_io_capability(const char *capability)
{
	if (g_str_equal(capability, ""))
		return IO_CAPABILITY_KEYBOARDDISPLAY;
	if (g_str_equal(capability, "DisplayOnly"))
		return IO_CAPABILITY_DISPLAYONLY;
	if (g_str_equal(capability, "DisplayYesNo"))
		return IO_CAPABILITY_DISPLAYYESNO;
	if (g_str_equal(capability, "KeyboardOnly"))
		return IO_CAPABILITY_KEYBOARDONLY;
	if (g_str_equal(capability, "NoInputNoOutput"))
		return IO_CAPABILITY_NOINPUTNOOUTPUT;
	if (g_str_equal(capability, "KeyboardDisplay"))
		return IO_CAPABILITY_KEYBOARDDISPLAY;
	return IO_CAPABILITY_INVALID;
}

static DBusMessage *register_agent(DBusConnection *conn,
					DBusMessage *msg, void *user_data)
{
	struct agent *agent;
	const char *sender, *path, *capability;
	uint8_t cap;

	sender = dbus_message_get_sender(msg);

	agent = g_hash_table_lookup(agent_list, sender);
	if (agent)
		return btd_error_already_exists(msg);

	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
						DBUS_TYPE_STRING, &capability,
						DBUS_TYPE_INVALID) == FALSE)
		return btd_error_invalid_args(msg);

	cap = parse_io_capability(capability);
	if (cap == IO_CAPABILITY_INVALID)
		return btd_error_invalid_args(msg);

	agent = agent_create(sender, path, cap);
	if (!agent)
		return btd_error_invalid_args(msg);

	DBG("agent %s", agent->owner);

	g_hash_table_replace(agent_list, agent->owner, agent);

	return dbus_message_new_method_return(msg);
}

static DBusMessage *unregister_agent(DBusConnection *conn,
					DBusMessage *msg, void *user_data)
{
	struct agent *agent;
	const char *sender, *path;

	sender = dbus_message_get_sender(msg);

	agent = g_hash_table_lookup(agent_list, sender);
	if (!agent)
		return btd_error_does_not_exist(msg);

	DBG("agent %s", agent->owner);

	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
						DBUS_TYPE_INVALID) == FALSE)
		return btd_error_invalid_args(msg);

	if (g_str_equal(path, agent->path) == FALSE)
		return btd_error_does_not_exist(msg);

	agent_disconnect(conn, agent);

	return dbus_message_new_method_return(msg);
}

static DBusMessage *request_default(DBusConnection *conn, DBusMessage *msg,
							void *user_data)
{
	struct agent *agent;
	const char *sender, *path;

	sender = dbus_message_get_sender(msg);

	agent = g_hash_table_lookup(agent_list, sender);
	if (!agent)
		return btd_error_does_not_exist(msg);

	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
						DBUS_TYPE_INVALID) == FALSE)
		return btd_error_invalid_args(msg);

	if (g_str_equal(path, agent->path) == FALSE)
		return btd_error_does_not_exist(msg);

	if (!add_default_agent(agent))
		return btd_error_failed(msg, "Failed to set as default");

	return dbus_message_new_method_return(msg);
}

static const GDBusMethodTable methods[] = {
	{ GDBUS_METHOD("RegisterAgent",
			GDBUS_ARGS({ "agent", "o"}, { "capability", "s" }),
			NULL, register_agent) },
	{ GDBUS_METHOD("UnregisterAgent", GDBUS_ARGS({ "agent", "o" }),
			NULL, unregister_agent) },
	{ GDBUS_METHOD("RequestDefaultAgent", GDBUS_ARGS({ "agent", "o" }),
			NULL, request_default ) },
	{ }
};

void btd_agent_init(void)
{
	agent_list = g_hash_table_new_full(g_str_hash, g_str_equal,
						NULL, agent_destroy);

	default_agents = queue_new();

	g_dbus_register_interface(btd_get_dbus_connection(),
				"/org/bluez", "org.bluez.AgentManager1",
				methods, NULL, NULL, NULL, NULL);
}

void btd_agent_cleanup(void)
{
	g_dbus_unregister_interface(btd_get_dbus_connection(),
				"/org/bluez", "org.bluez.AgentManager1");

	g_hash_table_destroy(agent_list);
	queue_destroy(default_agents, NULL);
}


text:
import { utility } from './lib/utility.js';
import { modelParser } from './lib/modelParser.js';
import { fileModel } from './models/file.model.js';

/**
 * A base class for managing file attachments on both published pages and drafts.  This class can not be instantiated directly.
 */
export class PageFileBase {
    constructor(pageId, filename) {
        if(this.constructor.name === 'PageFileBase') {
            throw new TypeError('PageFileBase must not be constructed directly.  Use one of PageFile() or DraftFile()');
        }
        this._pageId = utility.getResourceId(pageId, 'home');
        this._filename = utility.getFilenameId(filename);
    }

    /**
     * Get the URI for direct access to the file attachment.
     * @returns {String} - The file URI.
     */
    get fileUrl() {
        return this._plug.url;
    }

    /**
     * Gets the information for the file attachment.
     * @returns {Promise.<fileModel>} - A Promise that, when resolved, yields a {@link fileModel} containing the file information.
     */
    getInfo() {
        let fileModelParser = modelParser.createParser(fileModel);
        return this._plug.at('info').get().then((r) => r.json()).then(fileModelParser);
    }

    /**
     * Delete the file attachment fron the page.
     * @returns {Promise} - A Promise that, when resolved, indicates a successful delete operation.
     */
    delete() {
        return this._plug.delete();
    }

    /**
     * Get the description of the file attachment.
     * @returns {Promise.<String>} - A Promise that, when resolved, yields the file description.
     */
    getDescription() {
        return this._plug.at('description').get().then((r) => r.json());
    }

    /**
     * Remove the description from the file attachment.
     * @returns {Promise} - A Promise that, when resolved, indicates a successful removal.
     */
    clearDescription() {
        return this._plug.at('description').delete();
    }

    /**
     * Update the description of the file attachment.
     * @param {String} [description=''] - The new description to set.
     * @returns {Promise.<fileModel>} - A Promise that, when resolved, yields a {@link fileModel} containing the file information.
     */
    updateDescription(description = '') {
        let fileModelParser = modelParser.createParser(fileModel);
        return this._plug.at('description').put(description, utility.textRequestType).then((r) => r.json()).then(fileModelParser);
    }
}

redpajama_set_name: RedPajamaGithub


text:
<!doctype html>

    <title>Code coverage report for lib/waterline/adapter/sync/strategies/create.js</title>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="../../../../../prettify.css" />
    <link rel="stylesheet" href="../../../../../base.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1">

      all files / lib/waterline/adapter/sync/strategies/ create.js

        13.79%
        Statements
        4/29

        0%
        Branches
        0/14

        0%
        Functions
        0/5

        15.38%
        Lines
        4/26

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

3×
3×
3×

3×

/**
 * Module dependencies
 */

var _ = require('lodash');
var async = require('async');
var hasOwnProperty = require('../../../utils/helpers').object.hasOwnProperty;

/**
 * Try and synchronize the underlying physical-layer schema
 * in safely manner by only adding new collections and new attributes
 * to work with our app's collections. (i.e. models)
 *
 * @param  {Function} cb
 */
module.exports = function(cb) {
  var self = this;

  // Check that collection exists
  self.describe(function afterDescribe(err, attrs) {

    if (err) return cb(err);

    // if it doesn't go ahead and add it and get out
    if (!attrs) return self.define(cb);

    // Check if an addAttribute adapter method is defined
    if (!hasOwnProperty(self.dictionary, 'addAttribute')) {
      return cb();
    }

    // Find the relevant connections to run this on
    var connName = self.dictionary.addAttribute;
    var adapter = self.connections[connName]._adapter;

    // Check if adapter has addAttribute method
    if (!hasOwnProperty(adapter, 'addAttribute')) {
      return cb();
    }

    // The collection we're working with
    var collectionID = self.collection;

    // Remove hasMany association keys before sending down to adapter
    var schema = _.clone(self.query._schema.schema) || {};
    Object.keys(schema).forEach(function(key) {
      if (schema[key].type) return;
      delete schema[key];
    });

    // Iterate through each attribute in the new definition
    // Used for keeping track of previously undefined attributes
    // when updating the data stored at the physical layer.
    var newAttributes = _.reduce(schema, function checkAttribute(newAttributes, attribute, attrName) {
      if (!attrs[attrName]) {
        newAttributes[attrName] = attribute;
      }
      return newAttributes;
    }, {});

    // Add new attributes
    async.eachSeries(_.keys(newAttributes), function(attrName, next) {
      var attrDef = newAttributes[attrName];
      adapter.addAttribute(connName, collectionID, attrName, attrDef, next);
    }, cb);

  });
};

  Code coverage
  generated by istanbul at Fri Mar 18 2016 12:26:23 GMT-0500 (CDT)


text:
/*******************************************
Response internal include file
*******************************************/
#ifndef __KINESIS_VIDEO_RESPONSE_INCLUDE_I__
#define __KINESIS_VIDEO_RESPONSE_INCLUDE_I__

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

// Setting this timeout to terminate CURL connection
#define TIMEOUT_AFTER_STREAM_STOPPED (1 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND)

// HTTP status code not set
#define HTTP_STATUS_CODE_NOT_SET 0

// Pause/unpause interval for curl
#define CURL_PAUSE_UNPAUSE_INTERVAL (10 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND)

// CA file extension
#define CA_CERT_FILE_SUFFIX ".pem"

// Debug dump data file environment variable
#define KVS_DEBUG_DUMP_DATA_FILE_DIR_ENV_VAR "KVS_DEBUG_DUMP_DATA_FILE_DIR"

// this is used by postReadCallback to sleep before checking for more data
#define MAX_GET_DATA_ITER 6

#define BASE_GET_DATA_SLEEP_TIME (20 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND)

/**
 * CURL callback function definitions
 */
typedef SIZE_T (*CurlCallbackFunc)(PCHAR, SIZE_T, SIZE_T, PVOID);

/**
 * Curl Response structure
 */
typedef struct __CurlResponse CurlResponse;
struct __CurlResponse {
    // Related request object
    PCurlRequest pCurlRequest;

    // Curl object to use for the calls
    CURL* pCurl;

    // Request Curl headers list
    struct curl_slist* pRequestHeaders;

    // Curl call data
    CallInfo callInfo;

    // Whether the call was force-terminated
    volatile ATOMIC_BOOL terminated;

    ///////////////////////////////////////////////
    // Variables needed for putMedia session

    // track whether end-of-stream has been received from getKinesisVideoStreamData
    BOOL endOfStream;

    // Whether curl is paused
    volatile BOOL paused;

    // Whether to dump streaming session into mkv file
    BOOL debugDumpFile;

    // Path of debug dump file
    CHAR debugDumpFilePath[MAX_PATH_LEN + 1];

    // Lock for exclusive access
    MUTEX lock;

    ///////////////////////////////////////////////
};
typedef struct __CurlResponse* PCurlResponse;

////////////////////////////////////////////////////
// Function definitions
////////////////////////////////////////////////////
/**
 * Creates a Response object
 *
 * @param - PCurlRequest - IN - Curl Request object to use for the response
 * @param - PCurlResponse* - IN/OUT - The newly created object
 *
 * @return - STATUS code of the execution
 */
STATUS createCurlResponse(PCurlRequest, PCurlResponse*);

/**
 * Frees a Response object
 *
 * @param - PCurlResponse* - IN/OUT - The object to release
 *
 * @return - STATUS code of the execution
 */
STATUS freeCurlResponse(PCurlResponse*);

/**
 * Closes curl handles
 *
 * @param - PCurlResponse - IN - Curl response object to close
 *
 * @return - STATUS code of the execution
 */
STATUS closeCurlHandles(PCurlResponse);

/**
 * Debug prints statistics of the request/response
 *
 * @param - PCurlResponse - IN - Response object
 *
 */
VOID dumpResponseCurlEasyInfo(PCurlResponse);

/**
 * Terminates the ongoing curl session
 *
 * @param - PCurlResponse - IN - Response object
 * @param - UINT64 - IN - Timeout value to use in 100ns
 *
 */
VOID terminateCurlSession(PCurlResponse, UINT64);

/**
 * Performs the curl request/response session.
 *
 * NOTE: This is a blocking API
 *
 * @param - PCurlResponse - IN - Response object
 *
 * @return - STATUS code of the execution
 */
STATUS curlCompleteSync(PCurlResponse);

/**
 * Notifies when data is available to read
 *
 * @param - PCurlResponse - IN - Response object
 * @param - UINT64 - IN - Duration of the buffer available in 100ns
 * @param - UINT64 - IN - Size of the buffer available in bytes
 *
 * @return - STATUS code of the execution
 */
STATUS notifyDataAvailable(PCurlResponse, UINT64, UINT64);

/**
 * Convenience method to convert CURL return status to SERVICE_CALL_RESULT status.
 *
 * @param - CURLcode - curl_status the CURL status code of the call
 *
 * @return The CURL code translated into a SERVICE_CALL_RESULT value.
 */
SERVICE_CALL_RESULT getServiceCallResultFromCurlStatus(CURLcode);

/**
 * Initializes curl session
 *
 * @param - PRequestInfo - IN - Request info object
 * @param - PCurlCallInfo - IN - Curl call info object to initialize values for
 * @param - Curl** - OUT - Curl object pointer to be set
 * @param - PVOID - IN - Data object to pass to Curl
 * @param - CurlCallbackFunc - IN - Curl write header callback
 * @param - CurlCallbackFunc - IN - Curl read callback
 * @param - CurlCallbackFunc - IN - Curl write callback
 * @param - CurlCallbackFunc - IN - Curl post write callback
 *
 * @return - STATUS code of the execution
 */
STATUS initializeCurlSession(PRequestInfo, PCallInfo, CURL**, PVOID, CurlCallbackFunc, CurlCallbackFunc, CurlCallbackFunc, CurlCallbackFunc);

////////////////////////////////////////////////////
// Curl callbacks
////////////////////////////////////////////////////
SIZE_T writeHeaderCallback(PCHAR, SIZE_T, SIZE_T, PVOID);
SIZE_T postWriteCallback(PCHAR, SIZE_T, SIZE_T, PVOID);
SIZE_T postReadCallback(PCHAR, SIZE_T, SIZE_T, PVOID);
SIZE_T postResponseWriteCallback(PCHAR, SIZE_T, SIZE_T, PVOID);

#ifdef __cplusplus
}
#endif
#endif /* __KINESIS_VIDEO_RESPONSE_INCLUDE_I__ */


text:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.qingge</groupId>
    <artifactId>taotao-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>taotao-manager</artifactId>
  <packaging>pom</packaging>

  <!-- 依赖管理 -->
  <dependencies>
	  <dependency>
	  	<groupId>com.qingge</groupId>
	    <artifactId>taotao-common</artifactId>
	    <version>0.0.1-SNAPSHOT</version>
	  </dependency>
  </dependencies>
  <modules>
  	<module>taotao-manager-pojo</module>
  	<module>taotao-manager-mapper</module>
  	<module>taotao-manager-service</module>
  	<module>taotao-manager-web</module>
  </modules>
  <build>
  	<!-- 配置插件 -->
  	<plugins>
  		<plugin>
  			<groupId>org.apache.tomcat.maven</groupId>
			<artifactId>tomcat7-maven-plugin</artifactId>
  			<configuration>
  				<port>8080</port>
  				<path>/</path>
  			</configuration>
  		</plugin>
  	</plugins>
  </build>
</project>


text:
slug: spaghetti-strapsoff-the-shoulder
name: Spaghetti Straps,Off The Shoulder
---


text:
published: true
title: Ground Meat Mix
layout: post
categories: [beef]
rating:
---
### Servings
3.5 lbs

### Ingredients
- 4 slices white bread, torn into large pieces
- 1/2 cup whole milk
- 3 garlic cloves
- 1 small onion, coarsely chopped
- 1 large egg
- Coarse salt and freshly ground pepper
- 1 1/4 pounds ground chuck (80 percent to 85 percent lean)
- 11/4 pounds ground pork (80 percent to 85 percent lean)

### Directions
1. Working in batches, pulse bread in a food processor until medium-coarse crumbs form (you should have 3 cups breadcrumbs). Transfer to a bowl. Stir in milk; let stand for 10 minutes.
2. Meanwhile, puree garlic and onion until smooth. Pulse in egg, 2 1/2 teaspoons salt, and 3/4 teaspoon pepper to combine.
3. Mix garlic mixture into breadcrumb mixture. Add beef and pork, and mix until just barely combined; do not overmix. Divide mixture into 2 portions, and continue with variations.
4. Helpful Hint
5. Meat mixture can be refrigerated for up to 1 day or frozen for up to 1 month. Thaw in refrigerator overnight, then proceed with recipes.

### Source
http://www.marthastewart.com/recipe/ground-meat-mix


text:
/**
 * Serialization features used for communication with Discord.
 */
package net.dv8tion.jda.api.utils.data;


text:
var SupportCode                                = {};
SupportCode.Hook                               = require('./support_code/hook');
SupportCode.Library                            = require('./support_code/library');
SupportCode.StepDefinition                     = require('./support_code/step_definition');
SupportCode.StepDefinitionSnippetBuilder       = require('./support_code/step_definition_snippet_builder');
SupportCode.StepDefinitionSnippetBuilderSyntax = require('./support_code/step_definition_snippet_builder_syntax');
SupportCode.WorldConstructor                   = require('./support_code/world_constructor');
module.exports                                 = SupportCode;


text:
// Copyright (C) 2008 The Android Open Source Project
//
// 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 com.google.gerrit.reviewdb.server;

import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.Relation;
import com.google.gwtorm.server.Schema;
import com.google.gwtorm.server.Sequence;

/**
 * The review service database schema.
 *
 *
Root entities that are at the top level of some important data graph:
 *
 *

 *
{@link Account}: Per-user account registration, preferences, identity.
 *
{@link Change}: All review information about a single proposed change.
 *

 */
public interface ReviewDb extends Schema {
  /* If you change anything, update SchemaVersion.C to use a new version. */

  @Relation(id = 1)
  SchemaVersionAccess schemaVersion();

  // Deleted @Relation(id = 2)

  // Deleted @Relation(id = 3)

  // Deleted @Relation(id = 4)

  // Deleted @Relation(id = 6)

  // Deleted @Relation(id = 7)

  // Deleted @Relation(id = 8)

  // Deleted @Relation(id = 10)

  // Deleted @Relation(id = 11)

  // Deleted @Relation(id = 12)

  // Deleted @Relation(id = 13)

  // Deleted @Relation(id = 17)

  // Deleted @Relation(id = 18)

  // Deleted @Relation(id = 19)

  // Deleted @Relation(id = 20)

  @Relation(id = 21)
  ChangeAccess changes();

  @Relation(id = 22)
  PatchSetApprovalAccess patchSetApprovals();

  @Relation(id = 23)
  ChangeMessageAccess changeMessages();

  @Relation(id = 24)
  PatchSetAccess patchSets();

  // Deleted @Relation(id = 25)

  @Relation(id = 26)
  PatchLineCommentAccess patchComments();

  // Deleted @Relation(id = 28)

  // Deleted @Relation(id = 29)

  // Deleted @Relation(id = 30)

  int FIRST_ACCOUNT_ID = 1000000;

  /**
   * Next unique id for a {@link Account}.
   *
   * @deprecated use {@link com.google.gerrit.server.Sequences#nextAccountId()}.
   */
  @Sequence(startWith = FIRST_ACCOUNT_ID)
  @Deprecated
  int nextAccountId() throws OrmException;

  int FIRST_GROUP_ID = 1;

  /** Next unique id for a {@link AccountGroup}. */
  @Sequence(startWith = FIRST_GROUP_ID)
  @Deprecated
  int nextAccountGroupId() throws OrmException;

  int FIRST_CHANGE_ID = 1;

  /**
   * Next unique id for a {@link Change}.
   *
   * @deprecated use {@link com.google.gerrit.server.Sequences#nextChangeId()}.
   */
  @Sequence(startWith = FIRST_CHANGE_ID)
  @Deprecated
  int nextChangeId() throws OrmException;
}


text:
package com.lotame.android;

import android.os.AsyncTask;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

public class SendOverHTTP extends AsyncTask<String, Void, String> {
    Map<String, String> headerParams;
    int connectionTimeout;

    public SendOverHTTP(Map<String, String> params, int connectionTimeout) {
        headerParams = params;
        this.connectionTimeout = connectionTimeout;
    }

    public String send(String... urls) throws IOException {
        String url = urls[0];
        if (CrowdControl.debug) Log.d(CrowdControl.LOG_TAG, "Attempt GET from " + url);
        HttpURLConnection conn;
        StringBuilder response = new StringBuilder();

        conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setUseCaches(false);
        conn.setConnectTimeout(connectionTimeout);
        conn.setReadTimeout(connectionTimeout);

        synchronized (headerParams) {
            for (Map.Entry<String, String> entry : headerParams.entrySet()) {
                conn.setRequestProperty(entry.getKey(), entry.getValue());
            }
        }

        conn.setRequestProperty("User-Agent", "Crowd Control Android SDK");
        conn.setRequestProperty("Accept-Charset", "utf-8");

        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        try {
            for (String line = br.readLine(); line != null; line = br.readLine()) {
                response.append(line);
            }
            if (CrowdControl.debug)
                Log.d(CrowdControl.LOG_TAG, String.format("GET success from %s", url));
        } finally {
            br.close();
            conn.disconnect();
        }

        return response.toString();
    }

    @Override
    protected String doInBackground(String... urls) {
        try {
            return send(urls);
        } catch (Exception e) {
            if (CrowdControl.debug) Log.e(CrowdControl.LOG_TAG, "Async Send Failed", e);
        }

        return "send failed";
    }
}


text:
  Éveux est
       un village
       situé dans le département de Rhône en Rhône-Alpes. On dénombrait 926 habitants en 2008.

À coté de Éveux sont situées les communes de
Fleurieux-sur-l'Arbresle localisée à 2 km, 2 053 habitants,
Savigny à 3 km, 1 962 habitants,
Sain-Bel à 2 km, 2 148 habitants,
Nuelles à 2 km, 595 habitants,
Saint-Germain-sur-l'Arbresle localisée à 3 km, 1 329 habitants,
Lentilly à 3 km, 5 110 habitants,
 entre autres. De plus, Éveux est située à seulement 17 km de Lyon.

La ville compte quelques  aménagements, elle dispose, entre autres, de un terrain de tennis et une boucle de randonnée.

À Éveux, le prix moyen à la vente d'un appartement s'évalue à 4 031 € du m² en vente. la valorisation moyenne d'une maison à l'achat se situe à 2 838 € du m². À la location la valorisation moyenne se situe à 9,31 € du m² par mois.

Si vous envisagez de venir habiter à Éveux, vous pourrez facilement trouver une maison à acheter.

Le parc de logements, à Éveux, se décomposait en 2011 en 31 appartements et 425 maisons soit
 un marché plutôt équilibré.


text:
package org.drools.workbench.services.verifier.api.client.index;

import org.drools.workbench.services.verifier.api.client.configuration.AnalyzerConfiguration;

public class ObjectField
        extends FieldBase {

    public ObjectField( final String factType,
                        final String fieldType,
                        final String name,
                        final AnalyzerConfiguration configuration ) {
        super( factType,
               fieldType,
               name,
               configuration );
    }
}


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

<meta http-equiv="content-type" content="text/html; charset=US-ASCII">
<title>Pearl</title>
<link rel="previous" href="range.html">
<link rel="ToC" href="index.html">
<link rel="up" href="index.html">
<link rel="index" href="docindex.html">
<link rel="next" href="licence.html">

Previous | Contents | Index | Next

Chapter 36: Pearl

You have a grid of squares. Your job is to draw lines between the centres of horizontally or vertically adjacent squares, so that the lines form a single closed loop. In the resulting grid, some of the squares that the loop passes through will contain corners, and some will be straight horizontal or vertical lines. (And some squares can be completely empty – the loop doesn't have to pass through every square.)

Some of the squares contain black and white circles, which are clues that the loop must satisfy.

A black circle in a square indicates that that square is a corner, but neither of the squares adjacent to it in the loop is also a corner.

A while circle indicates that the square is a straight edge, but at least one of the squares adjacent to it in the loop is a corner.

(In both cases, the clue only constrains the two squares adjacent in the loop, that is, the squares that the loop passes into after leaving the clue square. The squares that are only adjacent in the grid are not constrained.)

Credit for this puzzle goes to Nikoli, who call it ‘Masyu’. [19].

Thanks to James Harvey for assistance with the implementation.

[19] http://www.nikoli.co.jp/en/puzzles/masyu/

36.1 Pearl controls

Click with the left button on a grid edge to draw a segment of the loop through that edge, or to remove a segment once it is drawn.

Drag with the left button through a series of squares to draw more than one segment of the loop in one go. Alternatively, drag over an existing part of the loop to undraw it, or to undraw part of it and then go in a different direction.

Click with the right button on a grid edge to mark it with a cross, indicating that you are sure the loop does not go through that edge. (For instance, if you have decided which of the squares adjacent to a white clue has to be a corner, but don't yet know which way the corner turns, you might mark the one way it can't go with a cross.)

Alternatively, use the cursor keys to move the cursor. Use the Enter key to begin and end keyboard `drag' operations. Use the Space key to cancel the drag. Use Ctrl-arrowkey and Shift-arrowkey to simulate a left or right click, respectively, on the edge in the given direction relative to the cursor, i.e. to draw a segment or a cross.

(All the actions described in section 2.2 are also available.)

36.2 Pearl parameters

These parameters are available from the ‘Custom...’ option on the ‘Type’ menu.

Width, Height

Size of grid in squares.

Difficulty

Controls the difficulty of the generated puzzle.

<address>
[Puzzles S60 version 1.5.r9411]</address>


text:
@implementation FNKYAxis

-(void) drawAxis:(UIView*) view
{
    UIBezierPath* bezPath = [[UIBezierPath alloc] init];
    [bezPath moveToPoint:CGPointMake(self.marginLeft, 0)];
    [bezPath addLineToPoint:CGPointMake(self.marginLeft, self.graphHeight)];
    [bezPath closePath];

    CAShapeLayer* layer = [[CAShapeLayer alloc] init];
    layer.path = bezPath.CGPath;
    layer.fillColor = self.fillColor.CGColor;
    layer.strokeColor = self.strokeColor.CGColor;

    [view.layer addSublayer:layer];

    CABasicAnimation* pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    pathAnimation.duration = 2;
    pathAnimation.fromValue = @(0);
    pathAnimation.toValue = @(1);

    [layer addAnimation:pathAnimation forKey:@"strokeEnd"];

    //Draw all lines
    CGFloat tickInterval = self.graphHeight / self.ticks;
    for (int index = 0 ; index < self.ticks+1 ; index++)
    {
        UIBezierPath* bezPath = [[UIBezierPath alloc] init];

        CGFloat xVal = self.marginLeft;
        CGFloat yVal = (index * tickInterval);

        [bezPath moveToPoint:CGPointMake(xVal, yVal)];
        [bezPath addLineToPoint:CGPointMake(xVal + self.graphWidth, yVal)];

        CAShapeLayer* layer  = [[CAShapeLayer alloc] init];
        layer.path = bezPath.CGPath;
        layer.fillColor = self.tickFillColor.CGColor;
        layer.strokeColor = self.tickStrokeColor.CGColor;

        [view.layer addSublayer:layer];

        CABasicAnimation* pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        pathAnimation.duration = self.animationDuration;
        pathAnimation.fromValue = @(0);
        pathAnimation.toValue = @(1);

        [layer addAnimation:pathAnimation forKey:@"strokeEnd"];
    }
}

-(UIView*) addTicksToView:(UIView*) view
{
    CGFloat tickInterval = self.graphHeight / self.ticks;

    UIView* labelView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40,  view.frame.size.height)];
    [labelView setAlpha:0.0];
    [view addSubview:labelView];
    labelView.translatesAutoresizingMaskIntoConstraints = NO;
    NSDictionary *labelViewDictionary = NSDictionaryOfVariableBindings(labelView);

    NSArray *widthConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-0-[labelView(40)]"
                                                                        options:0
                                                                        metrics:nil
                                                                          views:labelViewDictionary];
    [view addConstraints:widthConstraints];

    NSArray *heightConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[labelView]-0-|"
                                                                         options:0
                                                                         metrics:nil
                                                                           views:labelViewDictionary];
    [view addConstraints:heightConstraints];

    [view layoutSubviews];

    for (int index = 0 ; index < self.ticks ; index++)
    {
        if (index == self.ticks)
        {
            continue;
        }

        CGFloat yLoc = (index * tickInterval);
        CGFloat yVal = (index * tickInterval);

        //Okay those are the ticks. Now we need the labels
        UILabel* tickLabel = [[UILabel alloc] init];

        CGFloat originalVal = ((self.graphHeight - yVal) / self.scaleFactor) + self.axisMin;
        tickLabel.text = self.tickFormat(originalVal);
        tickLabel.textAlignment = NSTextAlignmentCenter;
        tickLabel.font = self.tickFont;
        [tickLabel setTextColor: self.tickLabelColor ? self.tickLabelColor : [UIColor blackColor]];
        [tickLabel setAdjustsFontSizeToFitWidth:YES];
        [tickLabel setMinimumScaleFactor:.5];
        [tickLabel setBackgroundColor:[[UIColor whiteColor] colorWithAlphaComponent:.5]];
        [labelView addSubview:tickLabel];

        tickLabel.translatesAutoresizingMaskIntoConstraints = NO;
        NSDictionary *viewDictionary = NSDictionaryOfVariableBindings(tickLabel);

        NSArray *widthConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-2-[tickLabel(36)]-2-|"
                                                                            options:0
                                                                            metrics:nil
                                                                              views:viewDictionary];
        [labelView addConstraints:widthConstraints];

        //TODO: This is a bit of a hack since I don't know what the height of the label is actually going to be
        NSArray *heightConstraints = [NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|-(%f)-[tickLabel]", yLoc - 5]
                                                                             options:0
                                                                             metrics:nil
                                                                               views:viewDictionary];
        [labelView addConstraints:heightConstraints];

        [labelView layoutSubviews];
    }

    [UIView animateWithDuration:1
                     animations:^{
                         [labelView setAlpha:1.0];

                     }];

    return labelView;
}

@end


text:
FROM mhart/alpine-node:latest

WORKDIR /vstsbot
COPY package.json .
RUN npm install --production

COPY ./output .

CMD ["node", "/vstsbot/app.js"]


text:
<?php
class Profile extends \common\models\base\ProfileBase
{
	/**
	 * behaviors to control time stamp, don't forget to use statement for expression
	 */
	public function behaviors()
	{
		return [
			BlameableBehavior::className(),
			TimestampBehavior::className(),
		];
	}

	/*
	public function beforeValidate()
	{
		if ($this->birthdate != null) {
			$new_date_format = date('Y-m-d', strtotime($this->birthdate));
			$this->birthdate = $new_date_format;
		}

		return parent::beforeValidate();
	}
	*/

	//*** relationships ***//

	/**
	 * @return \yii\db\ActiveQuery
	 */
	public function getGenderName()
	{
		return $this->gender->name;
	}

	/**
	 * get list of genders for dropdown
	 */
	public static function getGenderList()
	{
		$droptions = Gender::find()->asArray()->all();
		return ArrayHelper::map($droptions, 'id', 'name');
	}

	/**
	 * @get Username
	 */
	public function getUsername()
	{
		return $this->user->username;
	}

	/**
	 * @getUserId
	 */
	public function getUserId()
	{
		return $this->user ? $this->user->id : 'none';
	}

	/**
	 * @getUserLink
	 */
	public function getUserLink()
	{
		$url = Url::to(['user/view', 'id'=>$this->UserId]);
		$options = [];
		return Html::a($this->getUserName(), $url, $options);
	}

	/**
	 * @getProfileLink
	 */
	public function getProfileIdLink()
	{
		$url = Url::to(['profile/update', 'id'=>$this->id]);
		$options = [];
		return Html::a($this->id, $url, $options);
	}
}
?>

<?php
class ProfileBase extends \yii\db\ActiveRecord
{
/**
* @inheritdoc
*/
public static function tableName()
{
return '{{%profile}}';
}

	/**
 * @return \yii\db\ActiveQuery
 */
	public function getGender()
	{
	return $this->hasOne(Gender::className(), ['id' => 'gender_id']);
	}

	/**
 * @return \yii\db\ActiveQuery
 */
	public function getUser()
	{
	return $this->hasOne(User::className(), ['id' => 'user_id']);
	}
}


text:
using Orchard.ContentManagement;

namespace Orchard.Projections.Models {
    public class ProjectionPart : ContentPart<ProjectionPartRecord> {
    }
}


text:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:padding="5dp"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="53dp"
        android:padding="5dp"
        android:layout_height="match_parent"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"
        android:contentDescription="@string/iconLogDescription" />

    <TextView
        android:id="@+id/textView"
        android:layout_marginLeft="10dp"
        android:layout_marginStart="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginEnd="10dp"
        android:layout_toRightOf="@id/imageView"
        android:layout_toEndOf="@id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textStyle="bold"
        android:layout_centerVertical="true"
        android:textSize="20sp"/>

</RelativeLayout>


text:
package wx.sunl.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import wx.sunl.entry.WeixinOauth2Token;
import wx.sunl.model.SNSUserInfo;
import wx.sunl.util.AdvancedUtil;

/**
 * Servlet implementation class OAuthServlet
 */
public class OAuthServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public OAuthServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        // Óû§Í¬ÒâÊÚȨºó£¬ÄÜ»ñÈ¡µ½code
        String code = request.getParameter("code");
        String state = request.getParameter("state");

        // Óû§Í¬ÒâÊÚȨ
        if (!"authdeny".equals(code)) {
        	String APPID = "wx90716ffab2e94997";
        	String SECRET = "0b1d2d4bee0f211ff3fad8e97dec2366";
        	String requestUrl = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", APPID,SECRET,code);

        	// »ñÈ¡ÍøÒ³ÊÚȨaccess_token
            WeixinOauth2Token weixinOauth2Token = AdvancedUtil.getOauth2AccessToken(requestUrl, "GET");
            // ÍøÒ³ÊÚȨ½Ó¿Ú·ÃÎÊƾ֤
            String accessToken = weixinOauth2Token.getAccessToken();
            // Óû§±êʶ
            String openId = weixinOauth2Token.getOpenId();
            // »ñÈ¡Óû§ÐÅÏ¢
            SNSUserInfo snsUserInfo = AdvancedUtil.getSNSUserInfo(accessToken, openId);

            // ÉèÖÃÒª´«µÝµÄ²ÎÊý
            request.setAttribute("snsUserInfo", snsUserInfo);
            request.setAttribute("state", state);
        }
    	request.getRequestDispatcher("userLogin.jsp").forward(request, response);

	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}


text:
namespace BaseType.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class ss1 : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.AppJurnals",
                c => new
                    {
                        IdEntry = c.Guid(nullable: false),
                        IdTask = c.Guid(nullable: false),
                        DateEntry = c.DateTime(nullable: false),
                        Message = c.String(nullable: false),
                        MessageType = c.Int(nullable: false),
                        MessageCode = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.IdEntry);

            CreateTable(
                "dbo.Projects",
                c => new
                    {
                        IdProject = c.Guid(nullable: false),
                        Name = c.String(),
                        Comment = c.String(),
                        Purpose = c.String(),
                        DateCreate = c.DateTime(nullable: false),
                        DateUpdate = c.DateTime(nullable: false),
                        TypeProject = c.Int(nullable: false),
                        Author_IdUser = c.Guid(),
                    })
                .PrimaryKey(t => t.IdProject)
                .ForeignKey("dbo.Users", t => t.Author_IdUser)
                .Index(t => t.Author_IdUser);

            CreateTable(
                "dbo.Users",
                c => new
                    {
                        IdUser = c.Guid(nullable: false),
                        LoginName = c.String(maxLength: 50),
                        SID = c.Binary(maxLength: 600),
                        Authorization = c.Int(nullable: false),
                        Email = c.String(nullable: false, maxLength: 150),
                        Surname = c.String(nullable: false, maxLength: 50),
                        Name = c.String(nullable: false, maxLength: 50),
                        MiddleName = c.String(maxLength: 50),
                        BirthDate = c.DateTime(),
                        PhoneNumber = c.Int(nullable: false),
                        IsWork = c.Boolean(nullable: false),
                        Comment = c.String(maxLength: 250),
                        SystemRole = c.Int(nullable: false),
                        Post = c.String(maxLength: 60),
                    })
                .PrimaryKey(t => t.IdUser);

            CreateTable(
                "dbo.Members",
                c => new
                    {
                        IdProject = c.Guid(nullable: false),
                        IdUser = c.Guid(nullable: false),
                        Role = c.Int(nullable: false),
                        Comment = c.String(maxLength: 120),
                    })
                .PrimaryKey(t => new { t.IdProject, t.IdUser })
                .ForeignKey("dbo.Projects", t => t.IdProject, cascadeDelete: true)
                .ForeignKey("dbo.Users", t => t.IdUser, cascadeDelete: true)
                .Index(t => t.IdProject)
                .Index(t => t.IdUser);

            CreateTable(
                "dbo.Tasks",
                c => new
                    {
                        IdTask = c.Guid(nullable: false),
                        Author = c.Guid(nullable: false),
                        DateCreate = c.DateTime(nullable: false),
                        DateFinish = c.DateTime(nullable: false),
                        DateUpdate = c.DateTime(nullable: false),
                        DateFisrtNotification = c.DateTime(nullable: false),
                        DateLastNotification = c.DateTime(nullable: false),
                        DateEndNotofication = c.DateTime(nullable: false),
                        DateClose = c.DateTime(nullable: false),
                        NameTask = c.String(nullable: false),
                        Result = c.String(),
                        Description = c.String(),
                        Comment = c.String(),
                        ParentTask = c.Guid(nullable: false),
                        Status = c.Int(nullable: false),
                        Performer_IdUser = c.Guid(nullable: false),
                        Project_IdProject = c.Guid(),
                    })
                .PrimaryKey(t => t.IdTask)
                .ForeignKey("dbo.Users", t => t.Performer_IdUser, cascadeDelete: true)
                .ForeignKey("dbo.Projects", t => t.Project_IdProject)
                .Index(t => t.Performer_IdUser)
                .Index(t => t.Project_IdProject);

            CreateTable(
                "dbo.Properties",
                c => new
                    {
                        IdProperty = c.Guid(nullable: false),
                        Value = c.String(nullable: false),
                        Name = c.String(nullable: false),
                        TypeValue = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.IdProperty);

            CreateTable(
                "dbo.TaskComments",
                c => new
                    {
                        IdComment = c.Guid(nullable: false),
                        IdTask = c.Guid(nullable: false),
                        Message = c.String(),
                        DateMessage = c.DateTime(nullable: false),
                        AuthorUser_IdUser = c.Guid(),
                    })
                .PrimaryKey(t => new { t.IdComment, t.IdTask })
                .ForeignKey("dbo.Users", t => t.AuthorUser_IdUser)
                .Index(t => t.AuthorUser_IdUser);

        }

        public override void Down()
        {
            DropForeignKey("dbo.TaskComments", "AuthorUser_IdUser", "dbo.Users");
            DropForeignKey("dbo.Tasks", "Project_IdProject", "dbo.Projects");
            DropForeignKey("dbo.Tasks", "Performer_IdUser", "dbo.Users");
            DropForeignKey("dbo.Projects", "Author_IdUser", "dbo.Users");
            DropForeignKey("dbo.Members", "IdUser", "dbo.Users");
            DropForeignKey("dbo.Members", "IdProject", "dbo.Projects");
            DropIndex("dbo.TaskComments", new[] { "AuthorUser_IdUser" });
            DropIndex("dbo.Tasks", new[] { "Project_IdProject" });
            DropIndex("dbo.Tasks", new[] { "Performer_IdUser" });
            DropIndex("dbo.Members", new[] { "IdUser" });
            DropIndex("dbo.Members", new[] { "IdProject" });
            DropIndex("dbo.Projects", new[] { "Author_IdUser" });
            DropTable("dbo.TaskComments");
            DropTable("dbo.Properties");
            DropTable("dbo.Tasks");
            DropTable("dbo.Members");
            DropTable("dbo.Users");
            DropTable("dbo.Projects");
            DropTable("dbo.AppJurnals");
        }
    }
}


text:
package org.apache.spark.scheduler.cluster.k8s

import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger, AtomicLong}

import io.fabric8.kubernetes.api.model.PodBuilder
import io.fabric8.kubernetes.client.KubernetesClient
import scala.collection.mutable

import org.apache.spark.{SecurityManager, SparkConf, SparkException}
import org.apache.spark.deploy.k8s.Config._
import org.apache.spark.deploy.k8s.Constants._
import org.apache.spark.deploy.k8s.KubernetesConf
import org.apache.spark.internal.Logging
import org.apache.spark.util.{Clock, Utils}

private[spark] class ExecutorPodsAllocator(
    conf: SparkConf,
    secMgr: SecurityManager,
    executorBuilder: KubernetesExecutorBuilder,
    kubernetesClient: KubernetesClient,
    snapshotsStore: ExecutorPodsSnapshotsStore,
    clock: Clock) extends Logging {

  private val EXECUTOR_ID_COUNTER = new AtomicLong(0L)

  private val totalExpectedExecutors = new AtomicInteger(0)

  private val podAllocationSize = conf.get(KUBERNETES_ALLOCATION_BATCH_SIZE)

  private val podAllocationDelay = conf.get(KUBERNETES_ALLOCATION_BATCH_DELAY)

  private val podCreationTimeout = math.max(podAllocationDelay * 5, 60000)

  private val namespace = conf.get(KUBERNETES_NAMESPACE)

  private val kubernetesDriverPodName = conf
    .get(KUBERNETES_DRIVER_POD_NAME)

  private val shouldDeleteExecutors = conf.get(KUBERNETES_DELETE_EXECUTORS)

  private val driverPod = kubernetesDriverPodName
    .map(name => Option(kubernetesClient.pods()
      .withName(name)
      .get())
      .getOrElse(throw new SparkException(
        s"No pod was found named $kubernetesDriverPodName in the cluster in the " +
          s"namespace $namespace (this was supposed to be the driver pod.).")))

  // Executor IDs that have been requested from Kubernetes but have not been detected in any
  // snapshot yet. Mapped to the timestamp when they were created.
  private val newlyCreatedExecutors = mutable.Map.empty[Long, Long]

  private val dynamicAllocationEnabled = Utils.isDynamicAllocationEnabled(conf)

  private val hasPendingPods = new AtomicBoolean()

  private var lastSnapshot = ExecutorPodsSnapshot(Nil)

  def start(applicationId: String): Unit = {
    snapshotsStore.addSubscriber(podAllocationDelay) {
      onNewSnapshots(applicationId, _)
    }
  }

  def setTotalExpectedExecutors(total: Int): Unit = {
    totalExpectedExecutors.set(total)
    if (!hasPendingPods.get()) {
      snapshotsStore.notifySubscribers()
    }
  }

  private def onNewSnapshots(
      applicationId: String,
      snapshots: Seq[ExecutorPodsSnapshot]): Unit = synchronized {
    newlyCreatedExecutors --= snapshots.flatMap(_.executorPods.keys)
    // For all executors we've created against the API but have not seen in a snapshot
    // yet - check the current time. If the current time has exceeded some threshold,
    // assume that the pod was either never created (the API server never properly
    // handled the creation request), or the API server created the pod but we missed
    // both the creation and deletion events. In either case, delete the missing pod
    // if possible, and mark such a pod to be rescheduled below.
    val currentTime = clock.getTimeMillis()
    val timedOut = newlyCreatedExecutors.flatMap { case (execId, timeCreated) =>
      if (currentTime - timeCreated > podCreationTimeout) {
        Some(execId)
      } else {
        logDebug(s"Executor with id $execId was not found in the Kubernetes cluster since it" +
          s" was created ${currentTime - timeCreated} milliseconds ago.")
        None
      }
    }

    if (timedOut.nonEmpty) {
      logWarning(s"Executors with ids ${timedOut.mkString(",")} were not detected in the" +
        s" Kubernetes cluster after $podCreationTimeout ms despite the fact that a previous" +
        " allocation attempt tried to create them. The executors may have been deleted but the" +
        " application missed the deletion event.")

      newlyCreatedExecutors --= timedOut
      if (shouldDeleteExecutors) {
        Utils.tryLogNonFatalError {
          kubernetesClient
            .pods()
            .withLabel(SPARK_APP_ID_LABEL, applicationId)
            .withLabel(SPARK_ROLE_LABEL, SPARK_POD_EXECUTOR_ROLE)
            .withLabelIn(SPARK_EXECUTOR_ID_LABEL, timedOut.toSeq.map(_.toString): _*)
            .delete()
        }
      }
    }

    if (snapshots.nonEmpty) {
      lastSnapshot = snapshots.last
    }

    val currentRunningCount = lastSnapshot.executorPods.values.count {
      case PodRunning(_) => true
      case _ => false
    }

    val currentPendingExecutors = lastSnapshot.executorPods
      .filter {
        case (_, PodPending(_)) => true
        case _ => false
      }
      .map { case (id, _) => id }

    if (snapshots.nonEmpty) {
      logDebug(s"Pod allocation status: $currentRunningCount running, " +
        s"${currentPendingExecutors.size} pending, " +
        s"${newlyCreatedExecutors.size} unacknowledged.")
    }

    val currentTotalExpectedExecutors = totalExpectedExecutors.get

    // This variable is used later to print some debug logs. It's updated when cleaning up
    // excess pod requests, since currentPendingExecutors is immutable.
    var knownPendingCount = currentPendingExecutors.size

    // It's possible that we have outstanding pods that are outdated when dynamic allocation
    // decides to downscale the application. So check if we can release any pending pods early
    // instead of waiting for them to time out. Drop them first from the unacknowledged list,
    // then from the pending.
    //
    // TODO: with dynamic allocation off, handle edge cases if we end up with more running
    // executors than expected.
    val knownPodCount = currentRunningCount + currentPendingExecutors.size +
      newlyCreatedExecutors.size
    if (knownPodCount > currentTotalExpectedExecutors) {
      val excess = knownPodCount - currentTotalExpectedExecutors
      val knownPendingToDelete = currentPendingExecutors.take(excess - newlyCreatedExecutors.size)
      val toDelete = newlyCreatedExecutors.keys.take(excess).toList ++ knownPendingToDelete

      if (toDelete.nonEmpty) {
        logInfo(s"Deleting ${toDelete.size} excess pod requests (${toDelete.mkString(",")}).")
        Utils.tryLogNonFatalError {
          kubernetesClient
            .pods()
            .withField("status.phase", "Pending")
            .withLabel(SPARK_APP_ID_LABEL, applicationId)
            .withLabel(SPARK_ROLE_LABEL, SPARK_POD_EXECUTOR_ROLE)
            .withLabelIn(SPARK_EXECUTOR_ID_LABEL, toDelete.sorted.map(_.toString): _*)
            .delete()
          newlyCreatedExecutors --= toDelete
          knownPendingCount -= knownPendingToDelete.size
        }
      }
    }

    if (newlyCreatedExecutors.isEmpty
        && currentPendingExecutors.isEmpty
        && currentRunningCount < currentTotalExpectedExecutors) {
      val numExecutorsToAllocate = math.min(
        currentTotalExpectedExecutors - currentRunningCount, podAllocationSize)
      logInfo(s"Going to request $numExecutorsToAllocate executors from Kubernetes.")
      for ( _ <- 0 until numExecutorsToAllocate) {
        val newExecutorId = EXECUTOR_ID_COUNTER.incrementAndGet()
        val executorConf = KubernetesConf.createExecutorConf(
          conf,
          newExecutorId.toString,
          applicationId,
          driverPod)
        val executorPod = executorBuilder.buildFromFeatures(executorConf, secMgr,
          kubernetesClient)
        val podWithAttachedContainer = new PodBuilder(executorPod.pod)
          .editOrNewSpec()
          .addToContainers(executorPod.container)
          .endSpec()
          .build()
        kubernetesClient.pods().create(podWithAttachedContainer)
        newlyCreatedExecutors(newExecutorId) = clock.getTimeMillis()
        logDebug(s"Requested executor with id $newExecutorId from Kubernetes.")
      }
    }

    // Update the flag that helps the setTotalExpectedExecutors() callback avoid triggering this
    // update method when not needed.
    hasPendingPods.set(knownPendingCount + newlyCreatedExecutors.size > 0)

    // The code below just prints debug messages, which are only useful when there's a change
    // in the snapshot state. Since the messages are a little spammy, avoid them when we know
    // there are no useful updates.
    if (!log.isDebugEnabled || snapshots.isEmpty) {
      return
    }

    if (currentRunningCount >= currentTotalExpectedExecutors && !dynamicAllocationEnabled) {
      logDebug("Current number of running executors is equal to the number of requested" +
        " executors. Not scaling up further.")
    } else {
      val outstanding = knownPendingCount + newlyCreatedExecutors.size
      if (outstanding > 0) {
        logDebug(s"Still waiting for $outstanding executors before requesting more.")
      }
    }
  }
}


text:
package com.sevenbridges.apiclient.impl.transfer;

import com.sevenbridges.apiclient.file.File;
import com.sevenbridges.apiclient.impl.transfer.http.protocol.ZeroCopyChannelRangePut;
import com.sevenbridges.apiclient.impl.transfer.model.UploadPartContext;
import com.sevenbridges.apiclient.resource.ResourceException;
import com.sevenbridges.apiclient.transfer.PausedUploadException;
import com.sevenbridges.apiclient.transfer.UploadState;
import com.sevenbridges.apiclient.upload.PartUpload;
import com.sevenbridges.apiclient.upload.Upload;
import com.sevenbridges.apiclient.upload.UploadedPart;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.nio.protocol.BasicAsyncResponseConsumer;

import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;

public class UploadCallable implements Callable<File> {

  private final CloseableHttpAsyncClient client;
  private final DefaultUploadContext uploadContext;
  private final int partRetry;
  private final int maxParallelUploads;

  private final int partsNumber;
  private final long partSize;

  private final CountDownLatch partsLatch;
  private final PartsProducer producer;
  private int parallelUploadsCnt;

  UploadCallable(CloseableHttpAsyncClient client,
                 DefaultUploadContext cntx,
                 int maxPartRetry,
                 int maxParallelUploads) {
    this.client = client;
    this.uploadContext = cntx;
    this.partRetry = maxPartRetry;
    this.maxParallelUploads = maxParallelUploads;

    this.partsNumber = getPartsNumber(cntx);
    this.partSize = uploadContext.getUpload().getPartSize();
    List<UploadedPart> finishedParts = uploadContext.getUpload().getUploadedParts();
    if (finishedParts == null) {
      finishedParts = Collections.emptyList();
    }
    this.producer = new PartsProducer(partsNumber, finishedParts);
    this.partsLatch = new CountDownLatch(partsNumber - finishedParts.size());
    this.parallelUploadsCnt = 0;
  }

  @Override
  public File call() throws Exception {

    FileChannel fileChannel = uploadContext.getRandomAccessFile().getChannel();
    Map<Integer, Future<HttpResponse>> responses = new HashMap<>(partsNumber);
    try {
      client.start();
      uploadContext.setState(UploadState.RUNNING);
      uploadContext.getListener().uploadStarted();

      while (partsLatch.getCount() > 0) {
        // check if upload still exists
        try {
          Upload currUpload = uploadContext.getUpload();
          currUpload.reload();
        } catch (ResourceException e) {
          if (e.getCode() == 404) {
            throw new RuntimeException("Upload not found, probably aborted by some external use");
          }
          throw e;
        } catch (Exception e) {
          throw new RuntimeException("Error while trying to check upload state, aborting upload", e);
        }

        if (UploadState.PAUSING.equals(uploadContext.getState())) {
          uploadContext.setState(UploadState.PAUSED);
          List<UploadPartContext> successfulParts = producer.flushFinishedAndGetSuccessful();
          for (UploadPartContext uploadedPart : successfulParts) {
            // this part finished OK
            uploadContext.getUpload().reportUploadedPart(uploadedPart.getPartNumber(), uploadedPart.getUploadResponse());
            // decrement latch
            partsLatch.countDown();
            // report to listener
            uploadContext.getListener().partUploadFinished(uploadedPart.getPartNumber(), getCurrentPartSize(uploadedPart.getPartNumber()));
            // decrement parallel uploads cnt
            parallelUploadsCnt--;
            // remove from responses map (not needed, but cleaner)
            responses.remove(uploadedPart.getPartNumber());
          }
          for (Future<HttpResponse> response : responses.values()) {
            response.cancel(true);
          }
          throw new PausedUploadException("Upload is paused, this upload is aborted locally, but can be resumed with the same ID - " + uploadContext.getUploadId());
        }

        // get part for processing
        UploadPartContext partContext;
        if (parallelUploadsCnt < maxParallelUploads) {
          partContext = producer.takeNewOrFinished();
        } else {
          partContext = producer.takeFinished();
        }

        // process part depending of its state
        if (partContext.isFailedBeyondRetry()) { // this part failed with no more retries
          // report failed to listener
          uploadContext.getListener().partUploadFailed(partContext.getPartNumber(), partContext.getRetryCnt(), partContext.getEx());
          // abort upload
          abortUpload(responses);
          // throw execution exception
          throw new RuntimeException("Upload failed, part " + partContext.getPartNumber() + " failed beyond retry ", partContext.getEx());

        } else if (partContext.isNew()) { // this part was not initialized
          // get part upload from API server
          PartUpload partUploadResponse = uploadContext.getUpload().getPartUpload(partContext.getPartNumber());
          // submit part upload to async client
          Future<HttpResponse> execute = submitPartUpload(partUploadResponse.getUrl(), partContext.getPartNumber(), fileChannel, partRetry);
          // add future to the responses map, so it can be cancelled if upload fail
          responses.put(partContext.getPartNumber(), execute);
          // increment parallel uploads cnt
          parallelUploadsCnt++;
          // notify listener that new upload part started
          uploadContext.getListener().partUploadStarted(partContext.getPartNumber());

        } else if (partContext.isFailed()) { // this part failed, but can be retried
          // this part failed
          // report to listener
          uploadContext.getListener().partUploadFailed(partContext.getPartNumber(), partContext.getRetryCnt(), partContext.getEx());
          // set bytesAdder cell for this part to 0
          uploadContext.getBytesTransferredAdder().set(partContext.getPartNumber(), 0);
          // resubmit failed upload, decremented part retry
          PartUpload partUploadResponse = uploadContext.getUpload().getPartUpload(partContext.getPartNumber());
          Future<HttpResponse> execute = submitPartUpload(partUploadResponse.getUrl(), partContext.getPartNumber(), fileChannel, partRetry - 1);
          // add future to the responses map, so it can be cancelled if upload fail
          responses.put(partContext.getPartNumber(), execute);
          // notify listener that new upload part started
          uploadContext.getListener().partUploadStarted(partContext.getPartNumber());

        } else if (partContext.isSucceeded()) { // this part succeeded
          // this part finished OK
          uploadContext.getUpload().reportUploadedPart(partContext.getPartNumber(), partContext.getUploadResponse());
          // decrement latch
          partsLatch.countDown();
          // report to listener
          uploadContext.getListener().partUploadFinished(partContext.getPartNumber(), getCurrentPartSize(partContext.getPartNumber()));
          // decrement parallel uploads cnt
          parallelUploadsCnt--;
          // remove from responses map (not needed, but cleaner)
          responses.remove(partContext.getPartNumber());
        }
      }

      // finalize upload on API server
      File finishedFile = uploadContext.getUpload().completeUpload();
      // set state to finished
      uploadContext.setState(UploadState.FINISHED);
      // notify listener
      uploadContext.getListener().uploadFinished();
      return finishedFile;
    } catch (Exception e1) {
      // if paused, just propagate exception to cancel execution
      if (UploadState.PAUSED.equals(uploadContext.getState())) {
        throw e1;
      }
      // unrecoverable exception, abort upload
      uploadContext.getListener().uploadFailed(e1);
      try {
        abortUpload(responses);
      } catch (Exception e2) {
        throw new RuntimeException("Upload failed BUT aborting upload failed too due to exception - '"
            + e2.getMessage() + "'. Please abort this upload with id '"
            + uploadContext.getUploadId() + "' manually", e1);
      }
      throw new RuntimeException("Upload is aborted due to errors in execution", e1);
    } finally {
      try {
        if (fileChannel.isOpen()) {
          fileChannel.close();
        }
        uploadContext.getRandomAccessFile().close();
      } catch (IOException e) {
        // error while closing
        throw e;
      }
    }
  }

  private long getCurrentPartSize(int partNumber) {
    return partNumber == partsNumber
        ? uploadContext.getUploadSize() - (partNumber - 1) * partSize
        : partSize;
  }

  private Future<HttpResponse> submitPartUpload(String uploadUrl, int partNumber, FileChannel fileChannel, int retryCnt) {
    long fileOffset = (partNumber - 1) * partSize;
    long currentPartSize = getCurrentPartSize(partNumber);

    final ZeroCopyChannelRangePut httpPut = new ZeroCopyChannelRangePut(
        uploadUrl,
        fileChannel,
        fileOffset,
        currentPartSize,
        null,
        uploadContext.getBytesTransferredAdder(),
        partNumber);
    BasicAsyncResponseConsumer consumer = new BasicAsyncResponseConsumer();

    return client.execute(httpPut, consumer, new UploadCallable.PartUploadCallback(uploadUrl, partNumber, retryCnt));
  }

  private void abortUpload(Map<Integer, Future<HttpResponse>> responses) {
    for (Future<HttpResponse> response : responses.values()) {
      response.cancel(true);
    }
    uploadContext.getUpload().abortUpload();
  }

  private int getPartsNumber(DefaultUploadContext context) {
    return context.getUploadSize() % context.getUpload().getPartSize() == 0
        ? (int) (context.getUploadSize() / context.getUpload().getPartSize())
        : (int) (context.getUploadSize() / context.getUpload().getPartSize() + 1);
  }

  private class PartUploadCallback implements FutureCallback<HttpResponse> {

    private final int partNumber;
    private final String uploadUrl;
    private final int retryCnt;

    PartUploadCallback(String uploadUrl, int partNumber, int retryCnt) {
      this.partNumber = partNumber;
      this.uploadUrl = uploadUrl;
      this.retryCnt = retryCnt;
    }

    @Override
    public void completed(HttpResponse result) {
      if (checkUploadCompleted(result)) {
        UploadCallable.this.producer.putFinished(getSucceededPartContext(result));
      } else {
        UploadCallable.this.producer.putFinished(UploadPartContext
            .buildFailedContext(partNumber, uploadUrl, new RuntimeException("Malformed response from storage provider"), partRetry));
      }
    }

    @Override
    public void failed(Exception ex) {
      UploadCallable.this.producer.putFinished(UploadPartContext
          .buildFailedContext(partNumber, uploadUrl, ex, retryCnt));
    }

    @Override
    public void cancelled() {
      // do nothing, everything is cancelled
    }

    private boolean checkUploadCompleted(HttpResponse result) {
      int statusCode = result.getStatusLine().getStatusCode();
      return statusCode == HttpStatus.SC_OK && result.getFirstHeader("ETag") != null;
    }

    private UploadPartContext getSucceededPartContext(HttpResponse result) {
      final String eTag = result.getFirstHeader("ETag").getValue().replaceAll("\"", "");
      return UploadPartContext.buildSucceedContext(partNumber, eTag, uploadUrl);
    }

  }
}


text:
package com.onefishtwo.bbqtimer;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.textclassifier.TextClassifier;
import android.widget.EditText;

import com.onefishtwo.bbqtimer.state.ApplicationState;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;

/**
 * A Dialog to edit the recipe list.
 *

 * The FragmentActivity that instantiates a RecipeEditorDialogFragment must implement
 * RecipeEditorDialogFragmentListener.
 */
public class RecipeEditorDialogFragment extends DialogFragment {
    public static final String TAG = "RecipeEditor";
    private static final String KEY_TEXT_CONTENTS = "Text";
    static final String FALLBACK_CONTENTS = ":30\n1\n1:30\n2\n";

    /**
     * The FragmentActivity that instantiates a RecipeEditorDialogFragment must implement this
     * Listener interface so it can get the edited results. */
    @SuppressWarnings("unused")
    public interface RecipeEditorDialogFragmentListener {
        /** The user changed (edited or reset) the recipes. */
        void onEditorDialogPositiveClick(DialogInterface dialog, @NonNull String text);
        /** The user cancelled the dialog; no change to the recipes. */
        @SuppressWarnings("EmptyMethod")
        void onEditorDialogNegativeClick(DialogInterface dialog);
        // Override onDismiss() to notice all dismissal cases? onDismiss() calling hideKeyboard()
        // doesn't work. Maybe it gets called too late.
    }

    private RecipeEditorDialogFragmentListener listener;
    private EditText textField;

    /** Creates and initializes a recipe list editor dialog. */
    public static RecipeEditorDialogFragment newInstance(String text) {
        RecipeEditorDialogFragment dialog = new RecipeEditorDialogFragment();
        Bundle bundle = new Bundle();

        // The text is stored in the Arguments Bundle so it's available on re-create.
        // TODO: Save contents in onPause() or onDestroy()?
        if (text.trim().length() == 0) {
            text = FALLBACK_CONTENTS;
        }
        bundle.putString(KEY_TEXT_CONTENTS, text);
        dialog.setArguments(bundle);
        return dialog;
    }

    /**
     * API 27: Work around an Android bug where double-clicking an EditText field would cause these
     * log errors:
     *
     *   TextClassifierImpl: Error suggesting selection for text. No changes to selection suggested.
     *     java.io.FileNotFoundException: No file for null locale
     *         at android.view.textclassifier.TextClassifierImpl.getSmartSelection(TextClassifierImpl.java:208)
     *         ...
     *   TextClassifierImpl: Error getting assist info.
     *     java.io.FileNotFoundException: No file for null locale
     *         at android.view.textclassifier.TextClassifierImpl.getSmartSelection(TextClassifierImpl.java:208)
     *         ...
     *
     * API > 27: Work around an Android bug that calls the TextClassifier on the main thread
     * (UI thread) [e.g. when the user double-taps the EditText field, or long-presses it, or
     * dismisses the soft keyboard when there's a text selection], causing this log warning even
     * though no app code is on the call stack:
     *
     *   W/androidtc: TextClassifier called on main thread.
     *
     * To avoid the delay and potential ANR, just bypass the irrelevant TextClassifier. (This
     * problem might not occur on API 28 - 29, but it's safer to do this uniformly.)
     */
    @SuppressWarnings("SpellCheckingInspection")
    public static void workaroundTextClassifier(EditText editText) {
        if (Build.VERSION.SDK_INT >= 27) {
            editText.setTextClassifier(TextClassifier.NO_OP);
        }
    }

    @NonNull
    public String getInitContents() {
        Bundle bundle = getArguments();

        if (bundle == null) {
            return FALLBACK_CONTENTS;
        } else {
            String string = bundle.getString(KEY_TEXT_CONTENTS);
            return string == null ? FALLBACK_CONTENTS : string;
        }
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        try {
            listener = (RecipeEditorDialogFragmentListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(
                    context + " expected to implement RecipeEditorDialogFragmentListener");
        }
    }

    private void hideKeyboard(@Nullable View v) {
        MainActivity.hideKeyboard(requireActivity(), v);
        // TODO: v.clearFocus() to avoid showing keyboard again if you open the app from the background?
    }

    /**
     * The TextEdit field's focus changed, e.g. by TAB, arrow keys, or view.clearFocus().
     * If it lost focus, hide the soft keyboard to ensure it's not hiding the Save & Cancel buttons.
     */
    private void onEditTextFocusChange(View view, boolean nowHasFocus) {
        if (!nowHasFocus) {
            hideKeyboard(view);
        }
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        // This theme shows the dialog full-width and scrolling in a way that the soft keyboard
        // nicely resizes it, keeping the Reset/Cancel/Save buttons visible and accessible.
        // Using MaterialAlertDialogBuilder doesn't seem to accomplish that, but maybe it's a
        // question of the right theme.
        AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity(),
                R.style.ThemeOverlay_Material3_TextInputEditText_OutlinedBox);
        LayoutInflater inflater = requireActivity().getLayoutInflater();
        View content = inflater.inflate(R.layout.dialog_edit_recipes, null);
        // "To ensure consistent styling, the custom view should be inflated or constructed using
        // the alert dialog's themed context obtained via getContext()."

        builder.setTitle(R.string.edit_list_title)
                .setView(content);

        textField = content.findViewById(R.id.recipes_text_field);
        workaroundTextClassifier(textField);
        textField.setOnFocusChangeListener(this::onEditTextFocusChange);

        // Workaround: The XML scrolling attributes don't work very well.
        textField.setHorizontallyScrolling(true);
        textField.setHorizontalScrollBarEnabled(true);
        textField.setScrollbarFadingEnabled(false);

        if (textField != null) {
            textField.setText(getInitContents());

            builder.setPositiveButton(R.string.save_edits, this::saveEdits)
                    .setNeutralButton(R.string.reset, this::resetEdits)
                    .setNegativeButton(R.string.cancel_edits, this::cancelEdits);
        }

        return builder.create();
    }

    /**
     *
Hides the soft keyboard.
     *
Passes the given recipes (or if blank, the default recipes) to the listener.
     */
    private void saveText(@NonNull DialogInterface dialog, @NonNull String recipes) {
        hideKeyboard(textField);

        if (recipes.trim().length() == 0) {
            recipes = ApplicationState.getDefaultRecipes(textField.getContext());
        }
        listener.onEditorDialogPositiveClick(dialog, recipes);
    }

    /** DialogInterface.OnClickListener for the "Save" button. */
    private void saveEdits(@NonNull DialogInterface dialog, int which) {
        saveText(dialog, textField.getText().toString());
    }

    /** DialogInterface.OnClickListener for the "Reset" button. */
    private void resetEdits(@NonNull DialogInterface dialog, int which) {
        saveText(dialog, "");
    }

    /** DialogInterface.OnClickListener for the "Cancel" button. */
    private void cancelEdits(@NonNull DialogInterface dialog, int which) {
        hideKeyboard(textField);
        listener.onEditorDialogNegativeClick(dialog);
        dialog.cancel();
    }
}


text:
<!DOCTYPE html>

		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

		<title>Haskell po polsku</title>
		<meta name="author" content="Hubert Grzywacz">
		<meta name="description" content="Haskell po polsku">

		<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

		<link rel="stylesheet" href="./files/base.css">
		<link rel="stylesheet" href="./files/skeleton.css">
		<link rel="stylesheet" href="./files/typography.css">
		<link rel="stylesheet" href="./files/layout.css">
		<link rel="stylesheet" href="./files/syntax.css">
		<link rel="stylesheet" href="./files/custom.css">
		<link href="./files/fonts.css" rel="stylesheet">

Haskell po polsku

Hubert Grzywacz

Blog

Kontakt

Github

Gitlab

Posty

							Stos monad przy pomocy transformatorów

						- Grudzień 2019