// File: ixchow[P]http-tweak/tweak.cpp
// Function: tweak::sync()
void sync() {
	auto &internal = get_internal();
	std::unique_lock< std::mutex > lock(internal.mutex);

	if (!internal.server) internal.server = std::make_unique< http::server >(internal.port);

	//Read adjustments (and poll requests) from the server:
	internal.server->poll([&](http::request const &request, std::unique_ptr< http::response > response){
		if (request.method == "GET" && request.url == "/") {
			//serve UI:
			std::ifstream ui(internal.ui_file, std::ios::binary);
			std::ostringstream ss;
			ss << ui.rdbuf();
			response->body = ss.str();
		} else if (request.method == "GET" && request.url == "/tweaks") {
			//serve current state (...by registering a poll):
			internal.polls.emplace_back(0, std::move(response));
		} else if (request.method == "GET" && request.url.substr(0,8) == "/tweaks?") {
			//long poll:
			uint32_t serial = -1U;
			try {
				serial = std::stoul(request.url.substr(8));
			} catch (...) {
				std::cerr << "[tweak::sync()] got invalid serial in url '" + request.url + "'." << std::endl;
				serial = -1U;
			}
			if (serial != -1U) {
				internal.polls.emplace_back(std::stoul(request.url.substr(8)), std::move(response));
			}
		} else if (request.method == "POST" && request.url == "/tweaks") {
			//adjust current state
			//std::cout << "Got tweaks:\n" << request.body << std::endl; //DEBUG

			//looking at something like: {"name":"value","name2":"value2",...}

			std::string const &json = request.body;
			uint32_t i = 0;
			auto skip_wsp = [&json,&i]() {
				while (i < json.size()
					&& (json[i] == 0x09 || json[i] == 0x0A || json[i] == 0x0D || json[i] == 0x20)
					) ++i;
			};
			auto skip_char = [&json,&i](char c) -> bool {
				if (i >= json.size()) return false;
				if (json[i] != c) return false;
				++i;
				return true;
			};
			auto extract_string = [&json, &i](std::string *into) -> bool {
				if (i >= json.size() || json[i] != '"') return false;
				uint32_t begin = i;
				++i;
				while (i < json.size() && json[i] != '"') {
					if (json[i] == '\\') ++i;
					++i;
				}
				if (i >= json.size()) return false;
				assert(json[i] == '"');
				++i;
				uint32_t end = i;
				std::string data = json.substr(begin, end - begin);
				std::string err = "";
				if (!json_to_utf8(data, into, &err)) {
					std::cerr << "Error decoding json string: " << err << std::endl;
					return false;
				}
				return true;
			};
			skip_wsp();
			if (!skip_char('{')) {
				std::cerr << "Missing opening '{'" << std::endl;
				return;
			}
			skip_wsp();
			bool first = true;
			while (i < json.size()) {
				if (json[i] == '}') break; //closing character
				if (first) {
					first = false;
				} else {
					if (!skip_char(',')) {
						std::cerr << "Missing separating ','" << std::endl;
						return;
					}
					skip_wsp();
				}
				std::string name, value;
				if (!extract_string(&name)) {
					std::cerr << "Missing name string." << std::endl;
					return;
				}
				skip_wsp();
				if (!skip_char(':')) {
					std::cerr << "Missing separating ':'" << std::endl;
					return;
				}
				skip_wsp();
				if (!extract_string(&value)) {
					std::cerr << "Missing value string." << std::endl;
					return;
				}

				//std::cout << "Received: '" << name << "':'" << value << "'" << std::endl; //DEBUG
				internal.received[name] = value;

				skip_wsp();
			}
			if (!skip_char('}')) {
				std::cerr << "Missing closing '{'" << std::endl;
				return;
			}
			skip_wsp();
			if (i < json.size()) {
				std::cerr << "Trailing garbage" << std::endl;
				return;
			}
		} else {
			response->status.code = 404;
			response->status.message = "Not Found";
			response->body = "Not Found";
			response->headers.emplace_back("Content-Type", "text/plain");
		}
	});

	//Read all adjustments from the server, and encode current state and hits:
	std::map< std::string, std::string > state;
	for (auto tweak : internal.tweaks) {
		auto f = internal.received.find(tweak->name);
		if (f != internal.received.end()) {
			try {
				tweak->deserialize(f->second);
			} catch (...) {
				std::cerr << "Failed to deserialize " << f->first << " from '" << f->second << "'" << std::endl;
			}
		}
		state[tweak->name] = "{\"hint\":" + utf8_to_json(tweak->hint) + ",\"value\":" + utf8_to_json(tweak->serialize()) + "}";
	}
	internal.received.clear();

	std::string all_state = "{\n";
	for (auto const &name_value : state) {
		if (&name_value != &(*state.begin())) all_state += ",\n";
		all_state += utf8_to_json(name_value.first) + ":" + name_value.second;
	}
	all_state += "\n}";

	//if state has changed, update serial:
	if (internal.state != all_state) {
		internal.state = all_state;
		++internal.state_serial;
	}

	//respond to polls:
	for (auto poll = internal.polls.begin(); poll != internal.polls.end(); /* later */) {
		auto next = poll;
		++next;
		if (poll->serial != internal.state_serial) {
			poll->response->body = "{\"serial\":" + std::to_string(internal.state_serial) + ",\"state\":" + internal.state + "}";
			poll->response->headers.emplace_back("Content-Type", "application/json");
			internal.polls.erase(poll);
		}
		poll = next;
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x3b0, %rsp            # imm = 0x3B0
callq 0x6a00
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rsi
addq $0x20, %rsi
leaq -0x18(%rbp), %rdi
callq 0xa7d0
movq -0x8(%rbp), %rdi
addq $0x88, %rdi
callq 0xa960
testb $0x1, %al
jne 0x6cdc
movq -0x8(%rbp), %rsi
subq $-0x80, %rsi
leaq -0x20(%rbp), %rdi
callq 0xa9c0
jmp 0x6cac
movq -0x8(%rbp), %rdi
addq $0x88, %rdi
leaq -0x20(%rbp), %rsi
callq 0xaa40
leaq -0x20(%rbp), %rdi
callq 0xaa70
jmp 0x6cdc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x76c6
movq -0x8(%rbp), %rdi
addq $0x88, %rdi
callq 0xaac0
movq %rax, -0x340(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x58(%rbp)
leaq -0x50(%rbp), %rdi
movq %rdi, -0x338(%rbp)
leaq -0x58(%rbp), %rsi
callq 0x76e0
movq -0x340(%rbp), %rdi
movq -0x338(%rbp), %rsi
xorps %xmm0, %xmm0
callq 0xaae0
jmp 0x6d27
leaq -0x50(%rbp), %rdi
callq 0xb7b0
leaq -0x88(%rbp), %rdi
callq 0xb7d0
movq -0x8(%rbp), %rax
addq $0x48, %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rdi
callq 0xb7f0
movq %rax, -0x98(%rbp)
movq -0x90(%rbp), %rdi
callq 0xa8f0
movq %rax, -0xa0(%rbp)
leaq -0x98(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0xa8c0
testb $0x1, %al
jne 0x6d8d
jmp 0x7199
leaq -0x98(%rbp), %rdi
callq 0xb820
movq (%rax), %rax
movq %rax, -0xa8(%rbp)
movq -0x8(%rbp), %rdi
addq $0xd0, %rdi
movq -0xa8(%rbp), %rsi
callq 0xb850
movq %rax, -0x348(%rbp)
jmp 0x6dc3
movq -0x348(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0x8(%rbp), %rdi
addq $0xd0, %rdi
callq 0xb8b0
movq %rax, -0xb8(%rbp)
leaq -0xb0(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0xb880
testb $0x1, %al
jne 0x6e04
jmp 0x6f8f
movq -0xa8(%rbp), %rax
addq $0x60, %rax
movq %rax, -0x350(%rbp)
leaq -0xb0(%rbp), %rdi
callq 0xb920
movq %rax, %rsi
addq $0x20, %rsi
leaq -0xd8(%rbp), %rdi
callq 0x4220
jmp 0x6e37
movq -0x350(%rbp), %rdi
leaq -0xd8(%rbp), %rsi
callq 0xb8e0
jmp 0x6e4c
leaq -0xd8(%rbp), %rdi
callq 0x42f0
jmp 0x6f75
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
leaq -0x50(%rbp), %rdi
callq 0xb7b0
jmp 0x76c6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x76ba
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x6eae
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
leaq -0xd8(%rbp), %rdi
callq 0x42f0
movq -0x28(%rbp), %rdi
callq 0x4200
movq 0x1d12a(%rip), %rdi     # 0x23fe8
leaq 0x11328(%rip), %rsi     # 0x181ed
callq 0x4470
movq %rax, -0x358(%rbp)
jmp 0x6ed3
leaq -0xb0(%rbp), %rdi
callq 0xb920
movq -0x358(%rbp), %rdi
movq %rax, %rsi
callq 0x4430
movq %rax, -0x360(%rbp)
jmp 0x6ef7
movq -0x360(%rbp), %rdi
leaq 0x112ff(%rip), %rsi     # 0x18204
callq 0x4470
movq %rax, -0x368(%rbp)
jmp 0x6f13
leaq -0xb0(%rbp), %rdi
callq 0xb920
movq -0x368(%rbp), %rdi
movq %rax, %rsi
addq $0x20, %rsi
callq 0x4430
movq %rax, -0x370(%rbp)
jmp 0x6f3b
movq -0x370(%rbp), %rdi
leaq 0x117e2(%rip), %rsi     # 0x1872b
callq 0x4470
movq %rax, -0x378(%rbp)
jmp 0x6f57
movq -0x378(%rbp), %rdi
movq 0x1d023(%rip), %rsi     # 0x23f88
callq 0x44d0
jmp 0x6f6c
callq 0x46a0
jmp 0x6f73
jmp 0x6f75
jmp 0x6f8f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
callq 0x46a0
jmp 0x6f8a
jmp 0x76ba
movq -0xa8(%rbp), %rsi
addq $0x20, %rsi
leaq -0x178(%rbp), %rdi
callq 0x7770
jmp 0x6fa8
leaq 0x1125d(%rip), %rsi     # 0x1820c
leaq -0x158(%rbp), %rdi
leaq -0x178(%rbp), %rdx
callq 0xba60
jmp 0x6fc4
leaq 0x1124a(%rip), %rdx     # 0x18215
leaq -0x138(%rbp), %rdi
leaq -0x158(%rbp), %rsi
callq 0xb940
jmp 0x6fe0
movq -0xa8(%rbp), %rsi
addq $0x40, %rsi
leaq -0x1b8(%rbp), %rdi
callq 0xbab0
jmp 0x6ff9
leaq -0x198(%rbp), %rdi
leaq -0x1b8(%rbp), %rsi
callq 0x7770
jmp 0x700e
leaq -0x118(%rbp), %rdi
leaq -0x138(%rbp), %rsi
leaq -0x198(%rbp), %rdx
callq 0xb990
jmp 0x702a
leaq 0x111f5(%rip), %rdx     # 0x18226
leaq -0xf8(%rbp), %rdi
leaq -0x118(%rbp), %rsi
callq 0xb940
jmp 0x7046
movq -0xa8(%rbp), %rsi
leaq -0x88(%rbp), %rdi
callq 0xbb00
movq %rax, -0x380(%rbp)
jmp 0x7062
movq -0x380(%rbp), %rdi
leaq -0xf8(%rbp), %rsi
callq 0x4550
leaq -0xf8(%rbp), %rdi
callq 0x42f0
leaq -0x118(%rbp), %rdi
callq 0x42f0
leaq -0x198(%rbp), %rdi
callq 0x42f0
leaq -0x1b8(%rbp), %rdi
callq 0x42f0
leaq -0x138(%rbp), %rdi
callq 0x42f0
leaq -0x158(%rbp), %rdi
callq 0x42f0
leaq -0x178(%rbp), %rdi
callq 0x42f0
leaq -0x98(%rbp), %rdi
callq 0xbbe0
jmp 0x6d71
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x7188
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x717c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x7170
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x7164
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x7158
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x714c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
leaq -0xf8(%rbp), %rdi
callq 0x42f0
leaq -0x118(%rbp), %rdi
callq 0x42f0
leaq -0x198(%rbp), %rdi
callq 0x42f0
leaq -0x1b8(%rbp), %rdi
callq 0x42f0
leaq -0x138(%rbp), %rdi
callq 0x42f0
leaq -0x158(%rbp), %rdi
callq 0x42f0
leaq -0x178(%rbp), %rdi
callq 0x42f0
jmp 0x76ba
movq -0x8(%rbp), %rdi
addq $0xd0, %rdi
callq 0xbc10
leaq -0x1d9(%rbp), %rdi
movq %rdi, -0x388(%rbp)
callq 0x4720
movq -0x388(%rbp), %rdx
leaq 0x11055(%rip), %rsi     # 0x1821f
leaq -0x1d8(%rbp), %rdi
callq 0x4f80
jmp 0x71d8
leaq -0x1d9(%rbp), %rdi
callq 0x44f0
leaq -0x88(%rbp), %rax
movq %rax, -0x1e8(%rbp)
movq -0x1e8(%rbp), %rdi
callq 0xbc30
movq %rax, -0x1f0(%rbp)
movq -0x1e8(%rbp), %rdi
callq 0xb8b0
movq %rax, -0x1f8(%rbp)
leaq -0x1f0(%rbp), %rdi
leaq -0x1f8(%rbp), %rsi
callq 0xb880
testb $0x1, %al
jne 0x7234
jmp 0x73b4
leaq -0x1f0(%rbp), %rdi
callq 0xbc60
movq %rax, -0x200(%rbp)
movq -0x200(%rbp), %rax
movq %rax, -0x390(%rbp)
leaq -0x88(%rbp), %rdi
callq 0xbc30
movq %rax, -0x208(%rbp)
leaq -0x208(%rbp), %rdi
callq 0xbc60
movq %rax, %rcx
movq -0x390(%rbp), %rax
cmpq %rcx, %rax
je 0x72c8
leaq 0x10f98(%rip), %rsi     # 0x18222
leaq -0x1d8(%rbp), %rdi
callq 0x4460
jmp 0x7298
jmp 0x72c8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
leaq -0x1d9(%rbp), %rdi
callq 0x44f0
jmp 0x76ba
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x76ae
movq -0x200(%rbp), %rsi
leaq -0x268(%rbp), %rdi
callq 0x7770
jmp 0x72dd
leaq 0x10f57(%rip), %rdx     # 0x1823b
leaq -0x248(%rbp), %rdi
leaq -0x268(%rbp), %rsi
callq 0xb940
jmp 0x72f9
movq -0x200(%rbp), %rdx
addq $0x20, %rdx
leaq -0x228(%rbp), %rdi
leaq -0x248(%rbp), %rsi
callq 0xbc80
jmp 0x7319
leaq -0x1d8(%rbp), %rdi
leaq -0x228(%rbp), %rsi
callq 0x4580
jmp 0x732e
leaq -0x228(%rbp), %rdi
callq 0x42f0
leaq -0x248(%rbp), %rdi
callq 0x42f0
leaq -0x268(%rbp), %rdi
callq 0x42f0
leaq -0x1f0(%rbp), %rdi
callq 0xbcd0
jmp 0x7218
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x73a3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x7397
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
leaq -0x228(%rbp), %rdi
callq 0x42f0
leaq -0x248(%rbp), %rdi
callq 0x42f0
leaq -0x268(%rbp), %rdi
callq 0x42f0
jmp 0x76ae
leaq 0x10e6a(%rip), %rsi     # 0x18225
leaq -0x1d8(%rbp), %rdi
callq 0x4460
jmp 0x73c9
movq -0x8(%rbp), %rdi
addq $0xb0, %rdi
leaq -0x1d8(%rbp), %rsi
callq 0xbd00
testb $0x1, %al
jne 0x73e6
jmp 0x7412
movq -0x8(%rbp), %rdi
addq $0xb0, %rdi
leaq -0x1d8(%rbp), %rsi
callq 0x4070
jmp 0x73ff
movq -0x8(%rbp), %rax
movl 0xa8(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0xa8(%rax)
movq -0x8(%rbp), %rdi
addq $0x90, %rdi
callq 0x7960
movq %rax, -0x270(%rbp)
movq -0x8(%rbp), %rdi
addq $0x90, %rdi
callq 0x79c0
movq %rax, -0x278(%rbp)
leaq -0x270(%rbp), %rdi
leaq -0x278(%rbp), %rsi
callq 0x7990
testb $0x1, %al
jne 0x745c
jmp 0x7684
movq -0x270(%rbp), %rax
movq %rax, -0x280(%rbp)
leaq -0x280(%rbp), %rdi
callq 0x79f0
leaq -0x270(%rbp), %rdi
callq 0x7a10
movl (%rax), %eax
movq -0x8(%rbp), %rcx
cmpl 0xa8(%rcx), %eax
je 0x7671
movq -0x8(%rbp), %rax
movl 0xa8(%rax), %esi
leaq -0x320(%rbp), %rdi
callq 0xbd30
jmp 0x74ac
leaq 0x10d75(%rip), %rsi     # 0x18228
leaq -0x300(%rbp), %rdi
leaq -0x320(%rbp), %rdx
callq 0xba60
jmp 0x74c8
leaq 0x10d64(%rip), %rdx     # 0x18233
leaq -0x2e0(%rbp), %rdi
leaq -0x300(%rbp), %rsi
callq 0xb940
jmp 0x74e4
movq -0x8(%rbp), %rdx
addq $0xb0, %rdx
leaq -0x2c0(%rbp), %rdi
leaq -0x2e0(%rbp), %rsi
callq 0xbc80
jmp 0x7504
leaq 0x10d1b(%rip), %rdx     # 0x18226
leaq -0x2a0(%rbp), %rdi
leaq -0x2c0(%rbp), %rsi
callq 0xb940
jmp 0x7520
leaq -0x270(%rbp), %rdi
movq %rdi, -0x398(%rbp)
callq 0x7a10
movq %rax, %rdi
addq $0x8, %rdi
callq 0xbe10
movq %rax, %rdi
addq $0x40, %rdi
leaq -0x2a0(%rbp), %rsi
movq %rsi, -0x3a0(%rbp)
callq 0x4550
movq -0x3a0(%rbp), %rdi
callq 0x42f0
leaq -0x2c0(%rbp), %rdi
callq 0x42f0
leaq -0x2e0(%rbp), %rdi
callq 0x42f0
leaq -0x300(%rbp), %rdi
callq 0x42f0
leaq -0x320(%rbp), %rdi
callq 0x42f0
movq -0x398(%rbp), %rdi
callq 0x7a10
movq %rax, %rdi
addq $0x8, %rdi
callq 0xbe10
movq %rax, %rdi
addq $0x28, %rdi
leaq 0x10c82(%rip), %rsi     # 0x1823d
leaq 0x10c88(%rip), %rdx     # 0x1824a
callq 0xbe30
jmp 0x75c9
movq -0x8(%rbp), %rax
addq $0x90, %rax
movq %rax, -0x3a8(%rbp)
leaq -0x328(%rbp), %rdi
leaq -0x270(%rbp), %rsi
callq 0x7a80
movq -0x3a8(%rbp), %rdi
movq -0x328(%rbp), %rsi
callq 0x7a30
movq %rax, -0x330(%rbp)
jmp 0x7671
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x7663
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x7657
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
jmp 0x764b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
leaq -0x2c0(%rbp), %rdi
callq 0x42f0
leaq -0x2e0(%rbp), %rdi
callq 0x42f0
leaq -0x300(%rbp), %rdi
callq 0x42f0
leaq -0x320(%rbp), %rdi
callq 0x42f0
jmp 0x76ae
movq -0x280(%rbp), %rax
movq %rax, -0x270(%rbp)
jmp 0x7429
leaq -0x1d8(%rbp), %rdi
callq 0x42f0
leaq -0x88(%rbp), %rdi
callq 0xbeb0
leaq -0x18(%rbp), %rdi
callq 0xa850
addq $0x3b0, %rsp            # imm = 0x3B0
popq %rbp
retq
leaq -0x1d8(%rbp), %rdi
callq 0x42f0
leaq -0x88(%rbp), %rdi
callq 0xbeb0
leaq -0x18(%rbp), %rdi
callq 0xa850
movq -0x28(%rbp), %rdi
callq 0x4710
movq %rax, %rdi
callq 0x5490