text:
#include <iterator>

#include "libtorrent/config.hpp"

#ifdef TORRENT_WINDOWS
#include <direct.h> // for _mkdir and _getcwd
#include <sys/types.h> // for _stat
#include <sys/stat.h>
#endif

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/bind.hpp>
#include <boost/unordered_set.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/extensions/ut_metadata.hpp"
#include "libtorrent/extensions/ut_pex.hpp"
#include "libtorrent/extensions/smart_ban.hpp"

#include "libtorrent/torrent_info.hpp"
#include "libtorrent/announce_entry.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/identify_client.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/magnet_uri.hpp"
#include "libtorrent/bitfield.hpp"
#include "libtorrent/peer_info.hpp"
#include "libtorrent/bdecode.hpp"
#include "libtorrent/add_torrent_params.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/create_torrent.hpp"

#include "torrent_view.hpp"
#include "session_view.hpp"
#include "print.hpp"

using boost::bind;
using libtorrent::total_milliseconds;

void sleep_ms(int milliseconds)
{
#if defined TORRENT_WINDOWS || defined TORRENT_CYGWIN
	Sleep(milliseconds);
#elif defined TORRENT_BEOS
	snooze_until(system_time() + boost::int64_t(milliseconds) * 1000, B_SYSTEM_TIMEBASE);
#else
	usleep(milliseconds * 1000);
#endif
}

#ifdef _WIN32

#include <windows.h>
#include <conio.h>

bool sleep_and_input(int* c, int sleep)
{
	for (int i = 0; i < 2; ++i)
	{
		if (_kbhit())
		{
			*c = _getch();
			return true;
		}
		Sleep(sleep / 2);
	}
	return false;
};

#else

#include <stdio.h> // for snprintf
#include <stdlib.h> // for atoi

#include <termios.h>
#include <string.h>
#include <sys/ioctl.h>
#include <signal.h>

struct set_keypress
{
	set_keypress()
	{
		termios new_settings;
		tcgetattr(0,&stored_settings);
		new_settings = stored_settings;
		// Disable canonical mode, and set buffer size to 1 byte
		// and disable echo
		new_settings.c_lflag &= ~(ICANON | ECHO);
		new_settings.c_cc[VTIME] = 0;
		new_settings.c_cc[VMIN] = 1;
		tcsetattr(0,TCSANOW,&new_settings);
	}
	~set_keypress() { tcsetattr(0,TCSANOW,&stored_settings); }
	termios stored_settings;
};

bool sleep_and_input(int* c, int sleep)
{
	libtorrent::time_point start = libtorrent::clock_type::now();
	int ret = 0;
retry:
	fd_set set;
	FD_ZERO(&set);
	FD_SET(0, &set);
	timeval tv = {sleep/ 1000, (sleep % 1000) * 1000 };
	ret = select(1, &set, 0, 0, &tv);
	if (ret > 0)
	{
		*c = getc(stdin);
		return true;
	}
	if (errno == EINTR)
	{
		if (total_milliseconds(libtorrent::clock_type::now() - start) < sleep)
			goto retry;
		return false;
	}

	if (ret < 0 && errno != 0 && errno != ETIMEDOUT)
	{
		fprintf(stderr, "select failed: %s\n", strerror(errno));
		sleep_ms(500);
	}

	return false;
}

#endif

bool print_trackers = false;
bool print_peers = false;
bool print_log = false;
bool print_downloads = false;
bool print_matrix = false;
bool print_file_progress = false;
bool show_pad_files = false;
bool show_dht_status = false;
bool sequential_download = false;

bool print_ip = true;
bool print_timers = false;
bool print_block = false;
bool print_peer_rate = false;
bool print_fails = false;
bool print_send_bufs = true;
bool print_disk_stats = false;

// the number of times we've asked to save resume data
// without having received a response (successful or failure)
int num_outstanding_resume_data = 0;

#ifndef TORRENT_DISABLE_DHT
std::vector<libtorrent::dht_lookup> dht_active_requests;
std::vector<libtorrent::dht_routing_bucket> dht_routing_table;
#endif

int load_file(std::string const& filename, std::vector<char>& v
	, libtorrent::error_code& ec, int limit = 8000000)
{
	ec.clear();
	FILE* f = fopen(filename.c_str(), "rb");
	if (f == NULL)
	{
		ec.assign(errno, boost::system::system_category());
		return -1;
	}

	int r = fseek(f, 0, SEEK_END);
	if (r != 0)
	{
		ec.assign(errno, boost::system::system_category());
		fclose(f);
		return -1;
	}
	long s = ftell(f);
	if (s < 0)
	{
		ec.assign(errno, boost::system::system_category());
		fclose(f);
		return -1;
	}

	if (s > limit)
	{
		fclose(f);
		return -2;
	}

	r = fseek(f, 0, SEEK_SET);
	if (r != 0)
	{
		ec.assign(errno, boost::system::system_category());
		fclose(f);
		return -1;
	}

	v.resize(s);
	if (s == 0)
	{
		fclose(f);
		return 0;
	}

	r = fread(&v[0], 1, v.size(), f);
	if (r < 0)
	{
		ec.assign(errno, boost::system::system_category());
		fclose(f);
		return -1;
	}

	fclose(f);

	if (r != s) return -3;

	return 0;
}

bool is_absolute_path(std::string const& f)
{
	if (f.empty()) return false;
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
	int i = 0;
	// match the xx:\ or xx:/ form
	while (f[i] && strchr("abcdefghijklmnopqrstuvxyz", f[i])) ++i;
	if (i < int(f.size()-1) && f[i] == ':' && (f[i+1] == '\\' || f[i+1] == '/'))
		return true;

	// match the \\ form
	if (int(f.size()) >= 2 && f[0] == '\\' && f[1] == '\\')
		return true;
	return false;
#else
	if (f[0] == '/') return true;
	return false;
#endif
}

std::string leaf_path(std::string f)
{
	if (f.empty()) return "";
	char const* first = f.c_str();
	char const* sep = strrchr(first, '/');
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
	char const* altsep = strrchr(first, '\\');
	if (sep == 0 || altsep > sep) sep = altsep;
#endif
	if (sep == 0) return f;

	if (sep - first == int(f.size()) - 1)
	{
		// if the last character is a / (or \)
		// ignore it
		int len = 0;
		while (sep > first)
		{
			--sep;
			if (*sep == '/'
#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
				|| *sep == '\\'
#endif
				)
				return std::string(sep + 1, len);
			++len;
		}
		return std::string(first, len);
	}
	return std::string(sep + 1);
}

std::string path_append(std::string const& lhs, std::string const& rhs)
{
	if (lhs.empty() || lhs == ".") return rhs;
	if (rhs.empty() || rhs == ".") return lhs;

#if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2)
#define TORRENT_SEPARATOR "\\"
	bool need_sep = lhs[lhs.size()-1] != '\\' && lhs[lhs.size()-1] != '/';
#else
#define TORRENT_SEPARATOR "/"
	bool need_sep = lhs[lhs.size()-1] != '/';
#endif
	return lhs + (need_sep?TORRENT_SEPARATOR:"") + rhs;
}

bool is_hex(char const *in, int len)
{
	for (char const* end = in + len; in < end; ++in)
	{
		if (*in >= '0' && *in <= '9') continue;
		if (*in >= 'A' && *in <= 'F') continue;
		if (*in >= 'a' && *in <= 'f') continue;
		return false;
	}
	return true;
}

std::string print_endpoint(libtorrent::tcp::endpoint const& ep)
{
	using namespace libtorrent;
	error_code ec;
	char buf[200];
	address const& addr = ep.address();
#if TORRENT_USE_IPV6
	if (addr.is_v6())
		snprintf(buf, sizeof(buf), "[%s]:%d", addr.to_string(ec).c_str(), ep.port());
	else
#endif
		snprintf(buf, sizeof(buf), "%s:%d", addr.to_string(ec).c_str(), ep.port());
	return buf;
}

struct torrent_entry
{
	torrent_entry(libtorrent::torrent_handle h) : handle(h) {}
	libtorrent::torrent_handle handle;
	libtorrent::torrent_status status;
};

// maps filenames to torrent_handles
typedef std::map<std::string, libtorrent::torrent_handle> handles_t;
typedef std::map<libtorrent::sha1_hash, std::string> files_t;

files_t hash_to_filename;

using libtorrent::torrent_status;

bool yes(libtorrent::torrent_status const&)
{ return true; }

FILE* g_log_file = 0;

std::string const& piece_bar(libtorrent::bitfield const& p, int width)
{
#ifdef _WIN32
	int const table_size = 5;
#else
	int const table_size = 18;
	width *= 2; // we only print one character for every two "slots"
#endif

	double const piece_per_char = p.size() / double(width);
	static std::string bar;
	bar.clear();
	bar.reserve(width * 6);
	bar += "[";
	if (p.size() == 0)
	{
		for (int i = 0; i < width; ++i) bar += ' ';
		bar += "]";
		return bar;
	}

	// the [piece, piece + pieces_per_char) range is the pieces that are represented by each character
	double piece = 0;

	// we print two blocks at a time, so calculate the color in pair
	int color[2];
	int last_color[2] = { -1, -1};
	for (int i = 0; i < width; ++i, piece += piece_per_char)
	{
		int num_pieces = 0;
		int num_have = 0;
		int end = (std::max)(int(piece + piece_per_char), int(piece) + 1);
		for (int k = int(piece); k < end; ++k, ++num_pieces)
			if (p[k]) ++num_have;
		int const c = int(std::ceil(num_have / float((std::max)(num_pieces, 1)) * (table_size - 1)));
		char buf[40];
		color[i & 1] = c;

#ifndef _WIN32
		if ((i & 1) == 1)
		{
			// now, print color[0] and [1]
			// bg determines whether we're settings foreground or background color
			static int const bg[] = { 38, 48};
			for (int i = 0; i < 2; ++i)
			{
				if (color[i] != last_color[i])
				{
					snprintf(buf, sizeof(buf), "\x1b[%d;5;%dm", bg[i & 1], 232 + color[i]);
					last_color[i] = color[i];
					bar += buf;
				}
			}
			bar += "\u258C";
		}
#else
		static char const table[] = {' ', '\xb0', '\xb1', '\xb2', '\xdb'};
		bar += table[c];
#endif
	}
	bar += esc("0");
	bar += "]";
	return bar;
}

int peer_index(libtorrent::tcp::endpoint addr, std::vector<libtorrent::peer_info> const& peers)
{
	using namespace libtorrent;
	std::vector<peer_info>::const_iterator i = std::find_if(peers.begin()
		, peers.end(), boost::bind(&peer_info::ip, _1) == addr);
	if (i == peers.end()) return -1;

	return i - peers.begin();
}

// returns the number of lines printed
int print_peer_info(std::string& out
	, std::vector<libtorrent::peer_info> const& peers, int max_lines)
{
	using namespace libtorrent;
	int pos = 0;
	if (print_ip) out += "IP                             ";
	out += "progress        down     (total | peak   )  up      (total | peak   ) sent-req tmo bsy rcv flags         dn  up  source  ";
	if (print_fails) out += "fail hshf ";
	if (print_send_bufs) out += "rq sndb rcvb   q-bytes ";
	if (print_timers) out += "inactive wait timeout q-time ";
	out += "  v disk ^    rtt  ";
	if (print_block) out += "block-progress ";
	if (print_peer_rate) out += "peer-rate est.rec.rate ";
	out += "client \x1b[K\n";
	++pos;

	char str[500];
	for (std::vector<peer_info>::const_iterator i = peers.begin();
		i != peers.end(); ++i)
	{
		if (i->flags & (peer_info::handshake | peer_info::connecting))
			continue;

		if (print_ip)
		{
			snprintf(str, sizeof(str), "%-30s ", (::print_endpoint(i->ip) +
				(i->flags & peer_info::utp_socket ? " [uTP]" : "") +
				(i->flags & peer_info::i2p_socket ? " [i2p]" : "")
				).c_str());
			out += str;
		}

		char temp[10];
		snprintf(temp, sizeof(temp), "%d/%d"
			, i->download_queue_length
			, i->target_dl_queue_length);
		temp[7] = 0;

		char peer_progress[10];
		snprintf(peer_progress, sizeof(peer_progress), "%.1f%%", i->progress_ppm / 10000.f);
		snprintf(str, sizeof(str)
			, "%s %s%s (%s|%s) %s%s (%s|%s) %s%7s %4d%4d%4d %s%s%s%s%s%s%s%s%s%s%s%s%s %s%s%s %s%s%s %s%s%s%s%s%s "
			, progress_bar(i->progress_ppm / 1000, 15, col_green, '#', '-', peer_progress).c_str()
			, esc("32"), add_suffix(i->down_speed, "/s").c_str()
			, add_suffix(i->total_download).c_str(), add_suffix(i->download_rate_peak, "/s").c_str()
			, esc("31"), add_suffix(i->up_speed, "/s").c_str(), add_suffix(i->total_upload).c_str()
			, add_suffix(i->upload_rate_peak, "/s").c_str(), esc("0")

			, temp // sent requests and target number of outstanding reqs.
			, i->timed_out_requests
			, i->busy_requests
			, i->upload_queue_length

			, color("I", (i->flags & peer_info::interesting)?col_white:col_blue).c_str()
			, color("C", (i->flags & peer_info::choked)?col_white:col_blue).c_str()
			, color("i", (i->flags & peer_info::remote_interested)?col_white:col_blue).c_str()
			, color("c", (i->flags & peer_info::remote_choked)?col_white:col_blue).c_str()
			, color("x", (i->flags & peer_info::supports_extensions)?col_white:col_blue).c_str()
			, color("o", (i->flags & peer_info::local_connection)?col_white:col_blue).c_str()
			, color("p", (i->flags & peer_info::on_parole)?col_white:col_blue).c_str()
			, color("O", (i->flags & peer_info::optimistic_unchoke)?col_white:col_blue).c_str()
			, color("S", (i->flags & peer_info::snubbed)?col_white:col_blue).c_str()
			, color("U", (i->flags & peer_info::upload_only)?col_white:col_blue).c_str()
			, color("e", (i->flags & peer_info::endgame_mode)?col_white:col_blue).c_str()
			, color("E", (i->flags & peer_info::rc4_encrypted)?col_white:(i->flags & peer_info::plaintext_encrypted)?col_cyan:col_blue).c_str()
			, color("h", (i->flags & peer_info::holepunched)?col_white:col_blue).c_str()

			, color("d", (i->read_state & peer_info::bw_disk)?col_white:col_blue).c_str()
			, color("l", (i->read_state & peer_info::bw_limit)?col_white:col_blue).c_str()
			, color("n", (i->read_state & peer_info::bw_network)?col_white:col_blue).c_str()
			, color("d", (i->write_state & peer_info::bw_disk)?col_white:col_blue).c_str()
			, color("l", (i->write_state & peer_info::bw_limit)?col_white:col_blue).c_str()
			, color("n", (i->write_state & peer_info::bw_network)?col_white:col_blue).c_str()

			, color("t", (i->source & peer_info::tracker)?col_white:col_blue).c_str()
			, color("p", (i->source & peer_info::pex)?col_white:col_blue).c_str()
			, color("d", (i->source & peer_info::dht)?col_white:col_blue).c_str()
			, color("l", (i->source & peer_info::lsd)?col_white:col_blue).c_str()
			, color("r", (i->source & peer_info::resume_data)?col_white:col_blue).c_str()
			, color("i", (i->source & peer_info::incoming)?col_white:col_blue).c_str());
		out += str;

		if (print_fails)
		{
			snprintf(str, sizeof(str), "%3d %3d "
				, i->failcount, i->num_hashfails);
			out += str;
		}
		if (print_send_bufs)
		{
			snprintf(str, sizeof(str), "%2d %6d %6d%5dkB "
				, i->requests_in_buffer, i->used_send_buffer
				, i->used_receive_buffer
				, i->queue_bytes / 1000);
			out += str;
		}
		if (print_timers)
		{
			char req_timeout[20] = "-";
			// timeout is only meaningful if there is at least one outstanding
			// request to the peer
			if (i->download_queue_length > 0)
				snprintf(req_timeout, sizeof(req_timeout), "%d", i->request_timeout);

			snprintf(str, sizeof(str), "%8d %4d %7s %6d "
				, int(total_seconds(i->last_active))
				, int(total_seconds(i->last_request))
				, req_timeout
				, int(total_seconds(i->download_queue_time)));
			out += str;
		}
		snprintf(str, sizeof(str), "%s|%s %5d "
			, add_suffix(i->pending_disk_bytes).c_str()
			, add_suffix(i->pending_disk_read_bytes).c_str()
			, i->rtt);
		out += str;

		if (print_block)
		{
			if (i->downloading_piece_index >= 0)
			{
				char buf[50];
				snprintf(buf, sizeof(buf), "%d:%d", i->downloading_piece_index, i->downloading_block_index);
				out += progress_bar(
					i->downloading_progress * 1000 / i->downloading_total, 14, col_green, '-', '#', buf);
			}
			else
			{
				out += progress_bar(0, 14);
			}
		}

		if (print_peer_rate)
		{
			bool unchoked = (i->flags & peer_info::choked) == 0;

			snprintf(str, sizeof(str), " %s %s"
				, add_suffix(i->remote_dl_rate, "/s").c_str()
				, unchoked ? add_suffix(i->estimated_reciprocation_rate, "/s").c_str() : "      ");
			out += str;
		}
		out += " ";

		if (i->flags & peer_info::handshake)
		{
			out += esc("31");
			out += " waiting for handshake";
			out += esc("0");
		}
		else if (i->flags & peer_info::connecting)
		{
			out += esc("31");
			out += " connecting to peer";
			out += esc("0");
		}
		else
		{
			out += " ";
			out += i->client;
		}
		out += "\x1b[K\n";
		++pos;
		if (pos >= max_lines) break;
	}
	return pos;
}

int listen_port = 6881;
int allocation_mode = libtorrent::storage_mode_sparse;
std::string save_path(".");
int torrent_upload_limit = 0;
int torrent_download_limit = 0;
std::string monitor_dir;
std::string bind_to_interface = "";
int poll_interval = 5;
int max_connections_per_torrent = 50;
bool seed_mode = false;
int cache_size = 1024;

bool share_mode = false;
bool disable_storage = false;

bool quit = false;

void signal_handler(int signo)
{
	// make the main loop terminate
	quit = true;
}

// if non-empty, a peer that will be added to all torrents
std::string peer;

using boost::bind;

std::string path_to_url(std::string f)
{
	std::string ret = "file://"
#ifdef TORRENT_WINDOWS
		"/"
#endif
		;
	static char const hex_chars[] = "0123456789abcdef";
	static const char unreserved[] =
		"/-_!.~*()ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
		"0123456789";

	// make sure the path is an absolute path
	if (!is_absolute_path(f))
	{
		char cwd[TORRENT_MAX_PATH];
#if defined TORRENT_WINDOWS && !defined TORRENT_MINGW
		_getcwd(cwd, sizeof(cwd));
#else
		getcwd(cwd, sizeof(cwd));
#endif
		f = path_append(cwd, f);
	}

	for (int i = 0; i < int(f.size()); ++i)
	{
#ifdef TORRENT_WINDOWS
		if (f[i] == '\\') ret.push_back('/');
		else
#endif
		if (std::strchr(unreserved, f[i]) != NULL) ret.push_back(f[i]);
		else
		{
			ret.push_back('%');
			ret.push_back(hex_chars[boost::uint8_t(f[i]) >> 4]);
			ret.push_back(hex_chars[boost::uint8_t(f[i]) & 0xf]);
		}
	}
	return ret;
}

// monitored_dir is true if this torrent is added because
// it was found in the directory that is monitored. If it
// is, it should be remembered so that it can be removed
// if it's no longer in that directory.
void add_torrent(libtorrent::session& ses
	, handles_t& files
	, std::set<libtorrent::torrent_handle>& non_files
	, std::string torrent
	, int allocation_mode
	, std::string const& save_path
	, bool monitored_dir
	, int torrent_upload_limit
	, int torrent_download_limit)
{
	using namespace libtorrent;
	static int counter = 0;

	printf("[%d] %s\n", counter++, torrent.c_str());

	add_torrent_params p;
	if (seed_mode) p.flags |= add_torrent_params::flag_seed_mode;
	if (disable_storage) p.storage = disabled_storage_constructor;
	if (share_mode) p.flags |= add_torrent_params::flag_share_mode;

	std::string filename = path_append(save_path, path_append(".resume"
		, leaf_path(torrent) + ".resume"));

	error_code ec;
	load_file(filename, p.resume_data, ec);

	p.url = path_to_url(torrent);
	p.save_path = save_path;
	p.storage_mode = (storage_mode_t)allocation_mode;
	p.flags |= add_torrent_params::flag_paused;
	p.flags &= ~add_torrent_params::flag_duplicate_is_error;
	p.flags |= add_torrent_params::flag_auto_managed;
	p.userdata = (void*)strdup(torrent.c_str());
	ses.async_add_torrent(p);
	files.insert(std::pair<const std::string, torrent_handle>(torrent, torrent_handle()));
}

std::vector<std::string> list_dir(std::string path
	, bool (*filter_fun)(std::string const&)
	, libtorrent::error_code& ec)
{
	std::vector<std::string> ret;
#ifdef TORRENT_WINDOWS
	if (!path.empty() && path[path.size()-1] != '\\') path += "\\*";
	else path += "*";

	WIN32_FIND_DATAA fd;
	HANDLE handle = FindFirstFileA(path.c_str(), &fd);
	if (handle == INVALID_HANDLE_VALUE)
	{
		ec.assign(GetLastError(), boost::system::system_category());
		return ret;
	}

	do
	{
		std::string p = fd.cFileName;
		if (filter_fun(p))
			ret.push_back(p);

	} while (FindNextFileA(handle, &fd));
	FindClose(handle);
#else

	if (!path.empty() && path[path.size()-1] == '/')
		path.resize(path.size()-1);

	DIR* handle = opendir(path.c_str());
	if (handle == 0)
	{
		ec.assign(errno, boost::system::system_category());
		return ret;
	}

	struct dirent de;
	dirent* dummy;
	while (readdir_r(handle, &de, &dummy) == 0)
	{
		if (dummy == 0) break;

		std::string p = de.d_name;
		if (filter_fun(p))
			ret.push_back(p);
	}
	closedir(handle);
#endif
	return ret;
}

bool filter_fun(std::string const& p)
{
	for (int i = p.size() - 1; i >= 0; --i)
	{
		if (p[i] == '/') break;
#ifdef TORRENT_WINDOWS
		if (p[i] == '\\') break;
#endif
		if (p[i] != '.') continue;
		return p.compare(i, 8, ".torrent") == 0;
	}
	return false;
}

void scan_dir(std::string const& dir_path
	, libtorrent::session& ses
	, handles_t& files
	, std::set<libtorrent::torrent_handle>& non_files
	, int allocation_mode
	, std::string const& save_path
	, int torrent_upload_limit
	, int torrent_download_limit)
{
	std::set<std::string> valid;

	using namespace libtorrent;

	error_code ec;
	std::vector<std::string> ents = list_dir(dir_path, filter_fun, ec);
	if (ec)
	{
		fprintf(stderr, "failed to list directory: (%s : %d) %s\n"
			, ec.category().name(), ec.value(), ec.message().c_str());
		return;
	}

	for (std::vector<std::string>::iterator i = ents.begin()
		, end(ents.end()); i != end; ++i)
	{
		std::string file = path_append(dir_path, *i);

		handles_t::iterator k = files.find(file);
		if (k != files.end())
		{
			valid.insert(file);
			continue;
		}

		// the file has been added to the dir, start
		// downloading it.
		add_torrent(ses, files, non_files, file, allocation_mode
			, save_path, true, torrent_upload_limit, torrent_download_limit);
		valid.insert(file);
	}

	// remove the torrents that are no longer in the directory

	for (handles_t::iterator i = files.begin(); !files.empty() && i != files.end();)
	{
		if (i->first.empty() || valid.find(i->first) != valid.end())
		{
			++i;
			continue;
		}

		torrent_handle& h = i->second;
		if (!h.is_valid())
		{
			files.erase(i++);
			continue;
		}

		h.auto_managed(false);
		h.pause();
		// the alert handler for save_resume_data_alert
		// will save it to disk
		h.save_resume_data();
		++num_outstanding_resume_data;

		files.erase(i++);
	}
}

char const* timestamp()
{
	time_t t = std::time(0);
	tm* timeinfo = std::localtime(&t);
	static char str[200];
	std::strftime(str, 200, "%b %d %X", timeinfo);
	return str;
}

void print_alert(libtorrent::alert const* a, std::string& str)
{
	using namespace libtorrent;

	if (a->category() & alert::error_notification)
	{
		str += esc("31");
	}
	else if (a->category() & (alert::peer_notification | alert::storage_notification))
	{
		str += esc("33");
	}
	str += "[";
	str += timestamp();
	str += "] ";
	str += a->message();
	str += esc("0");

	if (g_log_file)
		fprintf(g_log_file, "[%s] %s\n", timestamp(),  a->message().c_str());
}

int save_file(std::string const& filename, std::vector<char>& v)
{
	FILE* f = fopen(filename.c_str(), "wb");
	if (f == NULL)
		return -1;

	int w = fwrite(&v[0], 1, v.size(), f);
	fclose(f);

	if (w < 0) return -1;
	if (w != int(v.size())) return -3;
	return 0;
}

// returns true if the alert was handled (and should not be printed to the log)
// returns false if the alert was not handled
bool handle_alert(torrent_view& view, session_view& ses_view
	, libtorrent::session& ses, libtorrent::alert* a
	, handles_t& files, std::set<libtorrent::torrent_handle>& non_files)
{
	using namespace libtorrent;

	if (session_stats_alert* s = alert_cast<session_stats_alert>(a))
	{
		ses_view.update_counters(s->values, sizeof(s->values)/sizeof(s->values[0])
			, duration_cast<microseconds>(s->timestamp().time_since_epoch()).count());
		return true;
	}

#ifndef TORRENT_DISABLE_DHT
	if (dht_stats_alert* p = alert_cast<dht_stats_alert>(a))
	{
		dht_active_requests = p->active_requests;
		dht_routing_table = p->routing_table;
		return true;
	}
#endif

#ifdef TORRENT_USE_OPENSSL
	if (torrent_need_cert_alert* p = alert_cast<torrent_need_cert_alert>(a))
	{
		torrent_handle h = p->handle;
		std::string base_name = path_append("certificates", to_hex(h.info_hash().to_string()));
		std::string cert = base_name + ".pem";
		std::string priv = base_name + "_key.pem";

#ifdef TORRENT_WINDOWS
		struct ::_stat st;
		int ret = ::_stat(cert.c_str(), &st);
		if (ret < 0 || (st.st_mode & _S_IFREG) == 0)
#else
		struct ::stat st;
		int ret = ::stat(cert.c_str(), &st);
		if (ret < 0 || (st.st_mode & S_IFREG) == 0)
#endif
		{
			char msg[256];
			snprintf(msg, sizeof(msg), "ERROR. could not load certificate %s: %s\n", cert.c_str(), strerror(errno));
			if (g_log_file) fprintf(g_log_file, "[%s] %s\n", timestamp(), msg);
			return true;
		}

#ifdef TORRENT_WINDOWS
		ret = ::_stat(priv.c_str(), &st);
		if (ret < 0 || (st.st_mode & _S_IFREG) == 0)
#else
		ret = ::stat(priv.c_str(), &st);
		if (ret < 0 || (st.st_mode & S_IFREG) == 0)
#endif
		{
			char msg[256];
			snprintf(msg, sizeof(msg), "ERROR. could not load private key %s: %s\n", priv.c_str(), strerror(errno));
			if (g_log_file) fprintf(g_log_file, "[%s] %s\n", timestamp(), msg);
			return true;
		}

		char msg[256];
		snprintf(msg, sizeof(msg), "loaded certificate %s and key %s\n", cert.c_str(), priv.c_str());
		if (g_log_file) fprintf(g_log_file, "[%s] %s\n", timestamp(), msg);

		h.set_ssl_certificate(cert, priv, "certificates/dhparams.pem", "1234");
		h.resume();
	}
#endif

	// don't log every peer we try to connect to
	if (alert_cast<peer_connect_alert>(a)) return true;

	if (peer_disconnected_alert* pd = alert_cast<peer_disconnected_alert>(a))
	{
		// ignore failures to connect and peers not responding with a
		// handshake. The peers that we successfully connect to and then
		// disconnect is more interesting.
		if (pd->operation == op_connect
			|| pd->error == errors::timed_out_no_handshake)
			return true;
	}

	if (metadata_received_alert* p = alert_cast<metadata_received_alert>(a))
	{
		// if we have a monitor dir, save the .torrent file we just received in it
		// also, add it to the files map, and remove it from the non_files list
		// to keep the scan dir logic in sync so it's not removed, or added twice
		torrent_handle h = p->handle;
		if (h.is_valid())
		{
			boost::shared_ptr<const torrent_info> ti = h.torrent_file();
			create_torrent ct(*ti);
			entry te = ct.generate();
			std::vector<char> buffer;
			bencode(std::back_inserter(buffer), te);
			sha1_hash hash = ti->info_hash();
			std::string filename = ti->name() + "." + to_hex(hash.to_string()) + ".torrent";
			filename = path_append(monitor_dir, filename);
			save_file(filename, buffer);

			files.insert(std::pair<std::string, libtorrent::torrent_handle>(filename, h));
			hash_to_filename[hash] = filename;
			non_files.erase(h);
		}
	}
	else if (add_torrent_alert* p = alert_cast<add_torrent_alert>(a))
	{
		std::string filename;
		if (p->params.userdata)
		{
			filename = (char*)p->params.userdata;
			free(p->params.userdata);
		}

		if (p->error)
		{
			fprintf(stderr, "failed to add torrent: %s %s\n", filename.c_str()
				, p->error.message().c_str());
		}
		else
		{
			torrent_handle h = p->handle;

			if (!filename.empty())
				files[filename] = h;
			else
				non_files.insert(h);

			h.set_max_connections(max_connections_per_torrent);
			h.set_max_uploads(-1);
			h.set_upload_limit(torrent_upload_limit);
			h.set_download_limit(torrent_download_limit);

			// if we have a peer specified, connect to it
			if (!peer.empty())
			{
				char* port = (char*) strrchr((char*)peer.c_str(), ':');
				if (port != NULL)
				{
					*port++ = 0;
					char const* ip = peer.c_str();
					int peer_port = atoi(port);
					error_code ec;
					if (peer_port > 0)
						h.connect_peer(tcp::endpoint(address::from_string(ip, ec), peer_port));
				}
			}

			sha1_hash info_hash;
			if (p->params.ti)
			{
				info_hash = p->params.ti->info_hash();
			}
			else if (!p->params.info_hash.is_all_zeros())
			{
				info_hash = p->params.info_hash;
			}
			else
			{
				info_hash = h.info_hash();
			}
			hash_to_filename.insert(std::make_pair(info_hash, filename));
		}
	}
	else if (torrent_finished_alert* p = alert_cast<torrent_finished_alert>(a))
	{
		p->handle.set_max_connections(max_connections_per_torrent / 2);

		// write resume data for the finished torrent
		// the alert handler for save_resume_data_alert
		// will save it to disk
		torrent_handle h = p->handle;
		h.save_resume_data();
		++num_outstanding_resume_data;
	}
	else if (save_resume_data_alert* p = alert_cast<save_resume_data_alert>(a))
	{
		--num_outstanding_resume_data;
		torrent_handle h = p->handle;
		TORRENT_ASSERT(p->resume_data);
		if (p->resume_data)
		{
			std::vector<char> out;
			bencode(std::back_inserter(out), *p->resume_data);
			torrent_status st = h.status(torrent_handle::query_save_path);
			save_file(path_append(st.save_path, path_append(".resume", leaf_path(
				hash_to_filename[st.info_hash]) + ".resume")), out);
			if (h.is_valid()
				&& non_files.find(h) == non_files.end()
				&& std::find_if(files.begin(), files.end()
					, boost::bind(&handles_t::value_type::second, _1) == h) == files.end())
				ses.remove_torrent(h);
		}
	}
	else if (save_resume_data_failed_alert* p = alert_cast<save_resume_data_failed_alert>(a))
	{
		--num_outstanding_resume_data;
		torrent_handle h = p->handle;
		if (h.is_valid())
		{
			fprintf(stderr, "FAILED TO SAVE RESUME DATA: %s\n"
				, h.status().name.c_str());
		}
		if (h.is_valid()
			&& non_files.find(h) == non_files.end()
			&& std::find_if(files.begin(), files.end()
				, boost::bind(&handles_t::value_type::second, _1) == h) == files.end())
			ses.remove_torrent(h);
	}
	else if (torrent_paused_alert* p = alert_cast<torrent_paused_alert>(a))
	{
		// write resume data for the finished torrent
		// the alert handler for save_resume_data_alert
		// will save it to disk
		torrent_handle h = p->handle;
		h.save_resume_data();
		++num_outstanding_resume_data;
	}
	else if (state_update_alert* p = alert_cast<state_update_alert>(a))
	{
		view.update_torrents(p->status);
		return true;
	}
	return false;
}

void print_piece(libtorrent::partial_piece_info* pp
	, libtorrent::cached_piece_info* cs
	, std::vector<libtorrent::peer_info> const& peers
	, torrent_status const* ts
	, std::string& out)
{
	using namespace libtorrent;

	char str[1024];
	assert(pp == 0 || cs == 0 || cs->piece == pp->piece_index);
	int piece = pp ? pp->piece_index : cs->piece;
	int num_blocks = pp ? pp->blocks_in_piece : cs->blocks.size();

	snprintf(str, sizeof(str), "%5d:[", piece);
	out += str;
	char const* last_color = 0;
	for (int j = 0; j < num_blocks; ++j)
	{
		int index = pp ? peer_index(pp->blocks[j].peer(), peers) % 36 : -1;
		char chr = '+';
		if (index >= 0)
			chr = (index < 10)?'0' + index:'A' + index - 10;
		bool snubbed = index >= 0 ? peers[index].flags & peer_info::snubbed : false;

		char const* color = "";

		if (pp == 0)
		{
			color = cs->blocks[j] ? esc("34;7") : esc("0");
			chr = ' ';
		}
		else
		{
			if (cs && cs->blocks[j] && pp->blocks[j].state != block_info::finished)
				color = esc("36;7");
			else if (pp->blocks[j].bytes_progress > 0
					&& pp->blocks[j].state == block_info::requested)
			{
				if (pp->blocks[j].num_peers > 1) color = esc("1;7");
				else color = snubbed ? esc("35;7") : esc("33;7");
				chr = '0' + (pp->blocks[j].bytes_progress * 10 / pp->blocks[j].block_size);
			}
			else if (pp->blocks[j].state == block_info::finished) color = esc("32;7");
			else if (pp->blocks[j].state == block_info::writing) color = esc("36;7");
			else if (pp->blocks[j].state == block_info::requested) color = snubbed ? esc("35;7") : esc("0");
			else { color = esc("0"); chr = ' '; }
		}
		if (last_color == 0 || strcmp(last_color, color) != 0)
		{
			snprintf(str, sizeof(str), "%s%c", color, chr);
			out += str;
		}
		else
			out += chr;

		last_color = color;
	}
	out += esc("0");
	out += "]";
/*
	char const* cache_kind_str[] = {"read", "write", "read-volatile"};
	snprintf(str, sizeof(str), " %3d cache age: %-5.1f state: %s%s\n"
		, cs ? cs->next_to_hash : 0
		, cs ? (total_milliseconds(clock_type::now() - cs->last_use) / 1000.f) : 0.f
		, cs ? cache_kind_str[cs->kind] : "N/A"
		, ts && ts->pieces.size() ? (ts->pieces[piece] ? " have" : " dont-have") : "");
	out += str;
*/
}

int main(int argc, char* argv[])
{
#ifndef _WIN32
	// sets the terminal to single-character mode
	// and resets when destructed
	set_keypress s;
#endif

	if (argc == 1)
	{
		fprintf(stderr, "usage: client_test [OPTIONS] [TORRENT|MAGNETURL]\n\n"
			"OPTIONS:\n"
			"\n CLIENT OPTIONS\n"
			"  -f <log file>         logs all events to the given file\n"
			"  -s <path>             sets the save path for downloads\n"
			"  -m <path>             sets the .torrent monitor directory\n"
			"  -t <seconds>          sets the scan interval of the monitor dir\n"
			"  -F <milliseconds>     sets the UI refresh rate. This is the number of\n"
			"                        milliseconds between screen refreshes.\n"
			"  -k                    enable high performance settings. This overwrites any other\n"
			"                        previous command line options, so be sure to specify this first\n"
			"  -G                    Add torrents in seed-mode (i.e. assume all pieces\n"
			"                        are present and check hashes on-demand)\n"
			"  -E <num-threads>      specify how many disk I/O threads to use\n"
			"\n BITTORRENT OPTIONS\n"
			"  -c <limit>            sets the max number of connections\n"
			"  -T <limit>            sets the max number of connections per torrent\n"
			"  -U <rate>             sets per-torrent upload rate\n"
			"  -D <rate>             sets per-torrent download rate\n"
			"  -d <rate>             limits the download rate\n"
			"  -u <rate>             limits the upload rate\n"
			"  -S <limit>            limits the upload slots\n"
			"  -A <num pieces>       allowed pieces set size\n"
			"  -H                    Don't start DHT\n"
			"  -X                    Don't start local peer discovery\n"
			"  -n                    announce to trackers in all tiers\n"
			"  -W <num peers>        Set the max number of peers to keep in the peer list\n"
			"  -B <seconds>          sets the peer timeout\n"
			"  -Q                    enables share mode. Share mode attempts to maximize\n"
			"                        share ratio rather than downloading\n"
			"  -K                    enable piece suggestions of read cache\n"
			"  -r <IP:port>          connect to specified peer\n"
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
			"  -e                    force encrypted bittorrent connections\n"
#endif
			"\n QUEING OPTIONS\n"
			"  -v <limit>            Set the max number of active downloads\n"
			"  -^ <limit>            Set the max number of active seeds\n"
			"\n NETWORK OPTIONS\n"
			"  -p <port>             sets the listen port\n"
			"  -w <seconds>          sets the retry time for failed web seeds\n"
			"  -x <file>             loads an emule IP-filter file\n"
			"  -P <host:port>        Use the specified SOCKS5 proxy\n"
			"  -L <user:passwd>      Use the specified username and password for the\n"
			"                        proxy specified by -P\n"
			"  -h                    allow multiple connections from the same IP\n"
			"  -M                    Disable TCP/uTP bandwidth balancing\n"
			"  -N                    Do not attempt to use UPnP and NAT-PMP to forward ports\n"
			"  -Y                    Rate limit local peers\n"
			"  -y                    Disable TCP connections (disable outgoing TCP and reject\n"
			"                        incoming TCP connections)\n"
			"  -J                    Disable uTP connections (disable outgoing uTP and reject\n"
			"                        incoming uTP connections)\n"
			"  -b <IP>               sets IP of the interface to bind the\n"
			"                        listen socket to\n"
			"  -I <IP>               sets the IP of the interface to bind\n"
			"                        outgoing peer connections to\n"
#if TORRENT_USE_I2P
			"  -i <i2p-host>         the hostname to an I2P SAM bridge to use\n"
#endif
			"  -l <limit>            sets the listen socket queue size\n"
			"\n DISK OPTIONS\n"
			"  -a <mode>             sets the allocation mode. [sparse|allocate]\n"
			"  -R <num blocks>       number of blocks per read cache line\n"
			"  -C <limit>            sets the max cache size. Specified in 16kB blocks\n"
			"  -j                    disable disk read-ahead\n"
			"  -z                    disable piece hash checks (used for benchmarking)\n"
			"  -0                    disable disk I/O, read garbage and don't flush to disk\n"
			"\n\n"
			"TORRENT is a path to a .torrent file\n"
			"MAGNETURL is a magnet link\n"
			"URL is a url to a torrent file\n"
			"\n"
			"Example for running benchmark:\n\n"
			"  client_test -k -z -N -h -H -M -l 2000 -S 1000 -T 1000 -c 1000 test.torrent\n");
			;
		return 0;
	}

	using namespace libtorrent;
	namespace lt = libtorrent;

	torrent_view view;
	session_view ses_view;

	settings_pack settings;
	settings.set_int(settings_pack::cache_size, cache_size);
	settings.set_int(settings_pack::active_loaded_limit, 20);
	settings.set_int(settings_pack::choking_algorithm, settings_pack::rate_based_choker);

	int refresh_delay = 500;
	bool rate_limit_locals = false;

	std::deque<std::string> events;

	time_point next_dir_scan = clock_type::now();

	// the string is the filename of the .torrent file, but only if
	// it was added through the directory monitor. It is used to
	// be able to remove torrents that were added via the directory
	// monitor when they're not in the directory anymore.
	handles_t files;

	// torrents that were not added via the monitor dir
	std::set<torrent_handle> non_files;

	// load the torrents given on the commandline

	std::vector<add_torrent_params> magnet_links;
	std::vector<std::string> torrents;
	ip_filter loaded_ip_filter;

	for (int i = 1; i < argc; ++i)
	{
		if (argv[i][0] != '-')
		{
			// match it against the <hash>@<tracker> format
			if (strlen(argv[i]) > 45
				&& ::is_hex(argv[i], 40)
				&& (strncmp(argv[i] + 40, "@http://", 8) == 0
					|| strncmp(argv[i] + 40, "@udp://", 7) == 0))
			{
				sha1_hash info_hash;
				from_hex(argv[i], 40, (char*)&info_hash[0]);

				add_torrent_params p;
				if (seed_mode) p.flags |= add_torrent_params::flag_seed_mode;
				if (disable_storage) p.storage = disabled_storage_constructor;
				if (share_mode) p.flags |= add_torrent_params::flag_share_mode;
				p.trackers.push_back(argv[i] + 41);
				p.info_hash = info_hash;
				p.save_path = save_path;
				p.storage_mode = (storage_mode_t)allocation_mode;
				p.flags |= add_torrent_params::flag_paused;
				p.flags &= ~add_torrent_params::flag_duplicate_is_error;
				p.flags |= add_torrent_params::flag_auto_managed;
				magnet_links.push_back(p);
				continue;
			}

			torrents.push_back(argv[i]);
			continue;
		}

		// if there's a flag but no argument following, ignore it
		if (argc == i) continue;
		char const* arg = argv[i+1];
		if (arg == NULL) arg = "";

		switch (argv[i][1])
		{
			case 'f': g_log_file = fopen(arg, "w+"); break;
			case 'h': settings.set_bool(settings_pack::allow_multiple_connections_per_ip, true); --i; break;
			case 'p': listen_port = atoi(arg); break;
			case 'k': high_performance_seed(settings); --i; break;
			case 'j': settings.set_bool(settings_pack::use_disk_read_ahead, false); --i; break;
			case 'z': settings.set_bool(settings_pack::disable_hash_checks, true); --i; break;
			case 'K': settings.set_int(settings_pack::suggest_mode, settings_pack::suggest_read_cache); --i; break;
			case 'B': settings.set_int(settings_pack::peer_timeout, atoi(arg)); break;
			case 'n': settings.set_bool(settings_pack::announce_to_all_tiers, true); --i; break;
			case 'G': seed_mode = true; --i; break;
			case 'E': settings.set_int(settings_pack::aio_threads, atoi(arg)); break;
			case 'd': settings.set_int(settings_pack::download_rate_limit, atoi(arg) * 1000); break;
			case 'u': settings.set_int(settings_pack::upload_rate_limit, atoi(arg) * 1000); break;
			case 'S':
				settings.set_int(settings_pack::unchoke_slots_limit, atoi(arg));
				settings.set_int(settings_pack::choking_algorithm, settings_pack::fixed_slots_choker);
				break;
			case 'a':
				if (strcmp(arg, "allocate") == 0) allocation_mode = storage_mode_allocate;
				else if (strcmp(arg, "sparse") == 0) allocation_mode = storage_mode_sparse;
				break;
			case 's': save_path = arg; break;
			case 'U': torrent_upload_limit = atoi(arg) * 1000; break;
			case 'D': torrent_download_limit = atoi(arg) * 1000; break;
			case 'm': monitor_dir = arg; break;
			case 'Q': share_mode = true; --i; break;
			case 'b': bind_to_interface = arg; break;
			case 'w': settings.set_int(settings_pack::urlseed_wait_retry, atoi(arg)); break;
			case 't': poll_interval = atoi(arg); break;
			case 'F': refresh_delay = atoi(arg); break;
			case 'H':
				settings.set_bool(settings_pack::enable_dht, false);
				--i;
				break;
			case 'l': settings.set_int(settings_pack::listen_queue_size, atoi(arg)); break;
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
			case 'e':
				{
					settings.set_int(settings_pack::out_enc_policy, settings_pack::pe_forced);
					settings.set_int(settings_pack::in_enc_policy, settings_pack::pe_forced);
					settings.set_int(settings_pack::allowed_enc_level, settings_pack::pe_rc4);
					settings.set_bool(settings_pack::prefer_rc4, true);
					--i;
					break;
				}
#endif
			case 'W':
				settings.set_int(settings_pack::max_peerlist_size, atoi(arg));
				settings.set_int(settings_pack::max_paused_peerlist_size, atoi(arg) / 2);
				break;
			case 'x':
				{
					FILE* filter = fopen(arg, "r");
					if (filter)
					{
						unsigned int a,b,c,d,e,f,g,h, flags;
						while (fscanf(filter, "%u.%u.%u.%u - %u.%u.%u.%u %u\n", &a, &b, &c, &d, &e, &f, &g, &h, &flags) == 9)
						{
							address_v4 start((a << 24) + (b << 16) + (c << 8) + d);
							address_v4 last((e << 24) + (f << 16) + (g << 8) + h);
							if (flags <= 127) flags = ip_filter::blocked;
							else flags = 0;
							loaded_ip_filter.add_rule(start, last, flags);
						}
						fclose(filter);
					}
				}
				break;
			case 'c': settings.set_int(settings_pack::connections_limit, atoi(arg)); break;
			case 'T': max_connections_per_torrent = atoi(arg); break;
#if TORRENT_USE_I2P
			case 'i':
				{
					settings.set_str(settings_pack::i2p_hostname, arg);
					settings.set_int(settings_pack::i2p_port, 7656);
					settings.set_int(settings_pack::proxy_type, settings_pack::i2p_proxy);
					break;
				}
#endif // TORRENT_USE_I2P
			case 'C':
				cache_size = atoi(arg);
				settings.set_int(settings_pack::cache_size, cache_size);
				settings.set_int(settings_pack::cache_buffer_chunk_size, 0);
				break;
			case 'A': settings.set_int(settings_pack::allowed_fast_set_size, atoi(arg)); break;
			case 'R': settings.set_int(settings_pack::read_cache_line_size, atoi(arg)); break;
			case 'M': settings.set_int(settings_pack::mixed_mode_algorithm, settings_pack::prefer_tcp); --i; break;
			case 'y':
				settings.set_bool(settings_pack::enable_outgoing_tcp, false);
				settings.set_bool(settings_pack::enable_incoming_tcp, false);
				--i;
				break;
			case 'J':
				settings.set_bool(settings_pack::enable_outgoing_utp, false);
				settings.set_bool(settings_pack::enable_incoming_utp, false);
				--i;
				break;
			case 'r': peer = arg; break;
			case 'P':
				{
					char* port = (char*) strrchr(arg, ':');
					if (port == 0)
					{
						fprintf(stderr, "invalid proxy hostname, no port found\n");
						break;
					}
					*port++ = 0;
					settings.set_str(settings_pack::proxy_hostname, arg);
					settings.set_int(settings_pack::proxy_port, atoi(port));
					if (atoi(port) == 0) {
						fprintf(stderr, "invalid proxy port\n");
						break;
					}
					if (settings.get_int(settings_pack::proxy_type) == settings_pack::none)
						settings.set_int(settings_pack::proxy_type, settings_pack::socks5);
				}
				break;
			case 'L':
				{
					char* pw = (char*) strchr(arg, ':');
					if (pw == 0)
					{
						fprintf(stderr, "invalid proxy username and password specified\n");
						break;
					}
					*pw++ = 0;
					settings.set_str(settings_pack::proxy_username, arg);
					settings.set_str(settings_pack::proxy_password, pw);
					settings.set_int(settings_pack::proxy_type, settings_pack::socks5_pw);
				}
				break;
			case 'I': settings.set_str(settings_pack::outgoing_interfaces, arg); break;
			case 'N':
				settings.set_bool(settings_pack::enable_upnp, false);
				settings.set_bool(settings_pack::enable_natpmp, false);
				--i;
				break;
			case 'Y':
				{
					--i;
					rate_limit_locals = true;
					break;
				}
			case 'X': settings.set_bool(settings_pack::enable_lsd, false); --i; break;
			case 'v': settings.set_int(settings_pack::active_downloads, atoi(arg));
				settings.set_int(settings_pack::active_limit, atoi(arg) * 2);
				break;
			case '^':
				settings.set_int(settings_pack::active_seeds, atoi(arg));
				settings.set_int(settings_pack::active_limit, atoi(arg) * 2);
				break;
			case '0': disable_storage = true; --i;
		}
		++i; // skip the argument
	}

	// create directory for resume files
#ifdef TORRENT_WINDOWS
	int ret = _mkdir(path_append(save_path, ".resume").c_str());
#else
	int ret = mkdir(path_append(save_path, ".resume").c_str(), 0777);
#endif
	if (ret < 0)
		fprintf(stderr, "failed to create resume file directory: (%d) %s\n"
			, errno, strerror(errno));

	if (bind_to_interface.empty()) bind_to_interface = "0.0.0.0";
	char iface_str[100];
	snprintf(iface_str, sizeof(iface_str), "%s:%d", bind_to_interface.c_str()
		, listen_port);
	settings.set_str(settings_pack::listen_interfaces, iface_str);

	settings.set_str(settings_pack::user_agent, "client_test/" LIBTORRENT_VERSION);
	settings.set_int(settings_pack::alert_mask, alert::all_categories
		& ~(alert::dht_notification
		+ alert::progress_notification
		+ alert::stats_notification
		+ alert::session_log_notification
		+ alert::torrent_log_notification
		+ alert::peer_log_notification
		+ alert::dht_log_notification
		+ alert::picker_log_notification
		));

	libtorrent::session ses(settings);

	if (rate_limit_locals)
	{
		ip_filter pcf;
		pcf.add_rule(address_v4::from_string("0.0.0.0")
			, address_v4::from_string("255.255.255.255"), 1 << lt::session::global_peer_class_id);
#if TORRENT_USE_IPV6
		pcf.add_rule(address_v6::from_string("::")
			, address_v6::from_string("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), 1);
#endif
		ses.set_peer_class_filter(pcf);
	}

	ses.set_ip_filter(loaded_ip_filter);

	error_code ec;

#ifndef TORRENT_DISABLE_DHT
	dht_settings dht;
	dht.privacy_lookups = true;
	ses.set_dht_settings(dht);

	std::vector<char> in;
	if (load_file(".ses_state", in, ec) == 0)
	{
		bdecode_node e;
		if (bdecode(&in[0], &in[0] + in.size(), e, ec) == 0)
			ses.load_state(e, session::save_dht_state);
	}
#endif

	for (std::vector<add_torrent_params>::iterator i = magnet_links.begin()
		, end(magnet_links.end()); i != end; ++i)
	{
		ses.async_add_torrent(*i);
	}

	for (std::vector<std::string>::iterator i = torrents.begin()
		, end(torrents.end()); i != end; ++i)
	{
		if (std::strstr(i->c_str(), "magnet:") == i->c_str())
		{
			add_torrent_params p;
			if (seed_mode) p.flags |= add_torrent_params::flag_seed_mode;
			if (disable_storage) p.storage = disabled_storage_constructor;
			if (share_mode) p.flags |= add_torrent_params::flag_share_mode;
			p.save_path = save_path;
			p.storage_mode = (storage_mode_t)allocation_mode;
			p.url = *i;

			std::vector<char> buf;
			add_torrent_params tmp;
			ec.clear();
			parse_magnet_uri(*i, tmp, ec);

			if (ec) continue;

			std::string filename = path_append(save_path, path_append(".resume"
				, to_hex(tmp.info_hash.to_string()) + ".resume"));

			load_file(filename, p.resume_data, ec);

			printf("adding URL: %s\n", i->c_str());
			ses.async_add_torrent(p);
			continue;
		}

		// if it's a torrent file, open it as usual
		add_torrent(ses, files, non_files, i->c_str()
			, allocation_mode, save_path, false
			, torrent_upload_limit, torrent_download_limit);
	}

	// main loop
	std::vector<peer_info> peers;
	std::vector<partial_piece_info> queue;

	int tick = 0;

#ifndef _WIN32
	signal(SIGTERM, signal_handler);
	signal(SIGINT, signal_handler);
#endif

	while (!quit)
	{
		++tick;
		ses.post_torrent_updates();
		ses.post_session_stats();
		ses.post_dht_stats();

		int terminal_width = 80;
		int terminal_height = 50;
		terminal_size(&terminal_width, &terminal_height);
		view.set_size(terminal_width, terminal_height / 3);
		ses_view.set_pos(terminal_height / 3);

		int c = 0;
		if (sleep_and_input(&c, refresh_delay))
		{

#ifdef _WIN32
#define ESCAPE_SEQ 224
#define LEFT_ARROW 75
#define RIGHT_ARROW 77
#define UP_ARROW 72
#define DOWN_ARROW 80
#else
#define ESCAPE_SEQ 27
#define LEFT_ARROW 68
#define RIGHT_ARROW 67
#define UP_ARROW 65
#define DOWN_ARROW 66
#endif

			torrent_handle h = view.get_active_handle();

			if (c == EOF) { break; }
			do
			{
				if (c == ESCAPE_SEQ)
				{
					// escape code, read another character
#ifdef _WIN32
					int c = _getch();
#else
					int c = getc(stdin);
					if (c == EOF) { break; }
					if (c != '[') continue;
					c = getc(stdin);
#endif
					if (c == EOF) break;
					if (c == LEFT_ARROW)
					{
						// arrow left
						int filter = view.filter();
						if (filter > 0)
						{
							--filter;
							view.set_filter(filter);
							h = view.get_active_handle();
						}
					}
					else if (c == RIGHT_ARROW)
					{
						// arrow right
						int filter = view.filter();
						if (filter < torrent_view::torrents_max - 1)
						{
							++filter;
							view.set_filter(filter);
							h = view.get_active_handle();
						}
					}
					else if (c == UP_ARROW)
					{
						// arrow up
						view.arrow_up();
						h = view.get_active_handle();
					}
					else if (c == DOWN_ARROW)
					{
						// arrow down
						view.arrow_down();
						h = view.get_active_handle();
					}
				}

				if (c == ' ')
				{
					if (ses.is_paused()) ses.resume();
					else ses.pause();
				}

				// add magnet link
				if (c == 'm')
				{
					char url[4096];
					puts("Enter magnet link:\n");
					scanf("%4095s", url);

					add_torrent_params p;
					if (seed_mode) p.flags |= add_torrent_params::flag_seed_mode;
					if (disable_storage) p.storage = disabled_storage_constructor;
					if (share_mode) p.flags |= add_torrent_params::flag_share_mode;
					p.save_path = save_path;
					p.storage_mode = (storage_mode_t)allocation_mode;
					p.url = url;

					std::vector<char> buf;
					if (std::strstr(url, "magnet:") == url)
					{
						add_torrent_params tmp;
						parse_magnet_uri(url, tmp, ec);

						if (ec) continue;

						std::string filename = path_append(save_path, path_append(".resume"
								, to_hex(tmp.info_hash.to_string()) + ".resume"));

						load_file(filename, p.resume_data, ec);
					}

					printf("adding URL: %s\n", url);
					ses.async_add_torrent(p);
				}

				if (c == 'q') break;

				if (c == 'W' && h.is_valid())
				{
					std::set<std::string> seeds = h.url_seeds();
					for (std::set<std::string>::iterator i = seeds.begin()
						, end(seeds.end()); i != end; ++i)
					{
						h.remove_url_seed(*i);
					}

					seeds = h.http_seeds();
					for (std::set<std::string>::iterator i = seeds.begin()
						, end(seeds.end()); i != end; ++i)
					{
						h.remove_http_seed(*i);
					}
				}

				if (c == 'D' && h.is_valid())
				{
					torrent_status const& st = view.get_active_torrent();
					printf("\n\nARE YOU SURE YOU WANT TO DELETE THE FILES FOR '%s'. THIS OPERATION CANNOT BE UNDONE. (y/N)"
						, st.name.c_str());
					char response = 'n';
					scanf("%c", &response);
					if (response == 'y')
					{
						// also delete the .torrent file from the torrent directory
						handles_t::iterator i = std::find_if(files.begin(), files.end()
							, boost::bind(&handles_t::value_type::second, _1) == st.handle);
						if (i != files.end())
						{
							error_code ec;
							std::string path;
							if (is_absolute_path(i->first)) path = i->first;
							else path = path_append(monitor_dir, i->first);
							if (::remove(path.c_str()) < 0)
								printf("failed to delete .torrent file: %s\n", ec.message().c_str());
							files.erase(i);
						}
						if (st.handle.is_valid())
							ses.remove_torrent(st.handle, lt::session::delete_files);
					}
				}

				if (c == 'j' && h.is_valid())
				{
					h.force_recheck();
				}

				if (c == 'r' && h.is_valid())
				{
					h.force_reannounce();
				}

				if (c == 's' && h.is_valid())
				{
					torrent_status const& ts = view.get_active_torrent();
					h.set_sequential_download(!ts.sequential_download);
				}

				if (c == 'R')
				{
					// save resume data for all torrents
					std::vector<torrent_status> torrents;
					ses.get_torrent_status(&torrents, &yes, 0);
					for (std::vector<torrent_status>::iterator i = torrents.begin()
						, end(torrents.end()); i != end; ++i)
					{
						if (i->need_save_resume)
						{
							i->handle.save_resume_data();
							++num_outstanding_resume_data;
						}
					}
				}

				if (c == 'o' && h.is_valid())
				{
					torrent_status const& ts = view.get_active_torrent();
					int num_pieces = ts.num_pieces;
					if (num_pieces > 300) num_pieces = 300;
					for (int i = 0; i < num_pieces; ++i)
					{
						h.set_piece_deadline(i, (i+5) * 1000, torrent_handle::alert_when_available);
					}
				}

				if (c == 'v' && h.is_valid())
				{
					h.scrape_tracker();
				}

				if (c == 'p' && h.is_valid())
				{
					torrent_status const& ts = view.get_active_torrent();
					if (!ts.auto_managed && ts.paused)
					{
						h.auto_managed(true);
					}
					else
					{
						h.auto_managed(false);
						h.pause(torrent_handle::graceful_pause);
					}
				}

				// toggle force-start
				if (c == 'k' && h.is_valid())
				{
					torrent_status const& ts = view.get_active_torrent();
					h.auto_managed(!ts.auto_managed);
					if (ts.auto_managed && ts.paused) h.resume();
				}

				if (c == 'c' && h.is_valid())
				{
					h.clear_error();
				}

				// toggle displays
				if (c == 't') print_trackers = !print_trackers;
				if (c == 'i') print_peers = !print_peers;
				if (c == 'l') print_log = !print_log;
				if (c == 'd') print_downloads = !print_downloads;
				if (c == 'y') print_matrix = !print_matrix;
				if (c == 'f') print_file_progress = !print_file_progress;
				if (c == 'P') show_pad_files = !show_pad_files;
				if (c == 'g') show_dht_status = !show_dht_status;
				if (c == 'u') ses_view.print_utp_stats(!ses_view.print_utp_stats());
				if (c == 'x') print_disk_stats = !print_disk_stats;
				// toggle columns
				if (c == '1') print_ip = !print_ip;
				if (c == '3') print_timers = !print_timers;
				if (c == '4') print_block = !print_block;
				if (c == '5') print_peer_rate = !print_peer_rate;
				if (c == '6') print_fails = !print_fails;
				if (c == '7') print_send_bufs = !print_send_bufs;
				if (c == 'C')
				{
					cache_size = (cache_size == 0) ? -1 : 0;
					settings_pack p;
					p.set_int(settings_pack::cache_size, cache_size);
					ses.apply_settings(p);
				}
				if (c == 'h')
				{
					clear_screen();
					set_cursor_pos(0,0);
					print(
						"HELP SCREEN (press any key to dismiss)\n\n"
						"CLIENT OPTIONS\n"
						"[q] quit client                                 [m] add magnet link\n"
						"\n"
						"TORRENT ACTIONS\n"
						"[p] pause/resume selected torrent               [C] toggle disk cache\n"
						"[s] toggle sequential download                  [j] force recheck\n"
						"[space] toggle session pause                    [c] clear error\n"
						"[v] scrape                                      [D] delete torrent and data\n"
						"[r] force reannounce                            [R] save resume data for all torrents\n"
						"[o] set piece deadlines (sequential dl)         [P] toggle auto-managed\n"
						"[k] toggle force-started                        [W] remove all web seeds\n"
						"\n"
						"DISPLAY OPTIONS\n"
						"left/right arrow keys: select torrent filter\n"
						"up/down arrow keys: select torrent\n"
						"[i] toggle show peers                           [d] toggle show downloading pieces\n"
						"[u] show uTP stats                              [f] toggle show files\n"
						"[g] show DHT                                    [x] toggle disk cache stats\n"
						"[t] show trackers                               [l] toggle show log\n"
						"[P] show pad files (in file list)               [y] toggle show piece matrix\n"
						"\n"
						"COLUMN OPTIONS\n"
						"[1] toggle IP column                            [2]\n"
						"[3] toggle timers column                        [4] toggle block progress column\n"
						"[5] toggle peer rate column                     [6] toggle failures column\n"
						"[7] toggle send buffers column\n"
						);
					int tmp;
					while (sleep_and_input(&tmp, 500) == false);
				}

			} while (sleep_and_input(&c, 0));
			if (c == 'q') break;
		}

		// loop through the alert queue to see if anything has happened.
		std::vector<alert*> alerts;
		ses.pop_alerts(&alerts);
		std::string now = timestamp();
		for (std::vector<alert*>::iterator i = alerts.begin()
			, end(alerts.end()); i != end; ++i)
		{
			TORRENT_TRY
			{
				if (!::handle_alert(view, ses_view, ses, *i, files, non_files))
				{
					// if we didn't handle the alert, print it to the log
					std::string event_string;
					print_alert(*i, event_string);
					events.push_back(event_string);
					if (events.size() >= 20) events.pop_front();
				}
			} TORRENT_CATCH(std::exception& e) {}
		}
		alerts.clear();

		std::string out;

		char str[500];

		int pos = view.height() + ses_view.height();
		set_cursor_pos(0, pos);

		int cache_flags = print_downloads ? 0 : lt::session::disk_cache_no_pieces;
		torrent_handle h = view.get_active_handle();

		cache_status cs;
		ses.get_cache_info(&cs, h, cache_flags);

#ifndef TORRENT_DISABLE_DHT
		if (show_dht_status)
		{
			// TODO: 3 expose these counters as performance counters
/*
			snprintf(str, sizeof(str), "DHT nodes: %d DHT cached nodes: %d "
				"total DHT size: %" PRId64 " total observers: %d\n"
				, sess_stat.dht_nodes, sess_stat.dht_node_cache, sess_stat.dht_global_nodes
				, sess_stat.dht_total_allocations);
			out += str;
*/

			int bucket = 0;
			for (std::vector<dht_routing_bucket>::iterator i = dht_routing_table.begin()
				, end(dht_routing_table.end()); i != end; ++i, ++bucket)
			{
				char const* progress_bar =
					"################################"
					"################################"
					"################################"
					"################################";
				char const* short_progress_bar = "--------";
				snprintf(str, sizeof(str)
					, "%3d [%3d, %d] %s%s\x1b[K\n"
					, bucket, i->num_nodes, i->num_replacements
					, progress_bar + (128 - i->num_nodes)
					, short_progress_bar + (8 - (std::min)(8, i->num_replacements)));
				out += str;
				pos += 1;
			}

			for (std::vector<dht_lookup>::iterator i = dht_active_requests.begin()
				, end(dht_active_requests.end()); i != end; ++i)
			{
				snprintf(str, sizeof(str)
					, "  %10s [limit: %2d] "
					"in-flight: %-2d "
					"left: %-3d "
					"1st-timeout: %-2d "
					"timeouts: %-2d "
					"responses: %-2d "
					"last_sent: %-2d\x1b[K\n"
					, i->type
					, i->branch_factor
					, i->outstanding_requests
					, i->nodes_left
					, i->first_timeout
					, i->timeouts
					, i->responses
					, i->last_sent);
				out += str;
				pos += 1;
			}
		}
#endif
		if (h.is_valid())
		{
			torrent_status const& s = view.get_active_torrent();

			print((piece_bar(s.pieces, 126) + "\x1b[K\n").c_str());
			pos += 1;

			if ((print_downloads && s.state != torrent_status::seeding)
				|| print_peers)
				h.get_peer_info(peers);

			if (print_peers && !peers.empty())
				pos += print_peer_info(out, peers, terminal_height - pos - 2);

			if (print_trackers)
			{
				snprintf(str, sizeof(str), "next_announce: %4" PRId64 " | current tracker: %s\x1b[K\n"
					, boost::int64_t(duration_cast<seconds>(s.next_announce).count())
					, s.current_tracker.c_str());
				out += str;
				pos += 1;
				std::vector<announce_entry> tr = h.trackers();
				time_point now = clock_type::now();
				for (std::vector<announce_entry>::iterator i = tr.begin()
					, end(tr.end()); i != end; ++i)
				{
					if (pos + 1 >= terminal_height) break;
					snprintf(str, sizeof(str), "%2d %-55s fails: %-3d (%-3d) %s %s %5d \"%s\" %s\x1b[K\n"
						, i->tier, i->url.c_str(), i->fails, i->fail_limit, i->verified?"OK ":"-  "
						, i->updating?"updating"
							:to_string(int(total_seconds(i->next_announce - now)), 8).c_str()
						, int(i->min_announce > now ? total_seconds(i->min_announce - now) : 0)
						, i->last_error ? i->last_error.message().c_str() : ""
						, i->message.c_str());
					out += str;
					pos += 1;
				}
			}

			if (print_matrix)
			{
				int height = 0;
				print(piece_matrix(s.pieces, terminal_width, &height).c_str());
				pos += height;
			}

			if (print_downloads)
			{
				h.get_download_queue(queue);

				std::sort(queue.begin(), queue.end(), boost::bind(&partial_piece_info::piece_index, _1)
					< boost::bind(&partial_piece_info::piece_index, _2));

				std::sort(cs.pieces.begin(), cs.pieces.end(), boost::bind(&cached_piece_info::piece, _1)
					> boost::bind(&cached_piece_info::piece, _2));

				int p = 0; // this is horizontal position
				for (std::vector<cached_piece_info>::iterator i = cs.pieces.begin();
					i != cs.pieces.end(); ++i)
				{
					if (pos + 3 >= terminal_height) break;

					partial_piece_info* pp = 0;
					partial_piece_info tmp;
					tmp.piece_index = i->piece;
					std::vector<partial_piece_info>::iterator ppi
						= std::lower_bound(queue.begin(), queue.end(), tmp
						, boost::bind(&partial_piece_info::piece_index, _1)
						< boost::bind(&partial_piece_info::piece_index, _2));
					if (ppi != queue.end() && ppi->piece_index == i->piece) pp = &*ppi;

					print_piece(pp, &*i, peers, &s, out);

					int num_blocks = pp ? pp->blocks_in_piece : i->blocks.size();
					p += num_blocks + 8;
					bool continuous_mode = 8 + num_blocks > terminal_width;
					if (continuous_mode)
					{
						while (p > terminal_width)
						{
							p -= terminal_width;
							++pos;
						}
					}
					else if (p + num_blocks + 8 > terminal_width)
					{
						out += "\x1b[K\n";
						pos += 1;
						p = 0;
					}

					if (pp) queue.erase(ppi);
				}

				for (std::vector<partial_piece_info>::iterator i = queue.begin()
					, end(queue.end()); i != end; ++i)
				{
					if (pos + 3 >= terminal_height) break;

					print_piece(&*i, 0, peers, &s, out);

					int num_blocks = i->blocks_in_piece;
					p += num_blocks + 8;
					bool continuous_mode = 8 + num_blocks > terminal_width;
					if (continuous_mode)
					{
						while (p > terminal_width)
						{
							p -= terminal_width;
							++pos;
						}
					}
					else if (p + num_blocks + 8 > terminal_width)
					{
						out += "\x1b[K\n";
						pos += 1;
						p = 0;
					}
				}
				if (p != 0)
				{
					out += "\x1b[K\n";
					pos += 1;
				}

				snprintf(str, sizeof(str), "%s %s read cache | %s %s downloading | %s %s cached | %s %s flushed | %s %s snubbed\x1b[K\n"
					, esc("34;7"), esc("0") // read cache
					, esc("33;7"), esc("0") // downloading
					, esc("36;7"), esc("0") // cached
					, esc("32;7"), esc("0") // flushed
					, esc("35;7"), esc("0") // snubbed
					);
				out += str;
				pos += 1;
			}

			if (print_file_progress && s.has_metadata)
			{
				std::vector<boost::int64_t> file_progress;
				h.file_progress(file_progress);
				std::vector<pool_file_status> file_status;
				h.file_status(file_status);
				std::vector<int> file_prio = h.file_priorities();
				std::vector<pool_file_status>::iterator f = file_status.begin();
				boost::shared_ptr<const torrent_info> ti = h.torrent_file();

				int p = 0; // this is horizontal position
				for (int i = 0; i < ti->num_files(); ++i)
				{
					if (pos + 1 >= terminal_height) break;

					bool pad_file = ti->files().pad_file_at(i);
					if (pad_file)
					{
						if (show_pad_files)
						{
							snprintf(str, sizeof(str), "\x1b[34m%-70s %s\x1b[0m\x1b[K\n"
								, ti->files().file_name(i).c_str()
								, add_suffix(ti->files().file_size(i)).c_str());
							out += str;
							pos += 1;
						}
						continue;
					}

					int progress = ti->files().file_size(i) > 0
						?file_progress[i] * 1000 / ti->files().file_size(i):1000;

					bool complete = file_progress[i] == ti->files().file_size(i);

					std::string title = ti->files().file_name(i);
					if (!complete)
					{
						snprintf(str, sizeof(str), " (%.1f%%)", progress / 10.f);
						title += str;
					}

					if (f != file_status.end() && f->file_index == i)
					{
						title += " [ ";
						if ((f->open_mode & file::rw_mask) == file::read_write) title += "read/write ";
						else if ((f->open_mode & file::rw_mask) == file::read_only) title += "read ";
						else if ((f->open_mode & file::rw_mask) == file::write_only) title += "write ";
						if (f->open_mode & file::random_access) title += "random_access ";
						if (f->open_mode & file::lock_file) title += "locked ";
						if (f->open_mode & file::sparse) title += "sparse ";
						title += "]";
						++f;
					}

					const int file_progress_width = 65;

					// do we need to line-break?
					if (p + file_progress_width + 13 > terminal_width)
					{
						out += "\x1b[K\n";
						pos += 1;
						p = 0;
					}

					snprintf(str, sizeof(str), "%s %7s p: %d ",
						progress_bar(progress, file_progress_width, complete ? col_green : col_yellow, '-', '#'
							, title.c_str()).c_str()
						, add_suffix(file_progress[i]).c_str()
						, file_prio[i]);

					p += file_progress_width + 13;
					out += str;
				}

				if (p != 0)
				{
					out += "\x1b[K\n";
					pos += 1;
				}
			}
		}

		if (print_log)
		{
			for (std::deque<std::string>::iterator i = events.begin();
				i != events.end(); ++i)
			{
				if (pos + 1 >= terminal_height) break;
				out += *i;
				out += "\x1b[K\n";
				pos += 1;
			}
		}

		// clear rest of screen
		out += "\x1b[J";
		print(out.c_str());

		fflush(stdout);

		if (!monitor_dir.empty()
			&& next_dir_scan < clock_type::now())
		{
			scan_dir(monitor_dir, ses, files, non_files
				, allocation_mode, save_path, torrent_upload_limit
				, torrent_download_limit);
			next_dir_scan = clock_type::now() + seconds(poll_interval);
		}
	}

	ses.pause();
	printf("saving resume data\n");
	std::vector<torrent_status> temp;
	ses.get_torrent_status(&temp, &yes, 0);
	for (std::vector<torrent_status>::iterator i = temp.begin();
		i != temp.end(); ++i)
	{
		torrent_status& st = *i;
		if (!st.handle.is_valid())
		{
			printf("  skipping, invalid handle\n");
			continue;
		}
		if (!st.has_metadata)
		{
			printf("  skipping %s, no metadata\n", st.name.c_str());
			continue;
		}
		if (!st.need_save_resume)
		{
			printf("  skipping %s, resume file up-to-date\n", st.name.c_str());
			continue;
		}

		// save_resume_data will generate an alert when it's done
		st.handle.save_resume_data();
		++num_outstanding_resume_data;
		printf("\r%d  ", num_outstanding_resume_data);
	}
	printf("\nwaiting for resume data [%d]\n", num_outstanding_resume_data);

	while (num_outstanding_resume_data > 0)
	{
		alert const* a = ses.wait_for_alert(seconds(10));
		if (a == 0) continue;

		std::vector<alert*> alerts;
		ses.pop_alerts(&alerts);
		std::string now = timestamp();
		for (std::vector<alert*>::iterator i = alerts.begin()
			, end(alerts.end()); i != end; ++i)
		{
			if (!::handle_alert(view, ses_view, ses, *i, files, non_files))
			{
				// if we didn't handle the alert, print it to the log
				std::string event_string;
				print_alert(*i, event_string);
			}
		}
	}

	if (g_log_file) fclose(g_log_file);

	// we're just saving the DHT state
#ifndef TORRENT_DISABLE_DHT
	printf("\nsaving session state\n");
	{
		entry session_state;
		ses.save_state(session_state, session::save_dht_state);

		std::vector<char> out;
		bencode(std::back_inserter(out), session_state);
		save_file(".ses_state", out);
	}
#endif

	printf("closing session");

	return 0;
}


text:
/*--------------------------------------------------*/

#import "___FILEBASENAME___.h"

/*--------------------------------------------------*/

static NSString* ___FILEBASENAMEASIDENTIFIER___ServerUrl = @"http://httpbin.org/";

/*--------------------------------------------------*/

@interface ___FILEBASENAMEASIDENTIFIER___ ()

+ (MobilyApiProvider*)___FILEBASENAMEASIDENTIFIER___Provider;

@end

/*--------------------------------------------------*/
#pragma mark -
/*--------------------------------------------------*/

@implementation ___FILEBASENAMEASIDENTIFIER___

#pragma mark Property

+ (MobilyApiProvider*)___FILEBASENAMEASIDENTIFIER___Provider {
    static MobilyApiProvider* ___FILEBASENAMEASIDENTIFIER___Provider = nil;
    if(___FILEBASENAMEASIDENTIFIER___Provider == nil) {
        ___FILEBASENAMEASIDENTIFIER___Provider = [[MobilyApiProvider alloc] initWithName:@"___FILEBASENAMEASIDENTIFIER___Provider" url:[NSURL URLWithString:___FILEBASENAMEASIDENTIFIER___ServerUrl]];
        [[MobilyApiManager shared] registerProvider:___FILEBASENAMEASIDENTIFIER___Provider];
    }
    return ___FILEBASENAMEASIDENTIFIER___Provider;
}

#pragma mark Public

+ (void)exampleRequestSuccess:(ApiSuccess)success failure:(ApiFailure)failure {
    [self.___FILEBASENAMEASIDENTIFIER___Provider sendRequest:[[MobilyApiRequest alloc] initWithGetRelativeUrl:@"/get"]
                                    byTarget:self
                               completeBlock:^(MobilyApiRequest* request, MobilyApiResponse* response) {
                                   if(response.httpError == nil) {
                                       if(success != nil) {
                                           success();
                                       }
                                   } else {
                                       if(failure != nil) {
                                           failure(@"error", response.httpError);
                                       }
                                   }
                               }];
}

@end

/*--------------------------------------------------*/

redpajama_set_name: RedPajamaGithub


text:
import gc
import sys
import unittest
import weakref

import greenlet

class GCTests(unittest.TestCase):
    def test_circular_greenlet(self):
        class circular_greenlet(greenlet.greenlet):
            pass
        o = circular_greenlet()
        o.self = o
        o = weakref.ref(o)
        gc.collect()
        self.assertTrue(o() is None)
        self.assertFalse(gc.garbage, gc.garbage)

    def test_dead_circular_ref(self):
        o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch())
        gc.collect()
        self.assertTrue(o() is None)
        self.assertFalse(gc.garbage, gc.garbage)

    if greenlet.GREENLET_USE_GC:
        # These only work with greenlet gc support

        def test_inactive_ref(self):
            class inactive_greenlet(greenlet.greenlet):
                def __init__(self):
                    greenlet.greenlet.__init__(self, run=self.run)

                def run(self):
                    pass
            o = inactive_greenlet()
            o = weakref.ref(o)
            gc.collect()
            self.assertTrue(o() is None)
            self.assertFalse(gc.garbage, gc.garbage)

        def test_finalizer_crash(self):
            # This test is designed to crash when active greenlets
            # are made garbage collectable, until the underlying
            # problem is resolved. How does it work:
            # - order of object creation is important
            # - array is created first, so it is moved to unreachable first
            # - we create a cycle between a greenlet and this array
            # - we create an object that participates in gc, is only
            #   referenced by a greenlet, and would corrupt gc lists
            #   on destruction, the easiest is to use an object with
            #   a finalizer
            # - because array is the first object in unreachable it is
            #   cleared first, which causes all references to greenlet
            #   to disappear and causes greenlet to be destroyed, but since
            #   it is still live it causes a switch during gc, which causes
            #   an object with finalizer to be destroyed, which causes stack
            #   corruption and then a crash
            class object_with_finalizer(object):
                def __del__(self):
                    pass
            array = []
            parent = greenlet.getcurrent()
            def greenlet_body():
                greenlet.getcurrent().object = object_with_finalizer()
                try:
                    parent.switch()
                finally:
                    del greenlet.getcurrent().object
            g = greenlet.greenlet(greenlet_body)
            g.array = array
            array.append(g)
            g.switch()
            del array
            del g
            greenlet.getcurrent()
            gc.collect()


text:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.virginia.cs.utility;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

/**
 *
 * @author Wasi
 */
public class TxtFileReader {

    public static ArrayList<String> readFile(String filename, int numberOfLines) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF-8"));
            ArrayList<String> lines = new ArrayList<>();
            String line;
            int counter = 0;
            while ((line = reader.readLine()) != null) {
                if (counter == numberOfLines) {
                    break;
                }
                line = line.trim();
                if (line.isEmpty()) {
                    continue;
                }
                lines.add(line);
                counter++;
            }
            reader.close();
            return lines;
        } catch (IOException e) {
            System.err.format("[Error]Failed to open file %s!", filename);
            return null;
        }
    }
}


text:
To deploy a DigitalOcean droplet in the `sfo1` zone of size
`512mb` as a `Worker`:

```
deployment.deploy(new Machine({
  provider: "DigitalOcean",
  region: "sfo1",
  size: "512mb",
  role: "Worker"
}));
```

## Setup

1. Create a new key [here](https://cloud.digitalocean.com/settings/api/tokens).
Both read and write permissions are required.

2. Save the key in `~/.digitalocean/key` on the machine that will be running the
Quilt daemon.

## Floating IPs
To assign a floating IP to a machine, simply specify the IP as an attribute. For example,

```
deployment.deploy(new Machine({
  provider: "DigitalOcean",
  region: "sfo1",
  size: "512mb",
  floatingIp: "8.8.8.8",
  role: "Worker"
}));
```

Creating a floating IP is slightly unintuitive. Unless there are already
droplets running, the floating IP tab under "Networking" doesn't allow users to
create floating IPs. However, [this
link](https://cloud.digitalocean.com/networking/floating_ips/datacenter) can be
used to reserve IPs for a specific datacenter. If that link breaks, floating
IPs can always be created by creating a droplet, _then_ assigning it a new
floating IP. The floating IP will still be reserved for use after
disassociating it.

Note that DigitalOcean charges a fee of $.0006/hr for floating IPs that have
been reserved, but are not associated with a droplet.


text:
package org.apereo.cas;

import org.apereo.cas.authentication.AuthenticatedLdapAuthenticationHandlerTests;
import org.apereo.cas.authentication.DirectLdapAuthenticationHandlerTests;
import org.apereo.cas.authentication.LdapPasswordSynchronizationAuthenticationPostProcessorTests;
import org.apereo.cas.authentication.principal.PersonDirectoryPrincipalResolverLdaptiveTests;

import org.junit.platform.suite.api.SelectClasses;

/**
 * Test suite to run all LDAP tests.
 *
 * @author Misagh Moayyed
 * @since 4.1.0
 */
@SelectClasses({
    AuthenticatedLdapAuthenticationHandlerTests.class,
    PersonDirectoryPrincipalResolverLdaptiveTests.class,
    DirectLdapAuthenticationHandlerTests.class,
    LdapPasswordSynchronizationAuthenticationPostProcessorTests.class
})
public class AllLdapTestsSuite {
}


text:
<!DOCTYPE html>

    <title>Touch Activity Experiment</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="apple-mobile-web-app-capable" content="no" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="css/style.css">

Touch Activity Experiment

<button>實驗A</button>

<button>實驗B</button>

<button>實驗C</button>


text:
import os
from memorious.core import manager

def init():
    file_path = os.path.dirname(__file__)
    config_path = os.path.join(file_path, "..", "..", "config")
    manager.load_path(config_path)


text:
<?php

declare(strict_types=1);

require_once(dirname(__DIR__) . "/vendor/autoload.php");


text:
echo "preparing the rdp classifier..."
module load rdp_classifier_2.2
export RDP_JAR_PATH=/opt/rdp_classifier/2.2/rdp_classifier-2.2.jar
# get RDP taxonomy for each sequence
echo "assigning taxonomy in directory: " taxbiom "-$1"
assign_taxonomy.py -i $1.seqs.fa -m rdp -o taxbiom-$1
# add header line to output:
echo "Copying header files"
#cp ~/data/other/taxheader.txt taxbiom-$1/withheader.txt
printf "#OTUID\ttaxonomy\tconfidence\n" > taxbiom-$1/withheader.txt
cat taxbiom-$1/$1.seqs_tax_assignments.txt >> taxbiom-$1/withheader.txt
# add the taxonomy data to the biom table
echo "Adding the taxonomy to biom table: " $1 ".withtax.biom"
biom add-metadata -i $1.biom -o $1.withtax.biom --observation-metadata-fp taxbiom-$1/withheader.txt --observation-header OTUID,taxonomy --sc-separated taxonomy


text:
ACCEPTED

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
Sida 16:102. 1994

#### Original name
Myrica californica Cham.

### Remarks
null


text:
You'll need:
 - Python 3.6
 - Database like Postgresql is optionnal if you use Sublimall for personnal or few users

## Installation

```
cd /var/www
git clone https://github.com/toxinu/sublimall-server.git sublimall
cd sublimall
virtualenv -p /usr/bin/python3 venv
source venv/bin/activate
pip install -r requirements.txt
cp sublimall/local_settings_example.py sublimall/local_settings.py
./manage.py migrate
./manage.py createsuperuser
pip install gunicorn
```

## Deployment

I recommend using whatever software you are most familiar with for managing Sublimall process. For me, that software of choice is [Supervisor][0].
Configuring Supervisor couldn't be more simple. Just point it to the sentry executable in your virtualenv's bin/ folder and you're good to go.

If you want to use only for you or small team you can change `MAX_MEMBER` in your `local_settings.py` file.

```
[program:sublimall]
directory=/var/www/sublimall
command=/var/www/sublimall/venv/bin/gunicorn sublimall.wsgi:application --log-file=-
autostart=true
autorestart=true
redirect_stderr=true
```

For nginx, this is a production server configuration file dump:

```
server {
    listen 80;
    server_name example.com;

    error_log /var/log/nginx/sublimall.error.log;
    access_log /var/log/nginx/sublimall.access.log;

    client_max_body_size 150m;

    location /api {
        proxy_hide_header Server;

        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Ssl on;
        proxy_pass http://127.0.0.1:9002;
    }

    location / {
        rewrite ^ https://example.com$request_uri permanent;
    }
}
server {
    listen 443 ssl spdy;
    server_name example.com;

    ssl_certificate /etc/nginx/ssl/sublimall.public.crt;
    ssl_certificate_key /etc/nginx/ssl/sublimall.private.rsa;

    error_log /var/log/nginx/sublimall.error.log;
    access_log /var/log/nginx/sublimall.access.log;

    if ($http_host != "sublimall.org") {
        rewrite ^ https://example.com$request_uri permanent;
    }

    location /api {
        rewrite ^ http://example.com$request_uri permanent;
    }

    location /static {
        autoindex on;
        root /var/www/sublimall;
    }

    location / {
        proxy_hide_header Server;

        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Ssl on;
        proxy_pass http://127.0.0.1:9002;
    }
}
```

As you can see, configuration file include ssl, which you can drop easily.

## Plugin

And you just have to change your Sublime Text plugin settings.

```
"api_root_url": "http://<ip>:<port>",
```

[0]: http://supervisord.org/


text:
<!doctype html>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=0">
<title>test</title>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
<base target="_blank">


text:
import os
import io
from random import shuffle

def CreateTrainDev(in_direct, out_direct_train, out_direct_test, train_ratio, test_ratio, train_doc_file, out_train_tbl):

	cores = 2
	kerntype = "epanech"
	kern_dist = 100000
	file_type = "lgl"

	def SplitFiles(in_direct, out_direct_train, out_direct_test, train_ratio, test_ratio):
		train_files = 0
		test_files = 0

		if not os.path.exists(out_direct_train):
			os.makedirs(out_direct_train)
		if not os.path.exists(out_direct_test):
			os.makedirs(out_direct_test)

		files = os.listdir(in_direct)

		shuffle(files)

		#print files

		for f in files:
			test_xml = in_direct + "/" + f
			if float(test_files) <= float(train_files) * test_ratio and train_files >= 1:
				ouf = out_direct_test+"/"+f
				with io.open(ouf, 'w', encoding='utf-8') as w:
					rf = io.open(test_xml, 'r', encoding='utf-8')
					w.write(rf.read())
					rf.close()
				test_files += 1
			else:
				ouf = out_direct_train+"/"+f
				with io.open(ouf, 'w', encoding='utf-8') as w:
					rf = io.open(test_xml, 'r', encoding='utf-8')
					w.write(rf.read())
					rf.close()
				train_files += 1
		print "Test Files :", test_files
		print "Train Files: ", train_files

	SplitFiles(in_direct, out_direct_train, out_direct_test, train_ratio, test_ratio)

	#Create Pseudo-Documents from Toponyms
	import PseudoDocCreator as PSD
	#PSD.calc(out_direct_train, train_doc_file, 100, file_type)

	#Create Document Table
	import LoadDBV1 as LDB
	#LDB.Load(train_doc_file, out_train_tbl, conn_info, "wiki")

	#Calc Local Stats Tables
	import LocalSpatialStatsV1 as LS
	train_tbl_part1 = out_train_tbl+"_kernel"+str(kern_dist/1000)+"k"+"_"+kerntype
	LS.calc(train_doc_file, "gi", out_train_tbl, gtbl, conn_info, "DummyOutfile.txt", train_tbl_part1, kern_dist, kerntype, "wiki", False, "any", 0, cores, False)
	#LSS.calc(f, statistic, dtbl, gtbl, conn_info, outf, out_tbl, kern_dist, kerntype, traintype, listuse, whitelist_file, grid_min, cores, include_zero)
	train_tbl = train_tbl_part1 + "_gi"
	return train_tbl, out_direct_test

mode = "lgl"
outfile = "LGL_theta_Results_devsplit3.txt"
out_domain_stat_tbl = ""
conn_info = "dbname=topodb user=postgres host='localhost' port='5433' password='grant'"
gtbl = "globalgrid_5_clip_geog"
window = 15
percentile = 1.0
country_tbl = "countries_2012"
region_tbl = "regions_2012"
state_tbl = "states_2012"
geonames_tbl = "geonames_all"

if mode == "trconll":

	########Optimize for TR-CoNLL###########
	import TestResolver_TRCONLL_allits_Thetas as TR
	tst_tbl = "trconllf_dev"

	lamb_wiki = 0.9
	lamb_trconll = 0.1

	in_direct = "/home/grant/devel/TopCluster/trconllf/xml/dev"
	out_direct_train = "/home/grant/devel/TopCluster/trconllf/xml/dev_trainsplit1"
	out_direct_test = "/home/grant/devel/TopCluster/trconllf/xml/dev_testsplit1"
	train_ratio = .80
	test_ratio = .20
	#train_doc_file = "/home/grant/devel/TopCluster/trconllf/dev_trainsplit2_docfile.txt"
	out_train_tbl = "trconllf_dev_trainsplit1"

	it_size = 0.1
	train_tbl = "trconllf_dev_trainsplit1_kernel100k_epanech_gi"
	test_xml = "/home/grant/devel/TopCluster/trconllf/xml/dev_testsplit1"
	#train_tbl, test_xml = CreateTrainDev(in_direct, out_direct_train, out_direct_test, train_ratio, test_ratio, train_doc_file, out_train_tbl)

	#while lamb_wiki <= 1.0:

	TR.calc(train_tbl, out_domain_stat_tbl, test_xml, conn_info, gtbl, window, percentile, country_tbl, region_tbl, state_tbl, geonames_tbl, tst_tbl, lamb_trconll, lamb_wiki, outfile)

	#	#lamb_wiki += it_size
	#	#lamb_trconll += -1.0 * it_size

if mode == "cwar":
	########Optimize for Cwar###########
	import TestResolver_CWar_allits as TR
	tst_tbl = "cwar_dev"

	lamb_wiki = 0.0
	lamb_trconll = 1.0

	in_direct = "/home/grant/devel/TopCluster/cwar/cwar/xml/dev"
	#out_direct_train = "/home/grant/devel/TopCluster/cwar/cwar/xml/dev_trainsplit1"
	out_direct_train = "/home/grant/devel/TopCluster/cwar/cwar/xml/dev_trainsplit1"
	out_direct_test = "/home/grant/devel/TopCluster/cwar/cwar/xml/dev_testsplit1"
	train_ratio = .80
	test_ratio = .20
	train_doc_file = "/home/grant/devel/TopCluster/cwar/cwar/dev_trainsplit1_docfile.txt"
	out_train_tbl = "cwar_dev_trainsplit1"

	it_size = 0.1
	train_tbl = "cwar_dev_trainsplit1_kernel100k_epanech_gi"
	test_xml = "/home/grant/devel/TopCluster/cwar/cwar/xml/dev_testsplit1"
	#train_tbl, test_xml = CreateTrainDev(in_direct, out_direct_train, out_direct_test, train_ratio, test_ratio, train_doc_file, out_train_tbl)

	TR.calc(train_tbl, out_domain_stat_tbl, test_xml, conn_info, gtbl, window, percentile, place_name_weight, country_tbl, region_tbl, state_tbl, geonames_tbl, tst_tbl, outfile)

if mode == "lgl":
	import TestResolver_LGL_allits_Thetas as TR
	tst_tbl = "lgl_dev_classic"

	lamb_wiki = 0.5
	lamb_lgl = 0.5

	in_direct = "/home/grant/Downloads/LGL/articles/dev_classicxml"
	#out_direct_train = "/home/grant/devel/TopCluster/cwar/cwar/xml/dev_trainsplit1"
	out_direct_train = "/home/grant/Downloads/LGL/articles/dev_trainsplit3"
	out_direct_test = "/home/grant/Downloads/LGL/articles/dev_testsplit3"
	train_ratio = .80
	test_ratio = .20
	train_doc_file = "/home/grant/Downloads/LGL/dev_trainsplit3_docfile.txt"
	out_train_tbl = "lgl_dev_trainsplit2"

	#it_size = 0.1
	train_tbl = "lgl_dev_trainsplit3_kernel100k_epanech_gi"
	test_xml = "/home/grant/Downloads/LGL/articles/dev_testsplit3"
	#train_tbl, test_xml = CreateTrainDev(in_direct, out_direct_train, out_direct_test, train_ratio, test_ratio, train_doc_file, out_train_tbl)
	print "Done generating statistics tables"

	TR.calc(train_tbl, out_domain_stat_tbl, test_xml, conn_info, gtbl, window, percentile, country_tbl, region_tbl, state_tbl, geonames_tbl, tst_tbl, lamb_lgl, lamb_wiki, outfile)


text:
package com.mytest.imagematcher.ui;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;

import com.mytest.imagematcher.R;
import com.mytest.imagematcher.utils.ProjectPreferences;

import org.opencv.features2d.DescriptorExtractor;

public class SettingsActivity extends Activity {

	@SuppressWarnings("unused")
	private static RadioGroup descTypes;
	private static RadioButton brief, brisk, freak, orb;
	private static Button apply;
	private static EditText DIST_LIMIT, MIN_MATCHES;
	private static int descriptor, min_dist, min_matches;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_settings);
        final ProjectPreferences pref = ProjectPreferences.getInstance();
		descTypes = (RadioGroup) findViewById(R.id.radioGroup1);
		brief = (RadioButton) findViewById(R.id.radio0);
		brisk = (RadioButton) findViewById(R.id.radio1);
		freak = (RadioButton) findViewById(R.id.radio2);
		orb = (RadioButton) findViewById(R.id.radio3);
		apply = (Button) findViewById(R.id.button1);
		DIST_LIMIT = (EditText) findViewById(R.id.editText1);
		MIN_MATCHES = (EditText) findViewById(R.id.editText2);

        descriptor = pref.getDescriptor();
        min_dist = pref.getMinDist();
        min_matches = pref.getMinMatches();
        DIST_LIMIT.setText(min_dist + "");
        MIN_MATCHES.setText(min_matches + "");
        switch (descriptor) {
            case 3:
                orb.setChecked(true);
                break;
            case 4:
                brief.setChecked(true);
                break;
            case 5:
                brisk.setChecked(true);
                break;
            case 6:
                freak.setChecked(true);
                break;
        }

        apply.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                if (brief.isChecked())
                    descriptor = DescriptorExtractor.BRIEF;
                else if (brisk.isChecked())
                    descriptor = DescriptorExtractor.BRISK;
                else if (freak.isChecked())
                    descriptor = DescriptorExtractor.FREAK;
                else if (orb.isChecked())
                    descriptor = DescriptorExtractor.ORB;
                try {
                    min_dist = Integer.parseInt(DIST_LIMIT.getText().toString());
                    min_matches = Integer.parseInt(MIN_MATCHES.getText().toString());
                } catch (Exception e) {
                    e.printStackTrace();
                    min_dist = 80;
                    min_matches=100;
                }
                ProjectPreferences.getInstance().applyMachSettings(descriptor, min_dist, min_matches);
                finish();
            }
        });

		apply.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				int descriptor = 0, min_dist = 80, min_matches=100;
				if (brief.isChecked())
					descriptor = DescriptorExtractor.BRIEF;
				else if (brisk.isChecked())
					descriptor = DescriptorExtractor.BRISK;
				else if (freak.isChecked())
					descriptor = DescriptorExtractor.FREAK;
				else if (orb.isChecked())
					descriptor = DescriptorExtractor.ORB;
				try {
					min_dist = Integer.parseInt(DIST_LIMIT.getText().toString());
                    min_matches = Integer.parseInt(MIN_MATCHES.getText().toString());
				} catch (Exception e) {
					e.printStackTrace();
				}

                ProjectPreferences pref = ProjectPreferences.getInstance();
                pref.applyMachSettings(descriptor, min_dist, min_matches);
		        finish();
			}
		});
	}

	@Override
	protected void onNewIntent(Intent newIntent) {
		super.onNewIntent(newIntent);

	}

}


text:
BEGIN;

CREATE OR REPLACE VIEW cookbook_versions_by_rank(
    -- Cookbook Version fields
    major, -- these 3 are needed for version information (duh)
    minor,
    patch,
    version, -- concatenated string of the complete version
    serialized_object, -- needed to access recipe manifest

    -- Cookbook fields
    org_id, -- used for filtering
    name, -- both version and recipe queries require the cookbook name

    -- View-specific fields
    -- (also used for filtering)
    rank) AS
SELECT v.major,
       v.minor,
       v.patch,
       v.major || '.' || v.minor || '.' || v.patch,
       v.serialized_object,
       c.org_id,
       c.name,
       rank() OVER (PARTITION BY v.cookbook_id
                    ORDER BY v.major DESC, v.minor DESC, v.patch DESC)
FROM cookbooks AS c
JOIN cookbook_versions AS v
  ON c.id = v.cookbook_id;

COMMIT;


text:
namespace StockPriceSynEverydate
{
    using System;
    using System.Collections.Generic;

    public partial class stox_tb_StocksInfo
    {
        public long ID { get; set; }
        public Nullable<int> stock_info_id { get; set; }
        public System.DateTime trading_date { get; set; }
        public string time { get; set; }
        public Nullable<int> stock_id { get; set; }
        public string code { get; set; }
        public byte stock_type { get; set; }
        public Nullable<decimal> total_listing_qtty { get; set; }
        public Nullable<decimal> trading_unit { get; set; }
        public Nullable<byte> listting_status { get; set; }
        public Nullable<decimal> adjust_qtty { get; set; }
        public Nullable<byte> reference_status { get; set; }
        public Nullable<double> adjust_rate { get; set; }
        public Nullable<double> divident_rate { get; set; }
        public Nullable<byte> status { get; set; }
        public Nullable<decimal> total_room { get; set; }
        public Nullable<decimal> current_room { get; set; }
        public Nullable<decimal> basic_price { get; set; }
        public Nullable<decimal> open_price { get; set; }
        public Nullable<decimal> close_price { get; set; }
        public Nullable<decimal> current_price { get; set; }
        public Nullable<decimal> current_qtty { get; set; }
        public Nullable<decimal> highest_price { get; set; }
        public Nullable<decimal> lowest_price { get; set; }
        public Nullable<decimal> best_offer_price { get; set; }
        public Nullable<decimal> best_bid_price { get; set; }
        public Nullable<decimal> ceiling_price { get; set; }
        public Nullable<decimal> floor_price { get; set; }
        public Nullable<decimal> total_offer_qtty { get; set; }
        public Nullable<decimal> total_bid_qtty { get; set; }
        public Nullable<decimal> best_offer_qtty { get; set; }
        public Nullable<decimal> best_bid_qtty { get; set; }
        public Nullable<decimal> prior_price { get; set; }
        public Nullable<decimal> prior_close_price { get; set; }
        public Nullable<decimal> match_price { get; set; }
        public Nullable<decimal> match_qtty { get; set; }
        public Nullable<byte> deleted { get; set; }
        public Nullable<System.DateTime> date_created { get; set; }
        public Nullable<System.DateTime> date_modified { get; set; }
        public string modified_by { get; set; }
        public string created_by { get; set; }
        public string name { get; set; }
        public Nullable<int> parvalue { get; set; }
        public Nullable<int> floor_code { get; set; }
        public Nullable<decimal> match_value { get; set; }
        public Nullable<byte> is_calcindex { get; set; }
        public Nullable<byte> is_determinecl { get; set; }
        public Nullable<int> date_no { get; set; }
        public Nullable<int> offer_count { get; set; }
        public Nullable<int> bid_count { get; set; }
        public Nullable<decimal> average_price { get; set; }
        public Nullable<decimal> index_price { get; set; }
        public Nullable<decimal> prev_prior_price { get; set; }
        public Nullable<decimal> yieldmat { get; set; }
        public Nullable<decimal> prev_prior_close_price { get; set; }
        public Nullable<decimal> nm_total_traded_qtty { get; set; }
        public Nullable<decimal> nm_total_traded_value { get; set; }
        public Nullable<decimal> pt_match_qtty { get; set; }
        public Nullable<decimal> pt_match_price { get; set; }
        public Nullable<decimal> pt_total_traded_qtty { get; set; }
        public Nullable<decimal> pt_total_traded_value { get; set; }
        public Nullable<decimal> total_buy_trading_qtty { get; set; }
        public Nullable<int> buy_count { get; set; }
        public Nullable<decimal> total_buy_trading_value { get; set; }
        public Nullable<decimal> total_sell_trading_qtty { get; set; }
        public Nullable<int> sell_count { get; set; }
        public Nullable<decimal> total_sell_trading_value { get; set; }
        public Nullable<decimal> total_trading_qtty { get; set; }
        public Nullable<decimal> total_trading_value { get; set; }
        public Nullable<decimal> buy_foreign_qtty { get; set; }
        public Nullable<decimal> buy_foreign_value { get; set; }
        public Nullable<decimal> sell_foreign_qtty { get; set; }
        public Nullable<decimal> sell_foreign_value { get; set; }
        public Nullable<decimal> remain_foreign_qtty { get; set; }
        public Nullable<decimal> pt_yieldmat { get; set; }
        public Nullable<System.DateTime> dateReport { get; set; }
        public Nullable<double> ClosePrice_Adjusted { get; set; }
        public Nullable<double> Rate_Adjusted { get; set; }
        public Nullable<double> Highest_Adjusted { get; set; }
        public Nullable<double> Lowest_Adjusted { get; set; }
        public Nullable<double> OpenPrice_Adjusted { get; set; }
    }
}