git » sdk » commit 44ce859

Commit compiled code to a branch

author Stephen Paul Weber
2025-03-18 18:59:50 UTC
committer Stephen Paul Weber
2025-03-18 18:59:50 UTC
parent 6d4674a75503b08b354caff5291702150df0323a

Commit compiled code to a branch

npm/IDB.js +753 -0
npm/MediaStoreCache.js +80 -0
npm/browser.js +754 -0
npm/index.d.ts +38 -0
npm/index.js +40 -0
npm/snikket-browser-enums.ts +61 -0
npm/snikket-browser.d.ts +1109 -0
npm/snikket-browser.js +29045 -0
npm/snikket-enums.d.ts +54 -0
npm/snikket-enums.js +62 -0
npm/snikket-enums.ts +61 -0
npm/snikket.d.ts +1109 -0
npm/snikket.js +29522 -0
npm/sqlite-worker1.mjs +38 -0

diff --git a/npm/IDB.js b/npm/IDB.js
new file mode 100644
index 0000000..4f30c56
--- /dev/null
+++ b/npm/IDB.js
@@ -0,0 +1,753 @@
+// This example persistence driver is written in JavaScript
+// so that SDK users can easily see how to write their own
+
+import { snikket as enums } from "./snikket-enums.js";
+import { snikket } from "./snikket.js";
+
+export default (dbname, media, tokenize, stemmer) => {
+	if (!tokenize) tokenize = function(s) { return s.split(" "); }
+	if (!stemmer) stemmer = function(s) { return s; }
+
+	var db = null;
+	function openDb(version) {
+		var dbOpenReq = indexedDB.open(dbname, version);
+		dbOpenReq.onerror = console.error;
+		dbOpenReq.onupgradeneeded = (event) => {
+			const upgradeDb = event.target.result;
+			if (!db.objectStoreNames.contains("messages")) {
+				const messages = upgradeDb.createObjectStore("messages", { keyPath: ["account", "serverId", "serverIdBy", "localId"] });
+				messages.createIndex("chats", ["account", "chatId", "timestamp"]);
+				messages.createIndex("localId", ["account", "localId", "chatId"]);
+				messages.createIndex("accounts", ["account", "timestamp"]);
+			}
+			if (!db.objectStoreNames.contains("keyvaluepairs")) {
+				upgradeDb.createObjectStore("keyvaluepairs");
+			}
+			if (!db.objectStoreNames.contains("chats")) {
+				upgradeDb.createObjectStore("chats", { keyPath: ["account", "chatId"] });
+			}
+			if (!db.objectStoreNames.contains("services")) {
+				upgradeDb.createObjectStore("services", { keyPath: ["account", "serviceId"] });
+			}
+			if (!db.objectStoreNames.contains("reactions")) {
+				const reactions = upgradeDb.createObjectStore("reactions", { keyPath: ["account", "chatId", "senderId", "updateId"] });
+				reactions.createIndex("senders", ["account", "chatId", "messageId", "senderId", "timestamp"]);
+			}
+		};
+		dbOpenReq.onsuccess = (event) => {
+			db = event.target.result;
+			window.db = db;
+			if (!db.objectStoreNames.contains("messages") || !db.objectStoreNames.contains("keyvaluepairs") || !db.objectStoreNames.contains("chats") || !db.objectStoreNames.contains("services") || !db.objectStoreNames.contains("reactions")) {
+				db.close();
+				openDb(db.version + 1);
+				return;
+			}
+		};
+	}
+	openDb();
+
+	function promisifyRequest(request) {
+		return new Promise((resolve, reject) => {
+			request.oncomplete = request.onsuccess = () => resolve(request.result);
+			request.onabort = request.onerror = () => reject(request.error);
+		});
+	}
+
+	function hydrateStringReaction(r, senderId, timestamp) {
+		if (r.startsWith("ni://")){
+			return new snikket.CustomEmojiReaction(senderId, timestamp, "", r);
+		} else {
+			return new snikket.Reaction(senderId, timestamp, r);
+		}
+	}
+
+	function hydrateObjectReaction(r) {
+		if (r.uri) {
+			return new snikket.CustomEmojiReaction(r.senderId, r.timestamp, r.text, r.uri, r.envelopeId);
+		} else {
+			return new snikket.Reaction(r.senderId, r.timestamp, r.text, r.envelopeId, r.key);
+		}
+	}
+
+	function hydrateReactionsArray(reacts, senderId, timestamp) {
+		if (!reacts) return reacts;
+		return reacts.map(r => typeof r === "string" ? hydrateStringReaction(r, senderId, timestamp) : hydrateObjectReaction(r));
+	}
+
+	function hydrateReactions(map, timestamp) {
+		if (!map) return new Map();
+		const newMap = new Map();
+		for (const [k, reacts] of map) {
+			newMap.set(k, reacts.map(reactOrSender => typeof reactOrSender === "string" ? hydrateStringReaction(k, reactOrSender, timestamp) : hydrateObjectReaction(reactOrSender)));
+		}
+		return newMap;
+	}
+
+	function hydrateMessageSync(value) {
+		if (!value) return null;
+
+		const tx = db.transaction(["messages"], "readonly");
+		const store = tx.objectStore("messages");
+
+		const message = new snikket.ChatMessageBuilder();
+		message.localId = value.localId ? value.localId : null;
+		message.serverId = value.serverId ? value.serverId : null;
+		message.serverIdBy = value.serverIdBy ? value.serverIdBy : null;
+		message.replyId = value.replyId ? value.replyId : null;
+		message.syncPoint = !!value.syncPoint;
+		message.direction = value.direction;
+		message.status = value.status;
+		message.timestamp = value.timestamp && value.timestamp.toISOString();
+		message.to = value.to && snikket.JID.parse(value.to);
+		message.from = value.from && snikket.JID.parse(value.from);
+		message.sender = value.sender && snikket.JID.parse(value.sender);
+		message.senderId = value.senderId;
+		message.recipients = value.recipients.map((r) => snikket.JID.parse(r));
+		message.replyTo = value.replyTo.map((r) => snikket.JID.parse(r));
+		message.threadId = value.threadId;
+		message.attachments = value.attachments;
+		message.reactions = hydrateReactions(value.reactions, message.timestamp);
+		message.text = value.text;
+		message.lang = value.lang;
+		message.type = value.type || (value.isGroupchat || value.groupchat ? enums.MessageType.Channel : enums.MessageType.Chat);
+		message.payloads = (value.payloads || []).map(snikket.Stanza.parse);
+		message.stanza = value.stanza && snikket.Stanza.parse(value.stanza);
+		return message.build();
+	}
+
+	async function hydrateMessage(value) {
+		if (!value) return null;
+
+		const message = hydrateMessageSync(value);
+		const tx = db.transaction(["messages"], "readonly");
+		const store = tx.objectStore("messages");
+		const replyToMessage = value.replyToMessage && value.replyToMessage[1] !== message.serverId && value.replyToMessage[3] !== message.localId && await hydrateMessage((await promisifyRequest(store.openCursor(IDBKeyRange.only(value.replyToMessage))))?.value);
+
+		message.replyToMessage = replyToMessage;
+		message.versions = await Promise.all((value.versions || []).map(hydrateMessage));
+		return message;
+	}
+
+	function serializeMessage(account, message) {
+		return {
+			...message,
+			serverId: message.serverId || "",
+			serverIdBy: message.serverIdBy || "",
+			localId: message.localId || "",
+			syncPoint: !!message.syncPoint,
+			account: account,
+			chatId: message.chatId(),
+			to: message.to?.asString(),
+			from: message.from?.asString(),
+			senderId: message.senderId,
+			recipients: message.recipients.map((r) => r.asString()),
+			replyTo: message.replyTo.map((r) => r.asString()),
+			timestamp: new Date(message.timestamp),
+			replyToMessage: message.replyToMessage && [account, message.replyToMessage.serverId || "", message.replyToMessage.serverIdBy || "", message.replyToMessage.localId || ""],
+			versions: message.versions.map((m) => serializeMessage(account, m)),
+			payloads: message.payloads.map((p) => p.toString()),
+			stanza: message.stanza?.toString(),
+		}
+	}
+
+	function correctMessage(account, message, result) {
+		// Newest (by timestamp) version wins for head
+		const newVersions = message.versions.length < 2 ? [message] : message.versions;
+		const storedVersions = result.value.versions || [];
+		// TODO: dedupe? There shouldn't be dupes...
+		const versions = (storedVersions.length < 1 ? [result.value] : storedVersions).concat(newVersions.map((nv) => serializeMessage(account, nv))).sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
+		const head = {...versions[0]};
+		// Can't change primary key
+		head.serverIdBy = result.value.serverIdBy;
+		head.serverId = result.value.serverId;
+		head.localId = result.value.localId;
+		head.replyId = result.value.replyId;
+		head.timestamp = result.value.timestamp; // Edited version is not newer
+		head.versions = versions;
+		head.reactions = result.value.reactions; // Preserve these, edit doesn't touch them
+		// Calls can "edit" from multiple senders, but the original direction and sender holds
+		if (result.value.type === enums.MessageType.MessageCall) {
+			head.direction = result.value.direction;
+			head.senderId = result.value.senderId;
+			head.from = result.value.from;
+			head.to = result.value.to;
+			head.replyTo = result.value.replyTo;
+			head.recipients = result.value.recipients;
+		}
+		result.update(head);
+		return head;
+	}
+
+	function setReactions(reactionsMap, sender, reactions) {
+		for (const [reaction, reacts] of reactionsMap) {
+			const newReacts = reacts.filter((react) => react.senderId !== sender);
+			if (newReacts.length < 1) {
+				reactionsMap.delete(reaction);
+			} else {
+				reactionsMap.set(reaction, newReacts);
+			}
+		}
+		for (const reaction of reactions) {
+			reactionsMap.set(reaction.key, [...reactionsMap.get(reaction.key) || [], reaction]);
+		}
+		return reactionsMap;
+	}
+
+	const obj = {
+		lastId: function(account, jid, callback) {
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			var cursor = null;
+			if (jid === null) {
+				cursor = store.index("accounts").openCursor(
+					IDBKeyRange.bound([account], [account, []]),
+					"prev"
+				);
+			} else {
+				cursor = store.index("chats").openCursor(
+					IDBKeyRange.bound([account, jid], [account, jid, []]),
+					"prev"
+				);
+			}
+			cursor.onsuccess = (event) => {
+				if (!event.target.result || (event.target.result.value.syncPoint && event.target.result.value.serverId && (jid || event.target.result.value.serverIdBy === account))) {
+					callback(event.target.result ? event.target.result.value.serverId : null);
+				} else {
+					event.target.result.continue();
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback(null);
+			}
+		},
+
+		storeChats: function(account, chats) {
+			const tx = db.transaction(["chats"], "readwrite");
+			const store = tx.objectStore("chats");
+
+			for (const chat of chats) {
+				store.put({
+					account: account,
+					chatId: chat.chatId,
+					trusted: chat.trusted,
+					avatarSha1: chat.avatarSha1,
+					presence: new Map([...chat.presence.entries()].map(([k, p]) => [k, { caps: p.caps?.ver(), mucUser: p.mucUser?.toString() }])),
+					displayName: chat.displayName,
+					uiState: chat.uiState,
+					isBlocked: chat.isBlocked,
+					extensions: chat.extensions?.toString(),
+					readUpToId: chat.readUpToId,
+					readUpToBy: chat.readUpToBy,
+					disco: chat.disco,
+					class: chat instanceof snikket.DirectChat ? "DirectChat" : (chat instanceof snikket.Channel ? "Channel" : "Chat")
+				});
+			}
+		},
+
+		getChats: function(account, callback) {
+			(async () => {
+				const tx = db.transaction(["chats"], "readonly");
+				const store = tx.objectStore("chats");
+				const range = IDBKeyRange.bound([account], [account, []]);
+				const result = await promisifyRequest(store.getAll(range));
+				return await Promise.all(result.map(async (r) => new snikket.SerializedChat(
+					r.chatId,
+					r.trusted,
+					r.avatarSha1,
+					new Map(await Promise.all((r.presence instanceof Map ? [...r.presence.entries()] : Object.entries(r.presence)).map(
+						async ([k, p]) => [k, new snikket.Presence(p.caps && await new Promise((resolve) => this.getCaps(p.caps, resolve)), p.mucUser && snikket.Stanza.parse(p.mucUser))]
+					))),
+					r.displayName,
+					r.uiState,
+					r.isBlocked,
+					r.extensions,
+					r.readUpToId,
+					r.readUpToBy,
+					r.disco ? new snikket.Caps(r.disco.node, r.disco.identities, r.disco.features) : null,
+					r.class
+				)));
+			})().then(callback);
+		},
+
+		getChatsUnreadDetails: function(account, chatsArray, callback) {
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+
+			const cursor = store.index("accounts").openCursor(
+				IDBKeyRange.bound([account], [account, []]),
+				"prev"
+			);
+			const chats = {};
+			chatsArray.forEach((chat) => chats[chat.chatId] = chat);
+			const result = {};
+			var rowCount = 0;
+			cursor.onsuccess = (event) => {
+				if (event.target.result && rowCount < 40000) {
+					rowCount++;
+					const value = event.target.result.value;
+					if (result[value.chatId]) {
+						result[value.chatId] = result[value.chatId].then((details) => {
+							if (!details.foundAll) {
+								const readUpTo = chats[value.chatId]?.readUpTo();
+								if (readUpTo === value.serverId || readUpTo === value.localId || value.direction == enums.MessageDirection.MessageSent) {
+									details.foundAll = true;
+								} else {
+									details.unreadCount++;
+								}
+							}
+							return details;
+						});
+					} else {
+						const readUpTo = chats[value.chatId]?.readUpTo();
+						const haveRead = readUpTo === value.serverId || readUpTo === value.localId || value.direction == enums.MessageDirection.MessageSent;
+						result[value.chatId] = hydrateMessage(value).then((m) => ({ chatId: value.chatId, message: m, unreadCount: haveRead ? 0 : 1, foundAll: haveRead }));
+					}
+					event.target.result.continue();
+				} else {
+					Promise.all(Object.values(result)).then(callback);
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback([]);
+			}
+		},
+
+		getMessage: function(account, chatId, serverId, localId, callback) {
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			(async function() {
+				let result;
+				if (serverId) {
+					result = await promisifyRequest(store.openCursor(IDBKeyRange.bound([account, serverId], [account, serverId, []])));
+				} else {
+					result = await promisifyRequest(store.index("localId").openCursor(IDBKeyRange.only([account, localId, chatId])));
+				}
+				if (!result || !result.value) return null;
+				const message = result.value;
+				return await hydrateMessage(message);
+			})().then(callback);
+		},
+
+		storeReaction: function(account, update, callback) {
+			(async function() {
+				const tx = db.transaction(["messages", "reactions"], "readwrite");
+				const store = tx.objectStore("messages");
+				const reactionStore = tx.objectStore("reactions");
+				let result;
+				if (update.serverId) {
+					result = await promisifyRequest(store.openCursor(IDBKeyRange.bound([account, update.serverId, update.serverIdBy], [account, update.serverId, update.serverIdBy, []])));
+				} else {
+					result = await promisifyRequest(store.index("localId").openCursor(IDBKeyRange.only([account, update.localId, update.chatId])));
+				}
+				const lastFromSender = await promisifyRequest(reactionStore.index("senders").openCursor(IDBKeyRange.bound(
+					[account, update.chatId, update.serverId || update.localId, update.senderId],
+					[account, update.chatId, update.serverId || update.localId, update.senderId, []]
+				), "prev"));
+				const reactions = update.getReactions(hydrateReactionsArray(lastFromSender?.value?.reactions));
+				await promisifyRequest(reactionStore.put({...update, reactions: reactions, append: (update.kind === enums.ReactionUpdateKind.AppendReactions ? update.reactions : null), messageId: update.serverId || update.localId, timestamp: new Date(update.timestamp), account: account}));
+				if (!result || !result.value) return null;
+				if (lastFromSender?.value && lastFromSender.value.timestamp > new Date(update.timestamp)) return;
+				const message = result.value;
+				setReactions(message.reactions, update.senderId, reactions);
+				store.put(message);
+				return await hydrateMessage(message);
+			})().then(callback);
+		},
+
+		storeMessages(account, messages, callback) {
+			Promise.all(messages.map(m =>
+				new Promise(resolve => this.storeMessage(account, m, resolve))
+			)).then(callback);
+		},
+
+		storeMessage: function(account, message, callback) {
+			if (!message.chatId()) throw "Cannot store a message with no chatId";
+			if (!message.serverId && !message.localId) throw "Cannot store a message with no id";
+			if (!message.serverId && message.isIncoming()) throw "Cannot store an incoming message with no server id";
+			if (message.serverId && !message.serverIdBy) throw "Cannot store a message with a server id and no by";
+			new Promise((resolve) =>
+				// Hydrate reply stubs
+				message.replyToMessage && !message.replyToMessage.serverIdBy ? this.getMessage(account, message.chatId(), message.replyToMessage.serverId, message.replyToMessage.localId, resolve) : resolve(message.replyToMessage)
+			).then((replyToMessage) => {
+				message.replyToMessage = replyToMessage;
+				const tx = db.transaction(["messages", "reactions"], "readwrite");
+				const store = tx.objectStore("messages");
+				return Promise.all([
+					promisifyRequest(store.index("localId").openCursor(IDBKeyRange.only([account, message.localId || [], message.chatId()]))),
+					promisifyRequest(tx.objectStore("reactions").openCursor(IDBKeyRange.only([account, message.chatId(), message.senderId, message.localId || ""])))
+				]).then(([result, reactionResult]) => {
+					if (reactionResult?.value?.append && message.html().trim() == "") {
+						this.getMessage(account, message.chatId(), reactionResult.value.serverId, reactionResult.value.localId, (reactToMessage) => {
+							const previouslyAppended = hydrateReactionsArray(reactionResult.value.append, reactionResult.value.senderId, reactionResult.value.timestamp).map(r => r.key);
+							const reactions = [];
+							for (const [k, reacts] of reactToMessage?.reactions || []) {
+								for (const react of reacts) {
+									if (react.senderId === message.senderId && !previouslyAppended.includes(k)) reactions.push(react);
+								}
+							}
+							this.storeReaction(account, new snikket.ReactionUpdate(message.localId, reactionResult.value.serverId, reactionResult.value.serverIdBy, reactionResult.value.localId, message.chatId(), message.senderId, message.timestamp, reactions, enums.ReactionUpdateKind.CompleteReactions), callback);
+						});
+						return true;
+					} else if (result?.value && !message.isIncoming() && result?.value.direction === enums.MessageDirection.MessageSent && message.versions.length < 1) {
+						// Duplicate, we trust our own sent ids
+						return promisifyRequest(result.delete());
+					} else if (result?.value && (result.value.sender == message.senderId || result.value.type == enums.MessageType.MessageCall) && (message.versions.length > 0 || (result.value.versions || []).length > 0)) {
+						hydrateMessage(correctMessage(account, message, result)).then(callback);
+						return true;
+					}
+				}).then((done) => {
+					if (!done) {
+						// There may be reactions already if we are paging backwards
+						const cursor = tx.objectStore("reactions").index("senders").openCursor(IDBKeyRange.bound([account, message.chatId(), message.getReplyId() || ""], [account, message.chatId(), message.getReplyId() || "", []]), "prev");
+						const reactions = new Map();
+						const reactionTimes = new Map();
+						cursor.onsuccess = (event) => {
+							if (event.target.result && event.target.result.value) {
+								const time = reactionTimes.get(event.target.result.senderId);
+								if (!time || time < event.target.result.value.timestamp) {
+									setReactions(reactions, event.target.result.value.senderId, hydrateReactionsArray(event.target.result.value.reactions, event.target.result.senderId, event.target.result.timestamp));
+									reactionTimes.set(event.target.result.value.senderId, event.target.result.value.timestamp);
+								}
+								event.target.result.continue();
+							} else {
+								message.reactions = reactions;
+								const req = store.put(serializeMessage(account, message));
+								req.onerror = () => { window.mylog.push("MSG STORE ERROR: " + req.error.name + " " + req.error.message); }
+								callback(message);
+							}
+						};
+						cursor.onerror = console.error;
+					}
+				});
+			});
+		},
+
+		updateMessage: function(account, message) {
+			const tx = db.transaction(["messages"], "readwrite");
+			const store = tx.objectStore("messages");
+			store.put(serializeMessage(account, message));
+		},
+
+		updateMessageStatus: function(account, localId, status, callback) {
+			const tx = db.transaction(["messages"], "readwrite");
+			const store = tx.objectStore("messages");
+			promisifyRequest(store.index("localId").openCursor(IDBKeyRange.bound([account, localId], [account, localId, []]))).then((result) => {
+				if (result?.value && result.value.direction === enums.MessageDirection.MessageSent && result.value.status !== enums.MessageStatus.MessageDeliveredToDevice) {
+					const newStatus = { ...result.value, status: status };
+					result.update(newStatus);
+					hydrateMessage(newStatus).then(callback);
+				}
+			});
+		},
+
+		getMessagesBefore: function(account, chatId, beforeId, beforeTime, callback) {
+			// TODO: if beforeId is present but beforeTime is null, lookup time
+			const bound = beforeTime ? new Date(beforeTime) : [];
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			const cursor = store.index("chats").openCursor(
+				IDBKeyRange.bound([account, chatId], [account, chatId, bound]),
+				"prev"
+			);
+			this.getMessagesFromCursor(cursor, beforeId, bound, (messages) => callback(messages.reverse()));
+		},
+
+		getMessagesAfter: function(account, chatId, afterId, afterTime, callback) {
+			// TODO: if afterId is present but afterTime is null, lookup time
+			const bound = afterTime ? [new Date(afterTime)] : [];
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			const cursor = store.index("chats").openCursor(
+				IDBKeyRange.bound([account, chatId].concat(bound), [account, chatId, []]),
+				"next"
+			);
+			this.getMessagesFromCursor(cursor, afterId, bound[0], callback);
+		},
+
+		getMessagesAround: function(account, chatId, id, timeArg, callback) {
+			if (!id && !timeArg) throw "Around what?";
+			new Promise((resolve, reject) => {
+				if (timeArg)  {
+					resolve(timeArg);
+				} else {
+					this.getMessage(account, chatId, id, null, (m) => {
+						m ? resolve(m.timestamp) : this.getMessage(account, chatId, null, id, (m2) => resolve(m2?.timestamp));
+					});
+				}
+			}).then((time) => {
+				if (!time) {
+					callback([]);
+					return;
+				}
+				const before = new Promise((resolve, reject) =>
+					this.getMessagesBefore(account, chatId, id, time, resolve)
+				);
+
+				const tx = db.transaction(["messages"], "readonly");
+				const store = tx.objectStore("messages");
+				const cursor = store.index("chats").openCursor(
+					IDBKeyRange.bound([account, chatId, new Date(time)], [account, chatId, []]),
+					"next"
+				);
+				const aroundAndAfter = new Promise((resolve, reject) =>
+					this.getMessagesFromCursor(cursor, null, null, resolve)
+				);
+
+				Promise.all([before, aroundAndAfter]).then((result) => {
+					callback(result.flat());
+				});
+			});
+		},
+
+		getMessagesFromCursor: function(cursor, id, bound, callback) {
+			const result = [];
+			cursor.onsuccess = (event) => {
+				if (event.target.result && result.length < 50) {
+					const value = event.target.result.value;
+					if (value.serverId === id || value.localId === id || (value.timestamp && value.timestamp.getTime() === (bound instanceof Date && bound.getTime()))) {
+						event.target.result.continue();
+						return;
+					}
+
+					result.push(hydrateMessage(value));
+					event.target.result.continue();
+				} else {
+					Promise.all(result).then(callback);
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback([]);
+			}
+		},
+
+		searchMessages: function(account, chatId, q, callback) {
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			var cursor;
+			if (chatId) {
+				cursor = store.index("chats").openCursor(
+					IDBKeyRange.bound([account, chatId], [account, chatId, []]),
+					"prev"
+				);
+			} else if (account) {
+				cursor = store.index("accounts").openCursor(
+					IDBKeyRange.bound([account], [account, []]),
+					"prev"
+				);
+			} else {
+				cursor = store.openCursor(undefined, "prev");
+			}
+			const qTok = new Set(tokenize(q).map(stemmer));
+			cursor.onsuccess = (event) => {
+				if (event.target.result) {
+					const value = event.target.result.value;
+					if (value.text && new Set(tokenize(value.text).map(stemmer)).isSupersetOf(qTok)) {
+						if (!callback(q, hydrateMessageSync(value))) return;
+					}
+					event.target.result.continue();
+				} else {
+					callback(null);
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback(null);
+			}
+		},
+
+		hasMedia: function(hashAlgorithm, hash, callback) {
+			media.hasMedia(hashAlgorithm, hash, callback);
+		},
+
+		removeMedia: function(hashAlgorithm, hash) {
+			media.removeMedia(hashAlgorithm, hash);
+		},
+
+		storeMedia: function(mime, buffer, callback) {
+		  media.storeMedia(mime, buffer, callback);
+		},
+
+		storeCaps: function(caps) {
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			store.put(caps, "caps:" + caps.ver()).onerror = console.error;
+		},
+
+		getCaps: function(ver, callback) {
+			(async function() {
+				const tx = db.transaction(["keyvaluepairs"], "readonly");
+				const store = tx.objectStore("keyvaluepairs");
+				const raw = await promisifyRequest(store.get("caps:" + ver));
+				if (raw) {
+					return (new snikket.Caps(raw.node, raw.identities.map((identity) => new snikket.Identity(identity.category, identity.type, identity.name)), raw.features));
+				}
+
+				return null;
+			})().then(callback);
+		},
+
+		storeLogin: function(login, clientId, displayName, token) {
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			store.put(clientId, "login:clientId:" + login).onerror = console.error;
+			store.put(displayName, "fn:" + login).onerror = console.error;
+			if (token != null) {
+				store.put(token, "login:token:" + login).onerror = console.error;
+				store.put(0, "login:fastCount:" + login).onerror = console.error;
+			}
+		},
+
+		storeStreamManagement: function(account, sm) {
+			// Don't bother on ios, the indexeddb is too broken
+			// https://bugs.webkit.org/show_bug.cgi?id=287876
+			if (navigator.userAgent.match(/(iPad|iPhone|iPod)/g)) return;
+
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			const req = store.put(sm, "sm:" + account);
+			req.onerror = () => { console.error("storeStreamManagement", req.error.name, req.error.message); }
+		},
+
+		getStreamManagement: function(account, callback) {
+			const tx = db.transaction(["keyvaluepairs"], "readonly");
+			const store = tx.objectStore("keyvaluepairs");
+			promisifyRequest(store.get("sm:" + account)).then(
+				(v) => {
+					if (v instanceof ArrayBuffer) {
+						callback(v);
+					} else if(!v) {
+						callback(null);
+					} else {
+						new Blob([JSON.stringify(v)], {type: "text/plain; charset=utf-8"}).arrayBuffer().then(callback);
+					}
+				},
+				(e) => {
+					console.error(e);
+					callback(null);
+				}
+			);
+		},
+
+		getLogin: function(login, callback) {
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			Promise.all([
+				promisifyRequest(store.get("login:clientId:" + login)),
+				promisifyRequest(store.get("login:token:" + login)),
+				promisifyRequest(store.get("login:fastCount:" + login)),
+				promisifyRequest(store.get("fn:" + login)),
+			]).then((result) => {
+				if (result[1]) {
+					store.put((result[2] || 0) + 1, "login:fastCount:" + login).onerror = console.error;
+				}
+				callback(result[0], result[1], result[2] || 0, result[3]);
+			}).catch((e) => {
+				console.error(e);
+				callback(null, null, 0, null);
+			});
+		},
+
+		removeAccount(account, completely) {
+			const tx = db.transaction(["keyvaluepairs", "services", "messages", "chats", "reactions"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			store.delete("login:clientId:" + account);
+			store.delete("login:token:" + account);
+			store.delete("login:fastCount:" + account);
+			store.delete("fn:" + account);
+			store.delete("sm:" + account);
+
+			if (!completely) return;
+
+			const servicesStore = tx.objectStore("services");
+			const servicesCursor = servicesStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			servicesCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const messagesStore = tx.objectStore("messages");
+			const messagesCursor = messagesStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			messagesCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const chatsStore = tx.objectStore("chats");
+			const chatsCursor = chatsStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			chatsCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const reactionsStore = tx.objectStore("reactions");
+			const reactionsCursor = reactionsStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			reactionsCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+		},
+
+		storeService(account, serviceId, name, node, caps) {
+			this.storeCaps(caps);
+
+			const tx = db.transaction(["services"], "readwrite");
+			const store = tx.objectStore("services");
+
+			store.put({
+				account: account,
+				serviceId: serviceId,
+				name: name,
+				node: node,
+				caps: caps.ver(),
+			});
+		},
+
+		findServicesWithFeature(account, feature, callback) {
+			const tx = db.transaction(["services"], "readonly");
+			const store = tx.objectStore("services");
+
+			// Almost full scan shouldn't be too expensive, how many services are we aware of?
+			const cursor = store.openCursor(IDBKeyRange.bound([account], [account, []]));
+			const result = [];
+			cursor.onsuccess = (event) => {
+				if (event.target.result) {
+					const value = event.target.result.value;
+					result.push(new Promise((resolve) => this.getCaps(value.caps, (caps) => resolve({ ...value, caps: caps }))));
+					event.target.result.continue();
+				} else {
+					Promise.all(result).then((items) => items.filter((item) => item.caps && item.caps.features.includes(feature))).then(callback);
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback([]);
+			}
+		},
+
+		get(k, callback) {
+			const tx = db.transaction(["keyvaluepairs"], "readonly");
+			const store = tx.objectStore("keyvaluepairs");
+			promisifyRequest(store.get(k)).then(callback);
+		},
+
+		set(k, v, callback) {
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			promisifyRequest(store.put(v, k)).then(callback);
+		}
+	};
+
+	media.setKV(obj);
+	return obj;
+};
diff --git a/npm/MediaStoreCache.js b/npm/MediaStoreCache.js
new file mode 100644
index 0000000..7afdba9
--- /dev/null
+++ b/npm/MediaStoreCache.js
@@ -0,0 +1,80 @@
+// This example MediaStore is written in JavaScript
+// so that SDK users can easily see how to write their own
+
+export default (cacheName) => {
+	var cache = null;
+	caches.open(cacheName).then((c) => cache = c);
+
+	function mkNiUrl(hashAlgorithm, hashBytes) {
+		const b64url = btoa(Array.from(new Uint8Array(hashBytes), (x) => String.fromCodePoint(x)).join("")).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
+		return "/.well-known/ni/" + hashAlgorithm + "/" + b64url;
+	}
+
+	return {
+		setKV(kv) {
+			this.kv = kv;
+		},
+
+		storeMedia(mime, buffer, callback) {
+			(async () => {
+				const sha256 = await crypto.subtle.digest("SHA-256", buffer);
+				const sha1 = await crypto.subtle.digest("SHA-1", buffer);
+				const sha256NiUrl = mkNiUrl("sha-256", sha256);
+				await cache.put(sha256NiUrl, new Response(buffer, { headers: { "Content-Type": mime } }));
+				if (this.kv) await new Promise((resolve) => this.kv.set(mkNiUrl("sha-1", sha1), sha256NiUrl, resolve));
+			})().then(callback);
+		},
+
+		removeMedia(hashAlgorithm, hash) {
+			(async () => {
+				let niUrl;
+				if (hashAlgorithm === "sha-256") {
+					niUrl = mkNiUrl(hashAlgorithm, hash);
+				} else {
+					niUrl = this.kv && await new Promise((resolve) => this.kv.get(mkNiUrl(hashAlgorithm, hash), resolve));
+					if (!niUrl) return;
+				}
+
+				return await cache.delete(niUrl);
+			})();
+		},
+
+		routeHashPathSW() {
+			const waitForMedia = async (uri) => {
+				const r = await this.getMediaResponse(uri);
+				if (r) return r;
+				await new Promise(resolve => setTimeout(resolve, 5000));
+				return await waitForMedia(uri);
+			};
+
+			addEventListener("fetch", (event) => {
+				const url = new URL(event.request.url);
+				if (url.pathname.startsWith("/.well-known/ni/")) {
+					event.respondWith(waitForMedia(url.pathname));
+				}
+			});
+		},
+
+		async getMediaResponse(uri) {
+			uri = uri.replace(/^ni:\/\/\//, "/.well-known/ni/").replace(/;/, "/");
+			var niUrl;
+			if (uri.split("/")[3] === "sha-256") {
+				niUrl = uri;
+			} else {
+				niUrl = this.kv && await new Promise((resolve) => this.kv.get(uri, resolve));
+				if (!niUrl) {
+					return null;
+				}
+			}
+
+			return await cache.match(niUrl);
+		},
+
+		hasMedia(hashAlgorithm, hash, callback) {
+			(async () => {
+				const response = await this.getMediaResponse(mkNiUrl(hashAlgorithm, hash));
+				return !!response;
+			})().then(callback);
+		}
+	};
+};
diff --git a/npm/browser.js b/npm/browser.js
new file mode 100644
index 0000000..508478a
--- /dev/null
+++ b/npm/browser.js
@@ -0,0 +1,754 @@
+// This example persistence driver is written in JavaScript
+// so that SDK users can easily see how to write their own
+
+import { snikket as enums } from "./snikket-enums.js";
+import { snikket } from "./snikket.js";
+
+const browser = (dbname, tokenize, stemmer) => {
+	if (!tokenize) tokenize = function(s) { return s.split(" "); }
+	if (!stemmer) stemmer = function(s) { return s; }
+
+	var db = null;
+	function openDb(version) {
+		var dbOpenReq = indexedDB.open(dbname, version);
+		dbOpenReq.onerror = console.error;
+		dbOpenReq.onupgradeneeded = (event) => {
+			const upgradeDb = event.target.result;
+			if (!db.objectStoreNames.contains("messages")) {
+				const messages = upgradeDb.createObjectStore("messages", { keyPath: ["account", "serverId", "serverIdBy", "localId"] });
+				messages.createIndex("chats", ["account", "chatId", "timestamp"]);
+				messages.createIndex("localId", ["account", "localId", "chatId"]);
+				messages.createIndex("accounts", ["account", "timestamp"]);
+			}
+			if (!db.objectStoreNames.contains("keyvaluepairs")) {
+				upgradeDb.createObjectStore("keyvaluepairs");
+			}
+			if (!db.objectStoreNames.contains("chats")) {
+				upgradeDb.createObjectStore("chats", { keyPath: ["account", "chatId"] });
+			}
+			if (!db.objectStoreNames.contains("services")) {
+				upgradeDb.createObjectStore("services", { keyPath: ["account", "serviceId"] });
+			}
+			if (!db.objectStoreNames.contains("reactions")) {
+				const reactions = upgradeDb.createObjectStore("reactions", { keyPath: ["account", "chatId", "senderId", "updateId"] });
+				reactions.createIndex("senders", ["account", "chatId", "messageId", "senderId", "timestamp"]);
+			}
+		};
+		dbOpenReq.onsuccess = (event) => {
+			db = event.target.result;
+			if (!db.objectStoreNames.contains("messages") || !db.objectStoreNames.contains("keyvaluepairs") || !db.objectStoreNames.contains("chats") || !db.objectStoreNames.contains("services") || !db.objectStoreNames.contains("reactions")) {
+				db.close();
+				openDb(db.version + 1);
+				return;
+			}
+		};
+	}
+	openDb();
+
+	var cache = null;
+	caches.open(dbname).then((c) => cache = c);
+
+	function mkNiUrl(hashAlgorithm, hashBytes) {
+		const b64url = btoa(Array.from(new Uint8Array(hashBytes), (x) => String.fromCodePoint(x)).join("")).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
+		return "/.well-known/ni/" + hashAlgorithm + "/" + b64url;
+	}
+
+	function promisifyRequest(request) {
+		return new Promise((resolve, reject) => {
+			request.oncomplete = request.onsuccess = () => resolve(request.result);
+			request.onabort = request.onerror = () => reject(request.error);
+		});
+	}
+
+	function hydrateStringReaction(r, senderId, timestamp) {
+		if (r.startsWith("ni://")){
+			return new snikket.CustomEmojiReaction(senderId, timestamp, "", r);
+		} else {
+			return new snikket.Reaction(senderId, timestamp, r);
+		}
+	}
+
+	function hydrateObjectReaction(r) {
+		if (r.uri) {
+			return new snikket.CustomEmojiReaction(r.senderId, r.timestamp, r.text, r.uri, r.envelopeId);
+		} else {
+			return new snikket.Reaction(r.senderId, r.timestamp, r.text, r.envelopeId, r.key);
+		}
+	}
+
+	function hydrateReactionsArray(reacts, senderId, timestamp) {
+		if (!reacts) return reacts;
+		return reacts.map(r => typeof r === "string" ? hydrateStringReaction(r, senderId, timestamp) : hydrateObjectReaction(r));
+	}
+
+	function hydrateReactions(map, timestamp) {
+		if (!map) return new Map();
+		const newMap = new Map();
+		for (const [k, reacts] of map) {
+			newMap.set(k, reacts.map(reactOrSender => typeof reactOrSender === "string" ? hydrateStringReaction(k, reactOrSender, timestamp) : hydrateObjectReaction(reactOrSender)));
+		}
+		return newMap;
+	}
+
+	function hydrateMessageSync(value) {
+		if (!value) return null;
+
+		const tx = db.transaction(["messages"], "readonly");
+		const store = tx.objectStore("messages");
+
+		const message = new snikket.ChatMessage();
+		message.localId = value.localId ? value.localId : null;
+		message.serverId = value.serverId ? value.serverId : null;
+		message.serverIdBy = value.serverIdBy ? value.serverIdBy : null;
+		message.replyId = value.replyId ? value.replyId : null;
+		message.syncPoint = !!value.syncPoint;
+		message.direction = value.direction;
+		message.status = value.status;
+		message.timestamp = value.timestamp && value.timestamp.toISOString();
+		message.to = value.to && snikket.JID.parse(value.to);
+		message.from = value.from && snikket.JID.parse(value.from);
+		message.sender = value.sender && snikket.JID.parse(value.sender);
+		message.recipients = value.recipients.map((r) => snikket.JID.parse(r));
+		message.replyTo = value.replyTo.map((r) => snikket.JID.parse(r));
+		message.threadId = value.threadId;
+		message.attachments = value.attachments;
+		message.reactions = hydrateReactions(value.reactions, message.timestamp);
+		message.text = value.text;
+		message.lang = value.lang;
+		message.type = value.type || (value.isGroupchat || value.groupchat ? enums.MessageType.Channel : enums.MessageType.Chat);
+		message.payloads = (value.payloads || []).map(snikket.Stanza.parse);
+		return message;
+	}
+
+	async function hydrateMessage(value) {
+		if (!value) return null;
+
+		const message = hydrateMessageSync(value);
+		const tx = db.transaction(["messages"], "readonly");
+		const store = tx.objectStore("messages");
+		const replyToMessage = value.replyToMessage && await hydrateMessage((await promisifyRequest(store.openCursor(IDBKeyRange.only(value.replyToMessage))))?.value);
+
+		message.replyToMessage = replyToMessage;
+		message.versions = await Promise.all((value.versions || []).map(hydrateMessage));
+		return message;
+	}
+
+	function serializeMessage(account, message) {
+		return {
+			...message,
+			serverId: message.serverId || "",
+			serverIdBy: message.serverIdBy || "",
+			localId: message.localId || "",
+			syncPoint: !!message.syncPoint,
+			account: account,
+			chatId: message.chatId(),
+			to: message.to?.asString(),
+			from: message.from?.asString(),
+			sender: message.sender?.asString(),
+			recipients: message.recipients.map((r) => r.asString()),
+			replyTo: message.replyTo.map((r) => r.asString()),
+			timestamp: new Date(message.timestamp),
+			replyToMessage: message.replyToMessage && [account, message.replyToMessage.serverId || "", message.replyToMessage.serverIdBy || "", message.replyToMessage.localId || ""],
+			versions: message.versions.map((m) => serializeMessage(account, m)),
+			payloads: message.payloads.map((p) => p.toString()),
+		}
+	}
+
+	function correctMessage(account, message, result) {
+		// Newest (by timestamp) version wins for head
+		const newVersions = message.versions.length < 1 ? [message] : message.versions;
+		const storedVersions = result.value.versions || [];
+		// TODO: dedupe? There shouldn't be dupes...
+		const versions = (storedVersions.length < 1 ? [result.value] : storedVersions).concat(newVersions.map((nv) => serializeMessage(account, nv))).sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
+		const head = {...versions[0]};
+		// Can't change primary key
+		head.serverIdBy = result.value.serverIdBy;
+		head.serverId = result.value.serverId;
+		head.localId = result.value.localId;
+		head.replyId = result.value.replyId;
+		head.timestamp = result.value.timestamp; // Edited version is not newer
+		head.versions = versions;
+		head.reactions = result.value.reactions; // Preserve these, edit doesn't touch them
+		// Calls can "edit" from multiple senders, but the original direction and sender holds
+		if (result.value.type === enums.MessageType.MessageCall) {
+			head.direction = result.value.direction;
+			head.sender = result.value.sender;
+			head.from = result.value.from;
+			head.to = result.value.to;
+			head.replyTo = result.value.replyTo;
+			head.recipients = result.value.recipients;
+		}
+		result.update(head);
+		return head;
+	}
+
+	function setReactions(reactionsMap, sender, reactions) {
+		for (const [reaction, reacts] of reactionsMap) {
+			const newReacts = reacts.filter((react) => react.senderId !== sender);
+			if (newReacts.length < 1) {
+				reactionsMap.delete(reaction);
+			} else {
+				reactionsMap.set(reaction, newReacts);
+			}
+		}
+		for (const reaction of reactions) {
+			reactionsMap.set(reaction.key, [...reactionsMap.get(reaction.key) || [], reaction]);
+		}
+		return reactionsMap;
+	}
+
+	return {
+		lastId: function(account, jid, callback) {
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			var cursor = null;
+			if (jid === null) {
+				cursor = store.index("accounts").openCursor(
+					IDBKeyRange.bound([account], [account, []]),
+					"prev"
+				);
+			} else {
+				cursor = store.index("chats").openCursor(
+					IDBKeyRange.bound([account, jid], [account, jid, []]),
+					"prev"
+				);
+			}
+			cursor.onsuccess = (event) => {
+				if (!event.target.result || (event.target.result.value.syncPoint && event.target.result.value.serverId && (jid || event.target.result.value.serverIdBy === account))) {
+					callback(event.target.result ? event.target.result.value.serverId : null);
+				} else {
+					event.target.result.continue();
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback(null);
+			}
+		},
+
+		storeChat: function(account, chat) {
+			const tx = db.transaction(["chats"], "readwrite");
+			const store = tx.objectStore("chats");
+
+			store.put({
+				account: account,
+				chatId: chat.chatId,
+				trusted: chat.trusted,
+				avatarSha1: chat.avatarSha1,
+				presence: new Map([...chat.presence.entries()].map(([k, p]) => [k, { caps: p.caps?.ver(), mucUser: p.mucUser?.toString() }])),
+				displayName: chat.displayName,
+				uiState: chat.uiState,
+				isBlocked: chat.isBlocked,
+				extensions: chat.extensions?.toString(),
+				readUpToId: chat.readUpToId,
+				readUpToBy: chat.readUpToBy,
+				disco: chat.disco,
+				class: chat instanceof snikket.DirectChat ? "DirectChat" : (chat instanceof snikket.Channel ? "Channel" : "Chat")
+			});
+		},
+
+		getChats: function(account, callback) {
+			(async () => {
+				const tx = db.transaction(["chats"], "readonly");
+				const store = tx.objectStore("chats");
+				const range = IDBKeyRange.bound([account], [account, []]);
+				const result = await promisifyRequest(store.getAll(range));
+				return await Promise.all(result.map(async (r) => new snikket.SerializedChat(
+					r.chatId,
+					r.trusted,
+					r.avatarSha1,
+					new Map(await Promise.all((r.presence instanceof Map ? [...r.presence.entries()] : Object.entries(r.presence)).map(
+						async ([k, p]) => [k, new snikket.Presence(p.caps && await new Promise((resolve) => this.getCaps(p.caps, resolve)), p.mucUser && snikket.Stanza.parse(p.mucUser))]
+					))),
+					r.displayName,
+					r.uiState,
+					r.isBlocked,
+					r.extensions,
+					r.readUpToId,
+					r.readUpToBy,
+					r.disco,
+					r.class
+				)));
+			})().then(callback);
+		},
+
+		getChatsUnreadDetails: function(account, chatsArray, callback) {
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+
+			const cursor = store.index("accounts").openCursor(
+				IDBKeyRange.bound([account], [account, []]),
+				"prev"
+			);
+			const chats = {};
+			chatsArray.forEach((chat) => chats[chat.chatId] = chat);
+			const result = {};
+			var rowCount = 0;
+			cursor.onsuccess = (event) => {
+				if (event.target.result && rowCount < 40000) {
+					rowCount++;
+					const value = event.target.result.value;
+					if (result[value.chatId]) {
+						result[value.chatId] = result[value.chatId].then((details) => {
+							if (!details.foundAll) {
+								const readUpTo = chats[value.chatId]?.readUpTo();
+								if (readUpTo === value.serverId || readUpTo === value.localId || value.direction == enums.MessageDirection.MessageSent) {
+									details.foundAll = true;
+								} else {
+									details.unreadCount++;
+								}
+							}
+							return details;
+						});
+					} else {
+						const readUpTo = chats[value.chatId]?.readUpTo();
+						const haveRead = readUpTo === value.serverId || readUpTo === value.localId || value.direction == enums.MessageDirection.MessageSent;
+						result[value.chatId] = hydrateMessage(value).then((m) => ({ chatId: value.chatId, message: m, unreadCount: haveRead ? 0 : 1, foundAll: haveRead }));
+					}
+					event.target.result.continue();
+				} else {
+					Promise.all(Object.values(result)).then(callback);
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback([]);
+			}
+		},
+
+		getMessage: function(account, chatId, serverId, localId, callback) {
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			(async function() {
+				let result;
+				if (serverId) {
+					result = await promisifyRequest(store.openCursor(IDBKeyRange.bound([account, serverId], [account, serverId, []])));
+				} else {
+					result = await promisifyRequest(store.index("localId").openCursor(IDBKeyRange.only([account, localId, chatId])));
+				}
+				if (!result || !result.value) return null;
+				const message = result.value;
+				return await hydrateMessage(message);
+			})().then(callback);
+		},
+
+		storeReaction: function(account, update, callback) {
+			(async function() {
+				const tx = db.transaction(["messages", "reactions"], "readwrite");
+				const store = tx.objectStore("messages");
+				const reactionStore = tx.objectStore("reactions");
+				let result;
+				if (update.serverId) {
+					result = await promisifyRequest(store.openCursor(IDBKeyRange.bound([account, update.serverId, update.serverIdBy], [account, update.serverId, update.serverIdBy, []])));
+				} else {
+					result = await promisifyRequest(store.index("localId").openCursor(IDBKeyRange.only([account, update.localId, update.chatId])));
+				}
+				const lastFromSender = await promisifyRequest(reactionStore.index("senders").openCursor(IDBKeyRange.bound(
+					[account, update.chatId, update.serverId || update.localId, update.senderId],
+					[account, update.chatId, update.serverId || update.localId, update.senderId, []]
+				), "prev"));
+				const reactions = update.getReactions(hydrateReactionsArray(lastFromSender?.value?.reactions));
+				await promisifyRequest(reactionStore.put({...update, reactions: reactions, append: (update.kind === enums.ReactionUpdateKind.AppendReactions ? update.reactions : null), messageId: update.serverId || update.localId, timestamp: new Date(update.timestamp), account: account}));
+				if (!result || !result.value) return null;
+				if (lastFromSender?.value && lastFromSender.value.timestamp > new Date(update.timestamp)) return;
+				const message = result.value;
+				setReactions(message.reactions, update.senderId, reactions);
+				store.put(message);
+				return await hydrateMessage(message);
+			})().then(callback);
+		},
+
+		storeMessage: function(account, message, callback) {
+			if (!message.chatId()) throw "Cannot store a message with no chatId";
+			if (!message.serverId && !message.localId) throw "Cannot store a message with no id";
+			if (!message.serverId && message.isIncoming()) throw "Cannot store an incoming message with no server id";
+			if (message.serverId && !message.serverIdBy) throw "Cannot store a message with a server id and no by";
+			new Promise((resolve) =>
+				// Hydrate reply stubs
+				message.replyToMessage && !message.replyToMessage.serverIdBy ? this.getMessage(account, message.chatId(), message.replyToMessage.getReplyId(), message.replyToMessage.getReplyId(), resolve) : resolve(message.replyToMessage)
+			).then((replyToMessage) => {
+				message.replyToMessage = replyToMessage;
+				const tx = db.transaction(["messages", "reactions"], "readwrite");
+				const store = tx.objectStore("messages");
+				return Promise.all([
+					promisifyRequest(store.index("localId").openCursor(IDBKeyRange.only([account, message.localId || [], message.chatId()]))),
+					promisifyRequest(tx.objectStore("reactions").openCursor(IDBKeyRange.only([account, message.chatId(), message.senderId(), message.localId || ""])))
+				]).then(([result, reactionResult]) => {
+					if (reactionResult?.value?.append && message.html().trim() == "") {
+						this.getMessage(account, message.chatId(), reactionResult.value.serverId, reactionResult.value.localId, (reactToMessage) => {
+							const previouslyAppended = hydrateReactionsArray(reactionResult.value.append, reactionResult.value.senderId, reactionResult.value.timestamp).map(r => r.key);
+							const reactions = [];
+							for (const [k, reacts] of reactToMessage.reactions) {
+								for (const react of reacts) {
+									if (react.senderId === message.senderId() && !previouslyAppended.includes(k)) reactions.push(react);
+								}
+							}
+							this.storeReaction(account, new snikket.ReactionUpdate(message.localId, reactionResult.value.serverId, reactionResult.value.serverIdBy, reactionResult.value.localId, message.chatId(), message.senderId(), message.timestamp, reactions, enums.ReactionUpdateKind.CompleteReactions), callback);
+						});
+						return true;
+					} else if (result?.value && !message.isIncoming() && result?.value.direction === enums.MessageDirection.MessageSent && message.versions.length < 1) {
+						// Duplicate, we trust our own sent ids
+						return promisifyRequest(result.delete());
+					} else if (result?.value && (result.value.sender == message.senderId() || result.value.type == enums.MessageType.MessageCall) && (message.versions.length > 0 || (result.value.versions || []).length > 0)) {
+						hydrateMessage(correctMessage(account, message, result)).then(callback);
+						return true;
+					}
+				}).then((done) => {
+					if (!done) {
+						// There may be reactions already if we are paging backwards
+						const cursor = tx.objectStore("reactions").index("senders").openCursor(IDBKeyRange.bound([account, message.chatId(), message.getReplyId() || ""], [account, message.chatId(), message.getReplyId() || "", []]), "prev");
+						const reactions = new Map();
+						const reactionTimes = new Map();
+						cursor.onsuccess = (event) => {
+							if (event.target.result && event.target.result.value) {
+								const time = reactionTimes.get(event.target.result.senderId);
+								if (!time || time < event.target.result.value.timestamp) {
+									setReactions(reactions, event.target.result.value.senderId, hydrateReactionsArray(event.target.result.value.reactions, event.target.result.senderId, event.target.result.timestamp));
+									reactionTimes.set(event.target.result.value.senderId, event.target.result.value.timestamp);
+								}
+								event.target.result.continue();
+							} else {
+								message.reactions = reactions;
+								store.put(serializeMessage(account, message));
+								callback(message);
+							}
+						};
+						cursor.onerror = console.error;
+					}
+				});
+			});
+		},
+
+		updateMessageStatus: function(account, localId, status, callback) {
+			const tx = db.transaction(["messages"], "readwrite");
+			const store = tx.objectStore("messages");
+			promisifyRequest(store.index("localId").openCursor(IDBKeyRange.bound([account, localId], [account, localId, []]))).then((result) => {
+				if (result?.value && result.value.direction === enums.MessageDirection.MessageSent && result.value.status !== enums.MessageStatus.MessageDeliveredToDevice) {
+					const newStatus = { ...result.value, status: status };
+					result.update(newStatus);
+					hydrateMessage(newStatus).then(callback);
+				}
+			});
+		},
+
+		getMessagesBefore: function(account, chatId, beforeId, beforeTime, callback) {
+			// TODO: if beforeId is present but beforeTime is null, lookup time
+			const bound = beforeTime ? new Date(beforeTime) : [];
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			const cursor = store.index("chats").openCursor(
+				IDBKeyRange.bound([account, chatId], [account, chatId, bound]),
+				"prev"
+			);
+			this.getMessagesFromCursor(cursor, beforeId, bound, (messages) => callback(messages.reverse()));
+		},
+
+		getMessagesAfter: function(account, chatId, afterId, afterTime, callback) {
+			// TODO: if afterId is present but afterTime is null, lookup time
+			const bound = afterTime ? [new Date(afterTime)] : [];
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			const cursor = store.index("chats").openCursor(
+				IDBKeyRange.bound([account, chatId].concat(bound), [account, chatId, []]),
+				"next"
+			);
+			this.getMessagesFromCursor(cursor, afterId, bound[0], callback);
+		},
+
+		getMessagesAround: function(account, chatId, id, time, callback) {
+			// TODO: if id is present but time is null, lookup time
+			if (!id && !time) throw "Around what?";
+			const before = new Promise((resolve, reject) =>
+				this.getMessagesBefore(account, chatId, id, time, resolve)
+			);
+
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			const cursor = store.index("chats").openCursor(
+				IDBKeyRange.bound([account, chatId, new Date(time)], [account, chatId, []]),
+				"next"
+			);
+			const aroundAndAfter = new Promise((resolve, reject) =>
+				this.getMessagesFromCursor(cursor, null, null, resolve)
+			);
+
+			Promise.all([before, aroundAndAfter]).then((result) => {
+				callback(result.flat());
+			});
+		},
+
+		getMessagesFromCursor: function(cursor, id, bound, callback) {
+			const result = [];
+			cursor.onsuccess = (event) => {
+				if (event.target.result && result.length < 50) {
+					const value = event.target.result.value;
+					if (value.serverId === id || value.localId === id || (value.timestamp && value.timestamp.getTime() === (bound instanceof Date && bound.getTime()))) {
+						event.target.result.continue();
+						return;
+					}
+
+					result.push(hydrateMessage(value));
+					event.target.result.continue();
+				} else {
+					Promise.all(result).then(callback);
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback([]);
+			}
+		},
+
+		searchMessages: function(account, chatId, q, callback) {
+			const tx = db.transaction(["messages"], "readonly");
+			const store = tx.objectStore("messages");
+			var cursor;
+			if (chatId) {
+				cursor = store.index("chats").openCursor(
+					IDBKeyRange.bound([account, chatId], [account, chatId, []]),
+					"prev"
+				);
+			} else if (account) {
+				cursor = store.index("accounts").openCursor(
+					IDBKeyRange.bound([account], [account, []]),
+					"prev"
+				);
+			} else {
+				cursor = store.openCursor(undefined, "prev");
+			}
+			const qTok = new Set(tokenize(q).map(stemmer));
+			cursor.onsuccess = (event) => {
+				if (event.target.result) {
+					const value = event.target.result.value;
+					if (value.text && new Set(tokenize(value.text).map(stemmer)).isSupersetOf(qTok)) {
+						if (!callback(q, hydrateMessageSync(value))) return;
+					}
+					event.target.result.continue();
+				} else {
+					callback(null);
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback(null);
+			}
+		},
+
+		routeHashPathSW: function() {
+			const waitForMedia = async (uri) => {
+				const r = await this.getMediaResponse(uri);
+				if (r) return r;
+				await new Promise(resolve => setTimeout(resolve, 5000));
+				return await waitForMedia(uri);
+			};
+
+			addEventListener("fetch", (event) => {
+				const url = new URL(event.request.url);
+				if (url.pathname.startsWith("/.well-known/ni/")) {
+					event.respondWith(waitForMedia(url.pathname));
+				}
+			});
+		},
+
+		getMediaResponse: async function(uri) {
+			uri = uri.replace(/^ni:\/\/\//, "/.well-known/ni/").replace(/;/, "/");
+			var niUrl;
+			if (uri.split("/")[3] === "sha-256") {
+				niUrl = uri;
+			} else {
+				const tx = db.transaction(["keyvaluepairs"], "readonly");
+				const store = tx.objectStore("keyvaluepairs");
+				niUrl = await promisifyRequest(store.get(uri));
+				if (!niUrl) {
+					return null;
+				}
+			}
+
+			return await cache.match(niUrl);
+		},
+
+		hasMedia: function(hashAlgorithm, hash, callback) {
+			(async () => {
+				const response = await this.getMediaResponse(hashAlgorithm, hash);
+				return !!response;
+			})().then(callback);
+		},
+
+		storeMedia: function(mime, buffer, callback) {
+			(async function() {
+				const sha256 = await crypto.subtle.digest("SHA-256", buffer);
+				const sha512 = await crypto.subtle.digest("SHA-512", buffer);
+				const sha1 = await crypto.subtle.digest("SHA-1", buffer);
+				const sha256NiUrl = mkNiUrl("sha-256", sha256);
+				await cache.put(sha256NiUrl, new Response(buffer, { headers: { "Content-Type": mime } }));
+
+				const tx = db.transaction(["keyvaluepairs"], "readwrite");
+				const store = tx.objectStore("keyvaluepairs");
+				await promisifyRequest(store.put(sha256NiUrl, mkNiUrl("sha-1", sha1)));
+				await promisifyRequest(store.put(sha256NiUrl, mkNiUrl("sha-512", sha512)));
+			})().then(callback);
+		},
+
+		storeCaps: function(caps) {
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			store.put(caps, "caps:" + caps.ver()).onerror = console.error;
+		},
+
+		getCaps: function(ver, callback) {
+			(async function() {
+				const tx = db.transaction(["keyvaluepairs"], "readonly");
+				const store = tx.objectStore("keyvaluepairs");
+				const raw = await promisifyRequest(store.get("caps:" + ver));
+				if (raw) {
+					return (new snikket.Caps(raw.node, raw.identities.map((identity) => new snikket.Identity(identity.category, identity.type, identity.name)), raw.features));
+				}
+
+				return null;
+			})().then(callback);
+		},
+
+		storeLogin: function(login, clientId, displayName, token) {
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			store.put(clientId, "login:clientId:" + login).onerror = console.error;
+			store.put(displayName, "fn:" + login).onerror = console.error;
+			if (token != null) {
+				store.put(token, "login:token:" + login).onerror = console.error;
+				store.put(0, "login:fastCount:" + login).onerror = console.error;
+			}
+		},
+
+		storeStreamManagement: function(account, sm) {
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			store.put(sm, "sm:" + account).onerror = console.error;
+		},
+
+		getStreamManagement: function(account, callback) {
+			const tx = db.transaction(["keyvaluepairs"], "readonly");
+			const store = tx.objectStore("keyvaluepairs");
+			promisifyRequest(store.get("sm:" + account)).then(
+				(v) => {
+					if (v instanceof ArrayBuffer) {
+						callback(v);
+					} else if(!v) {
+						callback(null);
+					} else {
+						new Blob([JSON.stringify(v)], {type: "text/plain; charset=utf-8"}).arrayBuffer().then(callback);
+					}
+				},
+				(e) => {
+					console.error(e);
+					callback(null);
+				}
+			);
+		},
+
+		getLogin: function(login, callback) {
+			const tx = db.transaction(["keyvaluepairs"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			Promise.all([
+				promisifyRequest(store.get("login:clientId:" + login)),
+				promisifyRequest(store.get("login:token:" + login)),
+				promisifyRequest(store.get("login:fastCount:" + login)),
+				promisifyRequest(store.get("fn:" + login)),
+			]).then((result) => {
+				if (result[1]) {
+					store.put((result[2] || 0) + 1, "login:fastCount:" + login).onerror = console.error;
+				}
+				callback(result[0], result[1], result[2] || 0, result[3]);
+			}).catch((e) => {
+				console.error(e);
+				callback(null, null, 0, null);
+			});
+		},
+
+		removeAccount(account, completely) {
+			const tx = db.transaction(["keyvaluepairs", "services", "messages", "chats", "reactions"], "readwrite");
+			const store = tx.objectStore("keyvaluepairs");
+			store.delete("login:clientId:" + account);
+			store.delete("login:token:" + account);
+			store.delete("login:fastCount:" + account);
+			store.delete("fn:" + account);
+			store.delete("sm:" + account);
+
+			if (!completely) return;
+
+			const servicesStore = tx.objectStore("services");
+			const servicesCursor = servicesStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			servicesCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const messagesStore = tx.objectStore("messages");
+			const messagesCursor = messagesStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			messagesCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const chatsStore = tx.objectStore("chats");
+			const chatsCursor = chatsStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			chatsCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+
+			const reactionsStore = tx.objectStore("reactions");
+			const reactionsCursor = reactionsStore.openCursor(IDBKeyRange.bound([account], [account, []]));
+			reactionsCursor.onsuccess = (event) => {
+				if (event.target.result) {
+					event.target.result.delete();
+					event.target.result.continue();
+				}
+			};
+		},
+
+		storeService(account, serviceId, name, node, caps) {
+			this.storeCaps(caps);
+
+			const tx = db.transaction(["services"], "readwrite");
+			const store = tx.objectStore("services");
+
+			store.put({
+				account: account,
+				serviceId: serviceId,
+				name: name,
+				node: node,
+				caps: caps.ver(),
+			});
+		},
+
+		findServicesWithFeature(account, feature, callback) {
+			const tx = db.transaction(["services"], "readonly");
+			const store = tx.objectStore("services");
+
+			// Almost full scan shouldn't be too expensive, how many services are we aware of?
+			const cursor = store.openCursor(IDBKeyRange.bound([account], [account, []]));
+			const result = [];
+			cursor.onsuccess = (event) => {
+				if (event.target.result) {
+					const value = event.target.result.value;
+					result.push(new Promise((resolve) => this.getCaps(value.caps, (caps) => resolve({ ...value, caps: caps }))));
+					event.target.result.continue();
+				} else {
+					Promise.all(result).then((items) => items.filter((item) => item.caps && item.caps.features.includes(feature))).then(callback);
+				}
+			}
+			cursor.onerror = (event) => {
+				console.error(event);
+				callback([]);
+			}
+		}
+	}
+};
+
+export default browser;
diff --git a/npm/index.d.ts b/npm/index.d.ts
new file mode 100644
index 0000000..94996b6
--- /dev/null
+++ b/npm/index.d.ts
@@ -0,0 +1,38 @@
+import IDBjs from "./IDB.js";
+import MediaStoreCachejs from "./MediaStoreCache.js";
+import { snikket as enums } from "./snikket-enums.js";
+import { snikket } from "./snikket.js";
+export import AvailableChat = snikket.AvailableChat;
+export import Caps = snikket.Caps;
+export import Channel = snikket.Channel;
+export import Chat = snikket.Chat;
+export import ChatAttachment = snikket.ChatAttachment;
+export import ChatMessage = snikket.ChatMessage;
+export import ChatMessageBuilder = snikket.ChatMessageBuilder;
+export import Client = snikket.Client;
+export import Config = snikket.Config;
+export import CustomEmojiReaction = snikket.CustomEmojiReaction;
+export import DirectChat = snikket.DirectChat;
+export import Hash = snikket.Hash;
+export import Identicon = snikket.Identicon;
+export import Identity = snikket.Identity;
+export import Notification = snikket.Notification;
+export import Participant = snikket.Participant;
+export import Push = snikket.Push;
+export import Reaction = snikket.Reaction;
+export import SerializedChat = snikket.SerializedChat;
+export import jingle = snikket.jingle;
+export declare const VERSION: string;
+export import ChatMessageEvent = enums.ChatMessageEvent;
+export import MessageDirection = enums.MessageDirection;
+export import MessageStatus = enums.MessageStatus;
+export import MessageType = enums.MessageType;
+export import ReactionUpdateKind = enums.ReactionUpdateKind;
+export import UiState = enums.UiState;
+export import UserState = enums.UserState;
+export declare namespace persistence {
+    export import IDB = IDBjs;
+    export import MediaStoreCache = MediaStoreCachejs;
+    export import Dummy = snikket.persistence.Dummy;
+    export import Sqlite = snikket.persistence.Sqlite;
+}
diff --git a/npm/index.js b/npm/index.js
new file mode 100644
index 0000000..6e70526
--- /dev/null
+++ b/npm/index.js
@@ -0,0 +1,40 @@
+import { snikket as enums } from "./snikket-enums.js";
+import IDBjs from "./IDB.js";
+import MediaStoreCachejs from "./MediaStoreCache.js";
+import { snikket } from "./snikket.js";
+// TODO: should we autogenerate this?
+export var AvailableChat = snikket.AvailableChat;
+export var Caps = snikket.Caps;
+export var Channel = snikket.Channel;
+export var Chat = snikket.Chat;
+export var ChatAttachment = snikket.ChatAttachment;
+export var ChatMessage = snikket.ChatMessage;
+export var ChatMessageBuilder = snikket.ChatMessageBuilder;
+export var Client = snikket.Client;
+export var Config = snikket.Config;
+export var CustomEmojiReaction = snikket.CustomEmojiReaction;
+export var DirectChat = snikket.DirectChat;
+export var Hash = snikket.Hash;
+export var Identicon = snikket.Identicon;
+export var Identity = snikket.Identity;
+export var Notification = snikket.Notification;
+export var Participant = snikket.Participant;
+export var Push = snikket.Push;
+export var Reaction = snikket.Reaction;
+export var SerializedChat = snikket.SerializedChat;
+export var jingle = snikket.jingle;
+export const VERSION = snikket.Version.HUMAN;
+export var ChatMessageEvent = enums.ChatMessageEvent;
+export var MessageDirection = enums.MessageDirection;
+export var MessageStatus = enums.MessageStatus;
+export var MessageType = enums.MessageType;
+export var ReactionUpdateKind = enums.ReactionUpdateKind;
+export var UiState = enums.UiState;
+export var UserState = enums.UserState;
+export var persistence;
+(function (persistence) {
+    persistence.IDB = IDBjs;
+    persistence.MediaStoreCache = MediaStoreCachejs;
+    persistence.Dummy = snikket.persistence.Dummy;
+    persistence.Sqlite = snikket.persistence.Sqlite;
+})(persistence || (persistence = {}));
diff --git a/npm/snikket-browser-enums.ts b/npm/snikket-browser-enums.ts
new file mode 100644
index 0000000..0f094be
--- /dev/null
+++ b/npm/snikket-browser-enums.ts
@@ -0,0 +1,61 @@
+/* tslint:disable */// Generated by Haxe TypeScript Declaration Generator :)
+
+export namespace snikket {
+	export const enum UiState {
+		Pinned = 0,
+		Open = 1,
+		Closed = 2,
+	}
+}
+
+export namespace snikket {
+	export const enum MessageDirection {
+		MessageReceived = 0,
+		MessageSent = 1,
+	}
+}
+
+export namespace snikket {
+	export const enum MessageStatus {
+		MessagePending = 0,
+		MessageDeliveredToServer = 1,
+		MessageDeliveredToDevice = 2,
+		MessageFailedToSend = 3,
+	}
+}
+
+export namespace snikket {
+	export const enum MessageType {
+		MessageChat = 0,
+		MessageCall = 1,
+		MessageChannel = 2,
+		MessageChannelPrivate = 3,
+	}
+}
+
+export namespace snikket {
+	export const enum UserState {
+		Gone = 0,
+		Inactive = 1,
+		Active = 2,
+		Composing = 3,
+		Paused = 4,
+	}
+}
+
+export namespace snikket {
+	export const enum ChatMessageEvent {
+		DeliveryEvent = 0,
+		CorrectionEvent = 1,
+		ReactionEvent = 2,
+		StatusEvent = 3,
+	}
+}
+
+export namespace snikket {
+	export const enum ReactionUpdateKind {
+		EmojiReactions = 0,
+		AppendReactions = 1,
+		CompleteReactions = 2,
+	}
+}
\ No newline at end of file
diff --git a/npm/snikket-browser.d.ts b/npm/snikket-browser.d.ts
new file mode 100644
index 0000000..9af6860
--- /dev/null
+++ b/npm/snikket-browser.d.ts
@@ -0,0 +1,1109 @@
+/* tslint:disable */// Generated by Haxe TypeScript Declaration Generator :)
+
+import { snikket as enums } from "./snikket-browser-enums";
+
+export namespace snikket {
+	export class Caps {
+		constructor(node: string, identities: snikket.Identity[], features: string[]);
+		node: string;
+		identities: snikket.Identity[];
+		features: string[];
+		isChannel(chatId: string): boolean;
+		discoReply(): snikket.Stanza;
+		addC(stanza: snikket.Stanza): snikket.Stanza;
+		verRaw(): snikket.Hash;
+		ver(): string;
+	}
+}
+
+export namespace snikket {
+	export class Identity {
+		constructor(category: string, type: string, name: string);
+		category: string;
+		type: string;
+		name: string;
+		addToDisco(stanza: snikket.Stanza): void;
+		ver(): string;
+	}
+}
+
+export namespace snikket {
+	export class GenericStream extends snikket.EventEmitter {
+		constructor();
+		_hx_constructor(): void;
+		clientId: string;
+		readonly csi: boolean;
+		connect(jid: string, sm: ArrayBuffer): void;
+		disconnect(): void;
+		sendStanza(stanza: snikket.Stanza): void;
+		newId(): string;
+		onIq(type: any, tag: string, xmlns: string, handler: (arg0: snikket.Stanza) => any): void;
+		sendIq(stanza: snikket.Stanza, callback: (stanza: snikket.Stanza) => void): void;
+	}
+}
+
+export namespace snikket {
+	export class Chat {
+		protected constructor(client: snikket.Client, stream: snikket.GenericStream, persistence: snikket.Persistence, chatId: string, uiState?: enums.UiState, isBlocked?: boolean, extensions?: snikket.Stanza, readUpToId?: string, readUpToBy?: string);
+		/**
+		 * ID of this Chat
+		 */
+		readonly chatId: string;
+		/**
+		 * Current state of this chat
+		 */
+		readonly uiState: enums.UiState;
+		readonly isBlocked: boolean;
+		/**
+		 * Fetch a page of messages before some point
+		 * @param beforeId id of the message to look before
+		 * @param beforeTime timestamp of the message to look before,
+		 * String in format YYYY-MM-DDThh:mm:ss[.sss]+00:00
+		 * @param handler takes one argument, an array of ChatMessage that are found
+		 */
+		getMessagesBefore(beforeId: string, beforeTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		/**
+		 * Fetch a page of messages after some point
+		 * @param afterId id of the message to look after
+		 * @param afterTime timestamp of the message to look after,
+		 * String in format YYYY-MM-DDThh:mm:ss[.sss]+00:00
+		 * @param handler takes one argument, an array of ChatMessage that are found
+		 */
+		getMessagesAfter(afterId: string, afterTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		/**
+		 * Fetch a page of messages around (before, including, and after) some point
+		 * @param aroundId id of the message to look around
+		 * @param aroundTime timestamp of the message to look around,
+		 * String in format YYYY-MM-DDThh:mm:ss[.sss]+00:00
+		 * @param handler takes one argument, an array of ChatMessage that are found
+		 */
+		getMessagesAround(aroundId: string, aroundTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		/**
+		 * Send a ChatMessage to this Chat
+		 * @param message the ChatMessage to send
+		 */
+		sendMessage(message: snikket.ChatMessageBuilder): void;
+		/**
+		 * Signals that all messages up to and including this one have probably
+		 * been displayed to the user
+		 * @param message the ChatMessage most recently displayed
+		 */
+		markReadUpTo(message: snikket.ChatMessage): void;
+		/**
+		 * Save this Chat on the server
+		 */
+		bookmark(): void;
+		/**
+		 * Get the list of IDs of participants in this Chat
+		 * @returns array of IDs
+		 */
+		getParticipants(): string[];
+		/**
+		 * Get the details for one participant in this Chat
+		 * @param participantId the ID of the participant to look up
+		 */
+		getParticipantDetails(participantId: string): snikket.Participant;
+		/**
+		 * Correct an already-send message by replacing it with a new one
+		 * @param localId the localId of the message to correct
+		 * must be the localId of the first version ever sent, not a subsequent correction
+		 * @param message the new ChatMessage to replace it with
+		 */
+		correctMessage(localId: string, message: snikket.ChatMessageBuilder): void;
+		/**
+		 * Add new reaction to a message in this Chat
+		 * @param m ChatMessage to react to
+		 * @param reaction emoji of the reaction
+		 */
+		addReaction(m: snikket.ChatMessage, reaction: snikket.Reaction): void;
+		/**
+		 * Remove an already-sent reaction from a message
+		 * @param m ChatMessage to remove the reaction from
+		 * @param reaction the emoji to remove
+		 */
+		removeReaction(m: snikket.ChatMessage, reaction: snikket.Reaction): void;
+		/**
+		 * Call this whenever the user is typing, can call on every keystroke
+		 * @param threadId optional, what thread the user has selected if any
+		 * @param content optional, what the user has typed so far
+		 */
+		typing(threadId: string, content: string): void;
+		/**
+		 * Call this whenever the user makes a chat or thread "active" in your UX
+		 * If you call this with true you MUST later call it will false
+		 * @param active true if the chat is "active", false otherwise
+		 * @param threadId optional, what thread the user has selected if any
+		 */
+		setActive(active: boolean, threadId: string): void;
+		/**
+		 * Archive this chat
+		 */
+		close(): void;
+		/**
+		 * Pin or unpin this chat
+		 */
+		togglePinned(): void;
+		/**
+		 * Block this chat so it will not re-open
+		 */
+		block(reportSpam: snikket.ChatMessage, onServer: boolean): void;
+		/**
+		 * Unblock this chat so it will open again
+		 */
+		unblock(onServer: boolean): void;
+		/**
+		 * An ID of the most recent message in this chat
+		 */
+		lastMessageId(): string;
+		/**
+		 * The timestamp of the most recent message in this chat
+		 */
+		lastMessageTimestamp(): string;
+		/**
+		 * Get the URI image to represent this Chat, or null
+		 */
+		getPhoto(): string;
+		/**
+		 * Get the URI to a placeholder image to represent this Chat
+		 */
+		getPlaceholder(): string;
+		/**
+		 * An ID of the last message displayed to the user
+		 */
+		readUpTo(): string;
+		/**
+		 * The number of message that have not yet been displayed to the user
+		 */
+		unreadCount(): number;
+		/**
+		 * A preview of the chat, such as the most recent message body
+		 */
+		preview(): string;
+		setDisplayName(fn: string): void;
+		/**
+		 * The display name of this Chat
+		 */
+		getDisplayName(): string;
+		setTrusted(trusted: boolean): void;
+		/**
+		 * Is this a chat with an entity we trust to see our online status?
+		 */
+		isTrusted(): boolean;
+		syncing(): boolean;
+		/**
+		 * Can audio calls be started in this Chat?
+		 */
+		canAudioCall(): boolean;
+		/**
+		 * Can video calls be started in this Chat?
+		 */
+		canVideoCall(): boolean;
+		/**
+		 * Start a new call in this Chat
+		 * @param audio do we want audio in this call
+		 * @param video do we want video in this call
+		 */
+		startCall(audio: boolean, video: boolean): void;
+		addMedia(streams: MediaStream[]): void;
+		/**
+		 * Accept any incoming calls in this Chat
+		 */
+		acceptCall(): void;
+		/**
+		 * Hangup or reject any calls in this chat
+		 */
+		hangup(): void;
+		/**
+		 * The current status of a call in this chat
+		 */
+		callStatus(): string;
+		/**
+		 * A DTMFSender for a call in this chat, or NULL
+		 */
+		dtmf(): RTCDTMFSender;
+		/**
+		 * All video tracks in all active calls in this chat
+		 */
+		videoTracks(): MediaStreamTrack[];
+	}
+}
+
+export namespace snikket {
+	export class DirectChat extends snikket.Chat {
+		protected constructor(client: snikket.Client, stream: snikket.GenericStream, persistence: snikket.Persistence, chatId: string, uiState?: enums.UiState, isBlocked?: boolean, extensions?: snikket.Stanza, readUpToId?: string, readUpToBy?: string);
+		getParticipants(): string[];
+		getParticipantDetails(participantId: string): snikket.Participant;
+		getMessagesBefore(beforeId: string, beforeTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(afterId: string, afterTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(aroundId: string, aroundTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		correctMessage(localId: string, message: snikket.ChatMessageBuilder): void;
+		sendMessage(message: snikket.ChatMessageBuilder): void;
+		removeReaction(m: snikket.ChatMessage, reaction: snikket.Reaction): void;
+		lastMessageId(): string;
+		markReadUpTo(message: snikket.ChatMessage): void;
+		bookmark(): void;
+		close(): void;
+	}
+}
+
+export namespace snikket {
+	export class Channel extends snikket.Chat {
+		protected constructor(client: snikket.Client, stream: snikket.GenericStream, persistence: snikket.Persistence, chatId: string, uiState?: enums.UiState, isBlocked?: boolean, extensions?: snikket.Stanza, readUpToId?: string, readUpToBy?: string, disco?: snikket.Caps);
+		setPresence(resource: string, presence: snikket.Presence): void;
+		isTrusted(): boolean;
+		preview(): string;
+		syncing(): boolean;
+		canAudioCall(): boolean;
+		canVideoCall(): boolean;
+		getParticipants(): string[];
+		getParticipantDetails(participantId: string): snikket.Participant;
+		getMessagesBefore(beforeId: string, beforeTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(afterId: string, afterTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(aroundId: string, aroundTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		correctMessage(localId: string, message: snikket.ChatMessageBuilder): void;
+		sendMessage(message: snikket.ChatMessageBuilder): void;
+		removeReaction(m: snikket.ChatMessage, reaction: snikket.Reaction): void;
+		lastMessageId(): string;
+		markReadUpTo(message: snikket.ChatMessage): void;
+		bookmark(): void;
+		close(): void;
+	}
+}
+
+export namespace snikket {
+	export class AvailableChat {
+		protected constructor(chatId: string, displayName: string, note: string, caps: snikket.Caps);
+		/**
+		 * The ID of the Chat this search result represents
+		 */
+		chatId: string;
+		/**
+		 * The display name of this search result
+		 */
+		displayName: string;
+		/**
+		 * A human-readable note associated with this search result
+		 */
+		note: string;
+		/**
+		 * Is this search result a channel?
+		 */
+		isChannel(): boolean;
+	}
+}
+
+export namespace snikket {
+	export class SerializedChat {
+		constructor(chatId: string, trusted: boolean, avatarSha1: ArrayBuffer, presence: Map<string,snikket.Presence>, displayName: string, uiState: enums.UiState, isBlocked: boolean, extensions: string, readUpToId: string, readUpToBy: string, disco: snikket.Caps, klass: string);
+		chatId: string;
+		trusted: boolean;
+		avatarSha1: ArrayBuffer;
+		presence: Map<string,snikket.Presence>;
+		displayName: string;
+		uiState: enums.UiState;
+		isBlocked: boolean;
+		extensions: string;
+		readUpToId: string;
+		readUpToBy: string;
+		disco: snikket.Caps;
+		klass: string;
+		toChat(client: snikket.Client, stream: snikket.GenericStream, persistence: snikket.Persistence): snikket.Chat;
+	}
+}
+
+export namespace snikket {
+	export class ChatAttachment {
+		constructor(name: string, mime: string, size: number, uris: string[], hashes: snikket.Hash[]);
+		name: string;
+		mime: string;
+		size: number;
+		uris: string[];
+		hashes: snikket.Hash[];
+	}
+}
+
+export namespace snikket {
+	export class ChatMessage {
+		protected constructor(params: {attachments?: snikket.ChatAttachment[], direction?: enums.MessageDirection, from: snikket.JID, lang?: string, localId?: string, payloads?: snikket.Stanza[], reactions?: Map<string,snikket.Reaction[]>, recipients?: snikket.JID[], replyId?: string, replyTo?: snikket.JID[], replyToMessage?: snikket.ChatMessage, senderId: string, serverId?: string, serverIdBy?: string, stanza?: snikket.Stanza, status?: enums.MessageStatus, syncPoint?: boolean, text?: string, threadId?: string, timestamp: string, to: snikket.JID, type?: enums.MessageType, versions?: snikket.ChatMessage[]});
+		/**
+		 * The ID as set by the creator of this message
+		 */
+		localId: string;
+		/**
+		 * The ID as set by the authoritative server
+		 */
+		serverId: string;
+		/**
+		 * The ID of the server which set the serverId
+		 */
+		serverIdBy: string;
+		/**
+		 * The type of this message (Chat, Call, etc)
+		 */
+		type: enums.MessageType;
+		/**
+		 * The timestamp of this message, in format YYYY-MM-DDThh:mm:ss[.sss]Z
+		 */
+		timestamp: string;
+		/**
+		 * The ID of the sender of this message
+		 */
+		senderId: string;
+		/**
+		 * Message this one is in reply to, or NULL
+		 */
+		readonly replyToMessage: snikket.ChatMessage;
+		/**
+		 * ID of the thread this message is in, or NULL
+		 */
+		threadId: string;
+		/**
+		 * Array of attachments to this message
+		 */
+		attachments: snikket.ChatAttachment[];
+		/**
+		 * Map of reactions to this message
+		 */
+		readonly reactions: Map<string,snikket.Reaction[]>;
+		/**
+		 * Body text of this message or NULL
+		 */
+		text: string;
+		/**
+		 * Language code for the body text
+		 */
+		lang: string;
+		/**
+		 * Direction of this message
+		 */
+		direction: enums.MessageDirection;
+		/**
+		 * Status of this message
+		 */
+		status: enums.MessageStatus;
+		/**
+		 * Array of past versions of this message, if it has been edited
+		 */
+		versions: snikket.ChatMessage[];
+		stanza: snikket.Stanza;
+		/**
+		 * Create a new ChatMessage in reply to this one
+		 */
+		reply(): snikket.ChatMessageBuilder;
+		getReplyId(): string;
+		/**
+		 * Get HTML version of the message body
+		 * WARNING: this is possibly untrusted HTML. You must parse or sanitize appropriately!
+		 */
+		html(): string;
+		/**
+		 * The ID of the Chat this message is associated with
+		 */
+		chatId(): string;
+		/**
+		 * The ID of the account associated with this message
+		 */
+		account(): string;
+		/**
+		 * Is this an incoming message?
+		 */
+		isIncoming(): boolean;
+		/**
+		 * The URI of an icon for the thread associated with this message, or NULL
+		 */
+		threadIcon(): string;
+		/**
+		 * The last status of the call if this message is related to a call
+		 */
+		callStatus(): string;
+		/**
+		 * The session id of the call if this message is related to a call
+		 */
+		callSid(): string;
+		/**
+		 * The duration of the call if this message is related to a call
+		 */
+		callDuration(): string;
+	}
+}
+
+export namespace snikket {
+	export class ChatMessageBuilder {
+		/**
+		 * @returns a new blank ChatMessageBuilder
+		 */
+		constructor(params?: {attachments?: snikket.ChatAttachment[], direction?: enums.MessageDirection, html?: string, lang?: string, localId?: string, payloads?: snikket.Stanza[], reactions?: Map<string,snikket.Reaction[]>, replyId?: string, replyToMessage?: snikket.ChatMessage, senderId?: string, serverId?: string, serverIdBy?: string, status?: enums.MessageStatus, syncPoint?: boolean, text?: string, threadId?: string, timestamp?: string, type?: enums.MessageType, versions?: snikket.ChatMessage[]});
+		/**
+		 * The ID as set by the creator of this message
+		 */
+		localId: string;
+		/**
+		 * The ID as set by the authoritative server
+		 */
+		serverId: string;
+		/**
+		 * The ID of the server which set the serverId
+		 */
+		serverIdBy: string;
+		/**
+		 * The type of this message (Chat, Call, etc)
+		 */
+		type: enums.MessageType;
+		/**
+		 * The timestamp of this message, in format YYYY-MM-DDThh:mm:ss[.sss]+00:00
+		 */
+		timestamp: string;
+		/**
+		 * Message this one is in reply to, or NULL
+		 */
+		replyToMessage: snikket.ChatMessage;
+		/**
+		 * ID of the thread this message is in, or NULL
+		 */
+		threadId: string;
+		/**
+		 * Array of attachments to this message
+		 */
+		readonly attachments: snikket.ChatAttachment[];
+		/**
+		 * Map of reactions to this message
+		 */
+		reactions: Map<string,snikket.Reaction[]>;
+		/**
+		 * Body text of this message or NULL
+		 */
+		text: string;
+		/**
+		 * Language code for the body text
+		 */
+		lang: string;
+		/**
+		 * Direction of this message
+		 */
+		direction: enums.MessageDirection;
+		/**
+		 * Status of this message
+		 */
+		status: enums.MessageStatus;
+		/**
+		 * Array of past versions of this message, if it has been edited
+		 */
+		readonly versions: snikket.ChatMessage[];
+		addAttachment(attachment: snikket.ChatAttachment): void;
+		/**
+		 * Set rich text using an HTML string
+		 * Also sets the plain text body appropriately
+		 */
+		setHtml(html: string): void;
+		/**
+		 * The ID of the Chat this message is associated with
+		 */
+		chatId(): string;
+		/**
+		 * The ID of the sender of this message
+		 */
+		get_senderId(): string;
+		isIncoming(): boolean;
+		build(): snikket.ChatMessage;
+	}
+}
+
+export namespace snikket {
+	export class EventHandler {
+		constructor(handlers: snikket.EventHandler[], callback: (arg0: any) => any, onlyOnce?: boolean);
+		call(data: any): any;
+		once(): snikket.EventHandler;
+		unsubscribe(): void;
+	}
+}
+
+export namespace snikket {
+	export class EventEmitter {
+		protected constructor();
+		once(eventName: string, callback: (arg0: any) => any): snikket.EventHandler;
+		trigger(eventName: string, eventData: any): any;
+	}
+}
+
+export namespace snikket.jingle {
+	export interface Session {
+		get_sid(): string;
+		accept(): void;
+		hangup(): void;
+		addMedia(streams: MediaStream[]): void;
+		callStatus(): string;
+		videoTracks(): MediaStreamTrack[];
+		dtmf(): RTCDTMFSender;
+	}
+}
+
+export namespace snikket.jingle {
+	export class Attribute {
+		constructor(key: string, value: string);
+		readonly key: string;
+		readonly value: string;
+		toSdp(): string;
+		toString(): string;
+		static parse(input: string): snikket.jingle.Attribute;
+	}
+}
+
+export namespace snikket.jingle {
+	export class Media {
+		constructor(mid: string, media: string, connectionData: string, port: string, protocol: string, attributes: snikket.jingle.Attribute[], formats: number[]);
+		readonly mid: string;
+		readonly media: string;
+		readonly connectionData: string;
+		readonly port: string;
+		readonly protocol: string;
+		readonly attributes: snikket.jingle.Attribute[];
+		readonly formats: number[];
+		toSdp(): string;
+		contentElement(initiator: boolean): snikket.Stanza;
+		toElement(sessionAttributes: snikket.jingle.Attribute[], initiator: boolean): snikket.Stanza;
+		getUfragPwd(sessionAttributes?: snikket.jingle.Attribute[]): {pwd: string, ufrag: string};
+		toTransportElement(sessionAttributes: snikket.jingle.Attribute[]): snikket.Stanza;
+		static fromElement(content: snikket.Stanza, initiator: boolean, hasGroup: boolean, existingDescription?: snikket.jingle.SessionDescription): snikket.jingle.Media;
+	}
+}
+
+export namespace snikket.jingle {
+	export class SessionDescription {
+		constructor(version: number, name: string, media: snikket.jingle.Media[], attributes: snikket.jingle.Attribute[], identificationTags: string[]);
+		readonly version: number;
+		readonly name: string;
+		readonly media: snikket.jingle.Media[];
+		readonly attributes: snikket.jingle.Attribute[];
+		readonly identificationTags: string[];
+		getUfragPwd(): {pwd: string, ufrag: string};
+		getFingerprint(): snikket.jingle.Attribute;
+		getDtlsSetup(): string;
+		addContent(newDescription: snikket.jingle.SessionDescription): snikket.jingle.SessionDescription;
+		toSdp(): string;
+		toStanza(action: string, sid: string, initiator: boolean): snikket.Stanza;
+		static parse(input: string): snikket.jingle.SessionDescription;
+		static fromStanza(iq: snikket.Stanza, initiator: boolean, existingDescription?: snikket.jingle.SessionDescription): snikket.jingle.SessionDescription;
+	}
+}
+
+export namespace snikket.jingle {
+	export class InitiatedSession implements snikket.jingle.Session {
+		protected constructor(client: snikket.Client, counterpart: snikket.JID, sid: string, remoteDescription: snikket.jingle.SessionDescription);
+		get_sid(): string;
+		accept(): void;
+		hangup(): void;
+		addMedia(streams: MediaStream[]): void;
+		callStatus(): string;
+		videoTracks(): MediaStreamTrack[];
+		dtmf(): RTCDTMFSender;
+		supplyMedia(streams: MediaStream[]): void;
+	}
+}
+
+export namespace snikket {
+	export class Client extends snikket.EventEmitter {
+		/**
+		 * Create a new Client to connect to a particular account
+		 * @param address the account to connect to
+		 * @param persistence the persistence layer to use for storage
+		 */
+		constructor(address: string, persistence: snikket.Persistence);
+		/**
+		 * Set to false to suppress sending available presence
+		 */
+		sendAvailable: boolean;
+		/**
+		 * Start this client running and trying to connect to the server
+		 */
+		start(): void;
+		/**
+		 * Destroy local data for this account
+		 * @param completely if true chats, messages, etc will be deleted as well
+		 */
+		logout(completely: boolean): void;
+		/**
+		 * Sets the password to be used in response to the password needed event
+		 * @param password
+		 */
+		usePassword(password: string): void;
+		/**
+		 * Get the account ID for this Client
+		 * @returns account id
+		 */
+		accountId(): string;
+		/**
+		 * Get the current display name for this account
+		 * @returns display name
+		 */
+		displayName(): string;
+		/**
+		 * Set the current display name for this account on the server
+		 * @param display name to set (ignored if empty or NULL)
+		 */
+		setDisplayName(displayName: string): void;
+		/**
+		 * Turn a file into a ChatAttachment for attaching to a ChatMessage
+		 */
+		prepareAttachment(source: File, callback: (arg0: snikket.ChatAttachment) => void): void;
+		/**
+		 * @returns array of open chats, sorted by last activity
+		 */
+		getChats(): snikket.Chat[];
+		/**
+		 * Search for chats the user can start or join
+		 * @param q the search query to use
+		 * @param callback takes two arguments, the query that was used and the array of results
+		 */
+		findAvailableChats(q: string, callback: (arg0: string, arg1: snikket.AvailableChat[]) => void): void;
+		/**
+		 * Start or join a chat from the search results
+		 * @returns the chat that was started
+		 */
+		startChat(availableChat: snikket.AvailableChat): snikket.Chat;
+		/**
+		 * Find a chat by id
+		 * @returns the chat if known, or NULL
+		 */
+		getChat(chatId: string): snikket.Chat;
+		subscribePush(reg: ServiceWorkerRegistration, push_service: string, vapid_key: {privateKey: CryptoKey, publicKey: CryptoKey}): void;
+		enablePush(push_service: string, vapid_private_key: CryptoKey, endpoint: string, p256dh: ArrayBuffer, auth: ArrayBuffer): void;
+		/**
+		 * Event fired when client needs a password for authentication
+		 * @param handler takes one argument, the Client that needs a password
+		 */
+		addPasswordNeededListener(handler: (arg0: snikket.Client) => void): void;
+		/**
+		 * Event fired when client is connected and fully synchronized
+		 * @param handler takes no arguments
+		 */
+		addStatusOnlineListener(handler: () => void): void;
+		/**
+		 * Event fired when client is disconnected
+		 * @param handler takes no arguments
+		 */
+		addStatusOfflineListener(handler: () => void): void;
+		/**
+		 * Event fired when connection fails with a fatal error and will not be retried
+		 * @param handler takes no arguments
+		 */
+		addConnectionFailedListener(handler: () => void): void;
+		addUserStateListener(handler: (arg0: string, arg1: string, arg2: string, arg3: enums.UserState) => void): void;
+		/**
+		 * Event fired when a new ChatMessage comes in on any Chat
+		 * Also fires when status of a ChatMessage changes,
+		 * when a ChatMessage is edited, or when a reaction is added
+		 * @param handler takes two arguments, the ChatMessage and ChatMessageEvent enum describing what happened
+		 */
+		addChatMessageListener(handler: (arg0: snikket.ChatMessage, arg1: enums.ChatMessageEvent) => void): void;
+		/**
+		 * Event fired when syncing a new ChatMessage that was send when offline.
+		 * Normally you don't want this, but it may be useful if you want to notify on app start.
+		 * @param handler takes one argument, the ChatMessage
+		 */
+		addSyncMessageListener(handler: (arg0: snikket.ChatMessage) => void): void;
+		/**
+		 * Event fired when a Chat's metadata is updated, or when a new Chat is added
+		 * @param handler takes one argument, an array of Chats that were updated
+		 */
+		addChatsUpdatedListener(handler: (arg0: snikket.Chat[]) => void): void;
+		/**
+		 * Event fired when a new call comes in
+		 * @param handler takes two arguments, the call Session and the associated Chat ID
+		 */
+		addCallRingListener(handler: (arg0: snikket.jingle.Session, arg1: string) => void): void;
+		/**
+		 * Event fired when a call is retracted or hung up
+		 * @param handler takes one argument, the associated Chat ID
+		 */
+		addCallRetractListener(handler: (arg0: string) => void): void;
+		/**
+		 * Event fired when an outgoing call starts ringing
+		 * @param handler takes one argument, the associated Chat ID
+		 */
+		addCallRingingListener(handler: (arg0: string) => void): void;
+		/**
+		 * Event fired when a call is asking for media to send
+		 * @param handler takes three arguments, the call Session,
+		 * a boolean indicating if audio is desired,
+		 * and a boolean indicating if video is desired
+		 */
+		addCallMediaListener(handler: (arg0: snikket.jingle.InitiatedSession, arg1: boolean, arg2: boolean) => void): void;
+		/**
+		 * Event fired when call has a new MediaStreamTrack to play
+		 * @param handler takes three arguments, the associated Chat ID,
+		 * the new MediaStreamTrack, and an array of any associated MediaStreams
+		 */
+		addCallTrackListener(handler: (arg0: string, arg1: MediaStreamTrack, arg2: MediaStream[]) => void): void;
+		/**
+		 * Let the SDK know the UI is in the foreground
+		 */
+		setInForeground(): void;
+		/**
+		 * Let the SDK know the UI is in the foreground
+		 */
+		setNotInForeground(): void;
+	}
+}
+
+export namespace snikket {
+	export class Config {
+		protected constructor();
+		/**
+		 * Produce /.well-known/ni/ paths instead of ni:/// URIs
+		 * for referencing media by hash.
+		 * This can be useful eg for intercepting with a Service Worker.
+		 */
+		static relativeHashUri: boolean;
+	}
+}
+
+export namespace haxe.io {
+	export class Bytes {
+		protected constructor(data: ArrayBuffer);
+		readonly length: number;
+		/**
+		 * Copies `len` bytes from `src` into this instance.
+		 * @param pos Zero-based location in `this` instance at which to start writing
+		 * bytes.
+		 * @param src Source `Bytes` instance from which to copy bytes.
+		 * @param srcpos Zero-based location at `src` from which bytes will be copied.
+		 * @param len Number of bytes to be copied.
+		 */
+		blit(pos: number, src: haxe.io.Bytes, srcpos: number, len: number): void;
+		/**
+		 * Sets `len` consecutive bytes starting from index `pos` of `this` instance
+		 * to `value`.
+		 */
+		fill(pos: number, len: number, value: number): void;
+		/**
+		 * Returns a new `Bytes` instance that contains a copy of `len` bytes of
+		 * `this` instance, starting at index `pos`.
+		 */
+		sub(pos: number, len: number): haxe.io.Bytes;
+		/**
+		 * Returns the 16-bit unsigned integer at the given position `pos` (in
+		 * little-endian encoding).
+		 */
+		getUInt16(pos: number): number;
+		/**
+		 * Returns the `len`-bytes long string stored at the given position `pos`,
+		 * interpreted with the given `encoding` (UTF-8 by default).
+		 */
+		getString(pos: number, len: number, encoding?: any): string;
+		/**
+		 * Returns a `String` representation of the bytes interpreted as UTF-8.
+		 */
+		toString(): string;
+		/**
+		 * Returns a hexadecimal `String` representation of the bytes of `this`
+		 * instance.
+		 */
+		toHex(): string;
+		/**
+		 * Returns the `Bytes` representation of the given `String`, using the
+		 * specified encoding (UTF-8 by default).
+		 */
+		static ofString(s: string, encoding?: any): haxe.io.Bytes;
+		/**
+		 * Returns the `Bytes` representation of the given `BytesData`.
+		 */
+		static ofData(b: ArrayBuffer): haxe.io.Bytes;
+		/**
+		 * Converts the given hexadecimal `String` to `Bytes`. `s` must be a string of
+		 * even length consisting only of hexadecimal digits. For example:
+		 * `"0FDA14058916052309"`.
+		 */
+		static ofHex(s: string): haxe.io.Bytes;
+	}
+}
+
+export namespace snikket {
+	export class Hash {
+		protected constructor(algorithm: string, hash: ArrayBuffer);
+		algorithm: string;
+		toUri(): string;
+		toHex(): string;
+		toBase64(): string;
+		toBase64Url(): string;
+		static fromHex(algorithm: string, hash: string): snikket.Hash;
+		static fromUri(uri: string): snikket.Hash;
+		static sha1(bytes: haxe.io.Bytes): snikket.Hash;
+		static sha256(bytes: haxe.io.Bytes): snikket.Hash;
+	}
+}
+
+export namespace snikket {
+	export class Identicon {
+		protected constructor();
+		static svg(source: string): string;
+	}
+}
+
+export namespace snikket {
+	export class JID {
+		constructor(node: string, domain: string, resource?: string);
+		node: string;
+		domain: string;
+		resource: string;
+		asBare(): snikket.JID;
+		withResource(resource: string): snikket.JID;
+		isValid(): boolean;
+		isDomain(): boolean;
+		isBare(): boolean;
+		equals(rhs: snikket.JID): boolean;
+		asString(): string;
+		static parse(jid: string): snikket.JID;
+	}
+}
+
+export namespace snikket {
+	export class Notification {
+		constructor(title: string, body: string, accountId: string, chatId: string, messageId: string, type: enums.MessageType, callStatus: string, callSid: string, imageUri: string, lang: string, timestamp: string);
+		readonly title: string;
+		readonly body: string;
+		readonly accountId: string;
+		readonly chatId: string;
+		readonly messageId: string;
+		readonly type: enums.MessageType;
+		readonly callStatus: string;
+		readonly callSid: string;
+		readonly imageUri: string;
+		readonly lang: string;
+		readonly timestamp: string;
+		static fromChatMessage(m: snikket.ChatMessage): snikket.Notification;
+		static fromThinStanza(stanza: snikket.Stanza): snikket.Notification;
+	}
+}
+
+export namespace snikket {
+	export class Participant {
+		protected constructor(displayName: string, photoUri: string, placeholderUri: string, isSelf: boolean);
+		displayName: string;
+		photoUri: string;
+		placeholderUri: string;
+		isSelf: boolean;
+	}
+}
+
+export namespace snikket {
+	export class Presence {
+		constructor(caps: snikket.Caps, mucUser: snikket.Stanza);
+		caps: snikket.Caps;
+		mucUser: snikket.Stanza;
+	}
+}
+
+export namespace snikket.Push {
+	export function receive(data: string, persistence: snikket.Persistence): snikket.Notification;
+}
+
+export namespace snikket {
+	export class Reaction {
+		constructor(senderId: string, timestamp: string, text: string, envelopeId?: string, key?: string);
+		senderId: string;
+		timestamp: string;
+		text: string;
+		key: string;
+		envelopeId: string;
+		render<T>(forText: (arg0: string) => T, forImage: (arg0: string, arg1: string) => T): T;
+	}
+}
+
+export namespace snikket {
+	export class CustomEmojiReaction extends snikket.Reaction {
+		constructor(senderId: string, timestamp: string, text: string, uri: string, envelopeId?: string);
+		uri: string;
+		render<T>(forText: (arg0: string) => T, forImage: (arg0: string, arg1: string) => T): T;
+	}
+}
+
+export namespace snikket {
+	export class ReactionUpdate {
+		constructor(updateId: string, serverId: string, serverIdBy: string, localId: string, chatId: string, senderId: string, timestamp: string, reactions: snikket.Reaction[], kind: enums.ReactionUpdateKind);
+		updateId: string;
+		serverId: string;
+		serverIdBy: string;
+		localId: string;
+		chatId: string;
+		senderId: string;
+		timestamp: string;
+		reactions: snikket.Reaction[];
+		kind: enums.ReactionUpdateKind;
+		getReactions(existingReactions: snikket.Reaction[]): snikket.Reaction[];
+	}
+}
+
+export namespace snikket._Stanza {
+	export interface NodeInterface {
+		serialize(): string;
+		clone(): snikket._Stanza.NodeInterface;
+		traverse(f: (arg0: snikket.Stanza) => boolean): snikket._Stanza.NodeInterface;
+	}
+}
+
+export namespace snikket {
+	export class StanzaError {
+		constructor(type_: string, condition_: string, text_?: string);
+		type: string;
+		condition: string;
+		text: string;
+	}
+}
+
+export namespace snikket {
+	export class Stanza implements snikket._Stanza.NodeInterface {
+		constructor(name: string, attr?: { [key: string]: string });
+		readonly name: string;
+		readonly attr: { [key: string]: string };
+		readonly children: any[];
+		serialize(): string;
+		toString(): string;
+		tag(name: string, attr?: { [key: string]: string }): snikket.Stanza;
+		text(content: string): snikket.Stanza;
+		textTag(tagName: string, textContent: string, attr?: { [key: string]: string }): snikket.Stanza;
+		up(): snikket.Stanza;
+		reset(): snikket.Stanza;
+		addChild(stanza: snikket.Stanza): snikket.Stanza;
+		addDirectChild(child: any): snikket.Stanza;
+		clone(): snikket.Stanza;
+		allTags(name?: string, xmlns?: string): snikket.Stanza[];
+		allText(): string[];
+		getFirstChild(): snikket.Stanza;
+		getChildren(): snikket._Stanza.NodeInterface[];
+		getChild(name?: string, xmlns?: string): snikket.Stanza;
+		getChildText(name?: string, xmlns?: string): string;
+		getText(): string;
+		find(path: string): any;
+		findChild(path: string): snikket.Stanza;
+		findText(path: string): string;
+		traverse(f: (arg0: snikket.Stanza) => boolean): snikket.Stanza;
+		getError(): snikket.StanzaError;
+		removeChildren(name?: string, xmlns_?: string): void;
+		static parse(s: string): snikket.Stanza;
+		static parseXmlBool(x: string): boolean;
+	}
+}
+
+export namespace snikket {
+	export class Version {
+		protected constructor();
+		static readonly HUMAN: string;
+	}
+}
+
+export namespace snikket {
+	export interface Persistence {
+		lastId(accountId: string, chatId: string, callback: (serverId: string) => void): void;
+		storeChats(accountId: string, chats: snikket.Chat[]): void;
+		getChats(accountId: string, callback: (chats: snikket.SerializedChat[]) => void): void;
+		getChatsUnreadDetails(accountId: string, chats: snikket.Chat[], callback: (details: {chatId: string, message: snikket.ChatMessage, unreadCount: number}[]) => void): void;
+		storeReaction(accountId: string, update: snikket.ReactionUpdate, callback: (arg0: snikket.ChatMessage) => void): void;
+		storeMessages(accountId: string, message: snikket.ChatMessage[], callback: (arg0: snikket.ChatMessage[]) => void): void;
+		updateMessage(accountId: string, message: snikket.ChatMessage): void;
+		updateMessageStatus(accountId: string, localId: string, status: enums.MessageStatus, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMessage(accountId: string, chatId: string, serverId: string, localId: string, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMessagesBefore(accountId: string, chatId: string, beforeId: string, beforeTime: string, callback: (messages: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(accountId: string, chatId: string, afterId: string, afterTime: string, callback: (messages: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(accountId: string, chatId: string, aroundId: string, aroundTime: string, callback: (messages: snikket.ChatMessage[]) => void): void;
+		hasMedia(hashAlgorithm: string, hash: ArrayBuffer, callback: (has: boolean) => void): void;
+		storeMedia(mime: string, bytes: ArrayBuffer, callback: () => void): void;
+		removeMedia(hashAlgorithm: string, hash: ArrayBuffer): void;
+		storeCaps(caps: snikket.Caps): void;
+		getCaps(ver: string, callback: (arg0: snikket.Caps) => void): void;
+		storeLogin(login: string, clientId: string, displayName: string, token: string): void;
+		getLogin(login: string, callback: (clientId: string, token: string, fastCount: number, displayName: string) => void): void;
+		removeAccount(accountId: string, completely: boolean): void;
+		storeStreamManagement(accountId: string, data: ArrayBuffer): void;
+		getStreamManagement(accountId: string, callback: (arg0: ArrayBuffer) => void): void;
+		storeService(accountId: string, serviceId: string, name: string, node: string, caps: snikket.Caps): void;
+		findServicesWithFeature(accountId: string, feature: string, callback: (arg0: {caps: snikket.Caps, name: string, node: string, serviceId: string}[]) => void): void;
+	}
+}
+
+export namespace snikket.persistence {
+	export class Dummy implements snikket.Persistence {
+		/**
+		 * Create a basic persistence layer that persists nothing
+		 * @returns new persistence layer
+		 */
+		constructor();
+		lastId(accountId: string, chatId: string, callback: (arg0: string) => void): void;
+		storeChats(accountId: string, chat: snikket.Chat[]): void;
+		getChats(accountId: string, callback: (arg0: snikket.SerializedChat[]) => void): void;
+		storeMessages(accountId: string, messages: snikket.ChatMessage[], callback: (arg0: snikket.ChatMessage[]) => void): void;
+		updateMessage(accountId: string, message: snikket.ChatMessage): void;
+		getMessage(accountId: string, chatId: string, serverId: string, localId: string, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMessagesBefore(accountId: string, chatId: string, beforeId: string, beforeTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(accountId: string, chatId: string, afterId: string, afterTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(accountId: string, chatId: string, aroundId: string, aroundTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getChatsUnreadDetails(accountId: string, chats: snikket.Chat[], callback: (arg0: {chatId: string, message: snikket.ChatMessage, unreadCount: number}[]) => void): void;
+		storeReaction(accountId: string, update: snikket.ReactionUpdate, callback: (arg0: snikket.ChatMessage) => void): void;
+		updateMessageStatus(accountId: string, localId: string, status: enums.MessageStatus, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMediaUri(hashAlgorithm: string, hash: ArrayBuffer, callback: (arg0: string) => void): void;
+		hasMedia(hashAlgorithm: string, hash: ArrayBuffer, callback: (arg0: boolean) => void): void;
+		storeMedia(mime: string, bd: ArrayBuffer, callback: () => void): void;
+		removeMedia(hashAlgorithm: string, hash: ArrayBuffer): void;
+		storeCaps(caps: snikket.Caps): void;
+		getCaps(ver: string, callback: (arg0: snikket.Caps) => void): void;
+		storeLogin(login: string, clientId: string, displayName: string, token: string): void;
+		getLogin(login: string, callback: (arg0: string, arg1: string, arg2: number, arg3: string) => void): void;
+		removeAccount(accountId: string, completely: boolean): void;
+		storeStreamManagement(accountId: string, sm: ArrayBuffer): void;
+		getStreamManagement(accountId: string, callback: (arg0: ArrayBuffer) => void): void;
+		storeService(accountId: string, serviceId: string, name: string, node: string, caps: snikket.Caps): void;
+		findServicesWithFeature(accountId: string, feature: string, callback: (arg0: {caps: snikket.Caps, name: string, node: string, serviceId: string}[]) => void): void;
+	}
+}
+
+export namespace snikket.persistence {
+	export interface KeyValueStore {
+		get(k: string, callback: (arg0: string) => void): void;
+		set(k: string, v: string, callback: () => void): void;
+	}
+}
+
+export namespace snikket.persistence {
+	export interface MediaStore {
+		hasMedia(hashAlgorithm: string, hash: ArrayBuffer, callback: (has: boolean) => void): void;
+		removeMedia(hashAlgorithm: string, hash: ArrayBuffer): void;
+		storeMedia(mime: string, bytes: ArrayBuffer, callback: () => void): void;
+	}
+}
+
+export namespace snikket.persistence {
+	export class Sqlite implements snikket.persistence.KeyValueStore, snikket.Persistence {
+		/**
+		 * Create a basic persistence layer based on sqlite
+		 * @param dbfile path to sqlite database
+		 * @params media a MediaStore to use for media
+		 * @returns new persistence layer
+		 */
+		constructor(dbfile: string, media: snikket.persistence.MediaStore);
+		get(k: string, callback: (arg0: string) => void): void;
+		set(k: string, v: string, callback: () => void): void;
+		lastId(accountId: string, chatId: string, callback: (arg0: string) => void): void;
+		storeChats(accountId: string, chats: snikket.Chat[]): void;
+		getChats(accountId: string, callback: (arg0: snikket.SerializedChat[]) => void): void;
+		storeMessages(accountId: string, messages: snikket.ChatMessage[], callback: (arg0: snikket.ChatMessage[]) => void): void;
+		updateMessage(accountId: string, message: snikket.ChatMessage): void;
+		getMessage(accountId: string, chatId: string, serverId: string, localId: string, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMessagesBefore(accountId: string, chatId: string, beforeId: string, beforeTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(accountId: string, chatId: string, afterId: string, afterTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(accountId: string, chatId: string, aroundId: string, aroundTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getChatsUnreadDetails(accountId: string, chats: snikket.Chat[], callback: (arg0: {chatId: string, message: snikket.ChatMessage, unreadCount: number}[]) => void): void;
+		storeReaction(accountId: string, update: snikket.ReactionUpdate, callback: (arg0: snikket.ChatMessage) => void): void;
+		updateMessageStatus(accountId: string, localId: string, status: enums.MessageStatus, callback: (arg0: snikket.ChatMessage) => void): void;
+		hasMedia(hashAlgorithm: string, hash: ArrayBuffer, callback: (arg0: boolean) => void): void;
+		removeMedia(hashAlgorithm: string, hash: ArrayBuffer): void;
+		storeMedia(mime: string, bd: ArrayBuffer, callback: () => void): void;
+		storeCaps(caps: snikket.Caps): void;
+		getCaps(ver: string, callback: (arg0: snikket.Caps) => void): void;
+		storeLogin(accountId: string, clientId: string, displayName: string, token: string): void;
+		getLogin(accountId: string, callback: (arg0: string, arg1: string, arg2: number, arg3: string) => void): void;
+		removeAccount(accountId: string, completely: boolean): void;
+		storeStreamManagement(accountId: string, sm: ArrayBuffer): void;
+		getStreamManagement(accountId: string, callback: (arg0: ArrayBuffer) => void): void;
+		storeService(accountId: string, serviceId: string, name: string, node: string, caps: snikket.Caps): void;
+		findServicesWithFeature(accountId: string, feature: string, callback: (arg0: {caps: snikket.Caps, name: string, node: string, serviceId: string}[]) => void): void;
+	}
+}
\ No newline at end of file
diff --git a/npm/snikket-browser.js b/npm/snikket-browser.js
new file mode 100644
index 0000000..3134b1e
--- /dev/null
+++ b/npm/snikket-browser.js
@@ -0,0 +1,29045 @@
+var exports = {};
+// Generated by Haxe 4.3.2
+import { sqlite3Worker1Promiser as snikket_persistence_Worker1 } from "@sqlite.org/sqlite-wasm";
+import snikket_streams_XmppJsScramSha1 from "@xmpp/sasl-scram-sha-1";
+import { client as snikket_streams_XmppJsClient } from "@xmpp/client";
+import { jid as snikket_streams_XmppJsJID } from "@xmpp/jid";
+import snikket_streams_XmppJsDebug from "@xmpp/debug";
+import snikket_streams_XmppJsXml from "@xmpp/xml";
+import * as snikket_streams_XmppJsLtx from "ltx";
+import snikket_streams_XmppJsId from "@xmpp/id";
+import snikket_streams_XmppJsError from "@xmpp/error";
+;(function ($hx_exports, $global) { "use strict";
+$hx_exports["snikket"] = $hx_exports["snikket"] || {};
+$hx_exports["snikket"]["Push"] = $hx_exports["snikket"]["Push"] || {};
+;$hx_exports["snikket"]["persistence"] = $hx_exports["snikket"]["persistence"] || {};
+var $estr = function() { return js_Boot.__string_rec(this,''); },$hxEnums = $hxEnums || {},$_;
+class DateTools {
+	static __format_get(d,e) {
+		switch(e) {
+		case "%":
+			return "%";
+		case "A":
+			return DateTools.DAY_NAMES[d.getDay()];
+		case "B":
+			return DateTools.MONTH_NAMES[d.getMonth()];
+		case "C":
+			return StringTools.lpad(Std.string(d.getFullYear() / 100 | 0),"0",2);
+		case "D":
+			return DateTools.__format(d,"%m/%d/%y");
+		case "F":
+			return DateTools.__format(d,"%Y-%m-%d");
+		case "M":
+			return StringTools.lpad(Std.string(d.getMinutes()),"0",2);
+		case "R":
+			return DateTools.__format(d,"%H:%M");
+		case "S":
+			return StringTools.lpad(Std.string(d.getSeconds()),"0",2);
+		case "T":
+			return DateTools.__format(d,"%H:%M:%S");
+		case "Y":
+			return Std.string(d.getFullYear());
+		case "a":
+			return DateTools.DAY_SHORT_NAMES[d.getDay()];
+		case "d":
+			return StringTools.lpad(Std.string(d.getDate()),"0",2);
+		case "e":
+			return Std.string(d.getDate());
+		case "b":case "h":
+			return DateTools.MONTH_SHORT_NAMES[d.getMonth()];
+		case "H":case "k":
+			return StringTools.lpad(Std.string(d.getHours()),e == "H" ? "0" : " ",2);
+		case "I":case "l":
+			let hour = d.getHours() % 12;
+			return StringTools.lpad(Std.string(hour == 0 ? 12 : hour),e == "I" ? "0" : " ",2);
+		case "m":
+			return StringTools.lpad(Std.string(d.getMonth() + 1),"0",2);
+		case "n":
+			return "\n";
+		case "p":
+			if(d.getHours() > 11) {
+				return "PM";
+			} else {
+				return "AM";
+			}
+			break;
+		case "r":
+			return DateTools.__format(d,"%I:%M:%S %p");
+		case "s":
+			return Std.string(d.getTime() / 1000 | 0);
+		case "t":
+			return "\t";
+		case "u":
+			let t = d.getDay();
+			if(t == 0) {
+				return "7";
+			} else if(t == null) {
+				return "null";
+			} else {
+				return "" + t;
+			}
+			break;
+		case "w":
+			return Std.string(d.getDay());
+		case "y":
+			return StringTools.lpad(Std.string(d.getFullYear() % 100),"0",2);
+		default:
+			throw new haxe_exceptions_NotImplementedException("Date.format %" + e + "- not implemented yet.",null,{ fileName : "DateTools.hx", lineNumber : 101, className : "DateTools", methodName : "__format_get"});
+		}
+	}
+	static __format(d,f) {
+		let r_b = "";
+		let p = 0;
+		while(true) {
+			let np = f.indexOf("%",p);
+			if(np < 0) {
+				break;
+			}
+			let len = np - p;
+			r_b += len == null ? HxOverrides.substr(f,p,null) : HxOverrides.substr(f,p,len);
+			r_b += Std.string(DateTools.__format_get(d,HxOverrides.substr(f,np + 1,1)));
+			p = np + 2;
+		}
+		let len = f.length - p;
+		r_b += len == null ? HxOverrides.substr(f,p,null) : HxOverrides.substr(f,p,len);
+		return r_b;
+	}
+	static format(d,f) {
+		return DateTools.__format(d,f);
+	}
+}
+DateTools.__name__ = "DateTools";
+class EReg {
+	constructor(r,opt) {
+		this.r = new RegExp(r,opt.split("u").join(""));
+	}
+	match(s) {
+		if(this.r.global) {
+			this.r.lastIndex = 0;
+		}
+		this.r.m = this.r.exec(s);
+		this.r.s = s;
+		return this.r.m != null;
+	}
+	matched(n) {
+		if(this.r.m != null && n >= 0 && n < this.r.m.length) {
+			return this.r.m[n];
+		} else {
+			throw haxe_Exception.thrown("EReg::matched");
+		}
+	}
+	matchedLeft() {
+		if(this.r.m == null) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		return HxOverrides.substr(this.r.s,0,this.r.m.index);
+	}
+	matchedRight() {
+		if(this.r.m == null) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		let sz = this.r.m.index + this.r.m[0].length;
+		return HxOverrides.substr(this.r.s,sz,this.r.s.length - sz);
+	}
+	matchedPos() {
+		if(this.r.m == null) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		return { pos : this.r.m.index, len : this.r.m[0].length};
+	}
+	matchSub(s,pos,len) {
+		if(len == null) {
+			len = -1;
+		}
+		if(this.r.global) {
+			this.r.lastIndex = pos;
+			this.r.m = this.r.exec(len < 0 ? s : HxOverrides.substr(s,0,pos + len));
+			let b = this.r.m != null;
+			if(b) {
+				this.r.s = s;
+			}
+			return b;
+		} else {
+			let b = this.match(len < 0 ? HxOverrides.substr(s,pos,null) : HxOverrides.substr(s,pos,len));
+			if(b) {
+				this.r.s = s;
+				this.r.m.index += pos;
+			}
+			return b;
+		}
+	}
+	split(s) {
+		let d = "#__delim__#";
+		return s.replace(this.r,d).split(d);
+	}
+	map(s,f) {
+		let offset = 0;
+		let buf_b = "";
+		do {
+			if(offset >= s.length) {
+				break;
+			} else if(!this.matchSub(s,offset)) {
+				buf_b += Std.string(HxOverrides.substr(s,offset,null));
+				break;
+			}
+			let p = this.matchedPos();
+			buf_b += Std.string(HxOverrides.substr(s,offset,p.pos - offset));
+			buf_b += Std.string(f(this));
+			if(p.len == 0) {
+				buf_b += Std.string(HxOverrides.substr(s,p.pos,1));
+				offset = p.pos + 1;
+			} else {
+				offset = p.pos + p.len;
+			}
+		} while(this.r.global);
+		if(!this.r.global && offset > 0 && offset < s.length) {
+			buf_b += Std.string(HxOverrides.substr(s,offset,null));
+		}
+		return buf_b;
+	}
+}
+EReg.__name__ = "EReg";
+Object.assign(EReg.prototype, {
+	__class__: EReg
+});
+class HxOverrides {
+	static cca(s,index) {
+		let x = s.charCodeAt(index);
+		if(x != x) {
+			return undefined;
+		}
+		return x;
+	}
+	static substr(s,pos,len) {
+		if(len == null) {
+			len = s.length;
+		} else if(len < 0) {
+			if(pos == 0) {
+				len = s.length + len;
+			} else {
+				return "";
+			}
+		}
+		return s.substr(pos,len);
+	}
+	static remove(a,obj) {
+		let i = a.indexOf(obj);
+		if(i == -1) {
+			return false;
+		}
+		a.splice(i,1);
+		return true;
+	}
+	static now() {
+		return Date.now();
+	}
+}
+HxOverrides.__name__ = "HxOverrides";
+class Lambda {
+	static array(it) {
+		let a = [];
+		let i = $getIterator(it);
+		while(i.hasNext()) {
+			let i1 = i.next();
+			a.push(i1);
+		}
+		return a;
+	}
+	static exists(it,f) {
+		let x = $getIterator(it);
+		while(x.hasNext()) {
+			let x1 = x.next();
+			if(f(x1)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static fold(it,f,first) {
+		let x = $getIterator(it);
+		while(x.hasNext()) {
+			let x1 = x.next();
+			first = f(x1,first);
+		}
+		return first;
+	}
+	static empty(it) {
+		return !$getIterator(it).hasNext();
+	}
+	static indexOf(it,v) {
+		let i = 0;
+		let v2 = $getIterator(it);
+		while(v2.hasNext()) {
+			let v21 = v2.next();
+			if(v == v21) {
+				return i;
+			}
+			++i;
+		}
+		return -1;
+	}
+	static find(it,f) {
+		let v = $getIterator(it);
+		while(v.hasNext()) {
+			let v1 = v.next();
+			if(f(v1)) {
+				return v1;
+			}
+		}
+		return null;
+	}
+	static findIndex(it,f) {
+		let i = 0;
+		let v = $getIterator(it);
+		while(v.hasNext()) {
+			let v1 = v.next();
+			if(f(v1)) {
+				return i;
+			}
+			++i;
+		}
+		return -1;
+	}
+}
+Lambda.__name__ = "Lambda";
+Math.__name__ = "Math";
+class Reflect {
+	static field(o,field) {
+		try {
+			return o[field];
+		} catch( _g ) {
+			return null;
+		}
+	}
+	static fields(o) {
+		let a = [];
+		if(o != null) {
+			let hasOwnProperty = Object.prototype.hasOwnProperty;
+			for( var f in o ) {
+			if(f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o,f)) {
+				a.push(f);
+			}
+			}
+		}
+		return a;
+	}
+	static compare(a,b) {
+		if(a == b) {
+			return 0;
+		} else if(a > b) {
+			return 1;
+		} else {
+			return -1;
+		}
+	}
+	static isEnumValue(v) {
+		if(v != null) {
+			return v.__enum__ != null;
+		} else {
+			return false;
+		}
+	}
+	static copy(o) {
+		if(o == null) {
+			return null;
+		}
+		let o2 = { };
+		let _g = 0;
+		let _g1 = Reflect.fields(o);
+		while(_g < _g1.length) {
+			let f = _g1[_g];
+			++_g;
+			o2[f] = Reflect.field(o,f);
+		}
+		return o2;
+	}
+}
+Reflect.__name__ = "Reflect";
+class Std {
+	static string(s) {
+		return js_Boot.__string_rec(s,"");
+	}
+	static parseInt(x) {
+		let v = parseInt(x);
+		if(isNaN(v)) {
+			return null;
+		}
+		return v;
+	}
+	static random(x) {
+		if(x <= 0) {
+			return 0;
+		} else {
+			return Math.floor(Math.random() * x);
+		}
+	}
+}
+Std.__name__ = "Std";
+class StringBuf {
+	constructor() {
+		this.b = "";
+	}
+}
+StringBuf.__name__ = "StringBuf";
+Object.assign(StringBuf.prototype, {
+	__class__: StringBuf
+});
+class StringTools {
+	static htmlEscape(s,quotes) {
+		let buf_b = "";
+		let _g_offset = 0;
+		let _g_s = s;
+		while(_g_offset < _g_s.length) {
+			let s = _g_s;
+			let index = _g_offset++;
+			let c = s.charCodeAt(index);
+			if(c >= 55296 && c <= 56319) {
+				c = c - 55232 << 10 | s.charCodeAt(index + 1) & 1023;
+			}
+			let c1 = c;
+			if(c1 >= 65536) {
+				++_g_offset;
+			}
+			let code = c1;
+			switch(code) {
+			case 34:
+				if(quotes) {
+					buf_b += "&quot;";
+				} else {
+					buf_b += String.fromCodePoint(code);
+				}
+				break;
+			case 38:
+				buf_b += "&amp;";
+				break;
+			case 39:
+				if(quotes) {
+					buf_b += "&#039;";
+				} else {
+					buf_b += String.fromCodePoint(code);
+				}
+				break;
+			case 60:
+				buf_b += "&lt;";
+				break;
+			case 62:
+				buf_b += "&gt;";
+				break;
+			default:
+				buf_b += String.fromCodePoint(code);
+			}
+		}
+		return buf_b;
+	}
+	static isSpace(s,pos) {
+		let c = HxOverrides.cca(s,pos);
+		if(!(c > 8 && c < 14)) {
+			return c == 32;
+		} else {
+			return true;
+		}
+	}
+	static ltrim(s) {
+		let l = s.length;
+		let r = 0;
+		while(r < l && StringTools.isSpace(s,r)) ++r;
+		if(r > 0) {
+			return HxOverrides.substr(s,r,l - r);
+		} else {
+			return s;
+		}
+	}
+	static rtrim(s) {
+		let l = s.length;
+		let r = 0;
+		while(r < l && StringTools.isSpace(s,l - r - 1)) ++r;
+		if(r > 0) {
+			return HxOverrides.substr(s,0,l - r);
+		} else {
+			return s;
+		}
+	}
+	static trim(s) {
+		return StringTools.ltrim(StringTools.rtrim(s));
+	}
+	static lpad(s,c,l) {
+		if(c.length <= 0) {
+			return s;
+		}
+		let buf_b = "";
+		l -= s.length;
+		while(buf_b.length < l) buf_b += c == null ? "null" : "" + c;
+		buf_b += s == null ? "null" : "" + s;
+		return buf_b;
+	}
+	static rpad(s,c,l) {
+		if(c.length <= 0) {
+			return s;
+		}
+		let buf_b = "";
+		buf_b += s == null ? "null" : "" + s;
+		while(buf_b.length < l) buf_b += c == null ? "null" : "" + c;
+		return buf_b;
+	}
+	static replace(s,sub,by) {
+		return s.split(sub).join(by);
+	}
+	static hex(n,digits) {
+		let s = "";
+		let hexChars = "0123456789ABCDEF";
+		do {
+			s = hexChars.charAt(n & 15) + s;
+			n >>>= 4;
+		} while(n > 0);
+		if(digits != null) {
+			while(s.length < digits) s = "0" + s;
+		}
+		return s;
+	}
+}
+StringTools.__name__ = "StringTools";
+class Type {
+	static enumParameters(e) {
+		let enm = $hxEnums[e.__enum__];
+		let params = enm.__constructs__[e._hx_index].__params__;
+		if(params != null) {
+			let _g = [];
+			let _g1 = 0;
+			while(_g1 < params.length) {
+				let p = params[_g1];
+				++_g1;
+				_g.push(e[p]);
+			}
+			return _g;
+		} else {
+			return [];
+		}
+	}
+}
+Type.__name__ = "Type";
+class XmlType {
+	static toString(this1) {
+		switch(this1) {
+		case 0:
+			return "Element";
+		case 1:
+			return "PCData";
+		case 2:
+			return "CData";
+		case 3:
+			return "Comment";
+		case 4:
+			return "DocType";
+		case 5:
+			return "ProcessingInstruction";
+		case 6:
+			return "Document";
+		}
+	}
+}
+class Xml {
+	constructor(nodeType) {
+		this.nodeType = nodeType;
+		this.children = [];
+		this.attributeMap = new haxe_ds_StringMap();
+	}
+	get(att) {
+		if(this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		return this.attributeMap.h[att];
+	}
+	set(att,value) {
+		if(this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		this.attributeMap.h[att] = value;
+	}
+	exists(att) {
+		if(this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		return Object.prototype.hasOwnProperty.call(this.attributeMap.h,att);
+	}
+	attributes() {
+		if(this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		return new haxe_ds__$StringMap_StringMapKeyIterator(this.attributeMap.h);
+	}
+	firstElement() {
+		if(this.nodeType != Xml.Document && this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		let _g = 0;
+		let _g1 = this.children;
+		while(_g < _g1.length) {
+			let child = _g1[_g];
+			++_g;
+			if(child.nodeType == Xml.Element) {
+				return child;
+			}
+		}
+		return null;
+	}
+	addChild(x) {
+		if(this.nodeType != Xml.Document && this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		if(x.parent != null) {
+			x.parent.removeChild(x);
+		}
+		this.children.push(x);
+		x.parent = this;
+	}
+	removeChild(x) {
+		if(this.nodeType != Xml.Document && this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		if(HxOverrides.remove(this.children,x)) {
+			x.parent = null;
+			return true;
+		}
+		return false;
+	}
+	toString() {
+		return haxe_xml_Printer.print(this);
+	}
+	static parse(str) {
+		return haxe_xml_Parser.parse(str);
+	}
+	static createElement(name) {
+		let xml = new Xml(Xml.Element);
+		if(xml.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeName = name;
+		return xml;
+	}
+	static createPCData(data) {
+		let xml = new Xml(Xml.PCData);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createCData(data) {
+		let xml = new Xml(Xml.CData);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createComment(data) {
+		let xml = new Xml(Xml.Comment);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createDocType(data) {
+		let xml = new Xml(Xml.DocType);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createProcessingInstruction(data) {
+		let xml = new Xml(Xml.ProcessingInstruction);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createDocument() {
+		return new Xml(Xml.Document);
+	}
+}
+Xml.__name__ = "Xml";
+Object.assign(Xml.prototype, {
+	__class__: Xml
+});
+var datetime_DTPeriod = $hxEnums["datetime.DTPeriod"] = { __ename__:true,__constructs__:null
+	,Year: ($_=function(n) { return {_hx_index:0,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Year",$_.__params__ = ["n"],$_)
+	,Month: ($_=function(n) { return {_hx_index:1,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Month",$_.__params__ = ["n"],$_)
+	,Day: ($_=function(n) { return {_hx_index:2,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Day",$_.__params__ = ["n"],$_)
+	,Hour: ($_=function(n) { return {_hx_index:3,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Hour",$_.__params__ = ["n"],$_)
+	,Minute: ($_=function(n) { return {_hx_index:4,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Minute",$_.__params__ = ["n"],$_)
+	,Second: ($_=function(n) { return {_hx_index:5,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Second",$_.__params__ = ["n"],$_)
+	,Week: ($_=function(n) { return {_hx_index:6,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Week",$_.__params__ = ["n"],$_)
+};
+datetime_DTPeriod.__constructs__ = [datetime_DTPeriod.Year,datetime_DTPeriod.Month,datetime_DTPeriod.Day,datetime_DTPeriod.Hour,datetime_DTPeriod.Minute,datetime_DTPeriod.Second,datetime_DTPeriod.Week];
+var datetime_DTSnap = $hxEnums["datetime.DTSnap"] = { __ename__:true,__constructs__:null
+	,Year: ($_=function(direction) { return {_hx_index:0,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Year",$_.__params__ = ["direction"],$_)
+	,Month: ($_=function(direction) { return {_hx_index:1,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Month",$_.__params__ = ["direction"],$_)
+	,Day: ($_=function(direction) { return {_hx_index:2,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Day",$_.__params__ = ["direction"],$_)
+	,Hour: ($_=function(direction) { return {_hx_index:3,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Hour",$_.__params__ = ["direction"],$_)
+	,Minute: ($_=function(direction) { return {_hx_index:4,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Minute",$_.__params__ = ["direction"],$_)
+	,Second: ($_=function(direction) { return {_hx_index:5,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Second",$_.__params__ = ["direction"],$_)
+	,Week: ($_=function(direction,day) { return {_hx_index:6,direction:direction,day:day,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Week",$_.__params__ = ["direction","day"],$_)
+};
+datetime_DTSnap.__constructs__ = [datetime_DTSnap.Year,datetime_DTSnap.Month,datetime_DTSnap.Day,datetime_DTSnap.Hour,datetime_DTSnap.Minute,datetime_DTSnap.Second,datetime_DTSnap.Week];
+class datetime_DateTime {
+	static now() {
+		return Math.floor(new Date().getTime() / 1000) + 62135596800.0;
+	}
+	static local() {
+		let utc = Math.floor(new Date().getTime() / 1000) + 62135596800.0;
+		return utc - 62135596800.0 + datetime_DateTime.getLocalOffset() + 62135596800.0;
+	}
+	static make(year,month,day,hour,minute,second) {
+		if(second == null) {
+			second = 0;
+		}
+		if(minute == null) {
+			minute = 0;
+		}
+		if(hour == null) {
+			hour = 0;
+		}
+		if(day == null) {
+			day = 1;
+		}
+		if(month == null) {
+			month = 1;
+		}
+		if(year == null) {
+			year = 1970;
+		}
+		return datetime_utils_DateTimeUtils.yearToStamp(year) + datetime_utils_DateTimeMonthUtils.toSeconds(month,year % 4 == 0 && (year % 100 == 0 ? year % 400 == 0 : true)) + (day - 1) * 86400 + hour * 3600 + minute * 60 + second - 62135596800.0 + 62135596800.0;
+	}
+	static fromTime(time) {
+		return time + 62135596800.0;
+	}
+	static fromString(str) {
+		return datetime_utils_DateTimeUtils.fromString(str);
+	}
+	static fromDate(date) {
+		return Math.floor(date.getTime() / 1000) + 62135596800.0;
+	}
+	static daysInMonth(month,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		return datetime_utils_DateTimeMonthUtils.days(month,isLeapYear);
+	}
+	static weeksInYear(year) {
+		let start = datetime_utils_DateTimeUtils.yearToStamp(year) - 62135596800.0 + 62135596800.0;
+		let weekDay = datetime_DateTime.getWeekDay(start);
+		if(weekDay == 4 || weekDay == 3 && datetime_DateTime.isLeapYear(start)) {
+			return 53;
+		} else {
+			return 52;
+		}
+	}
+	static isLeap(year) {
+		if(year % 4 == 0) {
+			if(year % 100 == 0) {
+				return year % 400 == 0;
+			} else {
+				return true;
+			}
+		} else {
+			return false;
+		}
+	}
+	static getLocalOffset() {
+		let now = new Date();
+		let year = now.getFullYear();
+		let month = now.getMonth() + 1;
+		let day = now.getDate();
+		let hour = now.getHours();
+		let minute = now.getMinutes();
+		let second = now.getSeconds();
+		if(second == null) {
+			second = 0;
+		}
+		if(minute == null) {
+			minute = 0;
+		}
+		if(hour == null) {
+			hour = 0;
+		}
+		if(day == null) {
+			day = 1;
+		}
+		if(month == null) {
+			month = 1;
+		}
+		if(year == null) {
+			year = 1970;
+		}
+		let local = datetime_utils_DateTimeUtils.yearToStamp(year) + datetime_utils_DateTimeMonthUtils.toSeconds(month,year % 4 == 0 && (year % 100 == 0 ? year % 400 == 0 : true)) + (day - 1) * 86400 + hour * 3600 + minute * 60 + second - 62135596800.0 + 62135596800.0;
+		return local - 62135596800.0 - (now.getTime() / 1000 | 0) | 0;
+	}
+	static _new(time) {
+		return time + 62135596800.0;
+	}
+	static utc(this1) {
+		return this1 - 62135596800.0 - datetime_DateTime.getLocalOffset() + 62135596800.0;
+	}
+	static getYear(this1) {
+		let cquads = (this1 / 12622780800.0 | 0) * 12622780800.0;
+		let centuries = ((this1 - cquads) / 3155673600.0 | 0) * 3155673600.0;
+		if(centuries > 9467020800.) {
+			centuries -= 3155673600.0;
+		}
+		let quads = ((this1 - cquads - centuries) / 126230400.0 | 0) * 126230400.0;
+		let years = (this1 - cquads - centuries - quads) / 31536000 | 0;
+		return (cquads / 12622780800.0 | 0) * 400 + (centuries / 3155673600.0 | 0) * 100 + (quads / 126230400.0 | 0) * 4 + (years == 4 ? years : years + 1);
+	}
+	static yearStart(this1) {
+		let cquads = (this1 / 12622780800.0 | 0) * 12622780800.0;
+		let centuries = ((this1 - cquads) / 3155673600.0 | 0) * 3155673600.0;
+		if(centuries > 9467020800.) {
+			centuries -= 3155673600.0;
+		}
+		let quads = ((this1 - cquads - centuries) / 126230400.0 | 0) * 126230400.0;
+		let years = (this1 - cquads - centuries - quads) / 31536000 | 0;
+		if(years == 4) {
+			--years;
+		}
+		return cquads + centuries + quads + years * 31536000 - 62135596800.0;
+	}
+	static monthStart(this1,month) {
+		if(month == null) {
+			month = 0;
+		}
+		if(month == 0) {
+			let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+			month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+		}
+		return datetime_DateTime.yearStart(this1) + datetime_utils_DateTimeMonthUtils.toSeconds(month,datetime_DateTime.isLeapYear(this1));
+	}
+	static getMonthStart(this1,month) {
+		return datetime_DateTime.monthStart(this1,month) + 62135596800.0;
+	}
+	static isLeapYear(this1) {
+		let year = datetime_DateTime.getYear(this1);
+		if(year % 4 == 0) {
+			if(year % 100 == 0) {
+				return year % 400 == 0;
+			} else {
+				return true;
+			}
+		} else {
+			return false;
+		}
+	}
+	static getMonth(this1) {
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		return datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+	}
+	static getDay(this1) {
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		return datetime_utils_DateTimeMonthUtils.getMonthDay(days,datetime_DateTime.isLeapYear(this1));
+	}
+	static daysInThisMonth(this1) {
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+		return datetime_utils_DateTimeMonthUtils.days(month,month == 2 && datetime_DateTime.isLeapYear(this1));
+	}
+	static getYearDay(this1) {
+		return ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+	}
+	static weeksInThisYear(this1) {
+		return datetime_DateTime.weeksInYear(datetime_DateTime.getYear(this1));
+	}
+	static getWeekDay(this1,mondayBased) {
+		if(mondayBased == null) {
+			mondayBased = false;
+		}
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+		let a = (14 - month) / 12 | 0;
+		let y = datetime_DateTime.getYear(this1) - a;
+		let m = month + 12 * a - 2;
+		let days1 = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let weekDay = (7000 + (datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(this1)) + y + (y / 4 | 0) - (y / 100 | 0) + (y / 400 | 0) + (31 * m / 12 | 0))) % 7;
+		if(mondayBased && weekDay == 0) {
+			return 7;
+		} else {
+			return weekDay;
+		}
+	}
+	static getWeekDayNum(this1,weekDay,num) {
+		if(num == null) {
+			num = 1;
+		}
+		return datetime_utils_DateTimeUtils.getWeekDayNum(this1 - 62135596800.0 + 62135596800.0,weekDay,num) + 62135596800.0;
+	}
+	static getWeek(this1) {
+		let week = (((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1 - datetime_DateTime.getWeekDay(this1,true) + 10) / 7 | 0;
+		let year = datetime_DateTime.getYear(this1);
+		if(week < 1) {
+			return datetime_DateTime.weeksInYear(year - 1);
+		} else if(week > 52 && week > datetime_DateTime.weeksInYear(year)) {
+			return 1;
+		} else {
+			return week;
+		}
+	}
+	static getHour(this1) {
+		return (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+	}
+	static getHour12(this1) {
+		let hour = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+		if(hour == 0) {
+			return 12;
+		} else if(hour > 12) {
+			return hour - 12;
+		} else {
+			return hour;
+		}
+	}
+	static getMinute(this1) {
+		return (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+	}
+	static getSecond(this1) {
+		return this1 - Math.floor(this1 / 60) * 60 | 0;
+	}
+	static add(this1,period) {
+		let time;
+		switch(period._hx_index) {
+		case 0:
+			let n = period.n;
+			time = datetime_utils_DateTimeUtils.addYear(this1 - 62135596800.0 + 62135596800.0,n);
+			break;
+		case 1:
+			let n1 = period.n;
+			time = datetime_utils_DateTimeUtils.addMonth(this1 - 62135596800.0 + 62135596800.0,n1);
+			break;
+		case 2:
+			let n2 = period.n;
+			time = this1 - 62135596800.0 + n2 * 86400;
+			break;
+		case 3:
+			let n3 = period.n;
+			time = this1 - 62135596800.0 + n3 * 3600;
+			break;
+		case 4:
+			let n4 = period.n;
+			time = this1 - 62135596800.0 + n4 * 60;
+			break;
+		case 5:
+			let n5 = period.n;
+			time = this1 - 62135596800.0 + n5;
+			break;
+		case 6:
+			let n6 = period.n;
+			time = this1 - 62135596800.0 + n6 * 7 * 86400;
+			break;
+		}
+		return time + 62135596800.0;
+	}
+	static sub(this1,period) {
+		let time;
+		switch(period._hx_index) {
+		case 0:
+			let n = period.n;
+			time = datetime_utils_DateTimeUtils.addYear(this1 - 62135596800.0 + 62135596800.0,-n);
+			break;
+		case 1:
+			let n1 = period.n;
+			time = datetime_utils_DateTimeUtils.addMonth(this1 - 62135596800.0 + 62135596800.0,-n1);
+			break;
+		case 2:
+			let n2 = period.n;
+			time = this1 - 62135596800.0 - n2 * 86400;
+			break;
+		case 3:
+			let n3 = period.n;
+			time = this1 - 62135596800.0 - n3 * 3600;
+			break;
+		case 4:
+			let n4 = period.n;
+			time = this1 - 62135596800.0 - n4 * 60;
+			break;
+		case 5:
+			let n5 = period.n;
+			time = this1 - 62135596800.0 - n5;
+			break;
+		case 6:
+			let n6 = period.n;
+			time = this1 - 62135596800.0 - n6 * 7 * 86400;
+			break;
+		}
+		return time + 62135596800.0;
+	}
+	static snap(this1,period) {
+		let time;
+		switch(period._hx_index) {
+		case 0:
+			let d = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapYear(this1 - 62135596800.0 + 62135596800.0,d);
+			break;
+		case 1:
+			let d1 = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapMonth(this1 - 62135596800.0 + 62135596800.0,d1);
+			break;
+		case 2:
+			let d2 = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapDay(this1 - 62135596800.0 + 62135596800.0,d2);
+			break;
+		case 3:
+			let d3 = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapHour(this1 - 62135596800.0 + 62135596800.0,d3);
+			break;
+		case 4:
+			let d4 = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapMinute(this1 - 62135596800.0 + 62135596800.0,d4);
+			break;
+		case 5:
+			let d5 = period.direction;
+			time = d5 == 1 ? this1 - 62135596800.0 + 1 : this1 - 62135596800.0;
+			break;
+		case 6:
+			let d6 = period.direction;
+			let day = period.day;
+			time = datetime_utils_DateTimeSnapUtils.snapWeek(this1 - 62135596800.0 + 62135596800.0,d6,day);
+			break;
+		}
+		return time + 62135596800.0;
+	}
+	static toString(this1) {
+		let Y = datetime_DateTime.getYear(this1);
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let M = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+		let days1 = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let D = datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(this1));
+		let h = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+		let m = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+		let s = this1 - Math.floor(this1 / 60) * 60 | 0;
+		return "" + Y + "-" + (M < 10 ? "0" + M : "" + M) + "-" + (D < 10 ? "0" + D : "" + D) + " " + (h < 10 ? "0" + h : "" + h) + ":" + (m < 10 ? "0" + m : "" + m) + ":" + (s < 10 ? "0" + s : "" + s);
+	}
+	static format(this1,format) {
+		return datetime_utils_DateTimeUtils.strftime(this1 - 62135596800.0 + 62135596800.0,format);
+	}
+	static getTime(this1) {
+		return this1 - 62135596800.0;
+	}
+	static getDate(this1) {
+		return new Date((this1 - 62135596800.0) * 1000);
+	}
+	static gt(this1,dt) {
+		return this1 - 62135596800.0 > dt - 62135596800.0;
+	}
+	static gte(this1,dt) {
+		return this1 - 62135596800.0 >= dt - 62135596800.0;
+	}
+	static lt(this1,dt) {
+		return this1 - 62135596800.0 < dt - 62135596800.0;
+	}
+	static lte(this1,dt) {
+		return this1 - 62135596800.0 <= dt - 62135596800.0;
+	}
+	static eq(this1,dt) {
+		return this1 - 62135596800.0 == dt - 62135596800.0;
+	}
+	static neq(this1,dt) {
+		return this1 - 62135596800.0 != dt - 62135596800.0;
+	}
+	static mathPlus1(this1,period) {
+		return datetime_DateTime.add(this1,period);
+	}
+	static mathPlus2(this1,period) {
+		return datetime_DateTime.add(this1,period);
+	}
+	static mathPlus3(this1,period) {
+		this1 = datetime_DateTime.add(this1,period) - 62135596800.0 + 62135596800.0;
+		return this1 + 62135596800.0;
+	}
+	static mathMinus1(this1,period) {
+		return datetime_DateTime.sub(this1,period);
+	}
+	static mathMinus2(this1,period) {
+		this1 = datetime_DateTime.sub(this1,period) - 62135596800.0 + 62135596800.0;
+		return this1 + 62135596800.0;
+	}
+	static dtiCreate(this1,begin) {
+		return datetime_DateTimeInterval.create(begin,this1 - 62135596800.0 + 62135596800.0);
+	}
+	static dtiMinus(this1,dti) {
+		return datetime_DateTimeInterval.subFrom(dti,this1 - 62135596800.0 + 62135596800.0);
+	}
+	static dtiPlus1(this1,dti) {
+		return datetime_DateTimeInterval.addTo(dti,this1 - 62135596800.0 + 62135596800.0);
+	}
+	static dtiPlus2(this1,dti) {
+		return datetime_DateTimeInterval.addTo(dti,this1 - 62135596800.0 + 62135596800.0);
+	}
+	static dtiMinus2(this1,dti) {
+		this1 = datetime_DateTimeInterval.subFrom(dti,this1 - 62135596800.0 + 62135596800.0) - 62135596800.0 + 62135596800.0;
+		return this1 + 62135596800.0;
+	}
+	static dtiPlus3(this1,dti) {
+		this1 = datetime_DateTimeInterval.addTo(dti,this1 - 62135596800.0 + 62135596800.0) - 62135596800.0 + 62135596800.0;
+		return this1 + 62135596800.0;
+	}
+}
+class datetime_DateTimeInterval {
+	static create(begin,end) {
+		let dtic = new datetime_cores_DateTimeIntervalCore();
+		dtic.begin = end - 62135596800.0 < begin - 62135596800.0 ? end : begin;
+		dtic.end = end - 62135596800.0 < begin - 62135596800.0 ? begin : end;
+		dtic.negative = end - 62135596800.0 < begin - 62135596800.0;
+		return dtic;
+	}
+	static _new(dtic) {
+		return dtic;
+	}
+	static invert(this1) {
+		this1.negative = !this1.negative;
+		return this1;
+	}
+	static addTo(this1,dt) {
+		return dt - 62135596800.0 + (this1.negative ? -1 : 1) * (this1.end - 62135596800.0 - (this1.begin - 62135596800.0)) + 62135596800.0;
+	}
+	static subFrom(this1,dt) {
+		return dt - 62135596800.0 - (this1.negative ? -1 : 1) * (this1.end - 62135596800.0 - (this1.begin - 62135596800.0)) + 62135596800.0;
+	}
+	static toString(this1) {
+		let years = this1.getYears();
+		let months = this1.getMonths();
+		let days = this1.getDays();
+		let hours = this1.getHours();
+		let minutes = this1.getMinutes();
+		let seconds = this1.getSeconds();
+		let parts = [];
+		if(years != 0) {
+			parts.push("" + years + "y");
+		}
+		if(months != 0) {
+			parts.push("" + months + "m");
+		}
+		if(days != 0) {
+			parts.push("" + days + "d");
+		}
+		if(hours != 0) {
+			parts.push("" + hours + "hrs");
+		}
+		if(minutes != 0) {
+			parts.push("" + minutes + "min");
+		}
+		if(seconds != 0) {
+			parts.push("" + seconds + "sec");
+		}
+		return (this1.negative ? "-" : "") + "(" + (parts.length == 0 ? "0sec" : parts.join(", ")) + ")";
+	}
+	static sign(this1) {
+		if(this1.negative) {
+			return -1;
+		} else {
+			return 1;
+		}
+	}
+	static format(this1,format) {
+		return datetime_utils_DateTimeIntervalUtils.strftime(this1,format);
+	}
+	static formatPartial(this1,format) {
+		return datetime_utils_DateTimeIntervalUtils.formatPartial(this1,format);
+	}
+	static eq(this1,dtic) {
+		if(this1.negative == dtic.negative) {
+			return this1.getTotalSeconds() == dtic.getTotalSeconds();
+		} else {
+			return false;
+		}
+	}
+	static gt(this1,dtic) {
+		if(this1.negative != dtic.negative) {
+			return dtic.negative;
+		}
+		let delta = this1.getTotalSeconds() - dtic.getTotalSeconds();
+		if(this1.negative) {
+			return delta < 0;
+		} else {
+			return delta > 0;
+		}
+	}
+	static gte(this1,dtic) {
+		if(!(this1.negative == dtic.negative && this1.getTotalSeconds() == dtic.getTotalSeconds())) {
+			if(this1.negative != dtic.negative) {
+				return dtic.negative;
+			} else {
+				let delta = this1.getTotalSeconds() - dtic.getTotalSeconds();
+				if(this1.negative) {
+					return delta < 0;
+				} else {
+					return delta > 0;
+				}
+			}
+		} else {
+			return true;
+		}
+	}
+	static lt(this1,dtic) {
+		let tmp;
+		if(!(this1.negative == dtic.negative && this1.getTotalSeconds() == dtic.getTotalSeconds())) {
+			if(this1.negative != dtic.negative) {
+				tmp = dtic.negative;
+			} else {
+				let delta = this1.getTotalSeconds() - dtic.getTotalSeconds();
+				tmp = this1.negative ? delta < 0 : delta > 0;
+			}
+		} else {
+			tmp = true;
+		}
+		return !tmp;
+	}
+	static lte(this1,dtic) {
+		let tmp;
+		if(this1.negative != dtic.negative) {
+			tmp = dtic.negative;
+		} else {
+			let delta = this1.getTotalSeconds() - dtic.getTotalSeconds();
+			tmp = this1.negative ? delta < 0 : delta > 0;
+		}
+		return !tmp;
+	}
+	static neq(this1,dtic) {
+		return !(this1.negative == dtic.negative && this1.getTotalSeconds() == dtic.getTotalSeconds());
+	}
+}
+class datetime_cores_DateTimeIntervalCore {
+	constructor() {
+		this.seconds = -1;
+		this.minutes = -1;
+		this.hours = -1;
+		this.days = -1;
+		this.months = -1;
+		this.years = -1;
+		this.negative = false;
+	}
+	getYears() {
+		if(this.years < 0) {
+			this.years = datetime_DateTime.getYear(this.end) - datetime_DateTime.getYear(this.begin);
+			let this1 = this.begin;
+			let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+			let m1 = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+			let this2 = this.end;
+			let days1 = ((this2 - 62135596800.0 - datetime_DateTime.yearStart(this2)) / 86400 | 0) + 1;
+			let m2 = datetime_utils_DateTimeMonthUtils.getMonth(days1,datetime_DateTime.isLeapYear(this2));
+			if(m2 < m1) {
+				this.years--;
+			} else if(m1 == m2) {
+				let this1 = this.begin;
+				let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+				let d1 = datetime_utils_DateTimeMonthUtils.getMonthDay(days,datetime_DateTime.isLeapYear(this1));
+				let this2 = this.end;
+				let days1 = ((this2 - 62135596800.0 - datetime_DateTime.yearStart(this2)) / 86400 | 0) + 1;
+				let d2 = datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(this2));
+				if(d2 < d1) {
+					this.years--;
+				} else if(d1 == d2) {
+					let this1 = this.begin;
+					let h1 = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+					let this2 = this.end;
+					let h2 = (this2 - Math.floor(this2 / 86400) * 86400) / 3600 | 0;
+					if(h2 < h1) {
+						this.years--;
+					} else if(h2 == h1) {
+						let this1 = this.begin;
+						let m1 = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+						let this2 = this.end;
+						let m2 = (this2 - Math.floor(this2 / 3600) * 3600) / 60 | 0;
+						if(m2 < m1) {
+							this.years--;
+						} else {
+							let tmp;
+							if(m2 == m1) {
+								let this1 = this.end;
+								let this2 = this.begin;
+								tmp = (this1 - Math.floor(this1 / 60) * 60 | 0) < (this2 - Math.floor(this2 / 60) * 60 | 0);
+							} else {
+								tmp = false;
+							}
+							if(tmp) {
+								this.years--;
+							}
+						}
+					}
+				}
+			}
+		}
+		return this.years;
+	}
+	getMonths() {
+		if(this.months < 0) {
+			let this1 = this.begin;
+			let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+			let monthBegin = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+			let this2 = this.end;
+			let days1 = ((this2 - 62135596800.0 - datetime_DateTime.yearStart(this2)) / 86400 | 0) + 1;
+			let monthEnd = datetime_utils_DateTimeMonthUtils.getMonth(days1,datetime_DateTime.isLeapYear(this2));
+			this.months = monthBegin <= monthEnd ? monthEnd - monthBegin : 12 - monthBegin + monthEnd;
+			let this3 = this.begin;
+			let days2 = ((this3 - 62135596800.0 - datetime_DateTime.yearStart(this3)) / 86400 | 0) + 1;
+			let d1 = datetime_utils_DateTimeMonthUtils.getMonthDay(days2,datetime_DateTime.isLeapYear(this3));
+			let this4 = this.end;
+			let days3 = ((this4 - 62135596800.0 - datetime_DateTime.yearStart(this4)) / 86400 | 0) + 1;
+			let d2 = datetime_utils_DateTimeMonthUtils.getMonthDay(days3,datetime_DateTime.isLeapYear(this4));
+			if(d2 < d1) {
+				this.months--;
+			} else if(d1 == d2) {
+				let this1 = this.begin;
+				let h1 = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+				let this2 = this.end;
+				let h2 = (this2 - Math.floor(this2 / 86400) * 86400) / 3600 | 0;
+				if(h2 < h1) {
+					this.months--;
+				} else if(h2 == h1) {
+					let this1 = this.begin;
+					let m1 = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+					let this2 = this.end;
+					let m2 = (this2 - Math.floor(this2 / 3600) * 3600) / 60 | 0;
+					if(m2 < m1) {
+						this.months--;
+					} else {
+						let tmp;
+						if(m2 == m1) {
+							let this1 = this.end;
+							let this2 = this.begin;
+							tmp = (this1 - Math.floor(this1 / 60) * 60 | 0) < (this2 - Math.floor(this2 / 60) * 60 | 0);
+						} else {
+							tmp = false;
+						}
+						if(tmp) {
+							this.months--;
+						}
+					}
+				}
+			}
+		}
+		return this.months;
+	}
+	getTotalMonths() {
+		return this.getYears() * 12 + this.getMonths();
+	}
+	getDays() {
+		if(this.days < 0) {
+			let this1 = this.begin;
+			let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+			let dayBegin = datetime_utils_DateTimeMonthUtils.getMonthDay(days,datetime_DateTime.isLeapYear(this1));
+			let this2 = this.end;
+			let days1 = ((this2 - 62135596800.0 - datetime_DateTime.yearStart(this2)) / 86400 | 0) + 1;
+			let dayEnd = datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(this2));
+			let tmp;
+			if(dayBegin <= dayEnd) {
+				tmp = dayEnd - dayBegin;
+			} else {
+				let this1 = this.begin;
+				let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+				tmp = datetime_utils_DateTimeMonthUtils.days(datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1)),datetime_DateTime.isLeapYear(this.begin)) - dayBegin + dayEnd;
+			}
+			this.days = tmp;
+			let this3 = this.begin;
+			let h1 = (this3 - Math.floor(this3 / 86400) * 86400) / 3600 | 0;
+			let this4 = this.end;
+			let h2 = (this4 - Math.floor(this4 / 86400) * 86400) / 3600 | 0;
+			if(h2 < h1) {
+				this.days--;
+			} else if(h2 == h1) {
+				let this1 = this.begin;
+				let m1 = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+				let this2 = this.end;
+				let m2 = (this2 - Math.floor(this2 / 3600) * 3600) / 60 | 0;
+				if(m2 < m1) {
+					this.days--;
+				} else {
+					let tmp;
+					if(m2 == m1) {
+						let this1 = this.end;
+						let this2 = this.begin;
+						tmp = (this1 - Math.floor(this1 / 60) * 60 | 0) < (this2 - Math.floor(this2 / 60) * 60 | 0);
+					} else {
+						tmp = false;
+					}
+					if(tmp) {
+						this.days--;
+					}
+				}
+			}
+		}
+		return this.days;
+	}
+	getTotalDays() {
+		return (this.end - 62135596800.0 - (this.begin - 62135596800.0)) / 86400 | 0;
+	}
+	getHours() {
+		if(this.hours < 0) {
+			let this1 = this.begin;
+			let hourBegin = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+			let this2 = this.end;
+			let hourEnd = (this2 - Math.floor(this2 / 86400) * 86400) / 3600 | 0;
+			this.hours = hourBegin <= hourEnd ? hourEnd - hourBegin : 24 - hourBegin + hourEnd;
+			let this3 = this.begin;
+			let m1 = (this3 - Math.floor(this3 / 3600) * 3600) / 60 | 0;
+			let this4 = this.end;
+			let m2 = (this4 - Math.floor(this4 / 3600) * 3600) / 60 | 0;
+			if(m2 < m1) {
+				this.hours--;
+			} else {
+				let tmp;
+				if(m2 == m1) {
+					let this1 = this.end;
+					let this2 = this.begin;
+					tmp = (this1 - Math.floor(this1 / 60) * 60 | 0) < (this2 - Math.floor(this2 / 60) * 60 | 0);
+				} else {
+					tmp = false;
+				}
+				if(tmp) {
+					this.hours--;
+				}
+			}
+		}
+		return this.hours;
+	}
+	getTotalHours() {
+		return (this.end - 62135596800.0 - (this.begin - 62135596800.0)) / 3600 | 0;
+	}
+	getMinutes() {
+		if(this.minutes < 0) {
+			let this1 = this.begin;
+			let minuteBegin = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+			let this2 = this.end;
+			let minuteEnd = (this2 - Math.floor(this2 / 3600) * 3600) / 60 | 0;
+			this.minutes = minuteBegin <= minuteEnd ? minuteEnd - minuteBegin : 60 - minuteBegin + minuteEnd;
+			let this3 = this.end;
+			let this4 = this.begin;
+			if((this3 - Math.floor(this3 / 60) * 60 | 0) < (this4 - Math.floor(this4 / 60) * 60 | 0)) {
+				this.minutes--;
+			}
+		}
+		return this.minutes;
+	}
+	getTotalMinutes() {
+		return (this.end - 62135596800.0 - (this.begin - 62135596800.0)) / 60 | 0;
+	}
+	getSeconds() {
+		if(this.seconds < 0) {
+			let this1 = this.begin;
+			let secondBegin = this1 - Math.floor(this1 / 60) * 60 | 0;
+			let this2 = this.end;
+			let secondEnd = this2 - Math.floor(this2 / 60) * 60 | 0;
+			this.seconds = secondBegin <= secondEnd ? secondEnd - secondBegin : 60 - secondBegin + secondEnd;
+		}
+		return this.seconds;
+	}
+	getTotalSeconds() {
+		return this.end - 62135596800.0 - (this.begin - 62135596800.0);
+	}
+	getTotalWeeks() {
+		return (this.end - 62135596800.0 - (this.begin - 62135596800.0)) / 604800 | 0;
+	}
+}
+datetime_cores_DateTimeIntervalCore.__name__ = "datetime.cores.DateTimeIntervalCore";
+Object.assign(datetime_cores_DateTimeIntervalCore.prototype, {
+	__class__: datetime_cores_DateTimeIntervalCore
+});
+class datetime_utils_DateTimeIntervalUtils {
+	constructor() {
+	}
+	static strftime(dti,format) {
+		let prevPos = 0;
+		let pos = format.indexOf("%");
+		let str = "";
+		while(pos >= 0) {
+			str += format.substring(prevPos,pos);
+			++pos;
+			switch(format.charCodeAt(pos)) {
+			case 37:
+				str += "%";
+				break;
+			case 68:
+				str += StringTools.lpad(dti.getDays() + "","0",2);
+				break;
+			case 72:
+				str += StringTools.lpad(dti.getHours() + "","0",2);
+				break;
+			case 73:
+				str += StringTools.lpad(dti.getMinutes() + "","0",2);
+				break;
+			case 77:
+				str += StringTools.lpad(dti.getMonths() + "","0",2);
+				break;
+			case 82:
+				str += dti.negative ? "-" : "+";
+				break;
+			case 83:
+				str += StringTools.lpad(dti.getSeconds() + "","0",2);
+				break;
+			case 89:
+				str += StringTools.lpad(dti.getYears() + "","0",2);
+				break;
+			case 97:
+				str += dti.getTotalDays() + "";
+				break;
+			case 98:
+				str += dti.getTotalMonths() + "";
+				break;
+			case 99:
+				str += dti.getTotalHours() + "";
+				break;
+			case 100:
+				str += dti.getDays() + "";
+				break;
+			case 101:
+				str += dti.getTotalMinutes() + "";
+				break;
+			case 102:
+				str += dti.getTotalSeconds() + "";
+				break;
+			case 104:
+				str += dti.getHours() + "";
+				break;
+			case 105:
+				str += dti.getMinutes() + "";
+				break;
+			case 109:
+				str += dti.getMonths() + "";
+				break;
+			case 114:
+				str += dti.negative ? "-" : "";
+				break;
+			case 115:
+				str += dti.getSeconds() + "";
+				break;
+			case 121:
+				str += dti.getYears() + "";
+				break;
+			}
+			prevPos = pos + 1;
+			pos = format.indexOf("%",pos + 1);
+		}
+		str += format.substring(prevPos);
+		return str;
+	}
+	static formatPartial(dti,format) {
+		let result = [];
+		let pos = 0;
+		let str = "";
+		let _g = 0;
+		let _g1 = format.length;
+		while(_g < _g1) {
+			let f = _g++;
+			pos = format[f].indexOf("%");
+			if(pos >= 0) {
+				switch(format[f].charCodeAt(pos + 1)) {
+				case 68:
+					if(dti.getDays() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getDays() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 72:
+					if(dti.getHours() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getHours() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 73:
+					if(dti.getMinutes() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getMinutes() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 77:
+					if(dti.getMonths() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getMonths() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 83:
+					if(dti.getSeconds() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getSeconds() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 89:
+					if(dti.getYears() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getYears() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 97:
+					if(dti.getTotalDays() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalDays() + format[f].substring(pos + 2);
+					break;
+				case 98:
+					if(dti.getTotalMonths() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalMonths() + format[f].substring(pos + 2);
+					break;
+				case 99:
+					if(dti.getTotalHours() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalHours() + format[f].substring(pos + 2);
+					break;
+				case 100:
+					if(dti.getDays() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getDays() + format[f].substring(pos + 2);
+					break;
+				case 101:
+					if(dti.getTotalMinutes() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalMinutes() + format[f].substring(pos + 2);
+					break;
+				case 102:
+					if(dti.getTotalSeconds() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalSeconds() + format[f].substring(pos + 2);
+					break;
+				case 104:
+					if(dti.getHours() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getHours() + format[f].substring(pos + 2);
+					break;
+				case 105:
+					if(dti.getMinutes() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getMinutes() + format[f].substring(pos + 2);
+					break;
+				case 109:
+					if(dti.getMonths() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getMonths() + format[f].substring(pos + 2);
+					break;
+				case 115:
+					if(dti.getSeconds() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getSeconds() + format[f].substring(pos + 2);
+					break;
+				case 121:
+					if(dti.getYears() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getYears() + format[f].substring(pos + 2);
+					break;
+				default:
+					continue;
+				}
+				result.push(str);
+			}
+		}
+		return result;
+	}
+}
+datetime_utils_DateTimeIntervalUtils.__name__ = "datetime.utils.DateTimeIntervalUtils";
+Object.assign(datetime_utils_DateTimeIntervalUtils.prototype, {
+	__class__: datetime_utils_DateTimeIntervalUtils
+});
+class datetime_utils_DateTimeMonthUtils {
+	constructor() {
+	}
+	static days(month,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		if(month == 1) {
+			return 31;
+		} else if(month == 2 && isLeapYear) {
+			return 29;
+		} else if(month == 2) {
+			return 28;
+		} else if(month == 3) {
+			return 31;
+		} else if(month == 4) {
+			return 30;
+		} else if(month == 5) {
+			return 31;
+		} else if(month == 6) {
+			return 30;
+		} else if(month == 7) {
+			return 31;
+		} else if(month == 8) {
+			return 31;
+		} else if(month == 9) {
+			return 30;
+		} else if(month == 10) {
+			return 31;
+		} else if(month == 11) {
+			return 30;
+		} else {
+			return 31;
+		}
+	}
+	static getMonth(days,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		if(days < 32) {
+			return 1;
+		} else if(isLeapYear) {
+			if(days < 61) {
+				return 2;
+			} else if(days < 92) {
+				return 3;
+			} else if(days < 122) {
+				return 4;
+			} else if(days < 153) {
+				return 5;
+			} else if(days < 183) {
+				return 6;
+			} else if(days < 214) {
+				return 7;
+			} else if(days < 245) {
+				return 8;
+			} else if(days < 275) {
+				return 9;
+			} else if(days < 306) {
+				return 10;
+			} else if(days < 336) {
+				return 11;
+			} else {
+				return 12;
+			}
+		} else if(days < 60) {
+			return 2;
+		} else if(days < 91) {
+			return 3;
+		} else if(days < 121) {
+			return 4;
+		} else if(days < 152) {
+			return 5;
+		} else if(days < 182) {
+			return 6;
+		} else if(days < 213) {
+			return 7;
+		} else if(days < 244) {
+			return 8;
+		} else if(days < 274) {
+			return 9;
+		} else if(days < 305) {
+			return 10;
+		} else if(days < 335) {
+			return 11;
+		} else {
+			return 12;
+		}
+	}
+	static getMonthDay(days,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		if(days < 32) {
+			return days;
+		} else if(isLeapYear) {
+			if(days < 61) {
+				return days - 31;
+			} else if(days < 92) {
+				return days - 60;
+			} else if(days < 122) {
+				return days - 91;
+			} else if(days < 153) {
+				return days - 121;
+			} else if(days < 183) {
+				return days - 152;
+			} else if(days < 214) {
+				return days - 182;
+			} else if(days < 245) {
+				return days - 213;
+			} else if(days < 275) {
+				return days - 244;
+			} else if(days < 306) {
+				return days - 274;
+			} else if(days < 336) {
+				return days - 305;
+			} else {
+				return days - 335;
+			}
+		} else if(days < 60) {
+			return days - 31;
+		} else if(days < 91) {
+			return days - 59;
+		} else if(days < 121) {
+			return days - 90;
+		} else if(days < 152) {
+			return days - 120;
+		} else if(days < 182) {
+			return days - 151;
+		} else if(days < 213) {
+			return days - 181;
+		} else if(days < 244) {
+			return days - 212;
+		} else if(days < 274) {
+			return days - 243;
+		} else if(days < 305) {
+			return days - 273;
+		} else if(days < 335) {
+			return days - 304;
+		} else {
+			return days - 334;
+		}
+	}
+	static toSeconds(month,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		return 86400 * (month == 1 ? 0 : isLeapYear ? month == 2 ? 31 : month == 3 ? 60 : month == 4 ? 91 : month == 5 ? 121 : month == 6 ? 152 : month == 7 ? 182 : month == 8 ? 213 : month == 9 ? 244 : month == 10 ? 274 : month == 11 ? 305 : 335 : month == 2 ? 31 : month == 3 ? 59 : month == 4 ? 90 : month == 5 ? 120 : month == 6 ? 151 : month == 7 ? 181 : month == 8 ? 212 : month == 9 ? 243 : month == 10 ? 273 : month == 11 ? 304 : 334);
+	}
+}
+datetime_utils_DateTimeMonthUtils.__name__ = "datetime.utils.DateTimeMonthUtils";
+Object.assign(datetime_utils_DateTimeMonthUtils.prototype, {
+	__class__: datetime_utils_DateTimeMonthUtils
+});
+class datetime_utils_DateTimeSnapUtils {
+	constructor() {
+	}
+	static snapYear(dt,direction) {
+		switch(direction) {
+		case -1:
+			return datetime_DateTime.yearStart(dt);
+		case 0:
+			let next = datetime_DateTime.yearStart(datetime_utils_DateTimeUtils.addYear(dt,1) + 62135596800.0);
+			let previous = datetime_DateTime.yearStart(dt);
+			if(next - (dt - 62135596800.0) > dt - 62135596800.0 - previous) {
+				return previous;
+			} else {
+				return next;
+			}
+			break;
+		case 1:
+			let next1 = datetime_utils_DateTimeUtils.addYear(dt,1) + 62135596800.0;
+			return datetime_DateTime.yearStart(next1);
+		}
+	}
+	static snapMonth(dt,direction) {
+		let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt));
+		let isLeap = datetime_DateTime.isLeapYear(dt);
+		switch(direction) {
+		case -1:
+			return datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap);
+		case 0:
+			let previous = datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap);
+			let next = datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap) + datetime_utils_DateTimeMonthUtils.days(month,isLeap) * 86400;
+			if(next - (dt - 62135596800.0) > dt - 62135596800.0 - previous) {
+				return previous;
+			} else {
+				return next;
+			}
+			break;
+		case 1:
+			return datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap) + datetime_utils_DateTimeMonthUtils.days(month,isLeap) * 86400;
+		}
+	}
+	static snapDay(dt,direction) {
+		let days = (dt - 62135596800.0) / 86400;
+		switch(direction) {
+		case -1:
+			return Math.floor(days) * 86400;
+		case 0:
+			return Math.round(days) * 86400;
+		case 1:
+			return Math.ceil(days) * 86400;
+		}
+	}
+	static snapHour(dt,direction) {
+		let hours = (dt - 62135596800.0) / 3600;
+		switch(direction) {
+		case -1:
+			return Math.floor(hours) * 3600;
+		case 0:
+			return Math.round(hours) * 3600;
+		case 1:
+			return Math.ceil(hours) * 3600;
+		}
+	}
+	static snapMinute(dt,direction) {
+		let minutes = (dt - 62135596800.0) / 60;
+		switch(direction) {
+		case -1:
+			return Math.floor(minutes) * 60;
+		case 0:
+			return Math.round(minutes) * 60;
+		case 1:
+			return Math.ceil(minutes) * 60;
+		}
+	}
+	static snapWeek(dt,direction,required) {
+		let current = datetime_DateTime.getWeekDay(dt);
+		let days = Math.floor((dt - 62135596800.0) / 86400);
+		switch(direction) {
+		case -1:
+			let diff = current >= required ? current - required : current + 7 - required;
+			return (days - diff) * 86400;
+		case 0:
+			let diff1 = current >= required ? current - required : current + 7 - required;
+			let previous = (days - diff1) * 86400;
+			let diff2 = required > current ? required - current : required + 7 - current;
+			let next = (days + diff2) * 86400;
+			if(next - (dt - 62135596800.0) > dt - 62135596800.0 - previous) {
+				return previous;
+			} else {
+				return next;
+			}
+			break;
+		case 1:
+			let diff3 = required > current ? required - current : required + 7 - current;
+			return (days + diff3) * 86400;
+		}
+	}
+}
+datetime_utils_DateTimeSnapUtils.__name__ = "datetime.utils.DateTimeSnapUtils";
+Object.assign(datetime_utils_DateTimeSnapUtils.prototype, {
+	__class__: datetime_utils_DateTimeSnapUtils
+});
+class datetime_utils_DateTimeUtils {
+	constructor() {
+	}
+	static fromString(str) {
+		if(str.length == 10 || str.charCodeAt(10) == 32) {
+			return datetime_utils_DateTimeUtils.parse(str);
+		} else if(str.charCodeAt(10) == 84) {
+			return datetime_utils_DateTimeUtils.fromIsoString(str);
+		} else {
+			throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Should be either `YYYY-MM-DD hh:mm:ss` or `YYYY-MM-DD` or `YYYY-MM-DDThh:mm:ss[.SSS]Z`");
+		}
+	}
+	static parse(str) {
+		let ylength = str.indexOf("-");
+		if(ylength < 1 || str.length - ylength != 6 && str.length - ylength != 15) {
+			throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Should be either `YYYY-MM-DD hh:mm:ss` or `YYYY-MM-DD`");
+		}
+		if(str.length - ylength == 6) {
+			str += " 00:00:00";
+		}
+		let year = Std.parseInt(HxOverrides.substr(str,0,ylength));
+		let month = Std.parseInt(HxOverrides.substr(str,ylength + 1,2));
+		let day = Std.parseInt(HxOverrides.substr(str,ylength + 4,2));
+		let hour = Std.parseInt(HxOverrides.substr(str,ylength + 7,2));
+		let minute = Std.parseInt(HxOverrides.substr(str,ylength + 10,2));
+		let second = Std.parseInt(HxOverrides.substr(str,ylength + 13,2));
+		if(year == null || month == null || day == null || hour == null || minute == null || second == null) {
+			throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Should be either `YYYY-MM-DD hh:mm:ss` or `YYYY-MM-DD`");
+		}
+		let year1 = year;
+		let month1 = month;
+		let day1 = day;
+		let hour1 = hour;
+		let minute1 = minute;
+		let second1 = second;
+		if(second1 == null) {
+			second1 = 0;
+		}
+		if(minute1 == null) {
+			minute1 = 0;
+		}
+		if(hour1 == null) {
+			hour1 = 0;
+		}
+		if(day1 == null) {
+			day1 = 1;
+		}
+		if(month1 == null) {
+			month1 = 1;
+		}
+		if(year1 == null) {
+			year1 = 1970;
+		}
+		return datetime_utils_DateTimeUtils.yearToStamp(year1) + datetime_utils_DateTimeMonthUtils.toSeconds(month1,year1 % 4 == 0 && (year1 % 100 == 0 ? year1 % 400 == 0 : true)) + (day1 - 1) * 86400 + hour1 * 3600 + minute1 * 60 + second1 - 62135596800.0 + 62135596800.0;
+	}
+	static fromIsoString(str) {
+		let tz = null;
+		let tzSep = str.charCodeAt(str.length - 6);
+		if(str.charCodeAt(str.length - 1) == 90) {
+			tz = 0;
+		} else if(tzSep == 43 || tzSep == 45) {
+			let tzHour = Std.parseInt(HxOverrides.substr(str,str.length - 5,2));
+			let tzMin = Std.parseInt(HxOverrides.substr(str,str.length - 2,2));
+			tz = tzHour * 60 + tzMin;
+			if(tzSep == 43) {
+				tz = -1 * tz;
+			}
+		}
+		if(tz == null) {
+			throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Not an ISO 8601 string: No timezone.");
+		}
+		if(str.length > 20) {
+			if(str.charCodeAt(19) != 46 && str.charCodeAt(19) != tzSep) {
+				throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Not an ISO 8601 string: Millisecond specification erroneous.");
+			}
+		}
+		return datetime_DateTime.add(datetime_utils_DateTimeUtils.parse(HxOverrides.substr(str,0,10) + " " + HxOverrides.substr(str,11,8)),datetime_DTPeriod.Minute(tz));
+	}
+	static clamp(value,min,max) {
+		if(value < min) {
+			return min;
+		} else if(value > max) {
+			return max;
+		} else {
+			return value;
+		}
+	}
+	static yearToStamp(year) {
+		--year;
+		let cquads = year / 400 | 0;
+		let quads = (year - cquads * 400) / 4 | 0;
+		let excessDays = quads / 25 | 0;
+		return cquads * 12622780800.0 + quads * 126230400.0 - excessDays * 86400 + (year - cquads * 400 - quads * 4) * 31536000;
+	}
+	static addYear(dt,amount) {
+		let year = datetime_DateTime.getYear(dt) + amount;
+		let time = datetime_DateTime.yearStart(dt);
+		let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let time1 = dt - 62135596800.0 - (time + datetime_utils_DateTimeMonthUtils.toSeconds(datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt)),datetime_DateTime.isLeapYear(dt)));
+		let tmp = datetime_utils_DateTimeUtils.yearToStamp(year);
+		let days1 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		return tmp + datetime_utils_DateTimeMonthUtils.toSeconds(datetime_utils_DateTimeMonthUtils.getMonth(days1,datetime_DateTime.isLeapYear(dt)),year % 4 == 0 && (year % 100 == 0 ? year % 400 == 0 : true)) + time1 - 62135596800.0;
+	}
+	static addMonth(dt,amount) {
+		let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt)) + amount;
+		if(month > 12) {
+			let years = month / 12 | 0;
+			dt = datetime_utils_DateTimeUtils.addYear(dt,years) + 62135596800.0;
+			month -= years * 12;
+		} else if(month <= 0) {
+			let years = (month / 12 | 0) - 1;
+			dt = datetime_utils_DateTimeUtils.addYear(dt,years) + 62135596800.0;
+			month -= years * 12;
+		}
+		let isLeap = datetime_DateTime.isLeapYear(dt);
+		let days1 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let value = datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(dt));
+		let max = datetime_utils_DateTimeMonthUtils.days(month,isLeap);
+		let day = value < 1 ? 1 : value > max ? max : value;
+		return datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap) + (day - 1) * 86400 + ((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) * 3600 + ((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) * 60 + (dt - Math.floor(dt / 60) * 60 | 0);
+	}
+	static getWeekDayNum(dt,weekDay,num) {
+		let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt));
+		if(num > 0) {
+			let start = datetime_DateTime.monthStart(dt,month) - 1 + 62135596800.0;
+			let first = datetime_DateTime.snap(start,datetime_DTSnap.Week(1,weekDay));
+			return datetime_DateTime.add(first,datetime_DTPeriod.Week(num - 1)) - 62135596800.0;
+		} else if(num < 0) {
+			let start = datetime_DateTime.monthStart(dt,month + 1) - 1 + 62135596800.0;
+			let first = datetime_DateTime.snap(start,datetime_DTSnap.Week(-1,weekDay));
+			return datetime_DateTime.add(first,datetime_DTPeriod.Week(num + 1)) - 62135596800.0;
+		} else {
+			return dt - 62135596800.0;
+		}
+	}
+	static strftime(dt,format) {
+		let prevPos = 0;
+		let pos = format.indexOf("%");
+		let str = "";
+		while(pos >= 0) {
+			str += format.substring(prevPos,pos);
+			++pos;
+			switch(format.charCodeAt(pos)) {
+			case 37:
+				str += "%";
+				break;
+			case 67:
+				str += StringTools.lpad((datetime_DateTime.getYear(dt) / 100 | 0) + "","0",2);
+				break;
+			case 68:
+				let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				let str1 = StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt)) + "/","0",3);
+				let days1 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += str1 + StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(dt)) + "/","0",3) + StringTools.lpad(HxOverrides.substr(datetime_DateTime.getYear(dt) + "",-2,null),"0",2);
+				break;
+			case 70:
+				let str2 = datetime_DateTime.getYear(dt) + "-";
+				let days2 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				let str3 = str2 + StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonth(days2,datetime_DateTime.isLeapYear(dt)) + "-","0",3);
+				let days3 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += str3 + StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonthDay(days3,datetime_DateTime.isLeapYear(dt)) + "","0",2);
+				break;
+			case 72:
+				str += StringTools.lpad(((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) + "","0",2);
+				break;
+			case 73:
+				str += StringTools.lpad(datetime_DateTime.getHour12(dt) + "","0",2);
+				break;
+			case 77:
+				str += StringTools.lpad(((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) + "","0",2);
+				break;
+			case 80:
+				str += ((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) < 12 ? "am" : "pm";
+				break;
+			case 82:
+				str += StringTools.lpad(((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) + ":","0",3) + StringTools.lpad(((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) + "","0",2);
+				break;
+			case 83:
+				str += StringTools.lpad((dt - Math.floor(dt / 60) * 60 | 0) + "","0",2);
+				break;
+			case 84:
+				str += StringTools.lpad(((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) + ":","0",3) + StringTools.lpad(((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) + ":","0",3) + StringTools.lpad((dt - Math.floor(dt / 60) * 60 | 0) + "","0",2);
+				break;
+			case 86:
+				str += StringTools.lpad(datetime_DateTime.getWeek(dt) + "","0",2);
+				break;
+			case 89:
+				str += datetime_DateTime.getYear(dt) + "";
+				break;
+			case 100:
+				let days4 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonthDay(days4,datetime_DateTime.isLeapYear(dt)) + "","0",2);
+				break;
+			case 101:
+				let days5 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonthDay(days5,datetime_DateTime.isLeapYear(dt)) + ""," ",2);
+				break;
+			case 106:
+				let day = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += StringTools.lpad("" + day,"0",3);
+				break;
+			case 107:
+				str += StringTools.lpad(((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) + ""," ",2);
+				break;
+			case 108:
+				str += StringTools.lpad(datetime_DateTime.getHour12(dt) + ""," ",2);
+				break;
+			case 109:
+				let days6 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonth(days6,datetime_DateTime.isLeapYear(dt)) + "","0",2);
+				break;
+			case 112:
+				str += ((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) < 12 ? "AM" : "PM";
+				break;
+			case 114:
+				str += StringTools.lpad(datetime_DateTime.getHour12(dt) + ":","0",3) + StringTools.lpad(((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) + ":","0",3) + StringTools.lpad((dt - Math.floor(dt / 60) * 60 | 0) + "","0",2);
+				break;
+			case 115:
+				str += dt - 62135596800.0 + "";
+				break;
+			case 117:
+				str += datetime_DateTime.getWeekDay(dt,true) + "";
+				break;
+			case 119:
+				str += datetime_DateTime.getWeekDay(dt) + "";
+				break;
+			case 121:
+				str += StringTools.lpad(HxOverrides.substr(datetime_DateTime.getYear(dt) + "",-2,null),"0",2);
+				break;
+			}
+			prevPos = pos + 1;
+			pos = format.indexOf("%",pos + 1);
+		}
+		str += format.substring(prevPos);
+		return str;
+	}
+}
+datetime_utils_DateTimeUtils.__name__ = "datetime.utils.DateTimeUtils";
+Object.assign(datetime_utils_DateTimeUtils.prototype, {
+	__class__: datetime_utils_DateTimeUtils
+});
+var haxe_StackItem = $hxEnums["haxe.StackItem"] = { __ename__:true,__constructs__:null
+	,CFunction: {_hx_name:"CFunction",_hx_index:0,__enum__:"haxe.StackItem",toString:$estr}
+	,Module: ($_=function(m) { return {_hx_index:1,m:m,__enum__:"haxe.StackItem",toString:$estr}; },$_._hx_name="Module",$_.__params__ = ["m"],$_)
+	,FilePos: ($_=function(s,file,line,column) { return {_hx_index:2,s:s,file:file,line:line,column:column,__enum__:"haxe.StackItem",toString:$estr}; },$_._hx_name="FilePos",$_.__params__ = ["s","file","line","column"],$_)
+	,Method: ($_=function(classname,method) { return {_hx_index:3,classname:classname,method:method,__enum__:"haxe.StackItem",toString:$estr}; },$_._hx_name="Method",$_.__params__ = ["classname","method"],$_)
+	,LocalFunction: ($_=function(v) { return {_hx_index:4,v:v,__enum__:"haxe.StackItem",toString:$estr}; },$_._hx_name="LocalFunction",$_.__params__ = ["v"],$_)
+};
+haxe_StackItem.__constructs__ = [haxe_StackItem.CFunction,haxe_StackItem.Module,haxe_StackItem.FilePos,haxe_StackItem.Method,haxe_StackItem.LocalFunction];
+class haxe_IMap {
+}
+haxe_IMap.__name__ = "haxe.IMap";
+haxe_IMap.__isInterface__ = true;
+Object.assign(haxe_IMap.prototype, {
+	__class__: haxe_IMap
+});
+class haxe_Exception extends Error {
+	constructor(message,previous,native) {
+		super(message);
+		this.message = message;
+		this.__previousException = previous;
+		this.__nativeException = native != null ? native : this;
+	}
+	unwrap() {
+		return this.__nativeException;
+	}
+	toString() {
+		return this.get_message();
+	}
+	get_message() {
+		return this.message;
+	}
+	get_native() {
+		return this.__nativeException;
+	}
+	static caught(value) {
+		if(((value) instanceof haxe_Exception)) {
+			return value;
+		} else if(((value) instanceof Error)) {
+			return new haxe_Exception(value.message,null,value);
+		} else {
+			return new haxe_ValueException(value,null,value);
+		}
+	}
+	static thrown(value) {
+		if(((value) instanceof haxe_Exception)) {
+			return value.get_native();
+		} else if(((value) instanceof Error)) {
+			return value;
+		} else {
+			let e = new haxe_ValueException(value);
+			return e;
+		}
+	}
+}
+haxe_Exception.__name__ = "haxe.Exception";
+haxe_Exception.__super__ = Error;
+Object.assign(haxe_Exception.prototype, {
+	__class__: haxe_Exception
+});
+class haxe__$Int64__$_$_$Int64 {
+	constructor(high,low) {
+		this.high = high;
+		this.low = low;
+	}
+}
+haxe__$Int64__$_$_$Int64.__name__ = "haxe._Int64.___Int64";
+Object.assign(haxe__$Int64__$_$_$Int64.prototype, {
+	__class__: haxe__$Int64__$_$_$Int64
+});
+class haxe_Log {
+	static formatOutput(v,infos) {
+		let str = Std.string(v);
+		if(infos == null) {
+			return str;
+		}
+		let pstr = infos.fileName + ":" + infos.lineNumber;
+		if(infos.customParams != null) {
+			let _g = 0;
+			let _g1 = infos.customParams;
+			while(_g < _g1.length) {
+				let v = _g1[_g];
+				++_g;
+				str += ", " + Std.string(v);
+			}
+		}
+		return pstr + ": " + str;
+	}
+	static trace(v,infos) {
+		let str = haxe_Log.formatOutput(v,infos);
+		if(typeof(console) != "undefined" && console.log != null) {
+			console.log(str);
+		}
+	}
+}
+haxe_Log.__name__ = "haxe.Log";
+class haxe_Timer {
+	constructor(time_ms) {
+		let me = this;
+		this.id = setInterval(function() {
+			me.run();
+		},time_ms);
+	}
+	stop() {
+		if(this.id == null) {
+			return;
+		}
+		clearInterval(this.id);
+		this.id = null;
+	}
+	run() {
+	}
+	static delay(f,time_ms) {
+		let t = new haxe_Timer(time_ms);
+		t.run = function() {
+			t.stop();
+			f();
+		};
+		return t;
+	}
+}
+haxe_Timer.__name__ = "haxe.Timer";
+Object.assign(haxe_Timer.prototype, {
+	__class__: haxe_Timer
+});
+class haxe_ValueException extends haxe_Exception {
+	constructor(value,previous,native) {
+		super(String(value),previous,native);
+		this.value = value;
+	}
+	unwrap() {
+		return this.value;
+	}
+}
+haxe_ValueException.__name__ = "haxe.ValueException";
+haxe_ValueException.__super__ = haxe_Exception;
+Object.assign(haxe_ValueException.prototype, {
+	__class__: haxe_ValueException
+});
+class haxe_crypto_Adler32 {
+	constructor() {
+		this.a1 = 1;
+		this.a2 = 0;
+	}
+	get() {
+		return this.a2 << 16 | this.a1;
+	}
+	update(b,pos,len) {
+		let a1 = this.a1;
+		let a2 = this.a2;
+		let _g = pos;
+		let _g1 = pos + len;
+		while(_g < _g1) {
+			let p = _g++;
+			let c = b.b[p];
+			a1 = (a1 + c) % 65521;
+			a2 = (a2 + a1) % 65521;
+		}
+		this.a1 = a1;
+		this.a2 = a2;
+	}
+	static make(b) {
+		let a = new haxe_crypto_Adler32();
+		a.update(b,0,b.length);
+		return a.get();
+	}
+}
+haxe_crypto_Adler32.__name__ = "haxe.crypto.Adler32";
+Object.assign(haxe_crypto_Adler32.prototype, {
+	__class__: haxe_crypto_Adler32
+});
+class haxe_io_Bytes {
+	constructor(data) {
+		this.length = data.byteLength;
+		this.b = new Uint8Array(data);
+		this.b.bufferValue = data;
+		data.hxBytes = this;
+		data.bytes = this.b;
+	}
+	blit(pos,src,srcpos,len) {
+		if(pos < 0 || srcpos < 0 || len < 0 || pos + len > this.length || srcpos + len > src.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		if(srcpos == 0 && len == src.b.byteLength) {
+			this.b.set(src.b,pos);
+		} else {
+			this.b.set(src.b.subarray(srcpos,srcpos + len),pos);
+		}
+	}
+	fill(pos,len,value) {
+		let _g = 0;
+		let _g1 = len;
+		while(_g < _g1) {
+			let i = _g++;
+			this.b[pos++] = value;
+		}
+	}
+	sub(pos,len) {
+		if(pos < 0 || len < 0 || pos + len > this.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		return new haxe_io_Bytes(this.b.buffer.slice(pos + this.b.byteOffset,pos + this.b.byteOffset + len));
+	}
+	getUInt16(pos) {
+		if(this.data == null) {
+			this.data = new DataView(this.b.buffer,this.b.byteOffset,this.b.byteLength);
+		}
+		return this.data.getUint16(pos,true);
+	}
+	getString(pos,len,encoding) {
+		if(pos < 0 || len < 0 || pos + len > this.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		if(encoding == null) {
+			encoding = haxe_io_Encoding.UTF8;
+		}
+		let s = "";
+		let b = this.b;
+		let i = pos;
+		let max = pos + len;
+		switch(encoding._hx_index) {
+		case 0:
+			let debug = pos > 0;
+			while(i < max) {
+				let c = b[i++];
+				if(c < 128) {
+					if(c == 0) {
+						break;
+					}
+					s += String.fromCodePoint(c);
+				} else if(c < 224) {
+					let code = (c & 63) << 6 | b[i++] & 127;
+					s += String.fromCodePoint(code);
+				} else if(c < 240) {
+					let c2 = b[i++];
+					let code = (c & 31) << 12 | (c2 & 127) << 6 | b[i++] & 127;
+					s += String.fromCodePoint(code);
+				} else {
+					let c2 = b[i++];
+					let c3 = b[i++];
+					let u = (c & 15) << 18 | (c2 & 127) << 12 | (c3 & 127) << 6 | b[i++] & 127;
+					s += String.fromCodePoint(u);
+				}
+			}
+			break;
+		case 1:
+			while(i < max) {
+				let c = b[i++] | b[i++] << 8;
+				s += String.fromCodePoint(c);
+			}
+			break;
+		}
+		return s;
+	}
+	toString() {
+		return this.getString(0,this.length);
+	}
+	toHex() {
+		let s_b = "";
+		let chars = [];
+		let str = "0123456789abcdef";
+		let _g = 0;
+		let _g1 = str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			chars.push(HxOverrides.cca(str,i));
+		}
+		let _g2 = 0;
+		let _g3 = this.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			let c = this.b[i];
+			s_b += String.fromCodePoint(chars[c >> 4]);
+			s_b += String.fromCodePoint(chars[c & 15]);
+		}
+		return s_b;
+	}
+	static ofString(s,encoding) {
+		if(encoding == haxe_io_Encoding.RawNative) {
+			let buf = new Uint8Array(s.length << 1);
+			let _g = 0;
+			let _g1 = s.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let c = s.charCodeAt(i);
+				buf[i << 1] = c & 255;
+				buf[i << 1 | 1] = c >> 8;
+			}
+			return new haxe_io_Bytes(buf.buffer);
+		}
+		let a = [];
+		let i = 0;
+		while(i < s.length) {
+			let c = s.charCodeAt(i++);
+			if(55296 <= c && c <= 56319) {
+				c = c - 55232 << 10 | s.charCodeAt(i++) & 1023;
+			}
+			if(c <= 127) {
+				a.push(c);
+			} else if(c <= 2047) {
+				a.push(192 | c >> 6);
+				a.push(128 | c & 63);
+			} else if(c <= 65535) {
+				a.push(224 | c >> 12);
+				a.push(128 | c >> 6 & 63);
+				a.push(128 | c & 63);
+			} else {
+				a.push(240 | c >> 18);
+				a.push(128 | c >> 12 & 63);
+				a.push(128 | c >> 6 & 63);
+				a.push(128 | c & 63);
+			}
+		}
+		return new haxe_io_Bytes(new Uint8Array(a).buffer);
+	}
+	static ofData(b) {
+		let hb = b.hxBytes;
+		if(hb != null) {
+			return hb;
+		}
+		return new haxe_io_Bytes(b);
+	}
+	static ofHex(s) {
+		if((s.length & 1) != 0) {
+			throw haxe_Exception.thrown("Not a hex string (odd number of digits)");
+		}
+		let a = [];
+		let i = 0;
+		let len = s.length >> 1;
+		while(i < len) {
+			let high = s.charCodeAt(i * 2);
+			let low = s.charCodeAt(i * 2 + 1);
+			high = (high & 15) + ((high & 64) >> 6) * 9;
+			low = (low & 15) + ((low & 64) >> 6) * 9;
+			a.push((high << 4 | low) & 255);
+			++i;
+		}
+		return new haxe_io_Bytes(new Uint8Array(a).buffer);
+	}
+}
+haxe_io_Bytes.__name__ = "haxe.io.Bytes";
+Object.assign(haxe_io_Bytes.prototype, {
+	__class__: haxe_io_Bytes
+});
+var haxe_io_Encoding = $hxEnums["haxe.io.Encoding"] = { __ename__:true,__constructs__:null
+	,UTF8: {_hx_name:"UTF8",_hx_index:0,__enum__:"haxe.io.Encoding",toString:$estr}
+	,RawNative: {_hx_name:"RawNative",_hx_index:1,__enum__:"haxe.io.Encoding",toString:$estr}
+};
+haxe_io_Encoding.__constructs__ = [haxe_io_Encoding.UTF8,haxe_io_Encoding.RawNative];
+class haxe_crypto_Base64 {
+	static encode(bytes,complement) {
+		if(complement == null) {
+			complement = true;
+		}
+		let str = new haxe_crypto_BaseCode(haxe_crypto_Base64.BYTES).encodeBytes(bytes).toString();
+		if(complement) {
+			switch(bytes.length % 3) {
+			case 1:
+				str += "==";
+				break;
+			case 2:
+				str += "=";
+				break;
+			default:
+			}
+		}
+		return str;
+	}
+	static decode(str,complement) {
+		if(complement == null) {
+			complement = true;
+		}
+		if(complement) {
+			while(HxOverrides.cca(str,str.length - 1) == 61) str = HxOverrides.substr(str,0,-1);
+		}
+		return new haxe_crypto_BaseCode(haxe_crypto_Base64.BYTES).decodeBytes(haxe_io_Bytes.ofString(str));
+	}
+	static urlEncode(bytes,complement) {
+		if(complement == null) {
+			complement = false;
+		}
+		let str = new haxe_crypto_BaseCode(haxe_crypto_Base64.URL_BYTES).encodeBytes(bytes).toString();
+		if(complement) {
+			switch(bytes.length % 3) {
+			case 1:
+				str += "==";
+				break;
+			case 2:
+				str += "=";
+				break;
+			default:
+			}
+		}
+		return str;
+	}
+	static urlDecode(str,complement) {
+		if(complement == null) {
+			complement = false;
+		}
+		if(complement) {
+			while(HxOverrides.cca(str,str.length - 1) == 61) str = HxOverrides.substr(str,0,-1);
+		}
+		return new haxe_crypto_BaseCode(haxe_crypto_Base64.URL_BYTES).decodeBytes(haxe_io_Bytes.ofString(str));
+	}
+}
+haxe_crypto_Base64.__name__ = "haxe.crypto.Base64";
+class haxe_crypto_BaseCode {
+	constructor(base) {
+		let len = base.length;
+		let nbits = 1;
+		while(len > 1 << nbits) ++nbits;
+		if(nbits > 8 || len != 1 << nbits) {
+			throw haxe_Exception.thrown("BaseCode : base length must be a power of two.");
+		}
+		this.base = base;
+		this.nbits = nbits;
+	}
+	encodeBytes(b) {
+		let nbits = this.nbits;
+		let base = this.base;
+		let size = b.length * 8 / nbits | 0;
+		let out = new haxe_io_Bytes(new ArrayBuffer(size + (b.length * 8 % nbits == 0 ? 0 : 1)));
+		let buf = 0;
+		let curbits = 0;
+		let mask = (1 << nbits) - 1;
+		let pin = 0;
+		let pout = 0;
+		while(pout < size) {
+			while(curbits < nbits) {
+				curbits += 8;
+				buf <<= 8;
+				buf |= b.b[pin++];
+			}
+			curbits -= nbits;
+			out.b[pout++] = base.b[buf >> curbits & mask];
+		}
+		if(curbits > 0) {
+			out.b[pout++] = base.b[buf << nbits - curbits & mask];
+		}
+		return out;
+	}
+	initTable() {
+		let tbl = [];
+		let _g = 0;
+		while(_g < 256) {
+			let i = _g++;
+			tbl[i] = -1;
+		}
+		let _g1 = 0;
+		let _g2 = this.base.length;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			tbl[this.base.b[i]] = i;
+		}
+		this.tbl = tbl;
+	}
+	decodeBytes(b) {
+		let nbits = this.nbits;
+		let base = this.base;
+		if(this.tbl == null) {
+			this.initTable();
+		}
+		let tbl = this.tbl;
+		let size = b.length * nbits >> 3;
+		let out = new haxe_io_Bytes(new ArrayBuffer(size));
+		let buf = 0;
+		let curbits = 0;
+		let pin = 0;
+		let pout = 0;
+		while(pout < size) {
+			while(curbits < 8) {
+				curbits += nbits;
+				buf <<= nbits;
+				let i = tbl[b.b[pin++]];
+				if(i == -1) {
+					throw haxe_Exception.thrown("BaseCode : invalid encoded char");
+				}
+				buf |= i;
+			}
+			curbits -= 8;
+			out.b[pout++] = buf >> curbits & 255;
+		}
+		return out;
+	}
+}
+haxe_crypto_BaseCode.__name__ = "haxe.crypto.BaseCode";
+Object.assign(haxe_crypto_BaseCode.prototype, {
+	__class__: haxe_crypto_BaseCode
+});
+class haxe_crypto_Crc32 {
+	static make(data) {
+		let c_crc = -1;
+		let b = data.b.bufferValue;
+		let _g = 0;
+		let _g1 = data.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let tmp = (c_crc ^ b.bytes[i]) & 255;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			c_crc = c_crc >>> 8 ^ tmp;
+		}
+		return c_crc ^ -1;
+	}
+}
+haxe_crypto_Crc32.__name__ = "haxe.crypto.Crc32";
+class haxe_crypto_Sha1 {
+	constructor() {
+	}
+	doEncode(x) {
+		let w = [];
+		let a = 1732584193;
+		let b = -271733879;
+		let c = -1732584194;
+		let d = 271733878;
+		let e = -1009589776;
+		let i = 0;
+		while(i < x.length) {
+			let olda = a;
+			let oldb = b;
+			let oldc = c;
+			let oldd = d;
+			let olde = e;
+			let j = 0;
+			while(j < 80) {
+				if(j < 16) {
+					w[j] = x[i + j];
+				} else {
+					let num = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16];
+					w[j] = num << 1 | num >>> 31;
+				}
+				let t = (a << 5 | a >>> 27) + this.ft(j,b,c,d) + e + w[j] + this.kt(j);
+				e = d;
+				d = c;
+				c = b << 30 | b >>> 2;
+				b = a;
+				a = t;
+				++j;
+			}
+			a += olda;
+			b += oldb;
+			c += oldc;
+			d += oldd;
+			e += olde;
+			i += 16;
+		}
+		return [a,b,c,d,e];
+	}
+	ft(t,b,c,d) {
+		if(t < 20) {
+			return b & c | ~b & d;
+		}
+		if(t < 40) {
+			return b ^ c ^ d;
+		}
+		if(t < 60) {
+			return b & c | b & d | c & d;
+		}
+		return b ^ c ^ d;
+	}
+	kt(t) {
+		if(t < 20) {
+			return 1518500249;
+		}
+		if(t < 40) {
+			return 1859775393;
+		}
+		if(t < 60) {
+			return -1894007588;
+		}
+		return -899497514;
+	}
+	static make(b) {
+		let h = new haxe_crypto_Sha1().doEncode(haxe_crypto_Sha1.bytes2blks(b));
+		let out = new haxe_io_Bytes(new ArrayBuffer(20));
+		let p = 0;
+		out.b[p++] = h[0] >>> 24;
+		out.b[p++] = h[0] >> 16 & 255;
+		out.b[p++] = h[0] >> 8 & 255;
+		out.b[p++] = h[0] & 255;
+		out.b[p++] = h[1] >>> 24;
+		out.b[p++] = h[1] >> 16 & 255;
+		out.b[p++] = h[1] >> 8 & 255;
+		out.b[p++] = h[1] & 255;
+		out.b[p++] = h[2] >>> 24;
+		out.b[p++] = h[2] >> 16 & 255;
+		out.b[p++] = h[2] >> 8 & 255;
+		out.b[p++] = h[2] & 255;
+		out.b[p++] = h[3] >>> 24;
+		out.b[p++] = h[3] >> 16 & 255;
+		out.b[p++] = h[3] >> 8 & 255;
+		out.b[p++] = h[3] & 255;
+		out.b[p++] = h[4] >>> 24;
+		out.b[p++] = h[4] >> 16 & 255;
+		out.b[p++] = h[4] >> 8 & 255;
+		out.b[p++] = h[4] & 255;
+		return out;
+	}
+	static bytes2blks(b) {
+		let nblk = (b.length + 8 >> 6) + 1;
+		let blks = [];
+		let _g = 0;
+		let _g1 = nblk * 16;
+		while(_g < _g1) {
+			let i = _g++;
+			blks[i] = 0;
+		}
+		let _g2 = 0;
+		let _g3 = b.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			let p = i >> 2;
+			blks[p] |= b.b[i] << 24 - ((i & 3) << 3);
+		}
+		let i = b.length;
+		let p = i >> 2;
+		blks[p] |= 128 << 24 - ((i & 3) << 3);
+		blks[nblk * 16 - 1] = b.length * 8;
+		return blks;
+	}
+}
+haxe_crypto_Sha1.__name__ = "haxe.crypto.Sha1";
+Object.assign(haxe_crypto_Sha1.prototype, {
+	__class__: haxe_crypto_Sha1
+});
+class haxe_crypto_Sha256 {
+	constructor() {
+	}
+	doEncode(m,l) {
+		let K = [1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998];
+		let HASH = [1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225];
+		let W = [];
+		W[64] = 0;
+		let a;
+		let b;
+		let c;
+		let d;
+		let e;
+		let f;
+		let g;
+		let h;
+		let T1;
+		let T2;
+		m[l >> 5] |= 128 << 24 - l % 32;
+		m[(l + 64 >> 9 << 4) + 15] = l;
+		let i = 0;
+		while(i < m.length) {
+			a = HASH[0];
+			b = HASH[1];
+			c = HASH[2];
+			d = HASH[3];
+			e = HASH[4];
+			f = HASH[5];
+			g = HASH[6];
+			h = HASH[7];
+			let _g = 0;
+			while(_g < 64) {
+				let j = _g++;
+				if(j < 16) {
+					W[j] = m[j + i];
+				} else {
+					let x = W[j - 2];
+					let x1 = (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ x >>> 10;
+					let y = W[j - 7];
+					let lsw = (x1 & 65535) + (y & 65535);
+					let msw = (x1 >> 16) + (y >> 16) + (lsw >> 16);
+					let x2 = msw << 16 | lsw & 65535;
+					let x3 = W[j - 15];
+					let y1 = (x3 >>> 7 | x3 << 25) ^ (x3 >>> 18 | x3 << 14) ^ x3 >>> 3;
+					let lsw1 = (x2 & 65535) + (y1 & 65535);
+					let msw1 = (x2 >> 16) + (y1 >> 16) + (lsw1 >> 16);
+					let x4 = msw1 << 16 | lsw1 & 65535;
+					let y2 = W[j - 16];
+					let lsw2 = (x4 & 65535) + (y2 & 65535);
+					let msw2 = (x4 >> 16) + (y2 >> 16) + (lsw2 >> 16);
+					W[j] = msw2 << 16 | lsw2 & 65535;
+				}
+				let y = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
+				let lsw = (h & 65535) + (y & 65535);
+				let msw = (h >> 16) + (y >> 16) + (lsw >> 16);
+				let x = msw << 16 | lsw & 65535;
+				let y1 = e & f ^ ~e & g;
+				let lsw1 = (x & 65535) + (y1 & 65535);
+				let msw1 = (x >> 16) + (y1 >> 16) + (lsw1 >> 16);
+				let x1 = msw1 << 16 | lsw1 & 65535;
+				let y2 = K[j];
+				let lsw2 = (x1 & 65535) + (y2 & 65535);
+				let msw2 = (x1 >> 16) + (y2 >> 16) + (lsw2 >> 16);
+				let x2 = msw2 << 16 | lsw2 & 65535;
+				let y3 = W[j];
+				let lsw3 = (x2 & 65535) + (y3 & 65535);
+				let msw3 = (x2 >> 16) + (y3 >> 16) + (lsw3 >> 16);
+				T1 = msw3 << 16 | lsw3 & 65535;
+				let x3 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);
+				let y4 = a & b ^ a & c ^ b & c;
+				let lsw4 = (x3 & 65535) + (y4 & 65535);
+				let msw4 = (x3 >> 16) + (y4 >> 16) + (lsw4 >> 16);
+				T2 = msw4 << 16 | lsw4 & 65535;
+				h = g;
+				g = f;
+				f = e;
+				let lsw5 = (d & 65535) + (T1 & 65535);
+				let msw5 = (d >> 16) + (T1 >> 16) + (lsw5 >> 16);
+				e = msw5 << 16 | lsw5 & 65535;
+				d = c;
+				c = b;
+				b = a;
+				let lsw6 = (T1 & 65535) + (T2 & 65535);
+				let msw6 = (T1 >> 16) + (T2 >> 16) + (lsw6 >> 16);
+				a = msw6 << 16 | lsw6 & 65535;
+			}
+			let y = HASH[0];
+			let lsw = (a & 65535) + (y & 65535);
+			let msw = (a >> 16) + (y >> 16) + (lsw >> 16);
+			HASH[0] = msw << 16 | lsw & 65535;
+			let y1 = HASH[1];
+			let lsw1 = (b & 65535) + (y1 & 65535);
+			let msw1 = (b >> 16) + (y1 >> 16) + (lsw1 >> 16);
+			HASH[1] = msw1 << 16 | lsw1 & 65535;
+			let y2 = HASH[2];
+			let lsw2 = (c & 65535) + (y2 & 65535);
+			let msw2 = (c >> 16) + (y2 >> 16) + (lsw2 >> 16);
+			HASH[2] = msw2 << 16 | lsw2 & 65535;
+			let y3 = HASH[3];
+			let lsw3 = (d & 65535) + (y3 & 65535);
+			let msw3 = (d >> 16) + (y3 >> 16) + (lsw3 >> 16);
+			HASH[3] = msw3 << 16 | lsw3 & 65535;
+			let y4 = HASH[4];
+			let lsw4 = (e & 65535) + (y4 & 65535);
+			let msw4 = (e >> 16) + (y4 >> 16) + (lsw4 >> 16);
+			HASH[4] = msw4 << 16 | lsw4 & 65535;
+			let y5 = HASH[5];
+			let lsw5 = (f & 65535) + (y5 & 65535);
+			let msw5 = (f >> 16) + (y5 >> 16) + (lsw5 >> 16);
+			HASH[5] = msw5 << 16 | lsw5 & 65535;
+			let y6 = HASH[6];
+			let lsw6 = (g & 65535) + (y6 & 65535);
+			let msw6 = (g >> 16) + (y6 >> 16) + (lsw6 >> 16);
+			HASH[6] = msw6 << 16 | lsw6 & 65535;
+			let y7 = HASH[7];
+			let lsw7 = (h & 65535) + (y7 & 65535);
+			let msw7 = (h >> 16) + (y7 >> 16) + (lsw7 >> 16);
+			HASH[7] = msw7 << 16 | lsw7 & 65535;
+			i += 16;
+		}
+		return HASH;
+	}
+	static make(b) {
+		let h = new haxe_crypto_Sha256().doEncode(haxe_crypto_Sha256.bytes2blks(b),b.length * 8);
+		let out = new haxe_io_Bytes(new ArrayBuffer(32));
+		let p = 0;
+		let _g = 0;
+		while(_g < 8) {
+			let i = _g++;
+			out.b[p++] = h[i] >>> 24;
+			out.b[p++] = h[i] >> 16 & 255;
+			out.b[p++] = h[i] >> 8 & 255;
+			out.b[p++] = h[i] & 255;
+		}
+		return out;
+	}
+	static bytes2blks(b) {
+		let nblk = (b.length + 8 >> 6) + 1;
+		let blks = [];
+		let _g = 0;
+		let _g1 = nblk * 16;
+		while(_g < _g1) {
+			let i = _g++;
+			blks[i] = 0;
+		}
+		let _g2 = 0;
+		let _g3 = b.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			let p = i >> 2;
+			blks[p] |= b.b[i] << 24 - ((i & 3) << 3);
+		}
+		let i = b.length;
+		let p = i >> 2;
+		blks[p] |= 128 << 24 - ((i & 3) << 3);
+		blks[nblk * 16 - 1] = b.length * 8;
+		return blks;
+	}
+}
+haxe_crypto_Sha256.__name__ = "haxe.crypto.Sha256";
+Object.assign(haxe_crypto_Sha256.prototype, {
+	__class__: haxe_crypto_Sha256
+});
+class haxe_ds_BalancedTree {
+	constructor() {
+	}
+	set(key,value) {
+		this.root = this.setLoop(key,value,this.root);
+	}
+	get(key) {
+		let node = this.root;
+		while(node != null) {
+			let c = this.compare(key,node.key);
+			if(c == 0) {
+				return node.value;
+			}
+			if(c < 0) {
+				node = node.left;
+			} else {
+				node = node.right;
+			}
+		}
+		return null;
+	}
+	exists(key) {
+		let node = this.root;
+		while(node != null) {
+			let c = this.compare(key,node.key);
+			if(c == 0) {
+				return true;
+			} else if(c < 0) {
+				node = node.left;
+			} else {
+				node = node.right;
+			}
+		}
+		return false;
+	}
+	iterator() {
+		let ret = [];
+		haxe_ds_BalancedTree.iteratorLoop(this.root,ret);
+		return new haxe_iterators_ArrayIterator(ret);
+	}
+	keyValueIterator() {
+		return new haxe_iterators_MapKeyValueIterator(this);
+	}
+	keys() {
+		let ret = [];
+		this.keysLoop(this.root,ret);
+		return new haxe_iterators_ArrayIterator(ret);
+	}
+	setLoop(k,v,node) {
+		if(node == null) {
+			return new haxe_ds_TreeNode(null,k,v,null);
+		}
+		let c = this.compare(k,node.key);
+		if(c == 0) {
+			return new haxe_ds_TreeNode(node.left,k,v,node.right,node == null ? 0 : node._height);
+		} else if(c < 0) {
+			let nl = this.setLoop(k,v,node.left);
+			return this.balance(nl,node.key,node.value,node.right);
+		} else {
+			let nr = this.setLoop(k,v,node.right);
+			return this.balance(node.left,node.key,node.value,nr);
+		}
+	}
+	keysLoop(node,acc) {
+		if(node != null) {
+			this.keysLoop(node.left,acc);
+			acc.push(node.key);
+			this.keysLoop(node.right,acc);
+		}
+	}
+	balance(l,k,v,r) {
+		let hl = l == null ? 0 : l._height;
+		let hr = r == null ? 0 : r._height;
+		if(hl > hr + 2) {
+			let _this = l.left;
+			let _this1 = l.right;
+			if((_this == null ? 0 : _this._height) >= (_this1 == null ? 0 : _this1._height)) {
+				return new haxe_ds_TreeNode(l.left,l.key,l.value,new haxe_ds_TreeNode(l.right,k,v,r));
+			} else {
+				return new haxe_ds_TreeNode(new haxe_ds_TreeNode(l.left,l.key,l.value,l.right.left),l.right.key,l.right.value,new haxe_ds_TreeNode(l.right.right,k,v,r));
+			}
+		} else if(hr > hl + 2) {
+			let _this = r.right;
+			let _this1 = r.left;
+			if((_this == null ? 0 : _this._height) > (_this1 == null ? 0 : _this1._height)) {
+				return new haxe_ds_TreeNode(new haxe_ds_TreeNode(l,k,v,r.left),r.key,r.value,r.right);
+			} else {
+				return new haxe_ds_TreeNode(new haxe_ds_TreeNode(l,k,v,r.left.left),r.left.key,r.left.value,new haxe_ds_TreeNode(r.left.right,r.key,r.value,r.right));
+			}
+		} else {
+			return new haxe_ds_TreeNode(l,k,v,r,(hl > hr ? hl : hr) + 1);
+		}
+	}
+	compare(k1,k2) {
+		return Reflect.compare(k1,k2);
+	}
+	static iteratorLoop(node,acc) {
+		if(node != null) {
+			haxe_ds_BalancedTree.iteratorLoop(node.left,acc);
+			acc.push(node.value);
+			haxe_ds_BalancedTree.iteratorLoop(node.right,acc);
+		}
+	}
+}
+haxe_ds_BalancedTree.__name__ = "haxe.ds.BalancedTree";
+haxe_ds_BalancedTree.__interfaces__ = [haxe_IMap];
+Object.assign(haxe_ds_BalancedTree.prototype, {
+	__class__: haxe_ds_BalancedTree
+});
+class haxe_ds_TreeNode {
+	constructor(l,k,v,r,h) {
+		if(h == null) {
+			h = -1;
+		}
+		this.left = l;
+		this.key = k;
+		this.value = v;
+		this.right = r;
+		if(h == -1) {
+			let tmp;
+			let _this = this.left;
+			let _this1 = this.right;
+			if((_this == null ? 0 : _this._height) > (_this1 == null ? 0 : _this1._height)) {
+				let _this = this.left;
+				tmp = _this == null ? 0 : _this._height;
+			} else {
+				let _this = this.right;
+				tmp = _this == null ? 0 : _this._height;
+			}
+			this._height = tmp + 1;
+		} else {
+			this._height = h;
+		}
+	}
+}
+haxe_ds_TreeNode.__name__ = "haxe.ds.TreeNode";
+Object.assign(haxe_ds_TreeNode.prototype, {
+	__class__: haxe_ds_TreeNode
+});
+var haxe_ds_Either = $hxEnums["haxe.ds.Either"] = { __ename__:true,__constructs__:null
+	,Left: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"haxe.ds.Either",toString:$estr}; },$_._hx_name="Left",$_.__params__ = ["v"],$_)
+	,Right: ($_=function(v) { return {_hx_index:1,v:v,__enum__:"haxe.ds.Either",toString:$estr}; },$_._hx_name="Right",$_.__params__ = ["v"],$_)
+};
+haxe_ds_Either.__constructs__ = [haxe_ds_Either.Left,haxe_ds_Either.Right];
+class haxe_ds_EnumValueMap extends haxe_ds_BalancedTree {
+	constructor() {
+		super();
+	}
+	compare(k1,k2) {
+		let d = k1._hx_index - k2._hx_index;
+		if(d != 0) {
+			return d;
+		}
+		let p1 = Type.enumParameters(k1);
+		let p2 = Type.enumParameters(k2);
+		if(p1.length == 0 && p2.length == 0) {
+			return 0;
+		}
+		return this.compareArgs(p1,p2);
+	}
+	compareArgs(a1,a2) {
+		let ld = a1.length - a2.length;
+		if(ld != 0) {
+			return ld;
+		}
+		let _g = 0;
+		let _g1 = a1.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let d = this.compareArg(a1[i],a2[i]);
+			if(d != 0) {
+				return d;
+			}
+		}
+		return 0;
+	}
+	compareArg(v1,v2) {
+		if(Reflect.isEnumValue(v1) && Reflect.isEnumValue(v2)) {
+			return this.compare(v1,v2);
+		} else if(((v1) instanceof Array) && ((v2) instanceof Array)) {
+			return this.compareArgs(v1,v2);
+		} else {
+			return Reflect.compare(v1,v2);
+		}
+	}
+}
+haxe_ds_EnumValueMap.__name__ = "haxe.ds.EnumValueMap";
+haxe_ds_EnumValueMap.__interfaces__ = [haxe_IMap];
+haxe_ds_EnumValueMap.__super__ = haxe_ds_BalancedTree;
+Object.assign(haxe_ds_EnumValueMap.prototype, {
+	__class__: haxe_ds_EnumValueMap
+});
+class haxe_ds_IntMap {
+	constructor() {
+		this.h = { };
+	}
+	get(key) {
+		return this.h[key];
+	}
+	exists(key) {
+		return this.h.hasOwnProperty(key);
+	}
+	keys() {
+		let a = [];
+		for( var key in this.h ) if(this.h.hasOwnProperty(key)) a.push(+key);
+		return new haxe_iterators_ArrayIterator(a);
+	}
+	iterator() {
+		return { ref : this.h, it : this.keys(), hasNext : function() {
+			return this.it.hasNext();
+		}, next : function() {
+			let i = this.it.next();
+			return this.ref[i];
+		}};
+	}
+	keyValueIterator() {
+		return new haxe_iterators_MapKeyValueIterator(this);
+	}
+}
+haxe_ds_IntMap.__name__ = "haxe.ds.IntMap";
+haxe_ds_IntMap.__interfaces__ = [haxe_IMap];
+Object.assign(haxe_ds_IntMap.prototype, {
+	__class__: haxe_ds_IntMap
+});
+class haxe_ds_ObjectMap {
+	constructor() {
+		this.h = { __keys__ : { }};
+	}
+	get(key) {
+		return this.h[key.__id__];
+	}
+	exists(key) {
+		return this.h.__keys__[key.__id__] != null;
+	}
+	keys() {
+		let a = [];
+		for( var key in this.h.__keys__ ) {
+		if(this.h.hasOwnProperty(key)) {
+			a.push(this.h.__keys__[key]);
+		}
+		}
+		return new haxe_iterators_ArrayIterator(a);
+	}
+	iterator() {
+		return { ref : this.h, it : this.keys(), hasNext : function() {
+			return this.it.hasNext();
+		}, next : function() {
+			let i = this.it.next();
+			return this.ref[i.__id__];
+		}};
+	}
+	keyValueIterator() {
+		return new haxe_iterators_MapKeyValueIterator(this);
+	}
+}
+haxe_ds_ObjectMap.__name__ = "haxe.ds.ObjectMap";
+haxe_ds_ObjectMap.__interfaces__ = [haxe_IMap];
+Object.assign(haxe_ds_ObjectMap.prototype, {
+	__class__: haxe_ds_ObjectMap
+});
+var haxe_ds_Option = $hxEnums["haxe.ds.Option"] = { __ename__:true,__constructs__:null
+	,Some: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"haxe.ds.Option",toString:$estr}; },$_._hx_name="Some",$_.__params__ = ["v"],$_)
+	,None: {_hx_name:"None",_hx_index:1,__enum__:"haxe.ds.Option",toString:$estr}
+};
+haxe_ds_Option.__constructs__ = [haxe_ds_Option.Some,haxe_ds_Option.None];
+class haxe_ds_StringMap {
+	constructor() {
+		this.h = Object.create(null);
+	}
+	exists(key) {
+		return Object.prototype.hasOwnProperty.call(this.h,key);
+	}
+	get(key) {
+		return this.h[key];
+	}
+	keys() {
+		return new haxe_ds__$StringMap_StringMapKeyIterator(this.h);
+	}
+	iterator() {
+		return new haxe_ds__$StringMap_StringMapValueIterator(this.h);
+	}
+	keyValueIterator() {
+		return new haxe_ds__$StringMap_StringMapKeyValueIterator(this.h);
+	}
+}
+haxe_ds_StringMap.__name__ = "haxe.ds.StringMap";
+haxe_ds_StringMap.__interfaces__ = [haxe_IMap];
+Object.assign(haxe_ds_StringMap.prototype, {
+	__class__: haxe_ds_StringMap
+});
+class haxe_ds__$StringMap_StringMapKeyIterator {
+	constructor(h) {
+		this.h = h;
+		this.keys = Object.keys(h);
+		this.length = this.keys.length;
+		this.current = 0;
+	}
+	hasNext() {
+		return this.current < this.length;
+	}
+	next() {
+		return this.keys[this.current++];
+	}
+}
+haxe_ds__$StringMap_StringMapKeyIterator.__name__ = "haxe.ds._StringMap.StringMapKeyIterator";
+Object.assign(haxe_ds__$StringMap_StringMapKeyIterator.prototype, {
+	__class__: haxe_ds__$StringMap_StringMapKeyIterator
+});
+class haxe_ds__$StringMap_StringMapValueIterator {
+	constructor(h) {
+		this.h = h;
+		this.keys = Object.keys(h);
+		this.length = this.keys.length;
+		this.current = 0;
+	}
+	hasNext() {
+		return this.current < this.length;
+	}
+	next() {
+		return this.h[this.keys[this.current++]];
+	}
+}
+haxe_ds__$StringMap_StringMapValueIterator.__name__ = "haxe.ds._StringMap.StringMapValueIterator";
+Object.assign(haxe_ds__$StringMap_StringMapValueIterator.prototype, {
+	__class__: haxe_ds__$StringMap_StringMapValueIterator
+});
+class haxe_ds__$StringMap_StringMapKeyValueIterator {
+	constructor(h) {
+		this.h = h;
+		this.keys = Object.keys(h);
+		this.length = this.keys.length;
+		this.current = 0;
+	}
+	hasNext() {
+		return this.current < this.length;
+	}
+	next() {
+		let key = this.keys[this.current++];
+		return { key : key, value : this.h[key]};
+	}
+}
+haxe_ds__$StringMap_StringMapKeyValueIterator.__name__ = "haxe.ds._StringMap.StringMapKeyValueIterator";
+Object.assign(haxe_ds__$StringMap_StringMapKeyValueIterator.prototype, {
+	__class__: haxe_ds__$StringMap_StringMapKeyValueIterator
+});
+class haxe_exceptions_PosException extends haxe_Exception {
+	constructor(message,previous,pos) {
+		super(message,previous);
+		if(pos == null) {
+			this.posInfos = { fileName : "(unknown)", lineNumber : 0, className : "(unknown)", methodName : "(unknown)"};
+		} else {
+			this.posInfos = pos;
+		}
+	}
+	toString() {
+		return "" + super.toString() + " in " + this.posInfos.className + "." + this.posInfos.methodName + " at " + this.posInfos.fileName + ":" + this.posInfos.lineNumber;
+	}
+}
+haxe_exceptions_PosException.__name__ = "haxe.exceptions.PosException";
+haxe_exceptions_PosException.__super__ = haxe_Exception;
+Object.assign(haxe_exceptions_PosException.prototype, {
+	__class__: haxe_exceptions_PosException
+});
+class haxe_exceptions_NotImplementedException extends haxe_exceptions_PosException {
+	constructor(message,previous,pos) {
+		if(message == null) {
+			message = "Not implemented";
+		}
+		super(message,previous,pos);
+	}
+}
+haxe_exceptions_NotImplementedException.__name__ = "haxe.exceptions.NotImplementedException";
+haxe_exceptions_NotImplementedException.__super__ = haxe_exceptions_PosException;
+Object.assign(haxe_exceptions_NotImplementedException.prototype, {
+	__class__: haxe_exceptions_NotImplementedException
+});
+class haxe_http_HttpBase {
+	constructor(url) {
+		if(haxe_http_HttpBase._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(url);
+	}
+	_hx_constructor(url) {
+		this.url = url;
+		this.headers = [];
+		this.params = [];
+		this.emptyOnData = $bind(this,this.onData);
+	}
+	setHeader(name,value) {
+		let _g = 0;
+		let _g1 = this.headers.length;
+		while(_g < _g1) {
+			let i = _g++;
+			if(this.headers[i].name == name) {
+				this.headers[i] = { name : name, value : value};
+				return;
+			}
+		}
+		this.headers.push({ name : name, value : value});
+	}
+	setPostData(data) {
+		this.postData = data;
+		this.postBytes = null;
+	}
+	onData(data) {
+	}
+	onBytes(data) {
+	}
+	onError(msg) {
+	}
+	onStatus(status) {
+	}
+	hasOnData() {
+		return $bind(this,this.onData) != this.emptyOnData;
+	}
+	success(data) {
+		this.responseBytes = data;
+		this.responseAsString = null;
+		if(this.hasOnData()) {
+			this.onData(this.get_responseData());
+		}
+		this.onBytes(this.responseBytes);
+	}
+	get_responseData() {
+		if(this.responseAsString == null && this.responseBytes != null) {
+			this.responseAsString = this.responseBytes.getString(0,this.responseBytes.length,haxe_io_Encoding.UTF8);
+		}
+		return this.responseAsString;
+	}
+}
+haxe_http_HttpBase.__name__ = "haxe.http.HttpBase";
+Object.assign(haxe_http_HttpBase.prototype, {
+	__class__: haxe_http_HttpBase
+});
+class haxe_http_HttpJs extends haxe_http_HttpBase {
+	constructor(url) {
+		haxe_http_HttpBase._hx_skip_constructor = true;
+		super();
+		haxe_http_HttpBase._hx_skip_constructor = false;
+		this._hx_constructor(url);
+	}
+	_hx_constructor(url) {
+		this.async = true;
+		this.withCredentials = false;
+		super._hx_constructor(url);
+	}
+	request(post) {
+		this.responseAsString = null;
+		this.responseBytes = null;
+		this.responseHeaders = null;
+		let r = this.req = js_Browser.createXMLHttpRequest();
+		let _gthis = this;
+		let onreadystatechange = function(_) {
+			if(r.readyState != 4) {
+				return;
+			}
+			let s;
+			try {
+				s = r.status;
+			} catch( _g ) {
+				s = null;
+			}
+			if(s == 0 && js_Browser.get_supported() && $global.location != null) {
+				let protocol = $global.location.protocol.toLowerCase();
+				let rlocalProtocol = new EReg("^(?:about|app|app-storage|.+-extension|file|res|widget):$","");
+				let isLocal = rlocalProtocol.match(protocol);
+				if(isLocal) {
+					s = r.response != null ? 200 : 404;
+				}
+			}
+			if(s == undefined) {
+				s = null;
+			}
+			if(s != null) {
+				_gthis.onStatus(s);
+			}
+			if(s != null && s >= 200 && s < 400) {
+				_gthis.req = null;
+				let headers = r.getAllResponseHeaders().split("\r\n");
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = headers;
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(v != "") {
+						_g.push(v);
+					}
+				}
+				headers = _g;
+				let onreadystatechange = new haxe_ds_StringMap();
+				_gthis.responseHeaders = onreadystatechange;
+				let _g3 = 0;
+				while(_g3 < headers.length) {
+					let hline = headers[_g3];
+					++_g3;
+					let a = hline.split(": ");
+					let hname = a.shift();
+					let hval = a.length == 1 ? a[0] : a.join(": ");
+					hval = StringTools.ltrim(StringTools.rtrim(hval));
+					_gthis.responseHeaders.h[hname] = hval;
+				}
+				_gthis.success(haxe_io_Bytes.ofData(r.response));
+			} else if(s == null || s == 0 && r.response == null) {
+				_gthis.req = null;
+				_gthis.onError("Failed to connect or resolve host");
+			} else if(s == null) {
+				_gthis.req = null;
+				let onreadystatechange = r.response != null ? haxe_io_Bytes.ofData(r.response) : null;
+				_gthis.responseBytes = onreadystatechange;
+				_gthis.onError("Http Error #" + r.status);
+			} else {
+				switch(s) {
+				case 12007:
+					_gthis.req = null;
+					_gthis.onError("Unknown host");
+					break;
+				case 12029:
+					_gthis.req = null;
+					_gthis.onError("Failed to connect to host");
+					break;
+				default:
+					_gthis.req = null;
+					let onreadystatechange = r.response != null ? haxe_io_Bytes.ofData(r.response) : null;
+					_gthis.responseBytes = onreadystatechange;
+					_gthis.onError("Http Error #" + r.status);
+				}
+			}
+		};
+		if(this.async) {
+			r.onreadystatechange = onreadystatechange;
+		}
+		let uri;
+		let _g = this.postData;
+		let _g1 = this.postBytes;
+		if(_g == null) {
+			if(_g1 == null) {
+				uri = null;
+			} else {
+				let bytes = _g1;
+				uri = new Blob([bytes.b.bufferValue]);
+			}
+		} else if(_g1 == null) {
+			let str = _g;
+			uri = str;
+		} else {
+			uri = null;
+		}
+		if(uri != null) {
+			post = true;
+		} else {
+			let _g = 0;
+			let _g1 = this.params;
+			while(_g < _g1.length) {
+				let p = _g1[_g];
+				++_g;
+				if(uri == null) {
+					uri = "";
+				} else {
+					uri = (uri == null ? "null" : Std.string(uri)) + "&";
+				}
+				let s = p.name;
+				let uri1 = (uri == null ? "null" : Std.string(uri)) + encodeURIComponent(s) + "=";
+				let s1 = p.value;
+				uri = uri1 + encodeURIComponent(s1);
+			}
+		}
+		try {
+			if(post) {
+				r.open("POST",this.url,this.async);
+			} else if(uri != null) {
+				let question = this.url.split("?").length <= 1;
+				r.open("GET",this.url + (question ? "?" : "&") + (uri == null ? "null" : Std.string(uri)),this.async);
+				uri = null;
+			} else {
+				r.open("GET",this.url,this.async);
+			}
+			r.responseType = "arraybuffer";
+		} catch( _g ) {
+			let e = haxe_Exception.caught(_g).unwrap();
+			this.req = null;
+			this.onError(e.toString());
+			return;
+		}
+		r.withCredentials = this.withCredentials;
+		if(!Lambda.exists(this.headers,function(h) {
+			return h.name == "Content-Type";
+		}) && post && this.postData == null) {
+			r.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
+		}
+		let _g2 = 0;
+		let _g3 = this.headers;
+		while(_g2 < _g3.length) {
+			let h = _g3[_g2];
+			++_g2;
+			r.setRequestHeader(h.name,h.value);
+		}
+		r.send(uri);
+		if(!this.async) {
+			onreadystatechange(null);
+		}
+	}
+}
+haxe_http_HttpJs.__name__ = "haxe.http.HttpJs";
+haxe_http_HttpJs.__super__ = haxe_http_HttpBase;
+Object.assign(haxe_http_HttpJs.prototype, {
+	__class__: haxe_http_HttpJs
+});
+class haxe_io_BytesBuffer {
+	constructor() {
+		this.pos = 0;
+		this.size = 0;
+	}
+	addByte(byte) {
+		if(this.pos == this.size) {
+			this.grow(1);
+		}
+		this.view.setUint8(this.pos++,byte);
+	}
+	addBytes(src,pos,len) {
+		if(pos < 0 || len < 0 || pos + len > src.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		if(this.pos + len > this.size) {
+			this.grow(len);
+		}
+		if(this.size == 0) {
+			return;
+		}
+		let sub = new Uint8Array(src.b.buffer,src.b.byteOffset + pos,len);
+		this.u8.set(sub,this.pos);
+		this.pos += len;
+	}
+	grow(delta) {
+		let req = this.pos + delta;
+		let nsize = this.size == 0 ? 16 : this.size;
+		while(nsize < req) nsize = nsize * 3 >> 1;
+		let nbuf = new ArrayBuffer(nsize);
+		let nu8 = new Uint8Array(nbuf);
+		if(this.size > 0) {
+			nu8.set(this.u8);
+		}
+		this.size = nsize;
+		this.buffer = nbuf;
+		this.u8 = nu8;
+		this.view = new DataView(this.buffer);
+	}
+	getBytes() {
+		if(this.size == 0) {
+			return new haxe_io_Bytes(new ArrayBuffer(0));
+		}
+		let b = new haxe_io_Bytes(this.buffer);
+		b.length = this.pos;
+		return b;
+	}
+}
+haxe_io_BytesBuffer.__name__ = "haxe.io.BytesBuffer";
+Object.assign(haxe_io_BytesBuffer.prototype, {
+	__class__: haxe_io_BytesBuffer
+});
+class haxe_io_Input {
+	readByte() {
+		throw new haxe_exceptions_NotImplementedException(null,null,{ fileName : "haxe/io/Input.hx", lineNumber : 53, className : "haxe.io.Input", methodName : "readByte"});
+	}
+	readBytes(s,pos,len) {
+		let k = len;
+		let b = s.b;
+		if(pos < 0 || len < 0 || pos + len > s.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		try {
+			while(k > 0) {
+				b[pos] = this.readByte();
+				++pos;
+				--k;
+			}
+		} catch( _g ) {
+			if(!((haxe_Exception.caught(_g).unwrap()) instanceof haxe_io_Eof)) {
+				throw _g;
+			}
+		}
+		return len - k;
+	}
+	close() {
+	}
+	set_bigEndian(b) {
+		this.bigEndian = b;
+		return b;
+	}
+	readUntil(end) {
+		let buf = new haxe_io_BytesBuffer();
+		let last;
+		while(true) {
+			last = this.readByte();
+			if(!(last != end)) {
+				break;
+			}
+			buf.addByte(last);
+		}
+		return buf.getBytes().toString();
+	}
+	readInt32() {
+		let ch1 = this.readByte();
+		let ch2 = this.readByte();
+		let ch3 = this.readByte();
+		let ch4 = this.readByte();
+		if(this.bigEndian) {
+			return ch4 | ch3 << 8 | ch2 << 16 | ch1 << 24;
+		} else {
+			return ch1 | ch2 << 8 | ch3 << 16 | ch4 << 24;
+		}
+	}
+}
+haxe_io_Input.__name__ = "haxe.io.Input";
+Object.assign(haxe_io_Input.prototype, {
+	__class__: haxe_io_Input
+});
+class haxe_io_BytesInput extends haxe_io_Input {
+	constructor(b,pos,len) {
+		super();
+		if(pos == null) {
+			pos = 0;
+		}
+		if(len == null) {
+			len = b.length - pos;
+		}
+		if(pos < 0 || len < 0 || pos + len > b.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		this.b = b.b;
+		this.pos = pos;
+		this.len = len;
+		this.totlen = len;
+	}
+	readByte() {
+		if(this.len == 0) {
+			throw haxe_Exception.thrown(new haxe_io_Eof());
+		}
+		this.len--;
+		return this.b[this.pos++];
+	}
+	readBytes(buf,pos,len) {
+		if(pos < 0 || len < 0 || pos + len > buf.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		if(this.len == 0 && len > 0) {
+			throw haxe_Exception.thrown(new haxe_io_Eof());
+		}
+		if(this.len < len) {
+			len = this.len;
+		}
+		let b1 = this.b;
+		let b2 = buf.b;
+		let _g = 0;
+		let _g1 = len;
+		while(_g < _g1) {
+			let i = _g++;
+			b2[pos + i] = b1[this.pos + i];
+		}
+		this.pos += len;
+		this.len -= len;
+		return len;
+	}
+}
+haxe_io_BytesInput.__name__ = "haxe.io.BytesInput";
+haxe_io_BytesInput.__super__ = haxe_io_Input;
+Object.assign(haxe_io_BytesInput.prototype, {
+	__class__: haxe_io_BytesInput
+});
+class haxe_io_Output {
+	writeByte(c) {
+		throw new haxe_exceptions_NotImplementedException(null,null,{ fileName : "haxe/io/Output.hx", lineNumber : 47, className : "haxe.io.Output", methodName : "writeByte"});
+	}
+	writeBytes(s,pos,len) {
+		if(pos < 0 || len < 0 || pos + len > s.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		let b = s.b;
+		let k = len;
+		while(k > 0) {
+			this.writeByte(b[pos]);
+			++pos;
+			--k;
+		}
+		return len;
+	}
+	close() {
+	}
+}
+haxe_io_Output.__name__ = "haxe.io.Output";
+Object.assign(haxe_io_Output.prototype, {
+	__class__: haxe_io_Output
+});
+class haxe_io_BytesOutput extends haxe_io_Output {
+	constructor() {
+		super();
+		this.b = new haxe_io_BytesBuffer();
+	}
+	writeByte(c) {
+		this.b.addByte(c);
+	}
+	writeBytes(buf,pos,len) {
+		this.b.addBytes(buf,pos,len);
+		return len;
+	}
+	getBytes() {
+		return this.b.getBytes();
+	}
+}
+haxe_io_BytesOutput.__name__ = "haxe.io.BytesOutput";
+haxe_io_BytesOutput.__super__ = haxe_io_Output;
+Object.assign(haxe_io_BytesOutput.prototype, {
+	__class__: haxe_io_BytesOutput
+});
+class haxe_io_Eof {
+	constructor() {
+	}
+	toString() {
+		return "Eof";
+	}
+}
+haxe_io_Eof.__name__ = "haxe.io.Eof";
+Object.assign(haxe_io_Eof.prototype, {
+	__class__: haxe_io_Eof
+});
+var haxe_io_Error = $hxEnums["haxe.io.Error"] = { __ename__:true,__constructs__:null
+	,Blocked: {_hx_name:"Blocked",_hx_index:0,__enum__:"haxe.io.Error",toString:$estr}
+	,Overflow: {_hx_name:"Overflow",_hx_index:1,__enum__:"haxe.io.Error",toString:$estr}
+	,OutsideBounds: {_hx_name:"OutsideBounds",_hx_index:2,__enum__:"haxe.io.Error",toString:$estr}
+	,Custom: ($_=function(e) { return {_hx_index:3,e:e,__enum__:"haxe.io.Error",toString:$estr}; },$_._hx_name="Custom",$_.__params__ = ["e"],$_)
+};
+haxe_io_Error.__constructs__ = [haxe_io_Error.Blocked,haxe_io_Error.Overflow,haxe_io_Error.OutsideBounds,haxe_io_Error.Custom];
+class haxe_io_FPHelper {
+	static i64ToDouble(low,high) {
+		haxe_io_FPHelper.helper.setInt32(0,low,true);
+		haxe_io_FPHelper.helper.setInt32(4,high,true);
+		return haxe_io_FPHelper.helper.getFloat64(0,true);
+	}
+	static doubleToI64(v) {
+		let i64 = haxe_io_FPHelper.i64tmp;
+		haxe_io_FPHelper.helper.setFloat64(0,v,true);
+		i64.low = haxe_io_FPHelper.helper.getInt32(0,true);
+		i64.high = haxe_io_FPHelper.helper.getInt32(4,true);
+		return i64;
+	}
+}
+haxe_io_FPHelper.__name__ = "haxe.io.FPHelper";
+class haxe_iterators_ArrayIterator {
+	constructor(array) {
+		this.current = 0;
+		this.array = array;
+	}
+	hasNext() {
+		return this.current < this.array.length;
+	}
+	next() {
+		return this.array[this.current++];
+	}
+}
+haxe_iterators_ArrayIterator.__name__ = "haxe.iterators.ArrayIterator";
+Object.assign(haxe_iterators_ArrayIterator.prototype, {
+	__class__: haxe_iterators_ArrayIterator
+});
+class haxe_iterators_MapKeyValueIterator {
+	constructor(map) {
+		this.map = map;
+		this.keys = map.keys();
+	}
+	hasNext() {
+		return this.keys.hasNext();
+	}
+	next() {
+		let key = this.keys.next();
+		return { value : this.map.get(key), key : key};
+	}
+}
+haxe_iterators_MapKeyValueIterator.__name__ = "haxe.iterators.MapKeyValueIterator";
+Object.assign(haxe_iterators_MapKeyValueIterator.prototype, {
+	__class__: haxe_iterators_MapKeyValueIterator
+});
+class haxe_xml_XmlParserException {
+	constructor(message,xml,position) {
+		this.xml = xml;
+		this.message = message;
+		this.position = position;
+		this.lineNumber = 1;
+		this.positionAtLine = 0;
+		let _g = 0;
+		let _g1 = position;
+		while(_g < _g1) {
+			let i = _g++;
+			let c = xml.charCodeAt(i);
+			if(c == 10) {
+				this.lineNumber++;
+				this.positionAtLine = 0;
+			} else if(c != 13) {
+				this.positionAtLine++;
+			}
+		}
+	}
+	toString() {
+		let c = js_Boot.getClass(this);
+		return c.__name__ + ": " + this.message + " at line " + this.lineNumber + " char " + this.positionAtLine;
+	}
+}
+haxe_xml_XmlParserException.__name__ = "haxe.xml.XmlParserException";
+Object.assign(haxe_xml_XmlParserException.prototype, {
+	__class__: haxe_xml_XmlParserException
+});
+class haxe_xml_Parser {
+	static parse(str,strict) {
+		if(strict == null) {
+			strict = false;
+		}
+		let doc = Xml.createDocument();
+		haxe_xml_Parser.doParse(str,strict,0,doc);
+		return doc;
+	}
+	static doParse(str,strict,p,parent) {
+		if(p == null) {
+			p = 0;
+		}
+		let xml = null;
+		let state = 1;
+		let next = 1;
+		let aname = null;
+		let start = 0;
+		let nsubs = 0;
+		let nbrackets = 0;
+		let buf = new StringBuf();
+		let escapeNext = 1;
+		let attrValQuote = -1;
+		while(p < str.length) {
+			let c = str.charCodeAt(p);
+			switch(state) {
+			case 0:
+				switch(c) {
+				case 9:case 10:case 13:case 32:
+					break;
+				default:
+					state = next;
+					continue;
+				}
+				break;
+			case 1:
+				if(c == 60) {
+					state = 0;
+					next = 2;
+				} else {
+					start = p;
+					state = 13;
+					continue;
+				}
+				break;
+			case 2:
+				switch(c) {
+				case 33:
+					if(str.charCodeAt(p + 1) == 91) {
+						p += 2;
+						if(HxOverrides.substr(str,p,6).toUpperCase() != "CDATA[") {
+							throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected <![CDATA[",str,p));
+						}
+						p += 5;
+						state = 17;
+						start = p + 1;
+					} else if(str.charCodeAt(p + 1) == 68 || str.charCodeAt(p + 1) == 100) {
+						if(HxOverrides.substr(str,p + 2,6).toUpperCase() != "OCTYPE") {
+							throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected <!DOCTYPE",str,p));
+						}
+						p += 8;
+						state = 16;
+						start = p + 1;
+					} else if(str.charCodeAt(p + 1) != 45 || str.charCodeAt(p + 2) != 45) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected <!--",str,p));
+					} else {
+						p += 2;
+						state = 15;
+						start = p + 1;
+					}
+					break;
+				case 47:
+					if(parent == null) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected node name",str,p));
+					}
+					start = p + 1;
+					state = 0;
+					next = 10;
+					break;
+				case 63:
+					state = 14;
+					start = p;
+					break;
+				default:
+					state = 3;
+					start = p;
+					continue;
+				}
+				break;
+			case 3:
+				if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c == 58 || c == 46 || c == 95 || c == 45)) {
+					if(p == start) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected node name",str,p));
+					}
+					xml = Xml.createElement(HxOverrides.substr(str,start,p - start));
+					parent.addChild(xml);
+					++nsubs;
+					state = 0;
+					next = 4;
+					continue;
+				}
+				break;
+			case 4:
+				switch(c) {
+				case 47:
+					state = 11;
+					break;
+				case 62:
+					state = 9;
+					break;
+				default:
+					state = 5;
+					start = p;
+					continue;
+				}
+				break;
+			case 5:
+				if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c == 58 || c == 46 || c == 95 || c == 45)) {
+					if(start == p) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected attribute name",str,p));
+					}
+					let tmp = HxOverrides.substr(str,start,p - start);
+					aname = tmp;
+					if(xml.exists(aname)) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Duplicate attribute [" + aname + "]",str,p));
+					}
+					state = 0;
+					next = 6;
+					continue;
+				}
+				break;
+			case 6:
+				if(c == 61) {
+					state = 0;
+					next = 7;
+				} else {
+					throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected =",str,p));
+				}
+				break;
+			case 7:
+				switch(c) {
+				case 34:case 39:
+					buf = new StringBuf();
+					state = 8;
+					start = p + 1;
+					attrValQuote = c;
+					break;
+				default:
+					throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected \"",str,p));
+				}
+				break;
+			case 8:
+				switch(c) {
+				case 38:
+					let len = p - start;
+					buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+					state = 18;
+					escapeNext = 8;
+					start = p + 1;
+					break;
+				case 60:case 62:
+					if(strict) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Invalid unescaped " + String.fromCodePoint(c) + " in attribute value",str,p));
+					} else if(c == attrValQuote) {
+						let len = p - start;
+						buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+						let val = buf.b;
+						buf = new StringBuf();
+						xml.set(aname,val);
+						state = 0;
+						next = 4;
+					}
+					break;
+				default:
+					if(c == attrValQuote) {
+						let len = p - start;
+						buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+						let val = buf.b;
+						buf = new StringBuf();
+						xml.set(aname,val);
+						state = 0;
+						next = 4;
+					}
+				}
+				break;
+			case 9:
+				p = haxe_xml_Parser.doParse(str,strict,p,xml);
+				start = p;
+				state = 1;
+				break;
+			case 10:
+				if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c == 58 || c == 46 || c == 95 || c == 45)) {
+					if(start == p) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected node name",str,p));
+					}
+					let v = HxOverrides.substr(str,start,p - start);
+					if(parent == null || parent.nodeType != 0) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Unexpected </" + v + ">, tag is not open",str,p));
+					}
+					if(parent.nodeType != Xml.Element) {
+						throw haxe_Exception.thrown("Bad node type, expected Element but found " + (parent.nodeType == null ? "null" : XmlType.toString(parent.nodeType)));
+					}
+					if(v != parent.nodeName) {
+						if(parent.nodeType != Xml.Element) {
+							throw haxe_Exception.thrown("Bad node type, expected Element but found " + (parent.nodeType == null ? "null" : XmlType.toString(parent.nodeType)));
+						}
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected </" + parent.nodeName + ">",str,p));
+					}
+					state = 0;
+					next = 12;
+					continue;
+				}
+				break;
+			case 11:
+				if(c == 62) {
+					state = 1;
+				} else {
+					throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected >",str,p));
+				}
+				break;
+			case 12:
+				if(c == 62) {
+					if(nsubs == 0) {
+						parent.addChild(Xml.createPCData(""));
+					}
+					return p;
+				} else {
+					throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected >",str,p));
+				}
+				break;
+			case 13:
+				if(c == 60) {
+					let len = p - start;
+					buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+					let child = Xml.createPCData(buf.b);
+					buf = new StringBuf();
+					parent.addChild(child);
+					++nsubs;
+					state = 0;
+					next = 2;
+				} else if(c == 38) {
+					let len = p - start;
+					buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+					state = 18;
+					escapeNext = 13;
+					start = p + 1;
+				}
+				break;
+			case 14:
+				if(c == 63 && str.charCodeAt(p + 1) == 62) {
+					++p;
+					let str1 = HxOverrides.substr(str,start + 1,p - start - 2);
+					parent.addChild(Xml.createProcessingInstruction(str1));
+					++nsubs;
+					state = 1;
+				}
+				break;
+			case 15:
+				if(c == 45 && str.charCodeAt(p + 1) == 45 && str.charCodeAt(p + 2) == 62) {
+					parent.addChild(Xml.createComment(HxOverrides.substr(str,start,p - start)));
+					++nsubs;
+					p += 2;
+					state = 1;
+				}
+				break;
+			case 16:
+				if(c == 91) {
+					++nbrackets;
+				} else if(c == 93) {
+					--nbrackets;
+				} else if(c == 62 && nbrackets == 0) {
+					parent.addChild(Xml.createDocType(HxOverrides.substr(str,start,p - start)));
+					++nsubs;
+					state = 1;
+				}
+				break;
+			case 17:
+				if(c == 93 && str.charCodeAt(p + 1) == 93 && str.charCodeAt(p + 2) == 62) {
+					let child = Xml.createCData(HxOverrides.substr(str,start,p - start));
+					parent.addChild(child);
+					++nsubs;
+					p += 2;
+					state = 1;
+				}
+				break;
+			case 18:
+				if(c == 59) {
+					let s = HxOverrides.substr(str,start,p - start);
+					if(s.charCodeAt(0) == 35) {
+						let c = s.charCodeAt(1) == 120 ? Std.parseInt("0" + HxOverrides.substr(s,1,s.length - 1)) : Std.parseInt(HxOverrides.substr(s,1,s.length - 1));
+						buf.b += String.fromCodePoint(c);
+					} else if(!Object.prototype.hasOwnProperty.call(haxe_xml_Parser.escapes.h,s)) {
+						if(strict) {
+							throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Undefined entity: " + s,str,p));
+						}
+						buf.b += Std.string("&" + s + ";");
+					} else {
+						buf.b += Std.string(haxe_xml_Parser.escapes.h[s]);
+					}
+					start = p + 1;
+					state = escapeNext;
+				} else if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c == 58 || c == 46 || c == 95 || c == 45) && c != 35) {
+					if(strict) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Invalid character in entity: " + String.fromCodePoint(c),str,p));
+					}
+					buf.b += String.fromCodePoint(38);
+					let len = p - start;
+					buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+					--p;
+					start = p + 1;
+					state = escapeNext;
+				}
+				break;
+			}
+			++p;
+		}
+		if(state == 1) {
+			start = p;
+			state = 13;
+		}
+		if(state == 13) {
+			if(parent.nodeType == 0) {
+				if(parent.nodeType != Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, expected Element but found " + (parent.nodeType == null ? "null" : XmlType.toString(parent.nodeType)));
+				}
+				throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Unclosed node <" + parent.nodeName + ">",str,p));
+			}
+			if(p != start || nsubs == 0) {
+				let len = p - start;
+				buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+				parent.addChild(Xml.createPCData(buf.b));
+				++nsubs;
+			}
+			return p;
+		}
+		if(!strict && state == 18 && escapeNext == 13) {
+			buf.b += String.fromCodePoint(38);
+			let len = p - start;
+			buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+			parent.addChild(Xml.createPCData(buf.b));
+			++nsubs;
+			return p;
+		}
+		throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Unexpected end",str,p));
+	}
+}
+haxe_xml_Parser.__name__ = "haxe.xml.Parser";
+class haxe_xml_Printer {
+	constructor(pretty) {
+		this.output = new StringBuf();
+		this.pretty = pretty;
+	}
+	writeNode(value,tabs) {
+		switch(value.nodeType) {
+		case 0:
+			this.output.b += Std.string(tabs + "<");
+			if(value.nodeType != Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, expected Element but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			this.output.b += Std.string(value.nodeName);
+			let attribute = value.attributes();
+			while(attribute.hasNext()) {
+				let attribute1 = attribute.next();
+				this.output.b += Std.string(" " + attribute1 + "=\"");
+				let input = StringTools.htmlEscape(value.get(attribute1),true);
+				this.output.b += Std.string(input);
+				this.output.b += "\"";
+			}
+			if(this.hasChildren(value)) {
+				this.output.b += ">";
+				if(this.pretty) {
+					this.output.b += "\n";
+				}
+				if(value.nodeType != Xml.Document && value.nodeType != Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+				}
+				let _g_current = 0;
+				let _g_array = value.children;
+				while(_g_current < _g_array.length) {
+					let child = _g_array[_g_current++];
+					this.writeNode(child,this.pretty ? tabs + "\t" : tabs);
+				}
+				this.output.b += Std.string(tabs + "</");
+				if(value.nodeType != Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, expected Element but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+				}
+				this.output.b += Std.string(value.nodeName);
+				this.output.b += ">";
+				if(this.pretty) {
+					this.output.b += "\n";
+				}
+			} else {
+				this.output.b += "/>";
+				if(this.pretty) {
+					this.output.b += "\n";
+				}
+			}
+			break;
+		case 1:
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			let nodeValue = value.nodeValue;
+			if(nodeValue.length != 0) {
+				let input = tabs + StringTools.htmlEscape(nodeValue);
+				this.output.b += Std.string(input);
+				if(this.pretty) {
+					this.output.b += "\n";
+				}
+			}
+			break;
+		case 2:
+			this.output.b += Std.string(tabs + "<![CDATA[");
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			this.output.b += Std.string(value.nodeValue);
+			this.output.b += "]]>";
+			if(this.pretty) {
+				this.output.b += "\n";
+			}
+			break;
+		case 3:
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			let commentContent = value.nodeValue;
+			let _this_r = new RegExp("[\n\r\t]+","g".split("u").join(""));
+			commentContent = commentContent.replace(_this_r,"");
+			commentContent = "<!--" + commentContent + "-->";
+			this.output.b += tabs == null ? "null" : "" + tabs;
+			let input = StringTools.trim(commentContent);
+			this.output.b += Std.string(input);
+			if(this.pretty) {
+				this.output.b += "\n";
+			}
+			break;
+		case 4:
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			this.output.b += Std.string("<!DOCTYPE " + value.nodeValue + ">");
+			if(this.pretty) {
+				this.output.b += "\n";
+			}
+			break;
+		case 5:
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			this.output.b += Std.string("<?" + value.nodeValue + "?>");
+			if(this.pretty) {
+				this.output.b += "\n";
+			}
+			break;
+		case 6:
+			if(value.nodeType != Xml.Document && value.nodeType != Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			let _g_current = 0;
+			let _g_array = value.children;
+			while(_g_current < _g_array.length) {
+				let child = _g_array[_g_current++];
+				this.writeNode(child,tabs);
+			}
+			break;
+		}
+	}
+	hasChildren(value) {
+		if(value.nodeType != Xml.Document && value.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+		}
+		let _g_current = 0;
+		let _g_array = value.children;
+		while(_g_current < _g_array.length) {
+			let child = _g_array[_g_current++];
+			switch(child.nodeType) {
+			case 0:case 1:
+				return true;
+			case 2:case 3:
+				if(child.nodeType == Xml.Document || child.nodeType == Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, unexpected " + (child.nodeType == null ? "null" : XmlType.toString(child.nodeType)));
+				}
+				if(StringTools.ltrim(child.nodeValue).length != 0) {
+					return true;
+				}
+				break;
+			default:
+			}
+		}
+		return false;
+	}
+	static print(xml,pretty) {
+		if(pretty == null) {
+			pretty = false;
+		}
+		let printer = new haxe_xml_Printer(pretty);
+		printer.writeNode(xml,"");
+		return printer.output.b;
+	}
+}
+haxe_xml_Printer.__name__ = "haxe.xml.Printer";
+Object.assign(haxe_xml_Printer.prototype, {
+	__class__: haxe_xml_Printer
+});
+class hsluv_Hsluv {
+	constructor() {
+	}
+	rgbToHex() {
+		this.hex = "#";
+		this.hex += hsluv_Hsluv.rgbChannelToHex(this.rgb_r);
+		this.hex += hsluv_Hsluv.rgbChannelToHex(this.rgb_g);
+		this.hex += hsluv_Hsluv.rgbChannelToHex(this.rgb_b);
+	}
+	hexToRgb() {
+		this.hex = this.hex.toLowerCase();
+		this.rgb_r = hsluv_Hsluv.hexToRgbChannel(this.hex,1);
+		this.rgb_g = hsluv_Hsluv.hexToRgbChannel(this.hex,3);
+		this.rgb_b = hsluv_Hsluv.hexToRgbChannel(this.hex,5);
+	}
+	xyzToRgb() {
+		this.rgb_r = hsluv_Hsluv.fromLinear(hsluv_Hsluv.m_r0 * this.xyz_x + hsluv_Hsluv.m_r1 * this.xyz_y + hsluv_Hsluv.m_r2 * this.xyz_z);
+		this.rgb_g = hsluv_Hsluv.fromLinear(hsluv_Hsluv.m_g0 * this.xyz_x + hsluv_Hsluv.m_g1 * this.xyz_y + hsluv_Hsluv.m_g2 * this.xyz_z);
+		this.rgb_b = hsluv_Hsluv.fromLinear(hsluv_Hsluv.m_b0 * this.xyz_x + hsluv_Hsluv.m_b1 * this.xyz_y + hsluv_Hsluv.m_b2 * this.xyz_z);
+	}
+	rgbToXyz() {
+		let lr = hsluv_Hsluv.toLinear(this.rgb_r);
+		let lg = hsluv_Hsluv.toLinear(this.rgb_g);
+		let lb = hsluv_Hsluv.toLinear(this.rgb_b);
+		this.xyz_x = 0.41239079926595 * lr + 0.35758433938387 * lg + 0.18048078840183 * lb;
+		this.xyz_y = 0.21263900587151 * lr + 0.71516867876775 * lg + 0.072192315360733 * lb;
+		this.xyz_z = 0.019330818715591 * lr + 0.11919477979462 * lg + 0.95053215224966 * lb;
+	}
+	xyzToLuv() {
+		let divider = this.xyz_x + 15 * this.xyz_y + 3 * this.xyz_z;
+		let varU = 4 * this.xyz_x;
+		let varV = 9 * this.xyz_y;
+		if(divider != 0) {
+			varU /= divider;
+			varV /= divider;
+		} else {
+			varU = NaN;
+			varV = NaN;
+		}
+		this.luv_l = hsluv_Hsluv.yToL(this.xyz_y);
+		if(this.luv_l == 0) {
+			this.luv_u = 0;
+			this.luv_v = 0;
+		} else {
+			this.luv_u = 13 * this.luv_l * (varU - hsluv_Hsluv.refU);
+			this.luv_v = 13 * this.luv_l * (varV - hsluv_Hsluv.refV);
+		}
+	}
+	luvToXyz() {
+		if(this.luv_l == 0) {
+			this.xyz_x = 0;
+			this.xyz_y = 0;
+			this.xyz_z = 0;
+			return;
+		}
+		let varU = this.luv_u / (13 * this.luv_l) + hsluv_Hsluv.refU;
+		let varV = this.luv_v / (13 * this.luv_l) + hsluv_Hsluv.refV;
+		this.xyz_y = hsluv_Hsluv.lToY(this.luv_l);
+		this.xyz_x = 0 - 9 * this.xyz_y * varU / ((varU - 4) * varV - varU * varV);
+		this.xyz_z = (9 * this.xyz_y - 15 * varV * this.xyz_y - varV * this.xyz_x) / (3 * varV);
+	}
+	luvToLch() {
+		this.lch_l = this.luv_l;
+		this.lch_c = Math.sqrt(this.luv_u * this.luv_u + this.luv_v * this.luv_v);
+		if(this.lch_c < 0.00000001) {
+			this.lch_h = 0;
+		} else {
+			let Hrad = Math.atan2(this.luv_v,this.luv_u);
+			this.lch_h = Hrad * 180.0 / Math.PI;
+			if(this.lch_h < 0) {
+				this.lch_h = 360 + this.lch_h;
+			}
+		}
+	}
+	lchToLuv() {
+		let Hrad = this.lch_h / 180.0 * Math.PI;
+		this.luv_l = this.lch_l;
+		this.luv_u = Math.cos(Hrad) * this.lch_c;
+		this.luv_v = Math.sin(Hrad) * this.lch_c;
+	}
+	calculateBoundingLines(l) {
+		let sub1 = Math.pow(l + 16,3) / 1560896;
+		let sub2 = sub1 > hsluv_Hsluv.epsilon ? sub1 : l / hsluv_Hsluv.kappa;
+		let s1r = sub2 * (284517 * hsluv_Hsluv.m_r0 - 94839 * hsluv_Hsluv.m_r2);
+		let s2r = sub2 * (838422 * hsluv_Hsluv.m_r2 + 769860 * hsluv_Hsluv.m_r1 + 731718 * hsluv_Hsluv.m_r0);
+		let s3r = sub2 * (632260 * hsluv_Hsluv.m_r2 - 126452 * hsluv_Hsluv.m_r1);
+		let s1g = sub2 * (284517 * hsluv_Hsluv.m_g0 - 94839 * hsluv_Hsluv.m_g2);
+		let s2g = sub2 * (838422 * hsluv_Hsluv.m_g2 + 769860 * hsluv_Hsluv.m_g1 + 731718 * hsluv_Hsluv.m_g0);
+		let s3g = sub2 * (632260 * hsluv_Hsluv.m_g2 - 126452 * hsluv_Hsluv.m_g1);
+		let s1b = sub2 * (284517 * hsluv_Hsluv.m_b0 - 94839 * hsluv_Hsluv.m_b2);
+		let s2b = sub2 * (838422 * hsluv_Hsluv.m_b2 + 769860 * hsluv_Hsluv.m_b1 + 731718 * hsluv_Hsluv.m_b0);
+		let s3b = sub2 * (632260 * hsluv_Hsluv.m_b2 - 126452 * hsluv_Hsluv.m_b1);
+		this.r0s = s1r / s3r;
+		this.r0i = s2r * l / s3r;
+		this.r1s = s1r / (s3r + 126452);
+		this.r1i = (s2r - 769860) * l / (s3r + 126452);
+		this.g0s = s1g / s3g;
+		this.g0i = s2g * l / s3g;
+		this.g1s = s1g / (s3g + 126452);
+		this.g1i = (s2g - 769860) * l / (s3g + 126452);
+		this.b0s = s1b / s3b;
+		this.b0i = s2b * l / s3b;
+		this.b1s = s1b / (s3b + 126452);
+		this.b1i = (s2b - 769860) * l / (s3b + 126452);
+	}
+	calcMaxChromaHpluv() {
+		let r0 = hsluv_Hsluv.distanceFromOrigin(this.r0s,this.r0i);
+		let r1 = hsluv_Hsluv.distanceFromOrigin(this.r1s,this.r1i);
+		let g0 = hsluv_Hsluv.distanceFromOrigin(this.g0s,this.g0i);
+		let g1 = hsluv_Hsluv.distanceFromOrigin(this.g1s,this.g1i);
+		let b0 = hsluv_Hsluv.distanceFromOrigin(this.b0s,this.b0i);
+		let b1 = hsluv_Hsluv.distanceFromOrigin(this.b1s,this.b1i);
+		return hsluv_Hsluv.min6(r0,r1,g0,g1,b0,b1);
+	}
+	calcMaxChromaHsluv(h) {
+		let hueRad = h / 360 * Math.PI * 2;
+		let r0 = hsluv_Hsluv.distanceFromOriginAngle(this.r0s,this.r0i,hueRad);
+		let r1 = hsluv_Hsluv.distanceFromOriginAngle(this.r1s,this.r1i,hueRad);
+		let g0 = hsluv_Hsluv.distanceFromOriginAngle(this.g0s,this.g0i,hueRad);
+		let g1 = hsluv_Hsluv.distanceFromOriginAngle(this.g1s,this.g1i,hueRad);
+		let b0 = hsluv_Hsluv.distanceFromOriginAngle(this.b0s,this.b0i,hueRad);
+		let b1 = hsluv_Hsluv.distanceFromOriginAngle(this.b1s,this.b1i,hueRad);
+		return hsluv_Hsluv.min6(r0,r1,g0,g1,b0,b1);
+	}
+	hsluvToLch() {
+		if(this.hsluv_l > 99.9999999) {
+			this.lch_l = 100;
+			this.lch_c = 0;
+		} else if(this.hsluv_l < 0.00000001) {
+			this.lch_l = 0;
+			this.lch_c = 0;
+		} else {
+			this.lch_l = this.hsluv_l;
+			this.calculateBoundingLines(this.hsluv_l);
+			let max = this.calcMaxChromaHsluv(this.hsluv_h);
+			this.lch_c = max / 100 * this.hsluv_s;
+		}
+		this.lch_h = this.hsluv_h;
+	}
+	lchToHsluv() {
+		if(this.lch_l > 99.9999999) {
+			this.hsluv_s = 0;
+			this.hsluv_l = 100;
+		} else if(this.lch_l < 0.00000001) {
+			this.hsluv_s = 0;
+			this.hsluv_l = 0;
+		} else {
+			this.calculateBoundingLines(this.lch_l);
+			let max = this.calcMaxChromaHsluv(this.lch_h);
+			this.hsluv_s = this.lch_c / max * 100;
+			this.hsluv_l = this.lch_l;
+		}
+		this.hsluv_h = this.lch_h;
+	}
+	hpluvToLch() {
+		if(this.hpluv_l > 99.9999999) {
+			this.lch_l = 100;
+			this.lch_c = 0;
+		} else if(this.hpluv_l < 0.00000001) {
+			this.lch_l = 0;
+			this.lch_c = 0;
+		} else {
+			this.lch_l = this.hpluv_l;
+			this.calculateBoundingLines(this.hpluv_l);
+			let max = this.calcMaxChromaHpluv();
+			this.lch_c = max / 100 * this.hpluv_p;
+		}
+		this.lch_h = this.hpluv_h;
+	}
+	lchToHpluv() {
+		if(this.lch_l > 99.9999999) {
+			this.hpluv_p = 0;
+			this.hpluv_l = 100;
+		} else if(this.lch_l < 0.00000001) {
+			this.hpluv_p = 0;
+			this.hpluv_l = 0;
+		} else {
+			this.calculateBoundingLines(this.lch_l);
+			let max = this.calcMaxChromaHpluv();
+			this.hpluv_p = this.lch_c / max * 100;
+			this.hpluv_l = this.lch_l;
+		}
+		this.hpluv_h = this.lch_h;
+	}
+	hsluvToRgb() {
+		this.hsluvToLch();
+		this.lchToLuv();
+		this.luvToXyz();
+		this.xyzToRgb();
+	}
+	hpluvToRgb() {
+		this.hpluvToLch();
+		this.lchToLuv();
+		this.luvToXyz();
+		this.xyzToRgb();
+	}
+	hsluvToHex() {
+		this.hsluvToRgb();
+		this.rgbToHex();
+	}
+	hpluvToHex() {
+		this.hpluvToRgb();
+		this.rgbToHex();
+	}
+	rgbToHsluv() {
+		this.rgbToXyz();
+		this.xyzToLuv();
+		this.luvToLch();
+		this.lchToHpluv();
+		this.lchToHsluv();
+	}
+	rgbToHpluv() {
+		this.rgbToXyz();
+		this.xyzToLuv();
+		this.luvToLch();
+		this.lchToHpluv();
+		this.lchToHpluv();
+	}
+	hexToHsluv() {
+		this.hexToRgb();
+		this.rgbToHsluv();
+	}
+	hexToHpluv() {
+		this.hexToRgb();
+		this.rgbToHpluv();
+	}
+	static fromLinear(c) {
+		if(c <= 0.0031308) {
+			return 12.92 * c;
+		} else {
+			return 1.055 * Math.pow(c,0.416666666666666685) - 0.055;
+		}
+	}
+	static toLinear(c) {
+		if(c > 0.04045) {
+			return Math.pow((c + 0.055) / 1.055,2.4);
+		} else {
+			return c / 12.92;
+		}
+	}
+	static yToL(Y) {
+		if(Y <= hsluv_Hsluv.epsilon) {
+			return Y / hsluv_Hsluv.refY * hsluv_Hsluv.kappa;
+		} else {
+			return 116 * Math.pow(Y / hsluv_Hsluv.refY,0.333333333333333315) - 16;
+		}
+	}
+	static lToY(L) {
+		if(L <= 8) {
+			return hsluv_Hsluv.refY * L / hsluv_Hsluv.kappa;
+		} else {
+			return hsluv_Hsluv.refY * Math.pow((L + 16) / 116,3);
+		}
+	}
+	static rgbChannelToHex(chan) {
+		let c = Math.round(chan * 255);
+		let digit2 = c % 16;
+		let digit1 = (c - digit2) / 16 | 0;
+		return hsluv_Hsluv.hexChars.charAt(digit1) + hsluv_Hsluv.hexChars.charAt(digit2);
+	}
+	static hexToRgbChannel(hex,offset) {
+		let digit1 = hsluv_Hsluv.hexChars.indexOf(hex.charAt(offset));
+		let digit2 = hsluv_Hsluv.hexChars.indexOf(hex.charAt(offset + 1));
+		let n = digit1 * 16 + digit2;
+		return n / 255.0;
+	}
+	static distanceFromOriginAngle(slope,intercept,angle) {
+		let d = intercept / (Math.sin(angle) - slope * Math.cos(angle));
+		if(d < 0) {
+			return Infinity;
+		} else {
+			return d;
+		}
+	}
+	static distanceFromOrigin(slope,intercept) {
+		return Math.abs(intercept) / Math.sqrt(Math.pow(slope,2) + 1);
+	}
+	static min6(f1,f2,f3,f4,f5,f6) {
+		return Math.min(f1,Math.min(f2,Math.min(f3,Math.min(f4,Math.min(f5,f6)))));
+	}
+}
+hsluv_Hsluv.__name__ = "hsluv.Hsluv";
+Object.assign(hsluv_Hsluv.prototype, {
+	__class__: hsluv_Hsluv
+});
+class htmlparser_CssSelector {
+	constructor(type) {
+		this.classes = [];
+		this.type = type;
+	}
+	static parse(selector) {
+		let r = [];
+		let selectors = new EReg("\\s*,\\s*","g").split(selector);
+		let _g = 0;
+		while(_g < selectors.length) {
+			let s = selectors[_g];
+			++_g;
+			if(s != "") {
+				r.push(htmlparser_CssSelector.parseInner(s));
+			}
+		}
+		return r;
+	}
+	static parseInner(selector) {
+		let rr = [];
+		selector = " " + selector;
+		let r = null;
+		let re = new EReg(htmlparser_CssSelector.reSelector,"gi");
+		let pos = 0;
+		while(re.matchSub(selector,pos)) {
+			let type1;
+			try {
+				type1 = re.matched(1);
+			} catch( _g ) {
+				type1 = null;
+			}
+			if(type1 == null) {
+				type1 = "";
+			}
+			let type2;
+			try {
+				type2 = re.matched(2);
+			} catch( _g ) {
+				type2 = null;
+			}
+			if(type2 == null) {
+				type2 = "";
+			}
+			if(type1.length > 0 || type2.length > 0) {
+				if(r != null) {
+					rr.push(r);
+				}
+				r = new htmlparser_CssSelector(type2.length > 0 ? ">" : " ");
+			}
+			let name = re.matched(4);
+			if(name != "*") {
+				let s = re.matched(3);
+				if(s == "#") {
+					r.id = name;
+				} else if(s == ".") {
+					r.classes.push(name);
+				} else {
+					r.tagNameLC = name.toLowerCase();
+				}
+				let sIndex;
+				try {
+					sIndex = re.matched(5);
+				} catch( _g ) {
+					sIndex = null;
+				}
+				if(sIndex != null && sIndex != "") {
+					r.index = Std.parseInt(sIndex.substring(1,sIndex.length - 1));
+					let f = r.index;
+					if(isNaN(f)) {
+						r.index = null;
+					}
+				}
+			}
+			let p = re.matchedPos();
+			pos = p.pos + p.len;
+		}
+		if(r != null) {
+			rr.push(r);
+		}
+		return rr;
+	}
+	static getMatched(re,n) {
+		try {
+			return re.matched(n);
+		} catch( _g ) {
+			return null;
+		}
+	}
+}
+htmlparser_CssSelector.__name__ = "htmlparser.CssSelector";
+Object.assign(htmlparser_CssSelector.prototype, {
+	__class__: htmlparser_CssSelector
+});
+class htmlparser_HtmlAttribute {
+	constructor(name,value,quote) {
+		this.name = name;
+		this.value = value;
+		this.quote = quote;
+	}
+	toString() {
+		if(this.value != null && this.quote != null) {
+			return this.name + "=" + this.quote + htmlparser_HtmlTools.escape(this.value,"\r\n" + (this.quote == "'" ? "\"" : "'")) + this.quote;
+		} else {
+			return this.name;
+		}
+	}
+}
+htmlparser_HtmlAttribute.__name__ = "htmlparser.HtmlAttribute";
+Object.assign(htmlparser_HtmlAttribute.prototype, {
+	__class__: htmlparser_HtmlAttribute
+});
+class htmlparser_HtmlNode {
+	remove() {
+		if(this.parent != null) {
+			this.parent.removeChild(this);
+		}
+	}
+	getPrevSiblingNode() {
+		if(this.parent == null) {
+			return null;
+		}
+		let siblings = this.parent.nodes;
+		let n = Lambda.indexOf(siblings,this);
+		if(n <= 0) {
+			return null;
+		}
+		if(n > 0) {
+			return siblings[n - 1];
+		}
+		return null;
+	}
+	getNextSiblingNode() {
+		if(this.parent == null) {
+			return null;
+		}
+		let siblings = this.parent.nodes;
+		let n = Lambda.indexOf(siblings,this);
+		if(n < 0) {
+			return null;
+		}
+		if(n + 1 < siblings.length) {
+			return siblings[n + 1];
+		}
+		return null;
+	}
+	toString() {
+		return "";
+	}
+	toText() {
+		return "";
+	}
+	hxSerialize(s) {
+	}
+	hxUnserialize(s) {
+	}
+}
+htmlparser_HtmlNode.__name__ = "htmlparser.HtmlNode";
+Object.assign(htmlparser_HtmlNode.prototype, {
+	__class__: htmlparser_HtmlNode
+});
+class htmlparser_HtmlNodeElement extends htmlparser_HtmlNode {
+	constructor(name,attributes) {
+		super();
+		this.name = name;
+		this.attributes = attributes;
+		this.nodes = [];
+		this.children = [];
+	}
+	getPrevSiblingElement() {
+		if(this.parent == null) {
+			return null;
+		}
+		let n = this.parent.children.indexOf(this);
+		if(n < 0) {
+			return null;
+		}
+		if(n > 0) {
+			return this.parent.children[n - 1];
+		}
+		return null;
+	}
+	getNextSiblingElement() {
+		if(this.parent == null) {
+			return null;
+		}
+		let n = this.parent.children.indexOf(this);
+		if(n < 0) {
+			return null;
+		}
+		if(n + 1 < this.parent.children.length) {
+			return this.parent.children[n + 1];
+		}
+		return null;
+	}
+	addChild(node,beforeNode) {
+		if(beforeNode == null) {
+			this.nodes.push(node);
+			node.parent = this;
+			if(((node) instanceof htmlparser_HtmlNodeElement)) {
+				this.children.push(node);
+			}
+		} else {
+			let n = this.nodes.indexOf(beforeNode);
+			if(n < 0) {
+				throw new haxe_Exception("`beforeNode` is not found.");
+			}
+			this.nodes.splice(n,0,node);
+			node.parent = this;
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = this.nodes;
+			while(_g1 < _g2.length) {
+				let v = _g2[_g1];
+				++_g1;
+				if(((v) instanceof htmlparser_HtmlNodeElement)) {
+					_g.push(v);
+				}
+			}
+			this.children = _g;
+		}
+	}
+	addChildren(nodesToAdd,beforeNode) {
+		let n = beforeNode != null ? this.nodes.indexOf(beforeNode) : 0;
+		if(n < 0) {
+			throw new haxe_Exception("`beforeNode` is not found.");
+		}
+		this.nodes = (n > 0 ? this.nodes.slice(0,n) : []).concat(nodesToAdd).concat(this.nodes.slice(n));
+		let _g = 0;
+		while(_g < nodesToAdd.length) {
+			let node = nodesToAdd[_g];
+			++_g;
+			node.parent = this;
+		}
+		let _g1 = [];
+		let _g2 = 0;
+		let _g3 = this.nodes;
+		while(_g2 < _g3.length) {
+			let v = _g3[_g2];
+			++_g2;
+			if(((v) instanceof htmlparser_HtmlNodeElement)) {
+				_g1.push(v);
+			}
+		}
+		this.children = _g1;
+	}
+	toString() {
+		let sAttrs_b = "";
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let a = _g1[_g];
+			++_g;
+			sAttrs_b += " ";
+			sAttrs_b += Std.string(a.toString());
+		}
+		let innerBuf_b = "";
+		let _g2 = 0;
+		let _g3 = this.nodes;
+		while(_g2 < _g3.length) {
+			let node = _g3[_g2];
+			++_g2;
+			innerBuf_b += Std.string(node.toString());
+		}
+		let inner = innerBuf_b;
+		if(inner == "" && this.isSelfClosing()) {
+			return "<" + this.name + sAttrs_b + " />";
+		}
+		if(this.name != null && this.name != "") {
+			return "<" + this.name + sAttrs_b + ">" + inner + "</" + this.name + ">";
+		} else {
+			return inner;
+		}
+	}
+	getAttribute(name) {
+		let nameLC = name.toLowerCase();
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let a = _g1[_g];
+			++_g;
+			if(a.name.toLowerCase() == nameLC) {
+				return a.value;
+			}
+		}
+		return null;
+	}
+	setAttribute(name,value) {
+		let nameLC = name.toLowerCase();
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let a = _g1[_g];
+			++_g;
+			if(a.name.toLowerCase() == nameLC) {
+				a.value = value;
+				return;
+			}
+		}
+		this.attributes.push(new htmlparser_HtmlAttribute(name,value,"\""));
+	}
+	removeAttribute(name) {
+		let nameLC = name.toLowerCase();
+		let _g = 0;
+		let _g1 = this.attributes.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let a = this.attributes[i];
+			if(a.name.toLowerCase() == nameLC) {
+				this.attributes.splice(i,1);
+				return;
+			}
+		}
+	}
+	hasAttribute(name) {
+		let nameLC = name.toLowerCase();
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let a = _g1[_g];
+			++_g;
+			if(a.name.toLowerCase() == nameLC) {
+				return true;
+			}
+		}
+		return false;
+	}
+	get_innerHTML() {
+		let r_b = "";
+		let _g = 0;
+		let _g1 = this.nodes;
+		while(_g < _g1.length) {
+			let node = _g1[_g];
+			++_g;
+			r_b += Std.string(node.toString());
+		}
+		return r_b;
+	}
+	set_innerHTML(value) {
+		let newNodes = htmlparser_HtmlParser.run(value);
+		this.nodes = [];
+		this.children = [];
+		let _g = 0;
+		while(_g < newNodes.length) {
+			let node = newNodes[_g];
+			++_g;
+			this.addChild(node);
+		}
+		return value;
+	}
+	get_innerText() {
+		return this.toText();
+	}
+	set_innerText(text) {
+		this.fastSetInnerHTML(htmlparser_HtmlTools.escape(text));
+		return text;
+	}
+	fastSetInnerHTML(html) {
+		this.nodes = [];
+		this.children = [];
+		this.addChild(new htmlparser_HtmlNodeText(html));
+	}
+	toText() {
+		let r_b = "";
+		let _g = 0;
+		let _g1 = this.nodes;
+		while(_g < _g1.length) {
+			let node = _g1[_g];
+			++_g;
+			r_b += Std.string(node.toText());
+		}
+		return r_b;
+	}
+	find(selector) {
+		let parsedSelectors = htmlparser_CssSelector.parse(selector);
+		let resNodes = [];
+		let _g = 0;
+		while(_g < parsedSelectors.length) {
+			let s = parsedSelectors[_g];
+			++_g;
+			let _g1 = 0;
+			let _g2 = this.children;
+			while(_g1 < _g2.length) {
+				let node = _g2[_g1];
+				++_g1;
+				let nodesToAdd = node.findInner(s);
+				let _g = 0;
+				while(_g < nodesToAdd.length) {
+					let nodeToAdd = nodesToAdd[_g];
+					++_g;
+					if(resNodes.indexOf(nodeToAdd) < 0) {
+						resNodes.push(nodeToAdd);
+					}
+				}
+			}
+		}
+		return resNodes;
+	}
+	findInner(selectors) {
+		if(selectors.length == 0) {
+			return [];
+		}
+		let nodes = [];
+		if(selectors[0].type == " ") {
+			let _g = 0;
+			let _g1 = this.children;
+			while(_g < _g1.length) {
+				let child = _g1[_g];
+				++_g;
+				nodes = nodes.concat(child.findInner(selectors));
+			}
+		}
+		if(this.isSelectorTrue(selectors[0])) {
+			if(selectors.length > 1) {
+				let subSelectors = selectors.slice(1);
+				let _g = 0;
+				let _g1 = this.children;
+				while(_g < _g1.length) {
+					let child = _g1[_g];
+					++_g;
+					nodes = nodes.concat(child.findInner(subSelectors));
+				}
+			} else if(selectors.length == 1) {
+				if(this.parent != null) {
+					nodes.push(this);
+				}
+			}
+		}
+		return nodes;
+	}
+	isSelectorTrue(selector) {
+		if(selector.tagNameLC != null && this.name.toLowerCase() != selector.tagNameLC) {
+			return false;
+		}
+		if(selector.id != null && this.getAttribute("id") != selector.id) {
+			return false;
+		}
+		let _g = 0;
+		let _g1 = selector.classes;
+		while(_g < _g1.length) {
+			let clas = _g1[_g];
+			++_g;
+			let reg = new EReg("(?:^|\\s)" + clas + "(?:$|\\s)","");
+			let classAttr = this.getAttribute("class");
+			if(classAttr == null || !reg.match(classAttr)) {
+				return false;
+			}
+		}
+		if(selector.index != null && (this.parent == null || this.parent.children.indexOf(this) + 1 != selector.index)) {
+			return false;
+		}
+		return true;
+	}
+	replaceChild(node,newNode) {
+		if(((newNode) instanceof Array)) {
+			this.replaceChildByMany(node,newNode);
+		} else {
+			this.replaceChildByOne(node,newNode);
+		}
+	}
+	replaceChildByOne(node,newNode) {
+		let n = this.nodes.indexOf(node);
+		if(n < 0) {
+			throw new haxe_Exception("Node to replace is not found.");
+		}
+		this.nodes[n].parent = null;
+		this.nodes[n] = newNode;
+		newNode.parent = this;
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.nodes;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(((v) instanceof htmlparser_HtmlNodeElement)) {
+				_g.push(v);
+			}
+		}
+		this.children = _g;
+	}
+	replaceChildByMany(node,newNodes) {
+		let n = this.nodes.indexOf(node);
+		if(n < 0) {
+			throw new haxe_Exception("Node to replace is not found.");
+		}
+		this.nodes[n].parent = null;
+		let lastNodes = this.nodes.slice(n + 1,this.nodes.length);
+		this.nodes = (n > 0 ? this.nodes.slice(0,n) : []).concat(newNodes).concat(lastNodes);
+		let _g = 0;
+		while(_g < newNodes.length) {
+			let n = newNodes[_g];
+			++_g;
+			n.parent = this;
+		}
+		let _g1 = [];
+		let _g2 = 0;
+		let _g3 = this.nodes;
+		while(_g2 < _g3.length) {
+			let v = _g3[_g2];
+			++_g2;
+			if(((v) instanceof htmlparser_HtmlNodeElement)) {
+				_g1.push(v);
+			}
+		}
+		this.children = _g1;
+	}
+	removeChild(node) {
+		let n = this.nodes.indexOf(node);
+		if(n < 0) {
+			throw new haxe_Exception("Node to remove is not found.");
+		}
+		this.nodes.splice(n,1);
+		node.parent = null;
+		if(((node) instanceof htmlparser_HtmlNodeElement)) {
+			n = this.children.indexOf(node);
+			if(n >= 0) {
+				this.children.splice(n,1);
+			}
+		}
+	}
+	getAttributesAssoc() {
+		let attrs = new haxe_ds_StringMap();
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let attr = _g1[_g];
+			++_g;
+			attrs.h[attr.name] = attr.value;
+		}
+		return attrs;
+	}
+	getAttributesObject() {
+		let attrs = { };
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let attr = _g1[_g];
+			++_g;
+			attrs[attr.name] = attr.value;
+		}
+		return attrs;
+	}
+	isSelfClosing() {
+		if(!Object.prototype.hasOwnProperty.call(htmlparser_HtmlParser.SELF_CLOSING_TAGS_HTML,this.name)) {
+			return this.name.indexOf(":") >= 0;
+		} else {
+			return true;
+		}
+	}
+	hxSerialize(s) {
+		s.serialize(this.name);
+		s.serialize(this.attributes);
+		s.serialize(this.nodes);
+	}
+	hxUnserialize(s) {
+		this.name = s.unserialize();
+		this.attributes = s.unserialize();
+		this.nodes = [];
+		this.children = [];
+		let ns = s.unserialize();
+		let _g = 0;
+		while(_g < ns.length) {
+			let n = ns[_g];
+			++_g;
+			this.addChild(n);
+		}
+	}
+}
+htmlparser_HtmlNodeElement.__name__ = "htmlparser.HtmlNodeElement";
+htmlparser_HtmlNodeElement.__super__ = htmlparser_HtmlNode;
+Object.assign(htmlparser_HtmlNodeElement.prototype, {
+	__class__: htmlparser_HtmlNodeElement
+});
+class htmlparser_HtmlNodeText extends htmlparser_HtmlNode {
+	constructor(text) {
+		super();
+		this.text = text;
+	}
+	toString() {
+		return this.text;
+	}
+	toText() {
+		return htmlparser_HtmlTools.unescape(this.text);
+	}
+	hxSerialize(s) {
+		s.serialize(this.text);
+	}
+	hxUnserialize(s) {
+		this.text = s.unserialize();
+	}
+}
+htmlparser_HtmlNodeText.__name__ = "htmlparser.HtmlNodeText";
+htmlparser_HtmlNodeText.__super__ = htmlparser_HtmlNode;
+Object.assign(htmlparser_HtmlNodeText.prototype, {
+	__class__: htmlparser_HtmlNodeText
+});
+class htmlparser_HtmlParser {
+	constructor() {
+	}
+	parse(str,tolerant) {
+		if(tolerant == null) {
+			tolerant = false;
+		}
+		this.tolerant = tolerant;
+		this.matches = [];
+		let pos = 0;
+		while(pos < str.length && htmlparser_HtmlParser.reMain.matchSub(str,pos)) {
+			let p = htmlparser_HtmlParser.reMain.matchedPos();
+			let re = htmlparser_HtmlParser.reMain;
+			let cdata;
+			try {
+				cdata = re.matched(1);
+			} catch( _g ) {
+				cdata = null;
+			}
+			if(cdata == null || cdata == "") {
+				let r = htmlparser_HtmlParser.reMain.matched(0);
+				let p1 = p.pos;
+				let re = htmlparser_HtmlParser.reMain;
+				let r1;
+				try {
+					r1 = re.matched(2);
+				} catch( _g ) {
+					r1 = null;
+				}
+				let re1 = htmlparser_HtmlParser.reMain;
+				let r2;
+				try {
+					r2 = re1.matched(3);
+				} catch( _g ) {
+					r2 = null;
+				}
+				let re2 = htmlparser_HtmlParser.reMain;
+				let r3;
+				try {
+					r3 = re2.matched(4);
+				} catch( _g ) {
+					r3 = null;
+				}
+				let re3 = htmlparser_HtmlParser.reMain;
+				let r4;
+				try {
+					r4 = re3.matched(5);
+				} catch( _g ) {
+					r4 = null;
+				}
+				let re4 = htmlparser_HtmlParser.reMain;
+				let r5;
+				try {
+					r5 = re4.matched(6);
+				} catch( _g ) {
+					r5 = null;
+				}
+				let re5 = htmlparser_HtmlParser.reMain;
+				let r6;
+				try {
+					r6 = re5.matched(7);
+				} catch( _g ) {
+					r6 = null;
+				}
+				let re6 = htmlparser_HtmlParser.reMain;
+				let r7;
+				try {
+					r7 = re6.matched(8);
+				} catch( _g ) {
+					r7 = null;
+				}
+				let re7 = htmlparser_HtmlParser.reMain;
+				let r8;
+				try {
+					r8 = re7.matched(9);
+				} catch( _g ) {
+					r8 = null;
+				}
+				let re8 = htmlparser_HtmlParser.reMain;
+				let r9;
+				try {
+					r9 = re8.matched(10);
+				} catch( _g ) {
+					r9 = null;
+				}
+				let re9 = htmlparser_HtmlParser.reMain;
+				let r10;
+				try {
+					r10 = re9.matched(11);
+				} catch( _g ) {
+					r10 = null;
+				}
+				let re10 = htmlparser_HtmlParser.reMain;
+				let r11;
+				try {
+					r11 = re10.matched(12);
+				} catch( _g ) {
+					r11 = null;
+				}
+				let re11 = htmlparser_HtmlParser.reMain;
+				let r12;
+				try {
+					r12 = re11.matched(13);
+				} catch( _g ) {
+					r12 = null;
+				}
+				let re12 = htmlparser_HtmlParser.reMain;
+				let r13;
+				try {
+					r13 = re12.matched(14);
+				} catch( _g ) {
+					r13 = null;
+				}
+				let r14 = { all : r, allPos : p1, script : r1, scriptAttrs : r2, scriptText : r3, style : r4, styleAttrs : r5, styleText : r6, elem : r7, tagOpen : r8, attrs : r9, tagEnd : r10, close : r11, tagClose : r12, comment : r13, tagOpenLC : null, tagCloseLC : null};
+				if(r14.tagOpen != null) {
+					r14.tagOpenLC = r14.tagOpen.toLowerCase();
+				}
+				if(r14.tagClose != null) {
+					r14.tagCloseLC = r14.tagClose.toLowerCase();
+				}
+				this.matches.push(r14);
+			}
+			pos = p.pos + p.len;
+		}
+		if(this.matches.length > 0) {
+			this.str = str;
+			this.i = 0;
+			let nodes = this.processMatches([]).nodes;
+			if(this.i < this.matches.length) {
+				throw haxe_Exception.thrown(new htmlparser_HtmlParserException("Not all nodes processed.",this.getPosition(this.i)));
+			}
+			return nodes;
+		}
+		if(str.length > 0) {
+			return [new htmlparser_HtmlNodeText(str)];
+		} else {
+			return [];
+		}
+	}
+	processMatches(openedTagsLC) {
+		let nodes = [];
+		let prevEnd = this.i > 0 ? this.matches[this.i - 1].allPos + this.matches[this.i - 1].all.length : 0;
+		let curStart = this.matches[this.i].allPos;
+		if(prevEnd < curStart) {
+			nodes.push(new htmlparser_HtmlNodeText(HxOverrides.substr(this.str,prevEnd,curStart - prevEnd)));
+		}
+		while(this.i < this.matches.length) {
+			let m = this.matches[this.i];
+			if(m.elem != null && m.elem != "") {
+				let ee = this.parseElement(openedTagsLC);
+				nodes.push(ee.element);
+				if(ee.closeTagLC != "") {
+					return { nodes : nodes, closeTagLC : ee.closeTagLC};
+				}
+			} else if(m.script != null && m.script != "") {
+				let scriptNode = this.newElement("script",htmlparser_HtmlParser.parseAttrs(m.scriptAttrs));
+				scriptNode.addChild(new htmlparser_HtmlNodeText(m.scriptText));
+				nodes.push(scriptNode);
+			} else if(m.style != null && m.style != "") {
+				let styleNode = this.newElement("style",htmlparser_HtmlParser.parseAttrs(m.styleAttrs));
+				styleNode.addChild(new htmlparser_HtmlNodeText(m.styleText));
+				nodes.push(styleNode);
+			} else if(m.close != null && m.close != "") {
+				if(m.tagCloseLC == openedTagsLC[openedTagsLC.length - 1]) {
+					break;
+				}
+				if(this.tolerant) {
+					if(openedTagsLC.lastIndexOf(m.tagCloseLC) >= 0) {
+						break;
+					}
+				} else {
+					throw haxe_Exception.thrown(new htmlparser_HtmlParserException("Closed tag <" + m.tagClose + "> don't match to open tag <" + openedTagsLC[openedTagsLC.length - 1] + ">.",this.getPosition(this.i)));
+				}
+			} else if(m.comment != null && m.comment != "") {
+				nodes.push(new htmlparser_HtmlNodeText(m.comment));
+			} else {
+				throw haxe_Exception.thrown(new htmlparser_HtmlParserException("Unexpected XML node.",this.getPosition(this.i)));
+			}
+			if(this.tolerant && this.i >= this.matches.length) {
+				break;
+			}
+			let curEnd = this.matches[this.i].allPos + this.matches[this.i].all.length;
+			let nextStart = this.i + 1 < this.matches.length ? this.matches[this.i + 1].allPos : this.str.length;
+			if(curEnd < nextStart) {
+				nodes.push(new htmlparser_HtmlNodeText(HxOverrides.substr(this.str,curEnd,nextStart - curEnd)));
+			}
+			this.i++;
+		}
+		return { nodes : nodes, closeTagLC : ""};
+	}
+	parseElement(openedTagsLC) {
+		let tag = this.matches[this.i].tagOpen;
+		let tagLC = this.matches[this.i].tagOpenLC;
+		let attrs = this.matches[this.i].attrs;
+		let isWithClose = this.matches[this.i].tagEnd != null && this.matches[this.i].tagEnd != "" || this.isSelfClosingTag(tagLC);
+		let elem = this.newElement(tag,htmlparser_HtmlParser.parseAttrs(attrs));
+		let closeTagLC = "";
+		if(!isWithClose) {
+			this.i++;
+			openedTagsLC.push(tagLC);
+			let m = this.processMatches(openedTagsLC);
+			let _g = 0;
+			let _g1 = m.nodes;
+			while(_g < _g1.length) {
+				let node = _g1[_g];
+				++_g;
+				elem.addChild(node);
+			}
+			openedTagsLC.pop();
+			closeTagLC = m.closeTagLC != tagLC ? m.closeTagLC : "";
+			if(this.i < this.matches.length || !this.tolerant) {
+				if(this.matches[this.i].close == null || this.matches[this.i].close == "" || this.matches[this.i].tagCloseLC != tagLC) {
+					if(!this.tolerant) {
+						throw haxe_Exception.thrown(new htmlparser_HtmlParserException("Tag <" + tag + "> not closed.",this.getPosition(this.i)));
+					} else {
+						closeTagLC = this.matches[this.i].tagCloseLC;
+					}
+				}
+			}
+		}
+		return { element : elem, closeTagLC : closeTagLC};
+	}
+	isSelfClosingTag(tag) {
+		return Object.prototype.hasOwnProperty.call(htmlparser_HtmlParser.SELF_CLOSING_TAGS_HTML,tag);
+	}
+	newElement(name,attributes) {
+		return new htmlparser_HtmlNodeElement(name,attributes);
+	}
+	getPosition(matchIndex) {
+		let m = this.matches[matchIndex];
+		let line = 1;
+		let lastNewLinePos = -1;
+		let i = 0;
+		while(i < m.allPos) {
+			let chars = i + 1 < this.str.length ? this.str.substring(i,i + 2) : this.str.charAt(i);
+			if(chars == "\r\n") {
+				i += 2;
+				lastNewLinePos = i;
+				++line;
+			} else if(chars.charAt(0) == "\n" || chars.charAt(0) == "\r") {
+				++i;
+				lastNewLinePos = i;
+				++line;
+			} else {
+				++i;
+			}
+		}
+		return { line : line, column : m.allPos - lastNewLinePos, length : m.all.length};
+	}
+	static run(str,tolerant) {
+		if(tolerant == null) {
+			tolerant = false;
+		}
+		return new htmlparser_HtmlParser().parse(str,tolerant);
+	}
+	static parseAttrs(str) {
+		let attributes = [];
+		let pos = 0;
+		while(pos < str.length && htmlparser_HtmlParser.reParseAttrs.matchSub(str,pos)) {
+			let name = htmlparser_HtmlParser.reParseAttrs.matched(1);
+			let value = htmlparser_HtmlParser.reParseAttrs.matched(2);
+			let quote = null;
+			let unescaped = null;
+			if(value != null) {
+				quote = HxOverrides.substr(value,0,1);
+				if(quote == "\"" || quote == "'") {
+					value = HxOverrides.substr(value,1,value.length - 2);
+				} else {
+					quote = "";
+				}
+				unescaped = htmlparser_HtmlTools.unescape(value);
+			}
+			attributes.push(new htmlparser_HtmlAttribute(name,unescaped,quote));
+			let p = htmlparser_HtmlParser.reParseAttrs.matchedPos();
+			pos = p.pos + p.len;
+		}
+		return attributes;
+	}
+	static getMatched(re,n) {
+		try {
+			return re.matched(n);
+		} catch( _g ) {
+			return null;
+		}
+	}
+}
+htmlparser_HtmlParser.__name__ = "htmlparser.HtmlParser";
+Object.assign(htmlparser_HtmlParser.prototype, {
+	__class__: htmlparser_HtmlParser
+});
+class htmlparser_HtmlParserException {
+	constructor(message,pos) {
+		this.message = message;
+		this.line = pos.line;
+		this.column = pos.column;
+		this.length = pos.length;
+	}
+	toString() {
+		return "Parse error at " + this.line + ":" + this.column + ". " + this.message;
+	}
+}
+htmlparser_HtmlParserException.__name__ = "htmlparser.HtmlParserException";
+Object.assign(htmlparser_HtmlParserException.prototype, {
+	__class__: htmlparser_HtmlParserException
+});
+class htmlparser_HtmlTools {
+	static get_htmlUnescapeMap() {
+		if(htmlparser_HtmlTools.htmlUnescapeMap == null) {
+			let _g = new haxe_ds_StringMap();
+			_g.h["nbsp"] = " ";
+			_g.h["amp"] = "&";
+			_g.h["lt"] = "<";
+			_g.h["gt"] = ">";
+			_g.h["quot"] = "\"";
+			_g.h["apos"] = "'";
+			_g.h["euro"] = "€";
+			_g.h["iexcl"] = "¡";
+			_g.h["cent"] = "¢";
+			_g.h["pound"] = "£";
+			_g.h["curren"] = "¤";
+			_g.h["yen"] = "¥";
+			_g.h["brvbar"] = "¦";
+			_g.h["sect"] = "§";
+			_g.h["uml"] = "¨";
+			_g.h["copy"] = "©";
+			_g.h["ordf"] = "ª";
+			_g.h["not"] = "¬";
+			_g.h["shy"] = "­";
+			_g.h["reg"] = "®";
+			_g.h["macr"] = "¯";
+			_g.h["deg"] = "°";
+			_g.h["plusmn"] = "±";
+			_g.h["sup2"] = "²";
+			_g.h["sup3"] = "³";
+			_g.h["acute"] = "´";
+			_g.h["micro"] = "µ";
+			_g.h["para"] = "¶";
+			_g.h["middot"] = "·";
+			_g.h["cedil"] = "¸";
+			_g.h["sup1"] = "¹";
+			_g.h["ordm"] = "º";
+			_g.h["raquo"] = "»";
+			_g.h["frac14"] = "¼";
+			_g.h["frac12"] = "½";
+			_g.h["frac34"] = "¾";
+			_g.h["iquest"] = "¿";
+			_g.h["Agrave"] = "À";
+			_g.h["Aacute"] = "Á";
+			_g.h["Acirc"] = "Â";
+			_g.h["Atilde"] = "Ã";
+			_g.h["Auml"] = "Ä";
+			_g.h["Aring"] = "Å";
+			_g.h["AElig"] = "Æ";
+			_g.h["Ccedil"] = "Ç";
+			_g.h["Egrave"] = "È";
+			_g.h["Eacute"] = "É";
+			_g.h["Ecirc"] = "Ê";
+			_g.h["Euml"] = "Ë";
+			_g.h["Igrave"] = "Ì";
+			_g.h["Iacute"] = "Í";
+			_g.h["Icirc"] = "Î";
+			_g.h["Iuml"] = "Ï";
+			_g.h["ETH"] = "Ð";
+			_g.h["Ntilde"] = "Ñ";
+			_g.h["Ograve"] = "Ò";
+			_g.h["Oacute"] = "Ó";
+			_g.h["Ocirc"] = "Ô";
+			_g.h["Otilde"] = "Õ";
+			_g.h["Ouml"] = "Ö";
+			_g.h["times"] = "×";
+			_g.h["Oslash"] = "Ø";
+			_g.h["Ugrave"] = "Ù";
+			_g.h["Uacute"] = "Ú";
+			_g.h["Ucirc"] = "Û";
+			_g.h["Uuml"] = "Ü";
+			_g.h["Yacute"] = "Ý";
+			_g.h["THORN"] = "Þ";
+			_g.h["szlig"] = "ß";
+			_g.h["agrave"] = "à";
+			_g.h["aacute"] = "á";
+			_g.h["acirc"] = "â";
+			_g.h["atilde"] = "ã";
+			_g.h["auml"] = "ä";
+			_g.h["aring"] = "å";
+			_g.h["aelig"] = "æ";
+			_g.h["ccedil"] = "ç";
+			_g.h["egrave"] = "è";
+			_g.h["eacute"] = "é";
+			_g.h["ecirc"] = "ê";
+			_g.h["euml"] = "ë";
+			_g.h["igrave"] = "ì";
+			_g.h["iacute"] = "í";
+			_g.h["icirc"] = "î";
+			_g.h["iuml"] = "ï";
+			_g.h["eth"] = "ð";
+			_g.h["ntilde"] = "ñ";
+			_g.h["ograve"] = "ò";
+			_g.h["oacute"] = "ó";
+			_g.h["ocirc"] = "ô";
+			_g.h["otilde"] = "õ";
+			_g.h["ouml"] = "ö";
+			_g.h["divide"] = "÷";
+			_g.h["oslash"] = "ø";
+			_g.h["ugrave"] = "ù";
+			_g.h["uacute"] = "ú";
+			_g.h["ucirc"] = "û";
+			_g.h["uuml"] = "ü";
+			_g.h["yacute"] = "ý";
+			_g.h["thorn"] = "þ";
+			htmlparser_HtmlTools.htmlUnescapeMap = _g;
+		}
+		return htmlparser_HtmlTools.htmlUnescapeMap;
+	}
+	static escape(text,chars) {
+		if(chars == null) {
+			chars = "";
+		}
+		let r = text.split("&").join("&amp;");
+		r = r.split("<").join("&lt;");
+		r = r.split(">").join("&gt;");
+		if(chars.indexOf("\"") >= 0) {
+			r = r.split("\"").join("&quot;");
+		}
+		if(chars.indexOf("'") >= 0) {
+			r = r.split("'").join("&apos;");
+		}
+		if(chars.indexOf(" ") >= 0) {
+			r = r.split(" ").join("&nbsp;");
+		}
+		if(chars.indexOf("\n") >= 0) {
+			r = r.split("\n").join("&#xA;");
+		}
+		if(chars.indexOf("\r") >= 0) {
+			r = r.split("\r").join("&#xD;");
+		}
+		return r;
+	}
+	static unescape(text) {
+		return new EReg("[<]!\\[CDATA\\[((?:.|[\r\n])*?)\\]\\][>]|&[^;]+;","g").map(text,function(re) {
+			let s = re.matched(0);
+			if(s.charAt(0) == "&") {
+				if(s.charAt(1) == "#") {
+					let numbers = s.substring(2,s.length - 1);
+					if(numbers.charAt(0) == "x") {
+						numbers = "0" + numbers;
+					}
+					let code = Std.parseInt(numbers);
+					if(code != null && code != 0) {
+						return String.fromCodePoint(code);
+					} else {
+						return s;
+					}
+				} else {
+					let r = htmlparser_HtmlTools.get_htmlUnescapeMap().h[s.substring(1,s.length - 1)];
+					if(r != null) {
+						return r;
+					} else {
+						return s;
+					}
+				}
+			}
+			return re.matched(1);
+		});
+	}
+}
+htmlparser_HtmlTools.__name__ = "htmlparser.HtmlTools";
+class httpstatus_HttpStatusCode {
+	static toMessage(this1) {
+		return httpstatus_HttpStatusMessage.fromCode(this1);
+	}
+	static toInt(this1) {
+		return this1;
+	}
+	static fromErrorCode(code) {
+		return code;
+	}
+	static toOutgoingResponse(this1) {
+		return new tink_http__$Response_OutgoingResponseData(new tink_http_ResponseHeaderBase(this1,httpstatus_HttpStatusMessage.fromCode(this1),[new tink_http_HeaderField("content-length","0")],"HTTP/1.1"),tink_io_Source.EMPTY);
+	}
+	static fromIncomingResponse(res) {
+		return res.header.statusCode;
+	}
+}
+class httpstatus_HttpStatusMessage {
+	static _new(statusCode) {
+		return httpstatus_HttpStatusMessage.fromCode(statusCode);
+	}
+	static fromCode(statusCode) {
+		switch(statusCode) {
+		case 100:
+			return "Continue";
+		case 101:
+			return "Switching Protocols";
+		case 102:
+			return "Processing";
+		case 200:
+			return "OK";
+		case 201:
+			return "Created";
+		case 202:
+			return "Accepted";
+		case 203:
+			return "Non-Authoritative Information";
+		case 204:
+			return "No Content";
+		case 205:
+			return "Reset Content";
+		case 206:
+			return "Partial Content";
+		case 207:
+			return "Multi-Status";
+		case 208:
+			return "Already Reported";
+		case 226:
+			return "IM Used";
+		case 300:
+			return "Multiple Choices";
+		case 301:
+			return "Moved Permanently";
+		case 302:
+			return "Found";
+		case 303:
+			return "See Other";
+		case 304:
+			return "Not Modified";
+		case 305:
+			return "Use Proxy";
+		case 306:
+			return "Switch Proxy";
+		case 307:
+			return "Temporary Redirect";
+		case 308:
+			return "Permanent Redirect";
+		case 400:
+			return "Bad Request";
+		case 401:
+			return "Unauthorized";
+		case 402:
+			return "Payment Required";
+		case 403:
+			return "Forbidden";
+		case 404:
+			return "Not Found";
+		case 405:
+			return "Method Not Allowed";
+		case 406:
+			return "Not Acceptable";
+		case 407:
+			return "Proxy Authentication Required";
+		case 408:
+			return "Request Timeout";
+		case 409:
+			return "Conflict";
+		case 410:
+			return "Gone";
+		case 411:
+			return "Length Required";
+		case 412:
+			return "Precondition Failed";
+		case 413:
+			return "Payload Too Large";
+		case 414:
+			return "URI Too Long";
+		case 415:
+			return "Unsupported Media Type";
+		case 416:
+			return "Range Not Satisfiable";
+		case 417:
+			return "Expectation Failed";
+		case 418:
+			return "I'm a teapot";
+		case 421:
+			return "Misdirected Request";
+		case 422:
+			return "Unprocessable Entity";
+		case 423:
+			return "Locked";
+		case 424:
+			return "Failed Dependency";
+		case 426:
+			return "Upgrade Required";
+		case 428:
+			return "Precondition Required";
+		case 429:
+			return "Too Many Requests";
+		case 431:
+			return "Request Header Fields Too Large";
+		case 451:
+			return "Unavailable For Legal Reasons";
+		case 500:
+			return "Internal Server Error";
+		case 501:
+			return "Not Implemented";
+		case 502:
+			return "Bad Gateway";
+		case 503:
+			return "Service Unavailable";
+		case 504:
+			return "Gateway Timeout";
+		case 505:
+			return "HTTP Version Not Supported";
+		case 506:
+			return "Variant Also Negotiates";
+		case 507:
+			return "Insufficient Storage";
+		case 508:
+			return "Loop Detected";
+		case 510:
+			return "Not Extended";
+		case 511:
+			return "Network Authentication Required";
+		default:
+			return "Unknown Status";
+		}
+	}
+}
+class hx_strings_AnyAsString {
+	static fromBool(value) {
+		if(value) {
+			return "true";
+		} else {
+			return "false";
+		}
+	}
+	static fromAny(value) {
+		return Std.string(value);
+	}
+}
+class hx_strings__$Char_CharCaseMapper {
+	constructor() {
+		this.mapL2U = new haxe_ds_IntMap();
+		this.mapU2L = new haxe_ds_IntMap();
+		this._addCaseMapping(97,65);
+		this._addCaseMapping(98,66);
+		this._addCaseMapping(99,67);
+		this._addCaseMapping(100,68);
+		this._addCaseMapping(101,69);
+		this._addCaseMapping(102,70);
+		this._addCaseMapping(103,71);
+		this._addCaseMapping(104,72);
+		this._addCaseMapping(105,73);
+		this._addCaseMapping(106,74);
+		this._addCaseMapping(107,75);
+		this._addCaseMapping(108,76);
+		this._addCaseMapping(109,77);
+		this._addCaseMapping(110,78);
+		this._addCaseMapping(111,79);
+		this._addCaseMapping(112,80);
+		this._addCaseMapping(113,81);
+		this._addCaseMapping(114,82);
+		this._addCaseMapping(115,83);
+		this._addCaseMapping(116,84);
+		this._addCaseMapping(117,85);
+		this._addCaseMapping(118,86);
+		this._addCaseMapping(119,87);
+		this._addCaseMapping(120,88);
+		this._addCaseMapping(121,89);
+		this._addCaseMapping(122,90);
+		this._addCaseMapping(224,192);
+		this._addCaseMapping(225,193);
+		this._addCaseMapping(226,194);
+		this._addCaseMapping(227,195);
+		this._addCaseMapping(228,196);
+		this._addCaseMapping(229,197);
+		this._addCaseMapping(230,198);
+		this._addCaseMapping(231,199);
+		this._addCaseMapping(232,200);
+		this._addCaseMapping(233,201);
+		this._addCaseMapping(234,202);
+		this._addCaseMapping(235,203);
+		this._addCaseMapping(236,204);
+		this._addCaseMapping(237,205);
+		this._addCaseMapping(238,206);
+		this._addCaseMapping(239,207);
+		this._addCaseMapping(240,208);
+		this._addCaseMapping(241,209);
+		this._addCaseMapping(242,210);
+		this._addCaseMapping(243,211);
+		this._addCaseMapping(244,212);
+		this._addCaseMapping(245,213);
+		this._addCaseMapping(246,214);
+		this._addCaseMapping(248,216);
+		this._addCaseMapping(249,217);
+		this._addCaseMapping(250,218);
+		this._addCaseMapping(251,219);
+		this._addCaseMapping(252,220);
+		this._addCaseMapping(253,221);
+		this._addCaseMapping(254,222);
+		this._addCaseMapping(255,376);
+		this._addCaseMapping(257,256);
+		this._addCaseMapping(259,258);
+		this._addCaseMapping(261,260);
+		this._addCaseMapping(263,262);
+		this._addCaseMapping(265,264);
+		this._addCaseMapping(267,266);
+		this._addCaseMapping(269,268);
+		this._addCaseMapping(271,270);
+		this._addCaseMapping(273,272);
+		this._addCaseMapping(275,274);
+		this._addCaseMapping(277,276);
+		this._addCaseMapping(279,278);
+		this._addCaseMapping(281,280);
+		this._addCaseMapping(283,282);
+		this._addCaseMapping(285,284);
+		this._addCaseMapping(287,286);
+		this._addCaseMapping(289,288);
+		this._addCaseMapping(291,290);
+		this._addCaseMapping(293,292);
+		this._addCaseMapping(295,294);
+		this._addCaseMapping(297,296);
+		this._addCaseMapping(299,298);
+		this._addCaseMapping(301,300);
+		this._addCaseMapping(303,302);
+		this._addCaseMapping(305,73);
+		this._addCaseMapping(307,306);
+		this._addCaseMapping(309,308);
+		this._addCaseMapping(311,310);
+		this._addCaseMapping(314,313);
+		this._addCaseMapping(316,315);
+		this._addCaseMapping(318,317);
+		this._addCaseMapping(320,319);
+		this._addCaseMapping(322,321);
+		this._addCaseMapping(324,323);
+		this._addCaseMapping(326,325);
+		this._addCaseMapping(328,327);
+		this._addCaseMapping(331,330);
+		this._addCaseMapping(333,332);
+		this._addCaseMapping(335,334);
+		this._addCaseMapping(337,336);
+		this._addCaseMapping(339,338);
+		this._addCaseMapping(341,340);
+		this._addCaseMapping(343,342);
+		this._addCaseMapping(345,344);
+		this._addCaseMapping(347,346);
+		this._addCaseMapping(349,348);
+		this._addCaseMapping(351,350);
+		this._addCaseMapping(353,352);
+		this._addCaseMapping(355,354);
+		this._addCaseMapping(357,356);
+		this._addCaseMapping(359,358);
+		this._addCaseMapping(361,360);
+		this._addCaseMapping(363,362);
+		this._addCaseMapping(365,364);
+		this._addCaseMapping(367,366);
+		this._addCaseMapping(369,368);
+		this._addCaseMapping(371,370);
+		this._addCaseMapping(373,372);
+		this._addCaseMapping(375,374);
+		this._addCaseMapping(378,377);
+		this._addCaseMapping(380,379);
+		this._addCaseMapping(382,381);
+		this._addCaseMapping(387,386);
+		this._addCaseMapping(389,388);
+		this._addCaseMapping(392,391);
+		this._addCaseMapping(396,395);
+		this._addCaseMapping(402,401);
+		this._addCaseMapping(409,408);
+		this._addCaseMapping(417,416);
+		this._addCaseMapping(419,418);
+		this._addCaseMapping(421,420);
+		this._addCaseMapping(424,423);
+		this._addCaseMapping(429,428);
+		this._addCaseMapping(432,431);
+		this._addCaseMapping(436,435);
+		this._addCaseMapping(438,437);
+		this._addCaseMapping(441,440);
+		this._addCaseMapping(445,444);
+		this._addCaseMapping(454,452);
+		this._addCaseMapping(457,455);
+		this._addCaseMapping(460,458);
+		this._addCaseMapping(462,461);
+		this._addCaseMapping(464,463);
+		this._addCaseMapping(466,465);
+		this._addCaseMapping(468,467);
+		this._addCaseMapping(470,469);
+		this._addCaseMapping(472,471);
+		this._addCaseMapping(474,473);
+		this._addCaseMapping(476,475);
+		this._addCaseMapping(479,478);
+		this._addCaseMapping(481,480);
+		this._addCaseMapping(483,482);
+		this._addCaseMapping(485,484);
+		this._addCaseMapping(487,486);
+		this._addCaseMapping(489,488);
+		this._addCaseMapping(491,490);
+		this._addCaseMapping(493,492);
+		this._addCaseMapping(495,494);
+		this._addCaseMapping(499,497);
+		this._addCaseMapping(501,500);
+		this._addCaseMapping(507,506);
+		this._addCaseMapping(509,508);
+		this._addCaseMapping(511,510);
+		this._addCaseMapping(513,512);
+		this._addCaseMapping(515,514);
+		this._addCaseMapping(517,516);
+		this._addCaseMapping(519,518);
+		this._addCaseMapping(521,520);
+		this._addCaseMapping(523,522);
+		this._addCaseMapping(525,524);
+		this._addCaseMapping(527,526);
+		this._addCaseMapping(529,528);
+		this._addCaseMapping(531,530);
+		this._addCaseMapping(533,532);
+		this._addCaseMapping(535,534);
+		this._addCaseMapping(595,385);
+		this._addCaseMapping(596,390);
+		this._addCaseMapping(599,394);
+		this._addCaseMapping(600,398);
+		this._addCaseMapping(601,399);
+		this._addCaseMapping(603,400);
+		this._addCaseMapping(608,403);
+		this._addCaseMapping(611,404);
+		this._addCaseMapping(616,407);
+		this._addCaseMapping(617,406);
+		this._addCaseMapping(623,412);
+		this._addCaseMapping(626,413);
+		this._addCaseMapping(629,415);
+		this._addCaseMapping(643,425);
+		this._addCaseMapping(648,430);
+		this._addCaseMapping(650,433);
+		this._addCaseMapping(651,434);
+		this._addCaseMapping(658,439);
+		this._addCaseMapping(924,181);
+		this._addCaseMapping(940,902);
+		this._addCaseMapping(941,904);
+		this._addCaseMapping(942,905);
+		this._addCaseMapping(943,906);
+		this._addCaseMapping(945,913);
+		this._addCaseMapping(946,914);
+		this._addCaseMapping(947,915);
+		this._addCaseMapping(948,916);
+		this._addCaseMapping(949,917);
+		this._addCaseMapping(950,918);
+		this._addCaseMapping(951,919);
+		this._addCaseMapping(952,920);
+		this._addCaseMapping(953,921);
+		this._addCaseMapping(954,922);
+		this._addCaseMapping(955,923);
+		this._addCaseMapping(956,924);
+		this._addCaseMapping(957,925);
+		this._addCaseMapping(958,926);
+		this._addCaseMapping(959,927);
+		this._addCaseMapping(960,928);
+		this._addCaseMapping(961,929);
+		this._addCaseMapping(963,931);
+		this._addCaseMapping(964,932);
+		this._addCaseMapping(965,933);
+		this._addCaseMapping(966,934);
+		this._addCaseMapping(967,935);
+		this._addCaseMapping(968,936);
+		this._addCaseMapping(969,937);
+		this._addCaseMapping(970,938);
+		this._addCaseMapping(971,939);
+		this._addCaseMapping(972,908);
+		this._addCaseMapping(973,910);
+		this._addCaseMapping(974,911);
+		this._addCaseMapping(995,994);
+		this._addCaseMapping(997,996);
+		this._addCaseMapping(999,998);
+		this._addCaseMapping(1001,1000);
+		this._addCaseMapping(1003,1002);
+		this._addCaseMapping(1005,1004);
+		this._addCaseMapping(1007,1006);
+		this._addCaseMapping(1072,1040);
+		this._addCaseMapping(1073,1041);
+		this._addCaseMapping(1074,1042);
+		this._addCaseMapping(1075,1043);
+		this._addCaseMapping(1076,1044);
+		this._addCaseMapping(1077,1045);
+		this._addCaseMapping(1078,1046);
+		this._addCaseMapping(1079,1047);
+		this._addCaseMapping(1080,1048);
+		this._addCaseMapping(1081,1049);
+		this._addCaseMapping(1082,1050);
+		this._addCaseMapping(1083,1051);
+		this._addCaseMapping(1084,1052);
+		this._addCaseMapping(1085,1053);
+		this._addCaseMapping(1086,1054);
+		this._addCaseMapping(1087,1055);
+		this._addCaseMapping(1088,1056);
+		this._addCaseMapping(1089,1057);
+		this._addCaseMapping(1090,1058);
+		this._addCaseMapping(1091,1059);
+		this._addCaseMapping(1092,1060);
+		this._addCaseMapping(1093,1061);
+		this._addCaseMapping(1094,1062);
+		this._addCaseMapping(1095,1063);
+		this._addCaseMapping(1096,1064);
+		this._addCaseMapping(1097,1065);
+		this._addCaseMapping(1098,1066);
+		this._addCaseMapping(1099,1067);
+		this._addCaseMapping(1100,1068);
+		this._addCaseMapping(1101,1069);
+		this._addCaseMapping(1102,1070);
+		this._addCaseMapping(1103,1071);
+		this._addCaseMapping(1105,1025);
+		this._addCaseMapping(1106,1026);
+		this._addCaseMapping(1107,1027);
+		this._addCaseMapping(1108,1028);
+		this._addCaseMapping(1109,1029);
+		this._addCaseMapping(1110,1030);
+		this._addCaseMapping(1111,1031);
+		this._addCaseMapping(1112,1032);
+		this._addCaseMapping(1113,1033);
+		this._addCaseMapping(1114,1034);
+		this._addCaseMapping(1115,1035);
+		this._addCaseMapping(1116,1036);
+		this._addCaseMapping(1118,1038);
+		this._addCaseMapping(1119,1039);
+		this._addCaseMapping(1121,1120);
+		this._addCaseMapping(1123,1122);
+		this._addCaseMapping(1125,1124);
+		this._addCaseMapping(1127,1126);
+		this._addCaseMapping(1129,1128);
+		this._addCaseMapping(1131,1130);
+		this._addCaseMapping(1133,1132);
+		this._addCaseMapping(1135,1134);
+		this._addCaseMapping(1137,1136);
+		this._addCaseMapping(1139,1138);
+		this._addCaseMapping(1141,1140);
+		this._addCaseMapping(1143,1142);
+		this._addCaseMapping(1145,1144);
+		this._addCaseMapping(1147,1146);
+		this._addCaseMapping(1149,1148);
+		this._addCaseMapping(1151,1150);
+		this._addCaseMapping(1153,1152);
+		this._addCaseMapping(1169,1168);
+		this._addCaseMapping(1171,1170);
+		this._addCaseMapping(1173,1172);
+		this._addCaseMapping(1175,1174);
+		this._addCaseMapping(1177,1176);
+		this._addCaseMapping(1179,1178);
+		this._addCaseMapping(1181,1180);
+		this._addCaseMapping(1183,1182);
+		this._addCaseMapping(1185,1184);
+		this._addCaseMapping(1187,1186);
+		this._addCaseMapping(1189,1188);
+		this._addCaseMapping(1191,1190);
+		this._addCaseMapping(1193,1192);
+		this._addCaseMapping(1195,1194);
+		this._addCaseMapping(1197,1196);
+		this._addCaseMapping(1199,1198);
+		this._addCaseMapping(1201,1200);
+		this._addCaseMapping(1203,1202);
+		this._addCaseMapping(1205,1204);
+		this._addCaseMapping(1207,1206);
+		this._addCaseMapping(1209,1208);
+		this._addCaseMapping(1211,1210);
+		this._addCaseMapping(1213,1212);
+		this._addCaseMapping(1215,1214);
+		this._addCaseMapping(1218,1217);
+		this._addCaseMapping(1220,1219);
+		this._addCaseMapping(1224,1223);
+		this._addCaseMapping(1228,1227);
+		this._addCaseMapping(1233,1232);
+		this._addCaseMapping(1235,1234);
+		this._addCaseMapping(1237,1236);
+		this._addCaseMapping(1239,1238);
+		this._addCaseMapping(1241,1240);
+		this._addCaseMapping(1243,1242);
+		this._addCaseMapping(1245,1244);
+		this._addCaseMapping(1247,1246);
+		this._addCaseMapping(1249,1248);
+		this._addCaseMapping(1251,1250);
+		this._addCaseMapping(1253,1252);
+		this._addCaseMapping(1255,1254);
+		this._addCaseMapping(1257,1256);
+		this._addCaseMapping(1259,1258);
+		this._addCaseMapping(1263,1262);
+		this._addCaseMapping(1265,1264);
+		this._addCaseMapping(1267,1266);
+		this._addCaseMapping(1269,1268);
+		this._addCaseMapping(1273,1272);
+		this._addCaseMapping(1377,1329);
+		this._addCaseMapping(1378,1330);
+		this._addCaseMapping(1379,1331);
+		this._addCaseMapping(1380,1332);
+		this._addCaseMapping(1381,1333);
+		this._addCaseMapping(1382,1334);
+		this._addCaseMapping(1383,1335);
+		this._addCaseMapping(1384,1336);
+		this._addCaseMapping(1385,1337);
+		this._addCaseMapping(1386,1338);
+		this._addCaseMapping(1387,1339);
+		this._addCaseMapping(1388,1340);
+		this._addCaseMapping(1389,1341);
+		this._addCaseMapping(1390,1342);
+		this._addCaseMapping(1391,1343);
+		this._addCaseMapping(1392,1344);
+		this._addCaseMapping(1393,1345);
+		this._addCaseMapping(1394,1346);
+		this._addCaseMapping(1395,1347);
+		this._addCaseMapping(1396,1348);
+		this._addCaseMapping(1397,1349);
+		this._addCaseMapping(1398,1350);
+		this._addCaseMapping(1399,1351);
+		this._addCaseMapping(1400,1352);
+		this._addCaseMapping(1401,1353);
+		this._addCaseMapping(1402,1354);
+		this._addCaseMapping(1403,1355);
+		this._addCaseMapping(1404,1356);
+		this._addCaseMapping(1405,1357);
+		this._addCaseMapping(1406,1358);
+		this._addCaseMapping(1407,1359);
+		this._addCaseMapping(1408,1360);
+		this._addCaseMapping(1409,1361);
+		this._addCaseMapping(1410,1362);
+		this._addCaseMapping(1411,1363);
+		this._addCaseMapping(1412,1364);
+		this._addCaseMapping(1413,1365);
+		this._addCaseMapping(1414,1366);
+		this._addCaseMapping(4304,4256);
+		this._addCaseMapping(4305,4257);
+		this._addCaseMapping(4306,4258);
+		this._addCaseMapping(4307,4259);
+		this._addCaseMapping(4308,4260);
+		this._addCaseMapping(4309,4261);
+		this._addCaseMapping(4310,4262);
+		this._addCaseMapping(4311,4263);
+		this._addCaseMapping(4312,4264);
+		this._addCaseMapping(4313,4265);
+		this._addCaseMapping(4314,4266);
+		this._addCaseMapping(4315,4267);
+		this._addCaseMapping(4316,4268);
+		this._addCaseMapping(4317,4269);
+		this._addCaseMapping(4318,4270);
+		this._addCaseMapping(4319,4271);
+		this._addCaseMapping(4320,4272);
+		this._addCaseMapping(4321,4273);
+		this._addCaseMapping(4322,4274);
+		this._addCaseMapping(4323,4275);
+		this._addCaseMapping(4324,4276);
+		this._addCaseMapping(4325,4277);
+		this._addCaseMapping(4326,4278);
+		this._addCaseMapping(4327,4279);
+		this._addCaseMapping(4328,4280);
+		this._addCaseMapping(4329,4281);
+		this._addCaseMapping(4330,4282);
+		this._addCaseMapping(4331,4283);
+		this._addCaseMapping(4332,4284);
+		this._addCaseMapping(4333,4285);
+		this._addCaseMapping(4334,4286);
+		this._addCaseMapping(4335,4287);
+		this._addCaseMapping(4336,4288);
+		this._addCaseMapping(4337,4289);
+		this._addCaseMapping(4338,4290);
+		this._addCaseMapping(4339,4291);
+		this._addCaseMapping(4340,4292);
+		this._addCaseMapping(4341,4293);
+		this._addCaseMapping(7681,7680);
+		this._addCaseMapping(7683,7682);
+		this._addCaseMapping(7685,7684);
+		this._addCaseMapping(7687,7686);
+		this._addCaseMapping(7689,7688);
+		this._addCaseMapping(7691,7690);
+		this._addCaseMapping(7693,7692);
+		this._addCaseMapping(7695,7694);
+		this._addCaseMapping(7697,7696);
+		this._addCaseMapping(7699,7698);
+		this._addCaseMapping(7701,7700);
+		this._addCaseMapping(7703,7702);
+		this._addCaseMapping(7705,7704);
+		this._addCaseMapping(7707,7706);
+		this._addCaseMapping(7709,7708);
+		this._addCaseMapping(7711,7710);
+		this._addCaseMapping(7713,7712);
+		this._addCaseMapping(7715,7714);
+		this._addCaseMapping(7717,7716);
+		this._addCaseMapping(7719,7718);
+		this._addCaseMapping(7721,7720);
+		this._addCaseMapping(7723,7722);
+		this._addCaseMapping(7725,7724);
+		this._addCaseMapping(7727,7726);
+		this._addCaseMapping(7729,7728);
+		this._addCaseMapping(7731,7730);
+		this._addCaseMapping(7733,7732);
+		this._addCaseMapping(7735,7734);
+		this._addCaseMapping(7737,7736);
+		this._addCaseMapping(7739,7738);
+		this._addCaseMapping(7741,7740);
+		this._addCaseMapping(7743,7742);
+		this._addCaseMapping(7745,7744);
+		this._addCaseMapping(7747,7746);
+		this._addCaseMapping(7749,7748);
+		this._addCaseMapping(7751,7750);
+		this._addCaseMapping(7753,7752);
+		this._addCaseMapping(7755,7754);
+		this._addCaseMapping(7757,7756);
+		this._addCaseMapping(7759,7758);
+		this._addCaseMapping(7761,7760);
+		this._addCaseMapping(7763,7762);
+		this._addCaseMapping(7765,7764);
+		this._addCaseMapping(7767,7766);
+		this._addCaseMapping(7769,7768);
+		this._addCaseMapping(7771,7770);
+		this._addCaseMapping(7773,7772);
+		this._addCaseMapping(7775,7774);
+		this._addCaseMapping(7777,7776);
+		this._addCaseMapping(7779,7778);
+		this._addCaseMapping(7781,7780);
+		this._addCaseMapping(7783,7782);
+		this._addCaseMapping(7785,7784);
+		this._addCaseMapping(7787,7786);
+		this._addCaseMapping(7789,7788);
+		this._addCaseMapping(7791,7790);
+		this._addCaseMapping(7793,7792);
+		this._addCaseMapping(7795,7794);
+		this._addCaseMapping(7797,7796);
+		this._addCaseMapping(7799,7798);
+		this._addCaseMapping(7801,7800);
+		this._addCaseMapping(7803,7802);
+		this._addCaseMapping(7805,7804);
+		this._addCaseMapping(7807,7806);
+		this._addCaseMapping(7809,7808);
+		this._addCaseMapping(7811,7810);
+		this._addCaseMapping(7813,7812);
+		this._addCaseMapping(7815,7814);
+		this._addCaseMapping(7817,7816);
+		this._addCaseMapping(7819,7818);
+		this._addCaseMapping(7821,7820);
+		this._addCaseMapping(7823,7822);
+		this._addCaseMapping(7825,7824);
+		this._addCaseMapping(7827,7826);
+		this._addCaseMapping(7829,7828);
+		this._addCaseMapping(7841,7840);
+		this._addCaseMapping(7843,7842);
+		this._addCaseMapping(7845,7844);
+		this._addCaseMapping(7847,7846);
+		this._addCaseMapping(7849,7848);
+		this._addCaseMapping(7851,7850);
+		this._addCaseMapping(7853,7852);
+		this._addCaseMapping(7855,7854);
+		this._addCaseMapping(7857,7856);
+		this._addCaseMapping(7859,7858);
+		this._addCaseMapping(7861,7860);
+		this._addCaseMapping(7863,7862);
+		this._addCaseMapping(7865,7864);
+		this._addCaseMapping(7867,7866);
+		this._addCaseMapping(7869,7868);
+		this._addCaseMapping(7871,7870);
+		this._addCaseMapping(7873,7872);
+		this._addCaseMapping(7875,7874);
+		this._addCaseMapping(7877,7876);
+		this._addCaseMapping(7879,7878);
+		this._addCaseMapping(7881,7880);
+		this._addCaseMapping(7883,7882);
+		this._addCaseMapping(7885,7884);
+		this._addCaseMapping(7887,7886);
+		this._addCaseMapping(7889,7888);
+		this._addCaseMapping(7891,7890);
+		this._addCaseMapping(7893,7892);
+		this._addCaseMapping(7895,7894);
+		this._addCaseMapping(7897,7896);
+		this._addCaseMapping(7899,7898);
+		this._addCaseMapping(7901,7900);
+		this._addCaseMapping(7903,7902);
+		this._addCaseMapping(7905,7904);
+		this._addCaseMapping(7907,7906);
+		this._addCaseMapping(7909,7908);
+		this._addCaseMapping(7911,7910);
+		this._addCaseMapping(7913,7912);
+		this._addCaseMapping(7915,7914);
+		this._addCaseMapping(7917,7916);
+		this._addCaseMapping(7919,7918);
+		this._addCaseMapping(7921,7920);
+		this._addCaseMapping(7923,7922);
+		this._addCaseMapping(7925,7924);
+		this._addCaseMapping(7927,7926);
+		this._addCaseMapping(7929,7928);
+		this._addCaseMapping(7936,7944);
+		this._addCaseMapping(7937,7945);
+		this._addCaseMapping(7938,7946);
+		this._addCaseMapping(7939,7947);
+		this._addCaseMapping(7940,7948);
+		this._addCaseMapping(7941,7949);
+		this._addCaseMapping(7942,7950);
+		this._addCaseMapping(7943,7951);
+		this._addCaseMapping(7952,7960);
+		this._addCaseMapping(7953,7961);
+		this._addCaseMapping(7954,7962);
+		this._addCaseMapping(7955,7963);
+		this._addCaseMapping(7956,7964);
+		this._addCaseMapping(7957,7965);
+		this._addCaseMapping(7968,7976);
+		this._addCaseMapping(7969,7977);
+		this._addCaseMapping(7970,7978);
+		this._addCaseMapping(7971,7979);
+		this._addCaseMapping(7972,7980);
+		this._addCaseMapping(7973,7981);
+		this._addCaseMapping(7974,7982);
+		this._addCaseMapping(7975,7983);
+		this._addCaseMapping(7984,7992);
+		this._addCaseMapping(7985,7993);
+		this._addCaseMapping(7986,7994);
+		this._addCaseMapping(7987,7995);
+		this._addCaseMapping(7988,7996);
+		this._addCaseMapping(7989,7997);
+		this._addCaseMapping(7990,7998);
+		this._addCaseMapping(7991,7999);
+		this._addCaseMapping(8000,8008);
+		this._addCaseMapping(8001,8009);
+		this._addCaseMapping(8002,8010);
+		this._addCaseMapping(8003,8011);
+		this._addCaseMapping(8004,8012);
+		this._addCaseMapping(8005,8013);
+		this._addCaseMapping(8017,8025);
+		this._addCaseMapping(8019,8027);
+		this._addCaseMapping(8021,8029);
+		this._addCaseMapping(8023,8031);
+		this._addCaseMapping(8032,8040);
+		this._addCaseMapping(8033,8041);
+		this._addCaseMapping(8034,8042);
+		this._addCaseMapping(8035,8043);
+		this._addCaseMapping(8036,8044);
+		this._addCaseMapping(8037,8045);
+		this._addCaseMapping(8038,8046);
+		this._addCaseMapping(8039,8047);
+		this._addCaseMapping(8064,8072);
+		this._addCaseMapping(8065,8073);
+		this._addCaseMapping(8066,8074);
+		this._addCaseMapping(8067,8075);
+		this._addCaseMapping(8068,8076);
+		this._addCaseMapping(8069,8077);
+		this._addCaseMapping(8070,8078);
+		this._addCaseMapping(8071,8079);
+		this._addCaseMapping(8080,8088);
+		this._addCaseMapping(8081,8089);
+		this._addCaseMapping(8082,8090);
+		this._addCaseMapping(8083,8091);
+		this._addCaseMapping(8084,8092);
+		this._addCaseMapping(8085,8093);
+		this._addCaseMapping(8086,8094);
+		this._addCaseMapping(8087,8095);
+		this._addCaseMapping(8096,8104);
+		this._addCaseMapping(8097,8105);
+		this._addCaseMapping(8098,8106);
+		this._addCaseMapping(8099,8107);
+		this._addCaseMapping(8100,8108);
+		this._addCaseMapping(8101,8109);
+		this._addCaseMapping(8102,8110);
+		this._addCaseMapping(8103,8111);
+		this._addCaseMapping(8112,8120);
+		this._addCaseMapping(8113,8121);
+		this._addCaseMapping(8144,8152);
+		this._addCaseMapping(8145,8153);
+		this._addCaseMapping(8160,8168);
+		this._addCaseMapping(8161,8169);
+		this._addCaseMapping(9424,9398);
+		this._addCaseMapping(9425,9399);
+		this._addCaseMapping(9426,9400);
+		this._addCaseMapping(9427,9401);
+		this._addCaseMapping(9428,9402);
+		this._addCaseMapping(9429,9403);
+		this._addCaseMapping(9430,9404);
+		this._addCaseMapping(9431,9405);
+		this._addCaseMapping(9432,9406);
+		this._addCaseMapping(9433,9407);
+		this._addCaseMapping(9434,9408);
+		this._addCaseMapping(9435,9409);
+		this._addCaseMapping(9436,9410);
+		this._addCaseMapping(9437,9411);
+		this._addCaseMapping(9438,9412);
+		this._addCaseMapping(9439,9413);
+		this._addCaseMapping(9440,9414);
+		this._addCaseMapping(9441,9415);
+		this._addCaseMapping(9442,9416);
+		this._addCaseMapping(9443,9417);
+		this._addCaseMapping(9444,9418);
+		this._addCaseMapping(9445,9419);
+		this._addCaseMapping(9446,9420);
+		this._addCaseMapping(9447,9421);
+		this._addCaseMapping(9448,9422);
+		this._addCaseMapping(9449,9423);
+		this._addCaseMapping(65345,65313);
+		this._addCaseMapping(65346,65314);
+		this._addCaseMapping(65347,65315);
+		this._addCaseMapping(65348,65316);
+		this._addCaseMapping(65349,65317);
+		this._addCaseMapping(65350,65318);
+		this._addCaseMapping(65351,65319);
+		this._addCaseMapping(65352,65320);
+		this._addCaseMapping(65353,65321);
+		this._addCaseMapping(65354,65322);
+		this._addCaseMapping(65355,65323);
+		this._addCaseMapping(65356,65324);
+		this._addCaseMapping(65357,65325);
+		this._addCaseMapping(65358,65326);
+		this._addCaseMapping(65359,65327);
+		this._addCaseMapping(65360,65328);
+		this._addCaseMapping(65361,65329);
+		this._addCaseMapping(65362,65330);
+		this._addCaseMapping(65363,65331);
+		this._addCaseMapping(65364,65332);
+		this._addCaseMapping(65365,65333);
+		this._addCaseMapping(65366,65334);
+		this._addCaseMapping(65367,65335);
+		this._addCaseMapping(65368,65336);
+		this._addCaseMapping(65369,65337);
+		this._addCaseMapping(65370,65338);
+	}
+	_addCaseMapping(lowerChar,upperChar) {
+		if(!this.mapU2L.h.hasOwnProperty(upperChar)) {
+			this.mapU2L.h[upperChar] = lowerChar;
+		}
+		if(!this.mapL2U.h.hasOwnProperty(lowerChar)) {
+			this.mapL2U.h[lowerChar] = upperChar;
+		}
+	}
+	isLowerCase(ch) {
+		return this.mapL2U.h.hasOwnProperty(ch);
+	}
+	isUpperCase(ch) {
+		return this.mapU2L.h.hasOwnProperty(ch);
+	}
+	toLowerCase(ch) {
+		let lowerChar = this.mapU2L.h[ch];
+		if(lowerChar == null) {
+			return ch;
+		} else {
+			return lowerChar;
+		}
+	}
+	toUpperCase(ch) {
+		let upperChar = this.mapL2U.h[ch];
+		if(upperChar == null) {
+			return ch;
+		} else {
+			return upperChar;
+		}
+	}
+}
+hx_strings__$Char_CharCaseMapper.__name__ = "hx.strings._Char.CharCaseMapper";
+Object.assign(hx_strings__$Char_CharCaseMapper.prototype, {
+	__class__: hx_strings__$Char_CharCaseMapper
+});
+class hx_strings_Char {
+	static fromString(str) {
+		return hx_strings_Strings.charCodeAt8(str,0);
+	}
+	static of(ch) {
+		return ch;
+	}
+	static op_plus_string(ch,other) {
+		return String.fromCodePoint(ch) + other;
+	}
+	static op_plus_string2(str,ch) {
+		return str + String.fromCodePoint(ch);
+	}
+	static op_plus(ch,other) {
+		return ch + other;
+	}
+	static isAscii(this1) {
+		if(this1 > -1) {
+			return this1 < 128;
+		} else {
+			return false;
+		}
+	}
+	static isAsciiAlpha(this1) {
+		if(!(this1 > 64 && this1 < 91)) {
+			if(this1 > 96) {
+				return this1 < 123;
+			} else {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+	static isAsciiAlphanumeric(this1) {
+		if(!(this1 > 64 && this1 < 91 || this1 > 96 && this1 < 123)) {
+			if(this1 > 47) {
+				return this1 < 58;
+			} else {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+	static isAsciiControl(this1) {
+		if(!(this1 > -1 && this1 < 32)) {
+			return this1 == 127;
+		} else {
+			return true;
+		}
+	}
+	static isAsciiPrintable(this1) {
+		if(this1 > 31) {
+			return this1 < 127;
+		} else {
+			return false;
+		}
+	}
+	static isDigit(this1) {
+		if(this1 > 47) {
+			return this1 < 58;
+		} else {
+			return false;
+		}
+	}
+	static isEOF(this1) {
+		return this1 != this1;
+	}
+	static isSpace(this1) {
+		return this1 == 32;
+	}
+	static isUTF8(this1) {
+		if(this1 > -1) {
+			return this1 < 1114112;
+		} else {
+			return false;
+		}
+	}
+	static isWhitespace(this1) {
+		if(!(this1 > 8 && this1 < 14)) {
+			return this1 == 32;
+		} else {
+			return true;
+		}
+	}
+	static isLowerCase(this1) {
+		return hx_strings_Char.CHAR_CASE_MAPPER.mapL2U.h.hasOwnProperty(this1);
+	}
+	static isUpperCase(this1) {
+		return hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(this1);
+	}
+	static toLowerCase(this1) {
+		let lowerChar = hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h[this1];
+		if(lowerChar == null) {
+			return this1;
+		} else {
+			return lowerChar;
+		}
+	}
+	static toUpperCase(this1) {
+		let upperChar = hx_strings_Char.CHAR_CASE_MAPPER.mapL2U.h[this1];
+		if(upperChar == null) {
+			return this1;
+		} else {
+			return upperChar;
+		}
+	}
+	static toInt(this1) {
+		return this1;
+	}
+	static toString(this1) {
+		return String.fromCodePoint(this1);
+	}
+}
+class hx_strings_CharIterator {
+	constructor(prevBufferSize) {
+		if(hx_strings_CharIterator._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(prevBufferSize);
+	}
+	_hx_constructor(prevBufferSize) {
+		this.prevBufferNextIdx = -1;
+		this.prevBufferPrevIdx = -1;
+		this.currChar = -1;
+		this.col = 0;
+		this.line = 0;
+		this.index = -1;
+		this.prevBuffer = prevBufferSize > 0 ? new hx_strings_internal__$RingBuffer_RingBufferImpl(prevBufferSize + 1) : null;
+	}
+	get_prevBufferLength() {
+		return this.prevBuffer.length;
+	}
+	get_current() {
+		if(this.index > -1) {
+			return this.currChar;
+		} else {
+			return null;
+		}
+	}
+	get_pos() {
+		return new hx_strings_CharPos(this.index,this.line,this.col);
+	}
+	hasPrev() {
+		return this.prevBufferPrevIdx > -1;
+	}
+	prev() {
+		if(this.prevBufferPrevIdx <= -1) {
+			throw haxe_Exception.thrown(new haxe_io_Eof());
+		}
+		let prevChar = this.prevBuffer.get(this.prevBufferPrevIdx);
+		this.currChar = prevChar.char;
+		this.index = prevChar.index;
+		this.line = prevChar.line;
+		this.col = prevChar.col;
+		this.prevBufferNextIdx = this.prevBufferPrevIdx + 1 < this.prevBuffer.length ? this.prevBufferPrevIdx + 1 : -1;
+		this.prevBufferPrevIdx--;
+		return this.currChar;
+	}
+	hasNext() {
+		if(this.prevBufferNextIdx > -1) {
+			return true;
+		} else {
+			return !this.isEOF();
+		}
+	}
+	next() {
+		if(this.prevBufferNextIdx > -1) {
+			let prevChar = this.prevBuffer.get(this.prevBufferNextIdx);
+			this.currChar = prevChar.char;
+			this.index = prevChar.index;
+			this.line = prevChar.line;
+			this.col = prevChar.col;
+			this.prevBufferPrevIdx = this.prevBufferNextIdx - 1;
+			this.prevBufferNextIdx = this.prevBufferNextIdx + 1 < this.prevBuffer.length ? this.prevBufferNextIdx + 1 : -1;
+			return this.currChar;
+		}
+		if(this.isEOF()) {
+			throw haxe_Exception.thrown(new haxe_io_Eof());
+		}
+		if(this.currChar == 10 || this.currChar < 0) {
+			this.line++;
+			this.col = 0;
+		}
+		this.index++;
+		this.col++;
+		this.currChar = this.getChar();
+		if(this.prevBuffer != null) {
+			this.prevBuffer.add(new hx_strings__$CharIterator_CharWithPos(this.currChar,this.index,this.col,this.line));
+			this.prevBufferPrevIdx = this.prevBuffer.length - 2;
+			this.prevBufferNextIdx = -1;
+		}
+		return this.currChar;
+	}
+	getChar() {
+		throw haxe_Exception.thrown("Not implemented");
+	}
+	isEOF() {
+		throw haxe_Exception.thrown("Not implemented");
+	}
+	static fromString(chars,prevBufferSize) {
+		if(prevBufferSize == null) {
+			prevBufferSize = 0;
+		}
+		if(chars == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		}
+		return new hx_strings__$CharIterator_StringCharIterator(chars,prevBufferSize);
+	}
+	static fromArray(chars,prevBufferSize) {
+		if(prevBufferSize == null) {
+			prevBufferSize = 0;
+		}
+		if(chars == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		}
+		return new hx_strings__$CharIterator_ArrayCharIterator(chars,prevBufferSize);
+	}
+	static fromInput(chars,prevBufferSize) {
+		if(prevBufferSize == null) {
+			prevBufferSize = 0;
+		}
+		if(chars == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		}
+		return new hx_strings__$CharIterator_InputCharIterator(chars,prevBufferSize);
+	}
+	static fromIterator(chars,prevBufferSize) {
+		if(prevBufferSize == null) {
+			prevBufferSize = 0;
+		}
+		if(chars == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		}
+		return new hx_strings__$CharIterator_IteratorCharIterator(chars,prevBufferSize);
+	}
+}
+hx_strings_CharIterator.__name__ = "hx.strings.CharIterator";
+Object.assign(hx_strings_CharIterator.prototype, {
+	__class__: hx_strings_CharIterator
+});
+class hx_strings_CharPos {
+	constructor(index,line,col) {
+		this.index = index;
+		this.line = line;
+		this.col = col;
+	}
+	toString() {
+		return "CharPos[index=" + this.index + ", line=" + this.line + ", col=" + this.col + "]";
+	}
+}
+hx_strings_CharPos.__name__ = "hx.strings.CharPos";
+Object.assign(hx_strings_CharPos.prototype, {
+	__class__: hx_strings_CharPos
+});
+class hx_strings__$CharIterator_CharWithPos extends hx_strings_CharPos {
+	constructor(char,index,line,col) {
+		super(index,line,col);
+		this.char = char;
+	}
+}
+hx_strings__$CharIterator_CharWithPos.__name__ = "hx.strings._CharIterator.CharWithPos";
+hx_strings__$CharIterator_CharWithPos.__super__ = hx_strings_CharPos;
+Object.assign(hx_strings__$CharIterator_CharWithPos.prototype, {
+	__class__: hx_strings__$CharIterator_CharWithPos
+});
+class hx_strings_internal__$RingBuffer_RingBufferImpl {
+	constructor(size) {
+		this.length = 0;
+		this.bufferEndIdx = -1;
+		this.bufferStartIdx = 0;
+		if(size < 1) {
+			throw haxe_Exception.thrown("[size] must be > 0");
+		}
+		this.buffer = new Array(size);
+		this.size = size;
+		this.bufferMaxIdx = size - 1;
+	}
+	add(item) {
+		if(this.length == this.size) {
+			this.bufferEndIdx = this.bufferStartIdx;
+			this.bufferStartIdx++;
+			if(this.bufferStartIdx > this.bufferMaxIdx) {
+				this.bufferStartIdx = 0;
+			}
+		} else {
+			this.bufferEndIdx++;
+			this.length++;
+		}
+		this.buffer[this.bufferEndIdx] = item;
+	}
+	get(index) {
+		if(index < 0 || index > this.bufferMaxIdx) {
+			throw haxe_Exception.thrown("[index] " + index + " is out of bound");
+		}
+		let realIdx = this.bufferStartIdx + index;
+		if(realIdx > this.bufferMaxIdx) {
+			realIdx -= this.length;
+		}
+		return this.buffer[realIdx];
+	}
+	iterator() {
+		return new hx_strings_internal__$RingBuffer_RingBufferIterator(this);
+	}
+	toArray() {
+		let arr = [];
+		let i = this.iterator();
+		while(i.hasNext()) {
+			let i1 = i.next();
+			arr.push(i1);
+		}
+		return arr;
+	}
+}
+hx_strings_internal__$RingBuffer_RingBufferImpl.__name__ = "hx.strings.internal._RingBuffer.RingBufferImpl";
+Object.assign(hx_strings_internal__$RingBuffer_RingBufferImpl.prototype, {
+	__class__: hx_strings_internal__$RingBuffer_RingBufferImpl
+});
+class hx_strings__$CharIterator_NullCharIterator extends hx_strings_CharIterator {
+	constructor() {
+		super(0);
+	}
+	isEOF() {
+		return true;
+	}
+}
+hx_strings__$CharIterator_NullCharIterator.__name__ = "hx.strings._CharIterator.NullCharIterator";
+hx_strings__$CharIterator_NullCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_NullCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_NullCharIterator
+});
+class hx_strings__$CharIterator_ArrayCharIterator extends hx_strings_CharIterator {
+	constructor(chars,prevBufferSize) {
+		super(prevBufferSize);
+		this.chars = chars;
+		this.charsMaxIndex = chars.length - 1;
+	}
+	isEOF() {
+		return this.index >= this.charsMaxIndex;
+	}
+	getChar() {
+		return this.chars[this.index];
+	}
+}
+hx_strings__$CharIterator_ArrayCharIterator.__name__ = "hx.strings._CharIterator.ArrayCharIterator";
+hx_strings__$CharIterator_ArrayCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_ArrayCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_ArrayCharIterator
+});
+class hx_strings__$CharIterator_IteratorCharIterator extends hx_strings_CharIterator {
+	constructor(chars,prevBufferSize) {
+		super(prevBufferSize);
+		this.chars = chars;
+	}
+	isEOF() {
+		return !this.chars.hasNext();
+	}
+	getChar() {
+		return this.chars.next();
+	}
+}
+hx_strings__$CharIterator_IteratorCharIterator.__name__ = "hx.strings._CharIterator.IteratorCharIterator";
+hx_strings__$CharIterator_IteratorCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_IteratorCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_IteratorCharIterator
+});
+class hx_strings__$CharIterator_InputCharIterator extends hx_strings_CharIterator {
+	constructor(chars,prevBufferSize) {
+		hx_strings_CharIterator._hx_skip_constructor = true;
+		super();
+		hx_strings_CharIterator._hx_skip_constructor = false;
+		this._hx_constructor(chars,prevBufferSize);
+	}
+	_hx_constructor(chars,prevBufferSize) {
+		this.nextCharAvailable = null;
+		this.nextChar = -1;
+		this.currCharIndex = -1;
+		this.byteIndex = 0;
+		super._hx_constructor(prevBufferSize);
+		this.input = chars;
+	}
+	isEOF() {
+		if(this.nextCharAvailable == null) {
+			try {
+				let byte1 = this.input.readByte();
+				this.byteIndex++;
+				let tmp;
+				if(byte1 <= 127) {
+					tmp = byte1;
+				} else {
+					byte1 &= -129;
+					byte1 &= -65;
+					let totalBytes = 2;
+					let isBit6Set = 1 == (byte1 >> 5 & 1);
+					let isBit5Set = false;
+					if(isBit6Set) {
+						byte1 &= -33;
+						++totalBytes;
+						isBit5Set = 1 == (byte1 >> 4 & 1);
+						if(isBit5Set) {
+							byte1 &= -17;
+							++totalBytes;
+							if(1 == (byte1 >> 3 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte1 + "]!");
+							}
+						}
+					}
+					let result = byte1 << 6 * (totalBytes - 1);
+					let byte = this.input.readByte();
+					this.byteIndex++;
+					if(1 != (byte >> 7 & 1)) {
+						throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+					}
+					if(1 == (byte >> 6 & 1)) {
+						throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+					}
+					let byte2 = byte & -129;
+					result += byte2 << 6 * (totalBytes - 2);
+					if(isBit6Set) {
+						let byte = this.input.readByte();
+						this.byteIndex++;
+						if(1 != (byte >> 7 & 1)) {
+							throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+						}
+						if(1 == (byte >> 6 & 1)) {
+							throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+						}
+						let byte3 = byte & -129;
+						result += byte3 << 6 * (totalBytes - 3);
+						if(isBit5Set) {
+							let byte = this.input.readByte();
+							this.byteIndex++;
+							if(1 != (byte >> 7 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+							}
+							if(1 == (byte >> 6 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+							}
+							let byte4 = byte & -129;
+							result += byte4 << 6 * (totalBytes - 4);
+						}
+					}
+					if(this.index == 0 && result == 65279) {
+						let byte1 = this.input.readByte();
+						this.byteIndex++;
+						if(byte1 <= 127) {
+							tmp = byte1;
+						} else {
+							byte1 &= -129;
+							byte1 &= -65;
+							let totalBytes = 2;
+							let isBit6Set = 1 == (byte1 >> 5 & 1);
+							let isBit5Set = false;
+							if(isBit6Set) {
+								byte1 &= -33;
+								++totalBytes;
+								isBit5Set = 1 == (byte1 >> 4 & 1);
+								if(isBit5Set) {
+									byte1 &= -17;
+									++totalBytes;
+									if(1 == (byte1 >> 3 & 1)) {
+										throw haxe_Exception.thrown("Valid UTF-8 byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte1 + "]!");
+									}
+								}
+							}
+							let result = byte1 << 6 * (totalBytes - 1);
+							let byte = this.input.readByte();
+							this.byteIndex++;
+							if(1 != (byte >> 7 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+							}
+							if(1 == (byte >> 6 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+							}
+							let byte2 = byte & -129;
+							result += byte2 << 6 * (totalBytes - 2);
+							if(isBit6Set) {
+								let byte = this.input.readByte();
+								this.byteIndex++;
+								if(1 != (byte >> 7 & 1)) {
+									throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+								}
+								if(1 == (byte >> 6 & 1)) {
+									throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+								}
+								let byte3 = byte & -129;
+								result += byte3 << 6 * (totalBytes - 3);
+								if(isBit5Set) {
+									let byte = this.input.readByte();
+									this.byteIndex++;
+									if(1 != (byte >> 7 & 1)) {
+										throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+									}
+									if(1 == (byte >> 6 & 1)) {
+										throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+									}
+									let byte4 = byte & -129;
+									result += byte4 << 6 * (totalBytes - 4);
+								}
+							}
+							tmp = this.index == 0 && result == 65279 ? this.readUtf8Char() : result;
+						}
+					} else {
+						tmp = result;
+					}
+				}
+				this.nextChar = tmp;
+				this.nextCharAvailable = true;
+			} catch( _g ) {
+				if(((haxe_Exception.caught(_g).unwrap()) instanceof haxe_io_Eof)) {
+					this.nextCharAvailable = false;
+				} else {
+					throw _g;
+				}
+			}
+		}
+		return this.nextCharAvailable != true;
+	}
+	getChar() {
+		if(this.index != this.currCharIndex) {
+			this.currCharIndex = this.index;
+			this.nextCharAvailable = null;
+			return this.nextChar;
+		}
+		return this.currChar;
+	}
+	readUtf8Char() {
+		let byte1 = this.input.readByte();
+		this.byteIndex++;
+		if(byte1 <= 127) {
+			return byte1;
+		}
+		byte1 &= -129;
+		byte1 &= -65;
+		let totalBytes = 2;
+		let isBit6Set = 1 == (byte1 >> 5 & 1);
+		let isBit5Set = false;
+		if(isBit6Set) {
+			byte1 &= -33;
+			++totalBytes;
+			isBit5Set = 1 == (byte1 >> 4 & 1);
+			if(isBit5Set) {
+				byte1 &= -17;
+				++totalBytes;
+				if(1 == (byte1 >> 3 & 1)) {
+					throw haxe_Exception.thrown("Valid UTF-8 byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte1 + "]!");
+				}
+			}
+		}
+		let result = byte1 << 6 * (totalBytes - 1);
+		let byte = this.input.readByte();
+		this.byteIndex++;
+		if(1 != (byte >> 7 & 1)) {
+			throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+		}
+		if(1 == (byte >> 6 & 1)) {
+			throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+		}
+		let byte2 = byte & -129;
+		result += byte2 << 6 * (totalBytes - 2);
+		if(isBit6Set) {
+			let byte = this.input.readByte();
+			this.byteIndex++;
+			if(1 != (byte >> 7 & 1)) {
+				throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+			}
+			if(1 == (byte >> 6 & 1)) {
+				throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+			}
+			let byte3 = byte & -129;
+			result += byte3 << 6 * (totalBytes - 3);
+			if(isBit5Set) {
+				let byte = this.input.readByte();
+				this.byteIndex++;
+				if(1 != (byte >> 7 & 1)) {
+					throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+				}
+				if(1 == (byte >> 6 & 1)) {
+					throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+				}
+				let byte4 = byte & -129;
+				result += byte4 << 6 * (totalBytes - 4);
+			}
+		}
+		if(this.index == 0 && result == 65279) {
+			return this.readUtf8Char();
+		}
+		return result;
+	}
+	readUtf8MultiSequenceByte() {
+		let byte = this.input.readByte();
+		this.byteIndex++;
+		if(1 != (byte >> 7 & 1)) {
+			throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+		}
+		if(1 == (byte >> 6 & 1)) {
+			throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+		}
+		return byte & -129;
+	}
+}
+hx_strings__$CharIterator_InputCharIterator.__name__ = "hx.strings._CharIterator.InputCharIterator";
+hx_strings__$CharIterator_InputCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_InputCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_InputCharIterator
+});
+class hx_strings__$CharIterator_StringCharIterator extends hx_strings_CharIterator {
+	constructor(chars,prevBufferSize) {
+		super(prevBufferSize);
+		this.chars = chars;
+		this.charsMaxIndex = (chars == null ? 0 : chars.length) - 1;
+	}
+	isEOF() {
+		return this.index >= this.charsMaxIndex;
+	}
+	getChar() {
+		return HxOverrides.cca(this.chars,this.index);
+	}
+}
+hx_strings__$CharIterator_StringCharIterator.__name__ = "hx.strings._CharIterator.StringCharIterator";
+hx_strings__$CharIterator_StringCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_StringCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_StringCharIterator
+});
+class hx_strings_Pattern {
+	constructor(pattern,options) {
+		this.pattern = pattern;
+		this.options = options;
+		this.ereg = new EReg(pattern,options);
+		this.options += "u";
+	}
+	matcher(str) {
+		return new hx_strings__$Pattern_MatcherImpl(this.ereg,this.pattern,this.options,str);
+	}
+	replace(str,replaceWith) {
+		return str.replace(this.ereg.r,replaceWith);
+	}
+	remove(str) {
+		return str.replace(this.ereg.r,"");
+	}
+	split(str) {
+		return this.ereg.split(str);
+	}
+	static compile(pattern,options) {
+		if(options == null) {
+			return new hx_strings_Pattern(pattern,"");
+		}
+		let _g = options;
+		let tmp;
+		switch(_g._hx_index) {
+		case 0:
+			let str = _g.v;
+			let str1 = hx_strings_Strings.toLowerCase8(str);
+			if(str1 == null || str1.length == 0) {
+				tmp = str1;
+			} else {
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = hx_strings_Strings.toChars(str1);
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(v == hx_strings_Strings.charCodeAt8("i",0) || v == hx_strings_Strings.charCodeAt8("m",0) || v == hx_strings_Strings.charCodeAt8("g",0)) {
+						_g.push(v);
+					}
+				}
+				let _this = _g;
+				let result = new Array(_this.length);
+				let _g3 = 0;
+				let _g4 = _this.length;
+				while(_g3 < _g4) {
+					let i = _g3++;
+					result[i] = String.fromCodePoint(_this[i]);
+				}
+				tmp = result.join("");
+			}
+			break;
+		case 1:
+			let opt = _g.v;
+			tmp = Std.string(opt);
+			break;
+		case 2:
+			let arr = _g.v;
+			let _g1 = [];
+			let _g2 = 0;
+			let _g3 = arr;
+			while(_g2 < _g3.length) {
+				let v = _g3[_g2];
+				++_g2;
+				if(v != null) {
+					_g1.push(v);
+				}
+			}
+			tmp = _g1.join("");
+			break;
+		}
+		return new hx_strings_Pattern(pattern,tmp);
+	}
+}
+hx_strings_Pattern.__name__ = "hx.strings.Pattern";
+Object.assign(hx_strings_Pattern.prototype, {
+	__class__: hx_strings_Pattern
+});
+class hx_strings_Matcher {
+}
+hx_strings_Matcher.__name__ = "hx.strings.Matcher";
+hx_strings_Matcher.__isInterface__ = true;
+Object.assign(hx_strings_Matcher.prototype, {
+	__class__: hx_strings_Matcher
+});
+class hx_strings__$Pattern_MatcherImpl {
+	constructor(ereg,pattern,options,str) {
+		let clone = new EReg(pattern,options);
+		this.ereg = clone;
+		this.str = str;
+	}
+	reset(str) {
+		this.str = str;
+		this.isMatch = null;
+		return this;
+	}
+	iterate(onMatch) {
+		let startAt = 0;
+		while(this.ereg.matchSub(this.str,startAt)) {
+			this.isMatch = true;
+			let matchedPos = this.ereg.matchedPos();
+			onMatch(this);
+			startAt = matchedPos.pos + matchedPos.len;
+		}
+		this.isMatch = false;
+	}
+	map(mapper) {
+		let _gthis = this;
+		return this.ereg.map(this.str,function(ereg) {
+			_gthis.isMatch = true;
+			return mapper(_gthis);
+		});
+	}
+	matched(n) {
+		if(n == null) {
+			n = 0;
+		}
+		if(!this.matches()) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		let result = this.ereg.matched(n);
+		return result;
+	}
+	matches() {
+		if(this.isMatch == null) {
+			this.isMatch = this.ereg.match(this.str);
+		}
+		return this.isMatch;
+	}
+	matchesInRegion(pos,len) {
+		if(len == null) {
+			len = -1;
+		}
+		return this.isMatch = this.ereg.matchSub(this.str,pos,len);
+	}
+	matchedPos() {
+		if(!this.matches()) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		return this.ereg.matchedPos();
+	}
+	substringAfterMatch() {
+		if(!this.matches()) {
+			return "";
+		}
+		return this.ereg.matchedRight();
+	}
+	substringBeforeMatch() {
+		if(!this.matches()) {
+			return "";
+		}
+		return this.ereg.matchedLeft();
+	}
+	_cloneEReg(from,pattern,options) {
+		let clone = new EReg(pattern,options);
+		return clone;
+	}
+}
+hx_strings__$Pattern_MatcherImpl.__name__ = "hx.strings._Pattern.MatcherImpl";
+hx_strings__$Pattern_MatcherImpl.__interfaces__ = [hx_strings_Matcher];
+Object.assign(hx_strings__$Pattern_MatcherImpl.prototype, {
+	__class__: hx_strings__$Pattern_MatcherImpl
+});
+class hx_strings_internal_OS {
+}
+hx_strings_internal_OS.__name__ = "hx.strings.internal.OS";
+class js_Boot {
+	static getClass(o) {
+		if(o == null) {
+			return null;
+		} else if(((o) instanceof Array)) {
+			return Array;
+		} else {
+			let cl = o.__class__;
+			if(cl != null) {
+				return cl;
+			}
+			let name = js_Boot.__nativeClassName(o);
+			if(name != null) {
+				return js_Boot.__resolveNativeClass(name);
+			}
+			return null;
+		}
+	}
+	static __string_rec(o,s) {
+		if(o == null) {
+			return "null";
+		}
+		if(s.length >= 5) {
+			return "<...>";
+		}
+		let t = typeof(o);
+		if(t == "function" && (o.__name__ || o.__ename__)) {
+			t = "object";
+		}
+		switch(t) {
+		case "function":
+			return "<function>";
+		case "object":
+			if(o.__enum__) {
+				let e = $hxEnums[o.__enum__];
+				let con = e.__constructs__[o._hx_index];
+				let n = con._hx_name;
+				if(con.__params__) {
+					s = s + "\t";
+					return n + "(" + ((function($this) {
+						var $r;
+						let _g = [];
+						{
+							let _g1 = 0;
+							let _g2 = con.__params__;
+							while(true) {
+								if(!(_g1 < _g2.length)) {
+									break;
+								}
+								let p = _g2[_g1];
+								_g1 = _g1 + 1;
+								_g.push(js_Boot.__string_rec(o[p],s));
+							}
+						}
+						$r = _g;
+						return $r;
+					}(this))).join(",") + ")";
+				} else {
+					return n;
+				}
+			}
+			if(((o) instanceof Array)) {
+				let str = "[";
+				s += "\t";
+				let _g = 0;
+				let _g1 = o.length;
+				while(_g < _g1) {
+					let i = _g++;
+					str += (i > 0 ? "," : "") + js_Boot.__string_rec(o[i],s);
+				}
+				str += "]";
+				return str;
+			}
+			let tostr;
+			try {
+				tostr = o.toString;
+			} catch( _g ) {
+				return "???";
+			}
+			if(tostr != null && tostr != Object.toString && typeof(tostr) == "function") {
+				let s2 = o.toString();
+				if(s2 != "[object Object]") {
+					return s2;
+				}
+			}
+			let str = "{\n";
+			s += "\t";
+			let hasp = o.hasOwnProperty != null;
+			let k = null;
+			for( k in o ) {
+			if(hasp && !o.hasOwnProperty(k)) {
+				continue;
+			}
+			if(k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__") {
+				continue;
+			}
+			if(str.length != 2) {
+				str += ", \n";
+			}
+			str += s + k + " : " + js_Boot.__string_rec(o[k],s);
+			}
+			s = s.substring(1);
+			str += "\n" + s + "}";
+			return str;
+		case "string":
+			return o;
+		default:
+			return String(o);
+		}
+	}
+	static __interfLoop(cc,cl) {
+		if(cc == null) {
+			return false;
+		}
+		if(cc == cl) {
+			return true;
+		}
+		let intf = cc.__interfaces__;
+		if(intf != null && (cc.__super__ == null || cc.__super__.__interfaces__ != intf)) {
+			let _g = 0;
+			let _g1 = intf.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let i1 = intf[i];
+				if(i1 == cl || js_Boot.__interfLoop(i1,cl)) {
+					return true;
+				}
+			}
+		}
+		return js_Boot.__interfLoop(cc.__super__,cl);
+	}
+	static __instanceof(o,cl) {
+		if(cl == null) {
+			return false;
+		}
+		switch(cl) {
+		case Array:
+			return ((o) instanceof Array);
+		case Bool:
+			return typeof(o) == "boolean";
+		case Dynamic:
+			return o != null;
+		case Float:
+			return typeof(o) == "number";
+		case Int:
+			if(typeof(o) == "number") {
+				return ((o | 0) === o);
+			} else {
+				return false;
+			}
+			break;
+		case String:
+			return typeof(o) == "string";
+		default:
+			if(o != null) {
+				if(typeof(cl) == "function") {
+					if(js_Boot.__downcastCheck(o,cl)) {
+						return true;
+					}
+				} else if(typeof(cl) == "object" && js_Boot.__isNativeObj(cl)) {
+					if(((o) instanceof cl)) {
+						return true;
+					}
+				}
+			} else {
+				return false;
+			}
+			if(cl == Class ? o.__name__ != null : false) {
+				return true;
+			}
+			if(cl == Enum ? o.__ename__ != null : false) {
+				return true;
+			}
+			return o.__enum__ != null ? $hxEnums[o.__enum__] == cl : false;
+		}
+	}
+	static __downcastCheck(o,cl) {
+		if(!((o) instanceof cl)) {
+			if(cl.__isInterface__) {
+				return js_Boot.__interfLoop(js_Boot.getClass(o),cl);
+			} else {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+	static __cast(o,t) {
+		if(o == null || js_Boot.__instanceof(o,t)) {
+			return o;
+		} else {
+			throw haxe_Exception.thrown("Cannot cast " + Std.string(o) + " to " + Std.string(t));
+		}
+	}
+	static __nativeClassName(o) {
+		let name = js_Boot.__toStr.call(o).slice(8,-1);
+		if(name == "Object" || name == "Function" || name == "Math" || name == "JSON") {
+			return null;
+		}
+		return name;
+	}
+	static __isNativeObj(o) {
+		return js_Boot.__nativeClassName(o) != null;
+	}
+	static __resolveNativeClass(name) {
+		return $global[name];
+	}
+}
+js_Boot.__name__ = "js.Boot";
+var hx_strings_internal__$Either3__$Either3 = $hxEnums["hx.strings.internal._Either3._Either3"] = { __ename__:true,__constructs__:null
+	,a: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"hx.strings.internal._Either3._Either3",toString:$estr}; },$_._hx_name="a",$_.__params__ = ["v"],$_)
+	,b: ($_=function(v) { return {_hx_index:1,v:v,__enum__:"hx.strings.internal._Either3._Either3",toString:$estr}; },$_._hx_name="b",$_.__params__ = ["v"],$_)
+	,c: ($_=function(v) { return {_hx_index:2,v:v,__enum__:"hx.strings.internal._Either3._Either3",toString:$estr}; },$_._hx_name="c",$_.__params__ = ["v"],$_)
+};
+hx_strings_internal__$Either3__$Either3.__constructs__ = [hx_strings_internal__$Either3__$Either3.a,hx_strings_internal__$Either3__$Either3.b,hx_strings_internal__$Either3__$Either3.c];
+class hx_strings_Strings {
+	static _length(str) {
+		return str.length;
+	}
+	static _getNotFoundDefault(str,notFoundDefault) {
+		switch(notFoundDefault) {
+		case 1:
+			return null;
+		case 2:
+			return "";
+		case 3:
+			return str;
+		}
+	}
+	static _charCodeAt8Unsafe(str,pos) {
+		return HxOverrides.cca(str,pos);
+	}
+	static _splitAsciiWordsUnsafe(str) {
+		let words = [];
+		let currentWord = new hx_strings_StringBuilder();
+		let chars = hx_strings_Strings.toChars(str);
+		let len = chars.length;
+		let lastIndex = len - 1;
+		let _g = 0;
+		let _g1 = len;
+		while(_g < _g1) {
+			let i = _g++;
+			let ch = chars[i];
+			if(ch > 64 && ch < 91 || ch > 96 && ch < 123) {
+				let chNext = i < lastIndex ? chars[i + 1] : -1;
+				currentWord.addChar(ch);
+				if(chNext > 47 && chNext < 58) {
+					words.push(currentWord.toString());
+					currentWord.clear();
+				} else if(hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(ch)) {
+					if(hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(chNext) && chars.length > i + 2) {
+						if(!hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(chars[i + 2])) {
+							words.push(currentWord.toString());
+							currentWord.clear();
+						}
+					}
+				} else if(hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(chNext)) {
+					words.push(currentWord.toString());
+					currentWord.clear();
+				}
+			} else if(ch > 47 && ch < 58) {
+				currentWord.addChar(ch);
+				let chNext = i < lastIndex ? chars[i + 1] : -1;
+				if(!(chNext > 47 && chNext < 58)) {
+					words.push(currentWord.toString());
+					currentWord.clear();
+				}
+			} else if(currentWord.len > 0) {
+				words.push(currentWord.toString());
+				currentWord.clear();
+			}
+		}
+		if(currentWord.len > 0) {
+			words.push(currentWord.toString());
+		}
+		return words;
+	}
+	static ansiToHtml(str,renderMethod,initialState) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(renderMethod == null) {
+			renderMethod = hx_strings_AnsiToHtmlRenderMethod.StyleAttributes;
+		}
+		let styleOrClassAttribute;
+		switch(renderMethod._hx_index) {
+		case 0:
+			styleOrClassAttribute = "style";
+			break;
+		case 1:
+			styleOrClassAttribute = "class";
+			break;
+		case 2:
+			let cb = renderMethod.func;
+			styleOrClassAttribute = "class";
+			break;
+		}
+		let sb = new hx_strings_StringBuilder();
+		if(initialState != null && (initialState.fgcolor != null || initialState.bgcolor != null || initialState.bold || initialState.underline || initialState.blink)) {
+			sb.add("<span " + styleOrClassAttribute + "=\"").add(initialState.toCSS(renderMethod)).add("\">");
+		}
+		let effectiveState = new hx_strings_AnsiState(initialState);
+		let strLenMinus1 = (str == null ? 0 : str.length) - 1;
+		let i = -1;
+		let lookAhead = new hx_strings_StringBuilder();
+		while(i < strLenMinus1) {
+			++i;
+			let ch = HxOverrides.cca(str,i);
+			if(ch == 27 && i < strLenMinus1 && HxOverrides.cca(str,i + 1) == 91) {
+				lookAhead.clear();
+				let currentState = new hx_strings_AnsiState(effectiveState);
+				let currentGraphicModeParam = 0;
+				let isValidEscapeSequence = false;
+				++i;
+				_hx_loop2: while(i < strLenMinus1) {
+					++i;
+					let ch2 = HxOverrides.cca(str,i);
+					lookAhead.addChar(ch2);
+					switch(ch2) {
+					case 48:
+						currentGraphicModeParam *= 10;
+						break;
+					case 49:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 1;
+						break;
+					case 50:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 2;
+						break;
+					case 51:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 3;
+						break;
+					case 52:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 4;
+						break;
+					case 53:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 5;
+						break;
+					case 54:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 6;
+						break;
+					case 55:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 7;
+						break;
+					case 56:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 8;
+						break;
+					case 57:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 9;
+						break;
+					case 59:
+						currentState.setGraphicModeParameter(currentGraphicModeParam);
+						currentGraphicModeParam = 0;
+						break;
+					case 109:
+						currentState.setGraphicModeParameter(currentGraphicModeParam);
+						if(effectiveState.fgcolor != null || effectiveState.bgcolor != null || effectiveState.bold || effectiveState.underline || effectiveState.blink) {
+							sb.add("</span>");
+						}
+						if(currentState.fgcolor != null || currentState.bgcolor != null || currentState.bold || currentState.underline || currentState.blink) {
+							sb.add("<span " + styleOrClassAttribute + "=\"").add(currentState.toCSS(renderMethod)).add("\">");
+						}
+						effectiveState = currentState;
+						isValidEscapeSequence = true;
+						break _hx_loop2;
+					default:
+						break _hx_loop2;
+					}
+				}
+				if(!isValidEscapeSequence) {
+					sb.addChar(27).add("[").add(Std.string(lookAhead));
+				}
+			} else {
+				sb.addChar(ch);
+			}
+		}
+		if(effectiveState.fgcolor != null || effectiveState.bgcolor != null || effectiveState.bold || effectiveState.underline || effectiveState.blink) {
+			sb.add("</span>");
+		}
+		return sb.toString();
+	}
+	static appendIfMissing(str,suffix) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0) {
+			return Std.string(str) + Std.string(suffix);
+		}
+		if(hx_strings_Strings.endsWith(str,suffix)) {
+			return str;
+		}
+		return Std.string(str) + Std.string(suffix);
+	}
+	static base64Encode(plain) {
+		if(plain == null) {
+			return null;
+		}
+		return haxe_crypto_Base64.encode(plain == null ? null : haxe_io_Bytes.ofString(plain));
+	}
+	static base64Decode(encoded) {
+		if(encoded == null) {
+			return null;
+		}
+		return haxe_crypto_Base64.decode(encoded).toString();
+	}
+	static charAt8(str,pos,resultIfOutOfBound) {
+		if(resultIfOutOfBound == null) {
+			resultIfOutOfBound = "";
+		}
+		if(str == null || str.length == 0 || pos < 0 || pos >= (str == null ? 0 : str.length)) {
+			return resultIfOutOfBound;
+		}
+		return str.charAt(pos);
+	}
+	static charCodeAt8(str,pos,resultIfOutOfBound) {
+		if(resultIfOutOfBound == null) {
+			resultIfOutOfBound = -1;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0 || pos < 0 || pos >= strLen) {
+			return resultIfOutOfBound;
+		}
+		return HxOverrides.cca(str,pos);
+	}
+	static compact(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		let needWhiteSpace = false;
+		let _g = 0;
+		let _g1 = hx_strings_Strings.toChars(str);
+		while(_g < _g1.length) {
+			let char = _g1[_g];
+			++_g;
+			if(char > 8 && char < 14 || char == 32) {
+				if(sb.len != 0) {
+					needWhiteSpace = true;
+				}
+				continue;
+			} else if(needWhiteSpace) {
+				sb.addChar(32);
+				needWhiteSpace = false;
+			}
+			sb.addChar(char);
+		}
+		return sb.toString();
+	}
+	static contains(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		if(searchFor == "") {
+			return true;
+		}
+		return searchIn.indexOf(searchFor) > -1;
+	}
+	static containsOnly(searchIn,allowedChars) {
+		if(searchIn == null || searchIn.length == 0) {
+			return true;
+		}
+		if(allowedChars == null) {
+			return false;
+		}
+		let allowedCharsArray;
+		let _g = allowedChars;
+		switch(_g._hx_index) {
+		case 0:
+			let str = _g.v;
+			allowedCharsArray = hx_strings_Strings.toChars(str);
+			break;
+		case 1:
+			let chars = _g.v;
+			allowedCharsArray = chars;
+			break;
+		}
+		let _g1 = 0;
+		let _g2 = hx_strings_Strings.toChars(searchIn);
+		while(_g1 < _g2.length) {
+			let ch = _g2[_g1];
+			++_g1;
+			if(allowedCharsArray.indexOf(ch) < 0) {
+				return false;
+			}
+		}
+		return true;
+	}
+	static containsAll(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(!(searchIn == null || candidate == null ? false : candidate == "" ? true : searchIn.indexOf(candidate) > -1)) {
+				return false;
+			}
+		}
+		return true;
+	}
+	static containsAllIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		searchIn = searchIn.toLowerCase();
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			let searchFor1 = candidate.toLowerCase();
+			if(!(searchIn == null || searchFor1 == null ? false : searchFor1 == "" ? true : searchIn.indexOf(searchFor1) > -1)) {
+				return false;
+			}
+		}
+		return true;
+	}
+	static containsAny(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(searchIn == null || candidate == null ? false : candidate == "" ? true : searchIn.indexOf(candidate) > -1) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static containsAnyIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		searchIn = searchIn.toLowerCase();
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			let searchFor1 = candidate.toLowerCase();
+			if(searchIn == null || searchFor1 == null ? false : searchFor1 == "" ? true : searchIn.indexOf(searchFor1) > -1) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static containsNone(searchIn,searchFor) {
+		return !hx_strings_Strings.containsAny(searchIn,searchFor);
+	}
+	static containsNoneIgnoreCase(searchIn,searchFor) {
+		return !hx_strings_Strings.containsAnyIgnoreCase(searchIn,searchFor);
+	}
+	static containsWhitespaces(searchIn) {
+		if(searchIn == null) {
+			return false;
+		}
+		let _g = 0;
+		let _g1 = hx_strings_Strings.toChars(searchIn);
+		while(_g < _g1.length) {
+			let ch = _g1[_g];
+			++_g;
+			if(ch > 8 && ch < 14 || ch == 32) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static countMatches(searchIn,searchFor,startAt) {
+		if(startAt == null) {
+			startAt = 0;
+		}
+		if(searchIn == null || searchIn.length == 0 || (searchFor == null || searchFor.length == 0) || startAt >= searchIn.length) {
+			return 0;
+		}
+		if(startAt < 0) {
+			startAt = 0;
+		}
+		let count = 0;
+		let foundAt = startAt > -1 ? startAt - 1 : 0;
+		while(true) {
+			foundAt = searchIn.indexOf(searchFor,foundAt + 1);
+			if(!(foundAt > -1)) {
+				break;
+			}
+			++count;
+		}
+		return count;
+	}
+	static countMatchesIgnoreCase(searchIn,searchFor,startAt) {
+		if(startAt == null) {
+			startAt = 0;
+		}
+		if(searchIn == null || searchIn.length == 0 || (searchFor == null || searchFor.length == 0) || startAt >= searchIn.length) {
+			return 0;
+		}
+		if(startAt < 0) {
+			startAt = 0;
+		}
+		searchIn = searchIn.toLowerCase();
+		searchFor = searchFor.toLowerCase();
+		let count = 0;
+		let foundAt = startAt > -1 ? startAt - 1 : 0;
+		while(true) {
+			foundAt = searchIn.indexOf(searchFor,foundAt + 1);
+			if(!(foundAt > -1)) {
+				break;
+			}
+			++count;
+		}
+		return count;
+	}
+	static compare(str,other) {
+		if(str == null) {
+			if(other == null) {
+				return 0;
+			} else {
+				return -1;
+			}
+		}
+		if(other == null) {
+			if(str == null) {
+				return 0;
+			} else {
+				return 1;
+			}
+		}
+		if(str > other) {
+			return 1;
+		} else if(str == other) {
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+	static compareIgnoreCase(str,other) {
+		if(str == null) {
+			if(other == null) {
+				return 0;
+			} else {
+				return -1;
+			}
+		}
+		if(other == null) {
+			if(str == null) {
+				return 0;
+			} else {
+				return 1;
+			}
+		}
+		let str1 = hx_strings_Strings.toLowerCase8(str);
+		let other1 = hx_strings_Strings.toLowerCase8(other);
+		if(str1 > other1) {
+			return 1;
+		} else if(str1 == other1) {
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+	static diff(left,right) {
+		let diff = new hx_strings_StringDiff();
+		diff.at = hx_strings_Strings.diffAt(left,right);
+		diff.left = hx_strings_Strings.substr8(left,diff.at);
+		diff.right = hx_strings_Strings.substr8(right,diff.at);
+		return diff;
+	}
+	static diffAt(str,other) {
+		if(str == other) {
+			return -1;
+		}
+		let strLen = str == null ? 0 : str.length;
+		let otherLen = other == null ? 0 : other.length;
+		if(strLen == 0 || otherLen == 0) {
+			return 0;
+		}
+		let checkLen = strLen > otherLen ? otherLen : strLen;
+		let _g = 0;
+		let _g1 = checkLen;
+		while(_g < _g1) {
+			let i = _g++;
+			if(HxOverrides.cca(str,i) != HxOverrides.cca(other,i)) {
+				return i;
+			}
+		}
+		return checkLen;
+	}
+	static ellipsizeLeft(str,maxLength,ellipsis) {
+		if(ellipsis == null) {
+			ellipsis = "...";
+		}
+		if((str == null ? 0 : str.length) <= maxLength) {
+			return str;
+		}
+		let ellipsisLen = ellipsis == null ? 0 : ellipsis.length;
+		if(maxLength < ellipsisLen) {
+			throw haxe_Exception.thrown("[maxLength] must not be smaller than " + ellipsisLen);
+		}
+		return ellipsis + Std.string(hx_strings_Strings.right(str,maxLength - ellipsisLen));
+	}
+	static ellipsizeMiddle(str,maxLength,ellipsis) {
+		if(ellipsis == null) {
+			ellipsis = "...";
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen <= maxLength) {
+			return str;
+		}
+		let ellipsisLen = ellipsis == null ? 0 : ellipsis.length;
+		if(maxLength < ellipsisLen) {
+			throw haxe_Exception.thrown("[maxLength] must not be smaller than " + ellipsisLen);
+		}
+		let maxStrLen = maxLength - ellipsisLen;
+		let leftLen = Math.round(maxStrLen / 2);
+		let rightLen = maxStrLen - leftLen;
+		return Std.string((str == null ? 0 : str.length) <= leftLen ? str : hx_strings_Strings.substring8(str,0,leftLen)) + ellipsis + Std.string(hx_strings_Strings.right(str,rightLen));
+	}
+	static ellipsizeRight(str,maxLength,ellipsis) {
+		if(ellipsis == null) {
+			ellipsis = "...";
+		}
+		if((str == null ? 0 : str.length) <= maxLength) {
+			return str;
+		}
+		let ellipsisLen = ellipsis == null ? 0 : ellipsis.length;
+		if(maxLength < ellipsisLen) {
+			throw haxe_Exception.thrown("[maxLength] must not be smaller than " + ellipsisLen);
+		}
+		let len = maxLength - ellipsisLen;
+		return Std.string((str == null ? 0 : str.length) <= len ? str : hx_strings_Strings.substring8(str,0,len)) + ellipsis;
+	}
+	static endsWith(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		return searchIn.endsWith(searchFor);
+	}
+	static endsWithAny(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(candidate != null && hx_strings_Strings.endsWith(searchIn,candidate)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static endsWithAnyIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		searchIn = hx_strings_Strings.toLowerCase8(searchIn);
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(candidate != null && hx_strings_Strings.endsWith(searchIn,hx_strings_Strings.toLowerCase8(candidate))) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static endsWithIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		return hx_strings_Strings.endsWith(searchIn.toLowerCase(),searchFor.toLowerCase());
+	}
+	static equals(str,other) {
+		return str == other;
+	}
+	static equalsIgnoreCase(str,other) {
+		return hx_strings_Strings.toLowerCase8(str) == hx_strings_Strings.toLowerCase8(other);
+	}
+	static filter(str,filter,separator) {
+		if(separator == null) {
+			separator = "";
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = hx_strings_Strings.split8(str,[separator]);
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(filter(v)) {
+				_g.push(v);
+			}
+		}
+		return _g.join(separator);
+	}
+	static filterChars(str,filter) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = hx_strings_Strings.toChars(str);
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(filter(v)) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			result[i] = String.fromCodePoint(_this[i]);
+		}
+		return result.join("");
+	}
+	static getFuzzyDistance(left,right) {
+		if(left == null || left.length == 0 || (right == null || right.length == 0)) {
+			return 0;
+		}
+		left = hx_strings_Strings.toLowerCase8(left);
+		right = hx_strings_Strings.toLowerCase8(right);
+		let leftChars = hx_strings_Strings.toChars(left);
+		let rightChars = hx_strings_Strings.toChars(right);
+		let leftLastMatchAt = -100;
+		let rightLastMatchAt = -100;
+		let score = 0;
+		let _g = 0;
+		let _g1 = leftChars.length;
+		while(_g < _g1) {
+			let leftIdx = _g++;
+			let leftChar = leftChars[leftIdx];
+			let _g1 = rightLastMatchAt > -1 ? rightLastMatchAt + 1 : 0;
+			let _g2 = rightChars.length;
+			while(_g1 < _g2) {
+				let rightIdx = _g1++;
+				let rightChar = rightChars[rightIdx];
+				if(leftChar == rightChar) {
+					++score;
+					if(leftLastMatchAt == leftIdx - 1 && rightLastMatchAt == rightIdx - 1) {
+						score += 2;
+					}
+					leftLastMatchAt = leftIdx;
+					rightLastMatchAt = rightIdx;
+					break;
+				}
+			}
+		}
+		return score;
+	}
+	static getLevenshteinDistance(left,right) {
+		let leftLen = left == null ? 0 : left.length;
+		let rightLen = right == null ? 0 : right.length;
+		if(leftLen == 0) {
+			return rightLen;
+		}
+		if(rightLen == 0) {
+			return leftLen;
+		}
+		if(leftLen > rightLen) {
+			let tmp = left;
+			left = right;
+			right = tmp;
+			let tmpLen = leftLen;
+			leftLen = rightLen;
+			rightLen = tmpLen;
+		}
+		let prevCosts = [];
+		let costs = [];
+		let _g = 0;
+		let _g1 = leftLen + 1;
+		while(_g < _g1) {
+			let leftIdx = _g++;
+			prevCosts.push(leftIdx);
+			costs.push(0);
+		}
+		let leftChars = hx_strings_Strings.toChars(left);
+		let rightChars = hx_strings_Strings.toChars(right);
+		let min = function(a,b) {
+			if(a > b) {
+				return b;
+			} else {
+				return a;
+			}
+		};
+		let _g2 = 1;
+		let _g3 = rightLen + 1;
+		while(_g2 < _g3) {
+			let rightIdx = _g2++;
+			let rightChar = rightChars[rightIdx - 1];
+			costs[0] = rightIdx;
+			let _g = 1;
+			let _g1 = leftLen + 1;
+			while(_g < _g1) {
+				let leftIdx = _g++;
+				let leftIdxMinus1 = leftIdx - 1;
+				let cost = leftChars[leftIdxMinus1] == rightChar ? 0 : 1;
+				costs[leftIdx] = min(min(costs[leftIdxMinus1] + 1,prevCosts[leftIdx] + 1),prevCosts[leftIdxMinus1] + cost);
+			}
+			let tmp = prevCosts;
+			prevCosts = costs;
+			costs = tmp;
+		}
+		return prevCosts[leftLen];
+	}
+	static getLongestCommonSubstring(left,right) {
+		if(left == null || right == null) {
+			return null;
+		}
+		let leftLen = left == null ? 0 : left.length;
+		let rightLen = right == null ? 0 : right.length;
+		if(leftLen == 0 || rightLen == 0) {
+			return "";
+		}
+		let leftChars = hx_strings_Strings.toChars(left);
+		let rightChars = hx_strings_Strings.toChars(right);
+		let leftSubStartAt = 0;
+		let leftSubLen = 0;
+		let _g = 0;
+		let _g1 = leftLen;
+		while(_g < _g1) {
+			let leftIdx = _g++;
+			let _g1 = 0;
+			let _g2 = rightLen;
+			while(_g1 < _g2) {
+				let rightIdx = _g1++;
+				let currLen = 0;
+				while(leftChars[leftIdx + currLen] == rightChars[rightIdx + currLen]) {
+					++currLen;
+					if(leftIdx + currLen >= leftLen || rightIdx + currLen >= rightLen) {
+						break;
+					}
+				}
+				if(currLen > leftSubLen) {
+					leftSubLen = currLen;
+					leftSubStartAt = leftIdx;
+				}
+			}
+		}
+		return hx_strings_Strings.substr8(left,leftSubStartAt,leftSubLen);
+	}
+	static hashCode(str,algo) {
+		if(str == null || str.length == 0) {
+			return 0;
+		}
+		if(algo == null) {
+			algo = hx_strings_HashCodeAlgorithm.PLATFORM_SPECIFIC;
+		}
+		if(algo == null) {
+			return haxe_crypto_Crc32.make(str == null ? null : haxe_io_Bytes.ofString(str));
+		} else {
+			switch(algo._hx_index) {
+			case 1:
+				return haxe_crypto_Adler32.make(str == null ? null : haxe_io_Bytes.ofString(str));
+			case 2:
+				return haxe_crypto_Crc32.make(str == null ? null : haxe_io_Bytes.ofString(str));
+			case 3:
+				let hc = 5381;
+				let _g = 0;
+				let _g1 = hx_strings_Strings.toChars(str);
+				while(_g < _g1.length) {
+					let ch = _g1[_g];
+					++_g;
+					hc = ((hc << 5) + hc | 0) ^ ch;
+				}
+				return hc;
+			case 4:
+				let hc1 = 0;
+				let _g2 = 0;
+				let _g3 = hx_strings_Strings.toChars(str);
+				while(_g2 < _g3.length) {
+					let ch = _g3[_g2];
+					++_g2;
+					hc1 = ((hc1 << 5) - hc1 | 0) + ch | 0;
+				}
+				return hc1;
+			case 5:
+				let hc2 = 0;
+				let _g4 = 0;
+				let _g5 = hx_strings_Strings.toChars(str);
+				while(_g4 < _g5.length) {
+					let ch = _g5[_g4];
+					++_g4;
+					hc2 = (((hc2 << 6) + (hc2 << 16) | 0) - hc2 | 0) + ch | 0;
+				}
+				return hc2;
+			default:
+				return haxe_crypto_Crc32.make(str == null ? null : haxe_io_Bytes.ofString(str));
+			}
+		}
+	}
+	static htmlDecode(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings.REGEX_HTML_UNESCAPE;
+		return new hx_strings__$Pattern_MatcherImpl(_this.ereg,_this.pattern,_this.options,str).map(function(m) {
+			let match = m.matched();
+			switch(match) {
+			case "&amp;":
+				return "&";
+			case "&apos;":
+				return "'";
+			case "&gt;":
+				return ">";
+			case "&lt;":
+				return "<";
+			case "&nbsp;":
+				return " ";
+			case "&quot;":
+				return "\"";
+			default:
+				let number = Std.parseInt(hx_strings_Strings.substr8(match,2,(match == null ? 0 : match.length) - 3));
+				if(number == null) {
+					throw haxe_Exception.thrown("Invalid HTML value " + match);
+				}
+				let this1 = number;
+				return String.fromCodePoint(this1);
+			}
+		});
+	}
+	static htmlEncode(str,escapeQuotes) {
+		if(escapeQuotes == null) {
+			escapeQuotes = false;
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		let isFirstSpace = true;
+		let _g = 0;
+		let _g1 = str == null ? 0 : str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let ch = HxOverrides.cca(str,i);
+			switch(ch) {
+			case 32:
+				if(isFirstSpace) {
+					sb.add(" ");
+					isFirstSpace = false;
+				} else {
+					sb.add("&nbsp;");
+				}
+				break;
+			case 34:
+				sb.add(escapeQuotes ? "&quot;" : "\"");
+				break;
+			case 38:
+				sb.add("&amp;");
+				break;
+			case 39:
+				sb.add(escapeQuotes ? "&#039;" : "'");
+				break;
+			case 60:
+				sb.add("&lt;");
+				break;
+			case 62:
+				sb.add("&gt;");
+				break;
+			default:
+				if(ch > 127) {
+					sb.add("&#").add(Std.string(ch)).add(";");
+				} else {
+					sb.addChar(ch);
+				}
+			}
+			if(ch != 32) {
+				isFirstSpace = true;
+			}
+		}
+		return sb.toString();
+	}
+	static insertAt(str,pos,insertion) {
+		if(str == null) {
+			return null;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(pos < 0) {
+			pos = strLen + pos;
+		}
+		if(pos < 0 || pos > strLen) {
+			throw haxe_Exception.thrown("Absolute value of [pos] must be <= str.length");
+		}
+		if(insertion == null || insertion.length == 0) {
+			return str;
+		}
+		return Std.string(hx_strings_Strings.substring8(str,0,pos)) + insertion + Std.string(hx_strings_Strings.substring8(str,pos));
+	}
+	static ifBlank(str,fallback) {
+		if(str == null ? true : StringTools.trim(str).length == 0) {
+			return fallback;
+		} else {
+			return str;
+		}
+	}
+	static ifEmpty(str,fallback) {
+		if(str == null || str.length == 0) {
+			return fallback;
+		} else {
+			return str;
+		}
+	}
+	static ifNull(str,fallback) {
+		if(str == null) {
+			return fallback;
+		} else {
+			return str;
+		}
+	}
+	static indentLines(str,indentWith) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0 || (indentWith == null || indentWith.length == 0)) {
+			return str;
+		}
+		let isFirstLine = true;
+		let sb = new hx_strings_StringBuilder();
+		let _g = 0;
+		let _g1 = hx_strings_Strings.REGEX_SPLIT_LINES.ereg.split(str);
+		while(_g < _g1.length) {
+			let line = _g1[_g];
+			++_g;
+			if(isFirstLine) {
+				isFirstLine = false;
+			} else {
+				sb.newLine();
+			}
+			sb.add(indentWith);
+			sb.add(line);
+		}
+		return sb.toString();
+	}
+	static indexOf8(str,searchFor,startAt) {
+		if(startAt == null) {
+			startAt = 0;
+		}
+		if(str == null || searchFor == null) {
+			return -1;
+		}
+		let strLen = str == null ? 0 : str.length;
+		let searchForLen = searchFor == null ? 0 : searchFor.length;
+		if(startAt < 0) {
+			startAt = 0;
+		}
+		if(searchForLen == 0) {
+			if(startAt == 0) {
+				return 0;
+			}
+			if(startAt > 0 && startAt < strLen) {
+				return startAt;
+			}
+			return strLen;
+		}
+		if(startAt >= strLen) {
+			return -1;
+		}
+		return str.indexOf(searchFor,startAt);
+	}
+	static isBlank(str) {
+		if(str == null) {
+			return true;
+		} else {
+			return StringTools.trim(str).length == 0;
+		}
+	}
+	static isDigits(str) {
+		if(str == null || str.length == 0) {
+			return false;
+		}
+		let _g = 0;
+		let _g1 = str == null ? 0 : str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let this1 = HxOverrides.cca(str,i);
+			if(!(this1 > 47 && this1 < 58)) {
+				return false;
+			}
+		}
+		return true;
+	}
+	static isEmpty(str) {
+		if(str != null) {
+			return str.length == 0;
+		} else {
+			return true;
+		}
+	}
+	static isNotBlank(str) {
+		if(str != null) {
+			return StringTools.trim(str).length > 0;
+		} else {
+			return false;
+		}
+	}
+	static isNotEmpty(str) {
+		if(str != null) {
+			return str.length > 0;
+		} else {
+			return false;
+		}
+	}
+	static isLowerCase(str) {
+		if(str == null || str.length == 0) {
+			return false;
+		}
+		return str == hx_strings_Strings.toLowerCase8(str);
+	}
+	static isUpperCase(str) {
+		if(str == null || str.length == 0) {
+			return false;
+		}
+		return str == hx_strings_Strings.toUpperCase8(str);
+	}
+	static iterate(str,callback,separator) {
+		if(separator == null) {
+			separator = "";
+		}
+		if(str == null || str.length == 0) {
+			return;
+		}
+		let _g = 0;
+		let _g1 = hx_strings_Strings.split8(str,[separator]);
+		while(_g < _g1.length) {
+			let sub = _g1[_g];
+			++_g;
+			callback(sub);
+		}
+	}
+	static iterateChars(str,callback) {
+		if(str == null || str.length == 0) {
+			return;
+		}
+		let _g = 0;
+		let _g1 = str == null ? 0 : str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			callback(HxOverrides.cca(str,i));
+		}
+	}
+	static lastIndexOf8(str,searchFor,startAt) {
+		if(str == null || searchFor == null) {
+			return -1;
+		}
+		let strLen = str == null ? 0 : str.length;
+		let searchForLen = searchFor == null ? 0 : searchFor.length;
+		if(startAt == null) {
+			startAt = strLen;
+		}
+		if(searchForLen == 0) {
+			if(startAt < 0) {
+				return 0;
+			}
+			if(startAt > strLen) {
+				return strLen;
+			}
+			return startAt;
+		}
+		if(startAt < 0) {
+			return -1;
+		} else if(startAt >= strLen) {
+			startAt = strLen - 1;
+		}
+		let strNeedsUTF8Workaround = str.length != strLen;
+		let searchForNeedsUTF8Workaround = searchFor.length != searchForLen;
+		if(!strNeedsUTF8Workaround && !searchForNeedsUTF8Workaround) {
+			return str.lastIndexOf(searchFor,startAt);
+		}
+		if(searchForNeedsUTF8Workaround && !strNeedsUTF8Workaround) {
+			return -1;
+		}
+		let searchForChars = hx_strings_Strings.toChars(searchFor);
+		startAt += searchForLen - 1;
+		let searchForPosToCheck = searchForLen - 1;
+		let strPos = strLen;
+		while(strPos-- > 0) {
+			if(strPos > startAt) {
+				continue;
+			}
+			let strCh = HxOverrides.cca(str,strPos);
+			if(strCh == searchForChars[searchForPosToCheck]) {
+				if(searchForPosToCheck == 0) {
+					return strPos;
+				}
+				--searchForPosToCheck;
+			} else {
+				searchForPosToCheck = searchForLen - 1;
+			}
+		}
+		return -1;
+	}
+	static length8(str) {
+		if(str == null) {
+			return 0;
+		}
+		return str.length;
+	}
+	static left(str,len) {
+		if((str == null ? 0 : str.length) <= len) {
+			return str;
+		}
+		return hx_strings_Strings.substring8(str,0,len);
+	}
+	static lpad(str,targetLength,padStr,canOverflow) {
+		if(canOverflow == null) {
+			canOverflow = true;
+		}
+		if(padStr == null) {
+			padStr = " ";
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(str == null || strLen > targetLength) {
+			return str;
+		}
+		if(padStr == null || padStr.length == 0) {
+			padStr = " ";
+		}
+		let sb = [str];
+		let padLen = padStr == null ? 0 : padStr.length;
+		while(strLen < targetLength) {
+			sb.unshift(padStr);
+			strLen += padLen;
+		}
+		if(canOverflow) {
+			return sb.join("");
+		}
+		return hx_strings_Strings.right(sb.join(""),targetLength);
+	}
+	static map(str,mapper,separator) {
+		if(separator == null) {
+			separator = "";
+		}
+		if(str == null) {
+			return null;
+		}
+		if(separator == null) {
+			throw haxe_Exception.thrown("[separator] must not be null");
+		}
+		let _this = hx_strings_Strings.split8(str,[separator]);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = mapper(_this[i]);
+		}
+		return result;
+	}
+	static prependIfMissing(str,suffix) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0) {
+			return suffix + Std.string(str);
+		}
+		if(hx_strings_Strings.startsWith(str,suffix)) {
+			return str;
+		}
+		return suffix + Std.string(str);
+	}
+	static quoteDouble(str) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0) {
+			return "\"\"";
+		}
+		if(!(str == null ? false : str.indexOf("\"") > -1)) {
+			return "\"" + Std.string(str) + "\"";
+		}
+		return "\"" + Std.string(hx_strings_Strings.replaceAll(str,"\"","\\\"")) + "\"";
+	}
+	static quoteSingle(str) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0) {
+			return "''";
+		}
+		if(!(str == null ? false : str.indexOf("'") > -1)) {
+			return "'" + Std.string(str) + "'";
+		}
+		return "'" + Std.string(hx_strings_Strings.replaceAll(str,"'","\\'")) + "'";
+	}
+	static removeAfter(str,searchFor) {
+		return hx_strings_Strings.substringBefore(str,searchFor);
+	}
+	static removeAfterLast(str,searchFor) {
+		return hx_strings_Strings.substringBeforeLast(str,searchFor);
+	}
+	static removeAfterIgnoreCase(str,searchFor) {
+		return hx_strings_Strings.substringBeforeIgnoreCase(str,searchFor);
+	}
+	static removeAfterLastIgnoreCase(str,searchFor) {
+		return hx_strings_Strings.substringBeforeLastIgnoreCase(str,searchFor);
+	}
+	static removeAt(str,pos,length) {
+		if(str == null || str.length == 0 || length < 1) {
+			return str;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(pos < 0) {
+			pos = strLen + pos;
+		}
+		if(pos < 0) {
+			throw haxe_Exception.thrown("[pos] must be smaller than -1 * str.length");
+		}
+		if(pos + length >= strLen) {
+			return hx_strings_Strings.substring8(str,0,pos);
+		}
+		return Std.string(hx_strings_Strings.substring8(str,0,pos)) + Std.string(hx_strings_Strings.substring8(str,pos + length));
+	}
+	static removeBefore(str,searchFor) {
+		return hx_strings_Strings.substringAfter(str,searchFor);
+	}
+	static removeBeforeLast(str,searchFor) {
+		return hx_strings_Strings.substringAfterLast(str,searchFor);
+	}
+	static removeBeforeIgnoreCase(str,searchFor) {
+		return hx_strings_Strings.substringAfterIgnoreCase(str,searchFor);
+	}
+	static removeBeforeLastIgnoreCase(str,searchFor) {
+		return hx_strings_Strings.substringAfterLastIgnoreCase(str,searchFor);
+	}
+	static removeAll(searchIn,searchFor) {
+		return hx_strings_Strings.replaceAll(searchIn,searchFor,"");
+	}
+	static removeFirst(searchIn,searchFor) {
+		return hx_strings_Strings.replaceFirst(searchIn,searchFor,"");
+	}
+	static removeFirstIgnoreCase(searchIn,searchFor) {
+		return hx_strings_Strings.replaceFirstIgnoreCase(searchIn,searchFor,"");
+	}
+	static removeAnsi(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return str.replace(hx_strings_Strings.REGEX_ANSI_ESC.ereg.r,"");
+	}
+	static removeLeading(searchIn,searchFor) {
+		if(searchIn == null || searchIn.length == 0 || (searchFor == null || searchFor.length == 0)) {
+			return searchIn;
+		}
+		while(hx_strings_Strings.startsWith(searchIn,searchFor)) searchIn = searchIn.substring(searchFor.length,searchIn.length);
+		return searchIn;
+	}
+	static removeTags(xml) {
+		if(xml == null || xml.length == 0) {
+			return xml;
+		}
+		return xml.replace(hx_strings_Strings.REGEX_REMOVE_XML_TAGS.ereg.r,"");
+	}
+	static removeTrailing(searchIn,searchFor) {
+		if(searchIn == null || searchIn.length == 0 || (searchFor == null || searchFor.length == 0)) {
+			return searchIn;
+		}
+		while(hx_strings_Strings.endsWith(searchIn,searchFor)) searchIn = searchIn.substring(0,searchIn.length - searchFor.length);
+		return searchIn;
+	}
+	static repeat(str,count,separator) {
+		if(separator == null) {
+			separator = "";
+		}
+		if(str == null) {
+			return null;
+		}
+		if(count < 1) {
+			return "";
+		}
+		if(count == 1) {
+			return str;
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = count;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(str);
+		}
+		return _g.join(separator);
+	}
+	static replaceAll(searchIn,searchFor,replaceWith) {
+		if(searchIn == null || (searchIn == null || searchIn.length == 0) || searchFor == null) {
+			return searchIn;
+		}
+		if(replaceWith == null) {
+			replaceWith = "null";
+		}
+		return StringTools.replace(searchIn,searchFor,replaceWith);
+	}
+	static replaceFirst(searchIn,searchFor,replaceWith) {
+		if(searchIn == null || (searchIn == null || searchIn.length == 0) || searchFor == null) {
+			return searchIn;
+		}
+		if(replaceWith == null) {
+			replaceWith = "null";
+		}
+		let foundAt;
+		if(searchFor.length == 0) {
+			if((searchIn == null ? 0 : searchIn.length) > 1) {
+				foundAt = 1;
+			} else {
+				return searchIn;
+			}
+		} else {
+			foundAt = hx_strings_Strings.indexOf8(searchIn,searchFor);
+		}
+		return Std.string(hx_strings_Strings.substr8(searchIn,0,foundAt)) + replaceWith + Std.string(hx_strings_Strings.substr8(searchIn,foundAt + (searchFor == null ? 0 : searchFor.length)));
+	}
+	static replaceFirstIgnoreCase(searchIn,searchFor,replaceWith) {
+		if(searchIn == null || (searchIn == null || searchIn.length == 0) || searchFor == null) {
+			return searchIn;
+		}
+		if(replaceWith == null) {
+			replaceWith = "null";
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt;
+		if(searchFor.length == 0) {
+			if((searchIn == null ? 0 : searchIn.length) > 1) {
+				foundAt = 1;
+			} else {
+				return searchIn;
+			}
+		} else {
+			foundAt = hx_strings_Strings.indexOf8(searchIn.toLowerCase(),searchFor);
+		}
+		return Std.string(hx_strings_Strings.substr8(searchIn,0,foundAt)) + replaceWith + Std.string(hx_strings_Strings.substr8(searchIn,foundAt + (searchFor == null ? 0 : searchFor.length)));
+	}
+	static reverse(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let chars = hx_strings_Strings.split8(str,[""]);
+		chars.reverse();
+		return chars.join("");
+	}
+	static right(str,len) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return hx_strings_Strings.substring8(str,(str == null ? 0 : str.length) - len);
+	}
+	static rpad(str,targetLength,padStr,canOverflow) {
+		if(canOverflow == null) {
+			canOverflow = true;
+		}
+		if(padStr == null) {
+			padStr = " ";
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(str == null || strLen > targetLength) {
+			return str;
+		}
+		if(padStr == null || padStr.length == 0) {
+			padStr = " ";
+		}
+		let padLen = padStr == null ? 0 : padStr.length;
+		let sb = new hx_strings_StringBuilder(str);
+		while(strLen < targetLength) {
+			sb.add(padStr);
+			strLen += padLen;
+		}
+		if(canOverflow) {
+			return sb.toString();
+		}
+		let str1 = sb.toString();
+		return (str1 == null ? 0 : str1.length) <= targetLength ? str1 : hx_strings_Strings.substring8(str1,0,targetLength);
+	}
+	static split8(str,separator,maxParts) {
+		if(maxParts == null) {
+			maxParts = 0;
+		}
+		if(str == null || separator == null) {
+			return null;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0) {
+			return [];
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = separator;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v != null) {
+				_g.push(v);
+			}
+		}
+		let separators = _g;
+		if(separators.length == 0) {
+			return null;
+		}
+		if(maxParts <= 0 && separators.length == 1) {
+			return str.split(separators[0]);
+		}
+		if(separators.indexOf("") > -1) {
+			if(maxParts <= 0) {
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = strLen;
+				while(_g1 < _g2) {
+					let i = _g1++;
+					_g.push(HxOverrides.substr(str,i,1));
+				}
+				return _g;
+			}
+			if(maxParts > strLen) {
+				maxParts = strLen;
+			}
+			--maxParts;
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = maxParts;
+			while(_g1 < _g2) {
+				let i = _g1++;
+				_g.push(HxOverrides.substr(str,i,1));
+			}
+			let result = _g;
+			result.push(HxOverrides.substr(str,maxParts,strLen - maxParts));
+			return result;
+		}
+		let _g3 = [];
+		let _g4 = 0;
+		while(_g4 < separators.length) {
+			let sep = separators[_g4];
+			++_g4;
+			_g3.push(sep == null ? 0 : sep.length);
+		}
+		let separatorsLengths = _g3;
+		let lastFoundAt = 0;
+		let result = [];
+		let resultCount = 0;
+		while(true) {
+			let separatorLen = 0;
+			let foundAt = -1;
+			let _g = 0;
+			let _g1 = separators.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let sepFoundAt = hx_strings_Strings.indexOf8(str,separators[i],lastFoundAt);
+				if(sepFoundAt != -1) {
+					if(foundAt == -1 || sepFoundAt < foundAt) {
+						foundAt = sepFoundAt;
+						separatorLen = separatorsLengths[i];
+					}
+				}
+			}
+			++resultCount;
+			if(foundAt == -1 || resultCount == maxParts) {
+				result.push(HxOverrides.substr(str,lastFoundAt,strLen - lastFoundAt));
+				break;
+			}
+			result.push(HxOverrides.substr(str,lastFoundAt,foundAt - lastFoundAt));
+			lastFoundAt = foundAt + separatorLen;
+		}
+		return result;
+	}
+	static splitAt(str,splitPos) {
+		if(str == null) {
+			return null;
+		}
+		if(splitPos == null || splitPos.length == 0) {
+			return [str];
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0) {
+			return [str];
+		}
+		let pos = [];
+		let _g = 0;
+		let _g1 = splitPos;
+		while(_g < _g1.length) {
+			let p = _g1[_g];
+			++_g;
+			if(p < 0) {
+				p = strLen + p;
+			}
+			if(p < 0 || p >= strLen) {
+				continue;
+			}
+			if(pos.indexOf(p) > -1) {
+				continue;
+			}
+			pos.push(p);
+		}
+		pos.sort(function(a,b) {
+			if(a < b) {
+				return -1;
+			} else if(a > b) {
+				return 1;
+			} else {
+				return 0;
+			}
+		});
+		let result = [];
+		let lastPos = 0;
+		let _g2 = 0;
+		while(_g2 < pos.length) {
+			let p = pos[_g2];
+			++_g2;
+			let chunk = hx_strings_Strings.substring8(str,lastPos,p);
+			if(chunk != null && chunk.length > 0) {
+				result.push(chunk);
+			}
+			lastPos = p;
+		}
+		let chunk = hx_strings_Strings.substring8(str,lastPos);
+		if(chunk != null && chunk.length > 0) {
+			result.push(chunk);
+		}
+		return result;
+	}
+	static splitEvery(str,count) {
+		if(str == null) {
+			return null;
+		}
+		if(count < 1) {
+			throw haxe_Exception.thrown("[count] must be greater than 0");
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0 || count >= strLen) {
+			return [str];
+		}
+		let result = [];
+		let pos = 0;
+		while(true) {
+			let chunk = hx_strings_Strings.substr8(str,pos,count);
+			pos += count;
+			if(chunk == null || chunk.length == 0) {
+				break;
+			}
+			result.push(chunk);
+		}
+		return result;
+	}
+	static splitLines(str) {
+		if(str == null || str.length == 0) {
+			return [];
+		} else {
+			return hx_strings_Strings.REGEX_SPLIT_LINES.ereg.split(str);
+		}
+	}
+	static startsWith(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		if(searchFor == null || searchFor.length == 0 || searchIn == searchFor) {
+			return true;
+		}
+		return searchIn.startsWith(searchFor);
+	}
+	static startsWithAny(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(candidate != null && hx_strings_Strings.startsWith(searchIn,candidate)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static startsWithAnyIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		searchIn = hx_strings_Strings.toLowerCase8(searchIn);
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(candidate != null && hx_strings_Strings.startsWith(searchIn,hx_strings_Strings.toLowerCase8(candidate))) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static startsWithIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		if(searchFor == null || searchFor.length == 0) {
+			return true;
+		}
+		return hx_strings_Strings.startsWith(searchIn.toLowerCase(),searchFor.toLowerCase());
+	}
+	static substr8(str,startAt,len) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(len == null) {
+			len = str == null ? 0 : str.length;
+		}
+		if(len <= 0) {
+			return "";
+		}
+		if(startAt < 0) {
+			startAt += str == null ? 0 : str.length;
+			if(startAt < 0) {
+				startAt = 0;
+			}
+		}
+		return HxOverrides.substr(str,startAt,len);
+	}
+	static substring8(str,startAt,endAt) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(endAt == null) {
+			endAt = str == null ? 0 : str.length;
+		}
+		return str.substring(startAt,endAt);
+	}
+	static substringAfter(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return str;
+		}
+		if(str == "" || searchFor == null || searchFor == "") {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAt = str.indexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAt + searchFor.length);
+	}
+	static substringAfterIgnoreCase(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt = str.toLowerCase().indexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAt + searchFor.length);
+	}
+	static substringBetween(str,after,before,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(before == null) {
+			before = after;
+		}
+		if(str == "" || (after == null || after.length == 0) || (before == null || before.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAfterAt = str.indexOf(after);
+		if(foundAfterAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundBeforeAt = str.indexOf(before,foundAfterAt + after.length);
+		if(foundBeforeAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAfterAt + after.length,foundBeforeAt);
+	}
+	static substringBetweenIgnoreCase(str,after,before,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(before == null) {
+			before = after;
+		}
+		if(str == "" || (after == null || after.length == 0) || (before == null || before.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let strLower = hx_strings_Strings.toLowerCase8(str);
+		let after1 = hx_strings_Strings.toLowerCase8(after);
+		let before1 = hx_strings_Strings.toLowerCase8(before);
+		let foundAfterAt = strLower.indexOf(after1);
+		if(foundAfterAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundBeforeAt = strLower.indexOf(before1,foundAfterAt + after1.length);
+		if(foundBeforeAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAfterAt + after1.length,foundBeforeAt);
+	}
+	static substringAfterLast(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAt = str.lastIndexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAt + searchFor.length);
+	}
+	static substringAfterLastIgnoreCase(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt = str.toLowerCase().lastIndexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAt + searchFor.length);
+	}
+	static substringBefore(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAt = str.indexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(0,foundAt);
+	}
+	static substringBeforeIgnoreCase(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt = str.toLowerCase().indexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(0,foundAt);
+	}
+	static substringBeforeLast(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAt = str.lastIndexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(0,foundAt);
+	}
+	static substringBeforeLastIgnoreCase(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt = str.toLowerCase().lastIndexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(0,foundAt);
+	}
+	static toBool(str) {
+		if(str == null || str.length == 0) {
+			return false;
+		}
+		switch(str.toLowerCase()) {
+		case "0":case "false":case "no":
+			return false;
+		default:
+			return true;
+		}
+	}
+	static toBytes(str) {
+		if(str == null) {
+			return null;
+		}
+		return haxe_io_Bytes.ofString(str);
+	}
+	static toChar(charCode) {
+		return charCode;
+	}
+	static toCharIterator(str) {
+		if(str == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		} else {
+			return new hx_strings__$CharIterator_StringCharIterator(str,0);
+		}
+	}
+	static toChars(str) {
+		if(str == null) {
+			return null;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0) {
+			return [];
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = strLen;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(HxOverrides.cca(str,i));
+		}
+		return _g;
+	}
+	static toPattern(str,options) {
+		if(str == null) {
+			return null;
+		}
+		return hx_strings_Pattern.compile(str,options);
+	}
+	static toEReg(str,opt) {
+		if(opt == null) {
+			opt = "";
+		}
+		if(str == null) {
+			throw haxe_Exception.thrown("[str] must not be null");
+		}
+		return new EReg(str,opt);
+	}
+	static toFloat(str,ifUnparseable) {
+		if(str == null) {
+			return ifUnparseable;
+		}
+		let result = parseFloat(str);
+		if(isNaN(result)) {
+			return ifUnparseable;
+		} else {
+			return result;
+		}
+	}
+	static toFloatOrNull(str,ifUnparseable) {
+		if(str == null) {
+			return ifUnparseable;
+		}
+		let result = parseFloat(str);
+		if(isNaN(result)) {
+			return ifUnparseable;
+		} else {
+			return result;
+		}
+	}
+	static toHex(num,minDigits,upperCase) {
+		if(upperCase == null) {
+			upperCase = true;
+		}
+		if(minDigits == null) {
+			minDigits = 0;
+		}
+		let hexed = StringTools.hex(num,0);
+		if(!upperCase) {
+			return hexed.toLowerCase();
+		}
+		if(hexed.length >= minDigits) {
+			return hexed;
+		}
+		return hx_strings_Strings.lpad(hexed,minDigits,"0");
+	}
+	static toInt(str,ifUnparseable) {
+		if(str == null) {
+			return ifUnparseable;
+		}
+		let result = Std.parseInt(str);
+		if(result == null) {
+			return ifUnparseable;
+		} else {
+			return result;
+		}
+	}
+	static toIntOrNull(str,ifUnparseable) {
+		if(str == null) {
+			return ifUnparseable;
+		}
+		let result = Std.parseInt(str);
+		if(result == null) {
+			return ifUnparseable;
+		} else {
+			return result;
+		}
+	}
+	static toLowerCase8(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return str.toLowerCase();
+	}
+	static toLowerCaseFirstChar(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let this1 = HxOverrides.cca(str,0);
+		let lowerChar = hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h[this1];
+		let firstChar = lowerChar == null ? this1 : lowerChar;
+		if(str.length == 1) {
+			return String.fromCodePoint(firstChar);
+		}
+		let other = hx_strings_Strings.substr8(str,1);
+		return String.fromCodePoint(firstChar) + other;
+	}
+	static toLowerCamel(str,keepUppercasedWords) {
+		if(keepUppercasedWords == null) {
+			keepUppercasedWords = true;
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		if(keepUppercasedWords) {
+			let _g = 0;
+			let _g1 = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			while(_g < _g1.length) {
+				let word = _g1[_g];
+				++_g;
+				sb.add(hx_strings_Strings.toUpperCaseFirstChar(word));
+			}
+		} else {
+			let _g = 0;
+			let _g1 = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			while(_g < _g1.length) {
+				let word = _g1[_g];
+				++_g;
+				sb.add(hx_strings_Strings.toUpperCaseFirstChar(hx_strings_Strings.toLowerCase8(word)));
+			}
+		}
+		return hx_strings_Strings.toLowerCaseFirstChar(sb.toString());
+	}
+	static toLowerHyphen(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.toLowerCase8(_this[i]);
+		}
+		return result.join("-");
+	}
+	static toLowerUnderscore(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.toLowerCase8(_this[i]);
+		}
+		return result.join("_");
+	}
+	static toTitle(str,keepUppercasedWords) {
+		if(keepUppercasedWords == null) {
+			keepUppercasedWords = true;
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(keepUppercasedWords) {
+			let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let s = _this[i];
+				result[i] = hx_strings_Strings.toUpperCase8(s) == s ? s : hx_strings_Strings.toUpperCaseFirstChar(hx_strings_Strings.toLowerCase8(s));
+			}
+			return result.join(" ");
+		}
+		let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.toUpperCaseFirstChar(hx_strings_Strings.toLowerCase8(_this[i]));
+		}
+		return result.join(" ");
+	}
+	static toUpperCamel(str,keepUppercasedWords) {
+		if(keepUppercasedWords == null) {
+			keepUppercasedWords = true;
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		if(keepUppercasedWords) {
+			let _g = 0;
+			let _g1 = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			while(_g < _g1.length) {
+				let word = _g1[_g];
+				++_g;
+				sb.add(hx_strings_Strings.toUpperCaseFirstChar(word));
+			}
+		} else {
+			let _g = 0;
+			let _g1 = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			while(_g < _g1.length) {
+				let word = _g1[_g];
+				++_g;
+				sb.add(hx_strings_Strings.toUpperCaseFirstChar(hx_strings_Strings.toLowerCase8(word)));
+			}
+		}
+		return sb.toString();
+	}
+	static toUpperUnderscore(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.toUpperCase8(_this[i]);
+		}
+		return result.join("_");
+	}
+	static toString(str) {
+		if(str == null) {
+			return "null";
+		} else {
+			return str;
+		}
+	}
+	static toUpperCase8(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		let _g = 0;
+		let _g1 = str == null ? 0 : str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let this1 = HxOverrides.cca(str,i);
+			let upperChar = hx_strings_Char.CHAR_CASE_MAPPER.mapL2U.h[this1];
+			sb.addChar(upperChar == null ? this1 : upperChar);
+		}
+		return sb.toString();
+	}
+	static toUpperCaseFirstChar(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let this1 = HxOverrides.cca(str,0);
+		let upperChar = hx_strings_Char.CHAR_CASE_MAPPER.mapL2U.h[this1];
+		let firstChar = upperChar == null ? this1 : upperChar;
+		if(str.length == 1) {
+			return String.fromCodePoint(firstChar);
+		}
+		let other = hx_strings_Strings.substr8(str,1);
+		return String.fromCodePoint(firstChar) + other;
+	}
+	static trim(str,charsToRemove) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(charsToRemove == null) {
+			return StringTools.trim(str);
+		}
+		let removableChars;
+		let _g = charsToRemove;
+		switch(_g._hx_index) {
+		case 0:
+			let str1 = _g.v;
+			removableChars = hx_strings_Strings.toChars(str1);
+			break;
+		case 1:
+			let chars = _g.v;
+			removableChars = chars;
+			break;
+		}
+		return hx_strings_Strings.trimLeft(hx_strings_Strings.trimRight(str,hx_strings_internal__$Either2__$Either2.b(removableChars)),hx_strings_internal__$Either2__$Either2.b(removableChars));
+	}
+	static trimRight(str,charsToRemove) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(charsToRemove == null) {
+			return StringTools.rtrim(str);
+		}
+		let removableChars;
+		let _g = charsToRemove;
+		switch(_g._hx_index) {
+		case 0:
+			let str1 = _g.v;
+			removableChars = hx_strings_Strings.toChars(str1);
+			break;
+		case 1:
+			let chars = _g.v;
+			removableChars = chars;
+			break;
+		}
+		if(removableChars.length == 0) {
+			return str;
+		}
+		let len = str == null ? 0 : str.length;
+		let i = len - 1;
+		while(i > -1 && removableChars.indexOf(hx_strings_Strings.charCodeAt8(hx_strings_Strings.charAt8(str,i),0)) > -1) --i;
+		if(i < len - 1) {
+			return hx_strings_Strings.substring8(str,0,i + 1);
+		}
+		return str;
+	}
+	static trimLeft(str,charsToRemove) {
+		if(str == null) {
+			return str;
+		}
+		if(charsToRemove == null) {
+			return StringTools.ltrim(str);
+		}
+		let removableChars;
+		let _g = charsToRemove;
+		switch(_g._hx_index) {
+		case 0:
+			let str1 = _g.v;
+			removableChars = hx_strings_Strings.toChars(str1);
+			break;
+		case 1:
+			let chars = _g.v;
+			removableChars = chars;
+			break;
+		}
+		if(removableChars.length == 0) {
+			return str;
+		}
+		let len = str == null ? 0 : str.length;
+		let i = 0;
+		while(i < len && removableChars.indexOf(hx_strings_Strings.charCodeAt8(hx_strings_Strings.charAt8(str,i),0)) > -1) ++i;
+		if(i > 0) {
+			return hx_strings_Strings.substring8(str,i,len);
+		}
+		return str;
+	}
+	static trimLines(str,charsToRemove) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings.REGEX_SPLIT_LINES.ereg.split(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.trim(_this[i],charsToRemove);
+		}
+		return result.join("\n");
+	}
+	static trimToNull(str) {
+		if(str == null) {
+			return null;
+		}
+		let trimmed = hx_strings_Strings.trim(str);
+		if(trimmed == null || trimmed.length == 0) {
+			return null;
+		}
+		return trimmed;
+	}
+	static trimToEmpty(str) {
+		let trimmed = hx_strings_Strings.trim(str);
+		if(trimmed == null || trimmed.length == 0) {
+			return "";
+		}
+		return trimmed;
+	}
+	static truncate(str,maxLength) {
+		if((str == null ? 0 : str.length) <= maxLength) {
+			return str;
+		} else {
+			return hx_strings_Strings.substring8(str,0,maxLength);
+		}
+	}
+	static urlDecode(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return decodeURIComponent(str.split("+").join(" "));
+	}
+	static urlEncode(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return encodeURIComponent(str);
+	}
+	static wrap(str,maxLineLength,splitLongWords,newLineSeparator) {
+		if(newLineSeparator == null) {
+			newLineSeparator = "\n";
+		}
+		if(splitLongWords == null) {
+			splitLongWords = true;
+		}
+		if((str == null ? 0 : str.length) <= maxLineLength || maxLineLength < 1) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		let wordChars = [];
+		let currLineLength = 0;
+		let _g = 0;
+		let _g1 = hx_strings_Strings.toChars(str);
+		while(_g < _g1.length) {
+			let ch = _g1[_g];
+			++_g;
+			if(ch > 8 && ch < 14 || ch == 32) {
+				if(wordChars.length > 0) {
+					let _g = 0;
+					while(_g < wordChars.length) {
+						let wordCh = wordChars[_g];
+						++_g;
+						if(currLineLength == maxLineLength && splitLongWords) {
+							sb.add(newLineSeparator);
+							currLineLength = 0;
+						}
+						++currLineLength;
+						sb.addChar(wordCh);
+					}
+					wordChars = [];
+				}
+				if(currLineLength >= maxLineLength) {
+					sb.add(newLineSeparator);
+					currLineLength = 0;
+				}
+				sb.addChar(ch);
+				++currLineLength;
+			} else {
+				wordChars.push(ch);
+			}
+		}
+		if(wordChars.length > 0) {
+			let _g = 0;
+			while(_g < wordChars.length) {
+				let wordCh = wordChars[_g];
+				++_g;
+				if(currLineLength == maxLineLength && splitLongWords) {
+					sb.add(newLineSeparator);
+					currLineLength = 0;
+				}
+				++currLineLength;
+				sb.addChar(wordCh);
+			}
+		}
+		return sb.toString();
+	}
+}
+hx_strings_Strings.__name__ = "hx.strings.Strings";
+class hx_strings_RandomStrings {
+	static _genAsciiAlpha() {
+		let chars = [];
+		chars.push(65);
+		chars.push(66);
+		chars.push(67);
+		chars.push(68);
+		chars.push(69);
+		chars.push(70);
+		chars.push(71);
+		chars.push(72);
+		chars.push(73);
+		chars.push(74);
+		chars.push(75);
+		chars.push(76);
+		chars.push(77);
+		chars.push(78);
+		chars.push(79);
+		chars.push(80);
+		chars.push(81);
+		chars.push(82);
+		chars.push(83);
+		chars.push(84);
+		chars.push(85);
+		chars.push(86);
+		chars.push(87);
+		chars.push(88);
+		chars.push(89);
+		chars.push(90);
+		chars.push(97);
+		chars.push(98);
+		chars.push(99);
+		chars.push(100);
+		chars.push(101);
+		chars.push(102);
+		chars.push(103);
+		chars.push(104);
+		chars.push(105);
+		chars.push(106);
+		chars.push(107);
+		chars.push(108);
+		chars.push(109);
+		chars.push(110);
+		chars.push(111);
+		chars.push(112);
+		chars.push(113);
+		chars.push(114);
+		chars.push(115);
+		chars.push(116);
+		chars.push(117);
+		chars.push(118);
+		chars.push(119);
+		chars.push(120);
+		chars.push(121);
+		chars.push(122);
+		return chars;
+	}
+	static randomAsciiAlpha(length) {
+		return hx_strings_RandomStrings.random(length,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA));
+	}
+	static randomAsciiAlphaNumeric(length) {
+		return hx_strings_RandomStrings.random(length,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC));
+	}
+	static randomDigits(length) {
+		return hx_strings_RandomStrings.random(length,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.DIGITS));
+	}
+	static random(length,chars) {
+		if(length == 0) {
+			return "";
+		}
+		if(length < 0) {
+			throw haxe_Exception.thrown("[count] must be positive value");
+		}
+		if(chars == null) {
+			throw haxe_Exception.thrown("[chars] must not be null");
+		}
+		let charsArray;
+		let _g = chars;
+		switch(_g._hx_index) {
+		case 0:
+			let str = _g.v;
+			charsArray = hx_strings_Strings.toChars(str);
+			break;
+		case 1:
+			let chars1 = _g.v;
+			charsArray = chars1;
+			break;
+		}
+		if(charsArray.length == 0) {
+			throw haxe_Exception.thrown("[chars] must not be empty");
+		}
+		let result = new hx_strings_StringBuilder();
+		let _g1 = 0;
+		let _g2 = length;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			result.addChar(charsArray[Math.floor(charsArray.length * Math.random())]);
+		}
+		return result.toString();
+	}
+	static randomSubstring(str,substringLength) {
+		if(substringLength == null) {
+			substringLength = 1;
+		}
+		if(str == null || str.length == 0) {
+			throw haxe_Exception.thrown("[str] must not be null or empty");
+		}
+		if(substringLength < 1) {
+			throw haxe_Exception.thrown("[substringLength] must not be smaller than 1");
+		}
+		let len = str == null ? 0 : str.length;
+		if(substringLength > len) {
+			throw haxe_Exception.thrown("[substringLength] must not be larger than str.length");
+		}
+		if(substringLength == len) {
+			return str;
+		}
+		let startAt = Math.floor((len - substringLength + 1) * Math.random());
+		return hx_strings_Strings.substr8(str,startAt,substringLength);
+	}
+	static randomUUIDv4(separator) {
+		if(separator == null) {
+			separator = "-";
+		}
+		if(separator == null) {
+			throw haxe_Exception.thrown("[separator] must not be null");
+		}
+		let variantByte = Math.floor(Math.random() * 16);
+		variantByte |= 8;
+		variantByte &= -5;
+		return (StringTools.hex(Math.floor(Math.random() * 65536),4) + StringTools.hex(Math.floor(Math.random() * 65536),4) + separator + StringTools.hex(Math.floor(Math.random() * 65536),4) + separator + "4" + StringTools.hex(Math.floor(Math.random() * 4096),3) + separator + StringTools.hex(variantByte) + StringTools.hex(Math.floor(Math.random() * 4096),3) + separator + StringTools.hex(Math.floor(Math.random() * 65536),4) + StringTools.hex(Math.floor(Math.random() * 65536),4) + StringTools.hex(Math.floor(Math.random() * 65536),4)).toLowerCase();
+	}
+}
+hx_strings_RandomStrings.__name__ = "hx.strings.RandomStrings";
+class hx_strings_StringBuilder {
+	constructor(initialContent) {
+		this.len = 0;
+		this.pre = null;
+		this.sb = new StringBuf();
+		if(initialContent != null) {
+			this.add(initialContent);
+		}
+	}
+	get_length() {
+		return this.len;
+	}
+	add(item) {
+		this.sb.b += Std.string(item == null ? "null" : item);
+		this.len += item == null ? 0 : item.length;
+		return this;
+	}
+	addChar(ch) {
+		if(ch > -1 && ch < 128) {
+			this.sb.b += String.fromCodePoint(ch);
+		} else {
+			let _this = this.sb;
+			let x = String.fromCodePoint(ch);
+			_this.b += Std.string(x);
+		}
+		this.len++;
+		return this;
+	}
+	addAll(items) {
+		let _g = 0;
+		while(_g < items.length) {
+			let item = items[_g];
+			++_g;
+			this.sb.b += Std.string(item);
+			this.len += item == null ? 0 : item.length;
+		}
+		return this;
+	}
+	clear() {
+		this.pre = null;
+		this.sb = new StringBuf();
+		this.len = 0;
+		return this;
+	}
+	isEmpty() {
+		return this.len == 0;
+	}
+	newLine() {
+		this.sb.b += "\n";
+		this.len++;
+		return this;
+	}
+	insert(pos,item) {
+		if(pos < 0) {
+			throw haxe_Exception.thrown("[pos] must not be negative");
+		}
+		if(pos > this.len) {
+			throw haxe_Exception.thrown("[pos] must not be greater than this.length");
+		}
+		if(pos == this.len) {
+			this.add(item);
+			return this;
+		}
+		if(pos == 0) {
+			if(this.pre == null) {
+				this.pre = [];
+			}
+			this.pre.unshift(item);
+			this.len += item == null ? 0 : item.length;
+			return this;
+		}
+		let pre_len = 0;
+		if(this.pre != null) {
+			let pre = this.pre;
+			let i = pre.length;
+			let _g = 0;
+			let _g1 = pre.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let str = pre[i];
+				let next_pre_len = pre_len + (str == null ? 0 : str.length);
+				if(next_pre_len == pos) {
+					pre.splice(i + 1,0,item);
+					this.len += item == null ? 0 : item.length;
+					return this;
+				}
+				if(next_pre_len > pos) {
+					let preSplitted = hx_strings_Strings.splitAt(pre[i],[pos - pre_len]);
+					pre[i] = preSplitted[0];
+					pre.splice(i + 1,0,item);
+					pre.splice(i + 2,0,preSplitted[1]);
+					this.len += item == null ? 0 : item.length;
+					return this;
+				}
+				pre_len = next_pre_len;
+			}
+		}
+		if(this.sb.b.length == 0) {
+			this.add(item);
+			return this;
+		}
+		let sbSplitted = hx_strings_Strings.splitAt(this.sb.b,[pos - pre_len]);
+		this.sb = new StringBuf();
+		this.sb.b += Std.string(sbSplitted[0]);
+		this.sb.b += Std.string(item);
+		this.len += item == null ? 0 : item.length;
+		this.sb.b += Std.string(sbSplitted[1]);
+		return this;
+	}
+	insertChar(pos,ch) {
+		if(pos < 0) {
+			throw haxe_Exception.thrown("[pos] must not be negative");
+		}
+		if(pos > this.len) {
+			throw haxe_Exception.thrown("[pos] must not be greater than this.length");
+		}
+		if(pos == this.len) {
+			this.addChar(ch);
+			return this;
+		}
+		if(pos == 0) {
+			if(this.pre == null) {
+				this.pre = [];
+			}
+			this.pre.unshift(String.fromCodePoint(ch));
+			this.len++;
+			return this;
+		}
+		let pre_len = 0;
+		if(this.pre != null) {
+			let pre = this.pre;
+			let i = pre.length;
+			let _g = 0;
+			let _g1 = pre.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let str = pre[i];
+				let next_pre_len = pre_len + (str == null ? 0 : str.length);
+				if(next_pre_len == pos) {
+					let x = String.fromCodePoint(ch);
+					pre.splice(i + 1,0,x);
+					this.len++;
+					return this;
+				}
+				if(next_pre_len > pos) {
+					let preSplitted = hx_strings_Strings.splitAt(pre[i],[pos - pre_len]);
+					pre[i] = preSplitted[0];
+					let x = String.fromCodePoint(ch);
+					pre.splice(i + 1,0,x);
+					pre.splice(i + 2,0,preSplitted[1]);
+					this.len++;
+					return this;
+				}
+				pre_len = next_pre_len;
+			}
+		}
+		if(this.sb.b.length == 0) {
+			this.addChar(ch);
+			return this;
+		}
+		let sbSplitted = hx_strings_Strings.splitAt(this.sb.b,[pos - pre_len]);
+		this.sb = new StringBuf();
+		this.sb.b += Std.string(sbSplitted[0]);
+		this.addChar(ch);
+		this.sb.b += Std.string(sbSplitted[1]);
+		return this;
+	}
+	insertAll(pos,items) {
+		if(pos < 0) {
+			throw haxe_Exception.thrown("[pos] must not be negative");
+		}
+		if(pos > this.len) {
+			throw haxe_Exception.thrown("[pos] must not be greater than this.length");
+		}
+		if(pos == this.len) {
+			this.addAll(items);
+			return this;
+		}
+		if(pos == 0) {
+			if(this.pre == null) {
+				this.pre = [];
+			}
+			let pre = this.pre;
+			let i = items.length;
+			while(i-- > 0) {
+				let item = items[i];
+				pre.unshift(item);
+				this.len += item == null ? 0 : item.length;
+			}
+			return this;
+		}
+		let pre_len = 0;
+		if(this.pre != null) {
+			let pre = this.pre;
+			let i = pre.length;
+			let _g = 0;
+			let _g1 = pre.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let str = pre[i];
+				let next_pre_len = pre_len + (str == null ? 0 : str.length);
+				if(next_pre_len == pos) {
+					let j = items.length;
+					while(j-- > 0) {
+						let item = items[j];
+						pre.splice(i + 1,0,item);
+						this.len += item == null ? 0 : item.length;
+					}
+					return this;
+				}
+				if(next_pre_len > pos) {
+					let preSplitted = hx_strings_Strings.splitAt(pre[i],[pos - pre_len]);
+					pre[i] = preSplitted[0];
+					pre.splice(i + 1,0,preSplitted[1]);
+					let j = items.length;
+					while(j-- > 0) {
+						let item = items[j];
+						pre.splice(i + 1,0,item);
+						this.len += item == null ? 0 : item.length;
+					}
+					return this;
+				}
+				pre_len = next_pre_len;
+			}
+		}
+		if(this.sb.b.length == 0) {
+			let _g = 0;
+			while(_g < items.length) {
+				let item = items[_g];
+				++_g;
+				this.add(item);
+			}
+			return this;
+		}
+		let sbSplitted = hx_strings_Strings.splitAt(this.sb.b,[pos - pre_len]);
+		this.sb = new StringBuf();
+		this.sb.b += Std.string(sbSplitted[0]);
+		let _g = 0;
+		while(_g < items.length) {
+			let item = items[_g];
+			++_g;
+			this.sb.b += Std.string(item);
+			this.len += item == null ? 0 : item.length;
+		}
+		this.sb.b += Std.string(sbSplitted[1]);
+		return this;
+	}
+	asOutput() {
+		return new hx_strings__$StringBuilder_OutputWrapper(this);
+	}
+	toString() {
+		if(this.pre == null) {
+			return this.sb.b;
+		}
+		let str = this.pre.join("") + this.sb.b;
+		this.clear();
+		this.add(str);
+		return str;
+	}
+}
+hx_strings_StringBuilder.__name__ = "hx.strings.StringBuilder";
+Object.assign(hx_strings_StringBuilder.prototype, {
+	__class__: hx_strings_StringBuilder
+});
+class hx_strings__$StringBuilder_OutputWrapper extends haxe_io_Output {
+	constructor(sb) {
+		super();
+		this.sb = sb;
+	}
+	flush() {
+		if(this.bo != null && this.bo.b.pos > 0) {
+			this.sb.add(this.bo.getBytes().toString());
+		}
+	}
+	writeByte(c) {
+		if(this.bo == null) {
+			this.bo = new haxe_io_BytesOutput();
+		}
+		this.bo.writeByte(c);
+	}
+	writeString(str,encoding) {
+		this.flush();
+		this.sb.add(str);
+	}
+}
+hx_strings__$StringBuilder_OutputWrapper.__name__ = "hx.strings._StringBuilder.OutputWrapper";
+hx_strings__$StringBuilder_OutputWrapper.__super__ = haxe_io_Output;
+Object.assign(hx_strings__$StringBuilder_OutputWrapper.prototype, {
+	__class__: hx_strings__$StringBuilder_OutputWrapper
+});
+class hx_strings_StringDiff {
+	constructor() {
+		this.at = -1;
+	}
+	toString() {
+		return "StringDiff[at=" + this.at + ", left=" + this.left + ", right=" + this.right + "]";
+	}
+}
+hx_strings_StringDiff.__name__ = "hx.strings.StringDiff";
+Object.assign(hx_strings_StringDiff.prototype, {
+	__class__: hx_strings_StringDiff
+});
+var hx_strings_HashCodeAlgorithm = $hxEnums["hx.strings.HashCodeAlgorithm"] = { __ename__:true,__constructs__:null
+	,PLATFORM_SPECIFIC: {_hx_name:"PLATFORM_SPECIFIC",_hx_index:0,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,ADLER32: {_hx_name:"ADLER32",_hx_index:1,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,CRC32B: {_hx_name:"CRC32B",_hx_index:2,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,DJB2A: {_hx_name:"DJB2A",_hx_index:3,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,JAVA: {_hx_name:"JAVA",_hx_index:4,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,SDBM: {_hx_name:"SDBM",_hx_index:5,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+};
+hx_strings_HashCodeAlgorithm.__constructs__ = [hx_strings_HashCodeAlgorithm.PLATFORM_SPECIFIC,hx_strings_HashCodeAlgorithm.ADLER32,hx_strings_HashCodeAlgorithm.CRC32B,hx_strings_HashCodeAlgorithm.DJB2A,hx_strings_HashCodeAlgorithm.JAVA,hx_strings_HashCodeAlgorithm.SDBM];
+var hx_strings_AnsiToHtmlRenderMethod = $hxEnums["hx.strings.AnsiToHtmlRenderMethod"] = { __ename__:true,__constructs__:null
+	,StyleAttributes: {_hx_name:"StyleAttributes",_hx_index:0,__enum__:"hx.strings.AnsiToHtmlRenderMethod",toString:$estr}
+	,CssClasses: {_hx_name:"CssClasses",_hx_index:1,__enum__:"hx.strings.AnsiToHtmlRenderMethod",toString:$estr}
+	,CssClassesCallback: ($_=function(func) { return {_hx_index:2,func:func,__enum__:"hx.strings.AnsiToHtmlRenderMethod",toString:$estr}; },$_._hx_name="CssClassesCallback",$_.__params__ = ["func"],$_)
+};
+hx_strings_AnsiToHtmlRenderMethod.__constructs__ = [hx_strings_AnsiToHtmlRenderMethod.StyleAttributes,hx_strings_AnsiToHtmlRenderMethod.CssClasses,hx_strings_AnsiToHtmlRenderMethod.CssClassesCallback];
+class hx_strings_AnsiState {
+	constructor(copyFrom) {
+		this.underline = false;
+		this.bold = false;
+		this.blink = false;
+		if(copyFrom == null) {
+			this.reset();
+		} else {
+			this.copyFrom(copyFrom);
+		}
+	}
+	isActive() {
+		if(!(this.fgcolor != null || this.bgcolor != null || this.bold || this.underline)) {
+			return this.blink;
+		} else {
+			return true;
+		}
+	}
+	reset() {
+		this.fgcolor = null;
+		this.bgcolor = null;
+		this.bold = false;
+		this.underline = false;
+		this.blink = false;
+	}
+	copyFrom(other) {
+		this.fgcolor = other.fgcolor;
+		this.bgcolor = other.bgcolor;
+		this.bold = other.bold;
+		this.underline = other.underline;
+		this.blink = other.blink;
+	}
+	setGraphicModeParameter(param) {
+		switch(param) {
+		case 0:
+			this.reset();
+			break;
+		case 1:
+			this.bold = true;
+			break;
+		case 4:
+			this.underline = true;
+			break;
+		case 5:
+			this.blink = true;
+			break;
+		case 30:
+			this.fgcolor = "black";
+			break;
+		case 31:
+			this.fgcolor = "red";
+			break;
+		case 32:
+			this.fgcolor = "green";
+			break;
+		case 33:
+			this.fgcolor = "yellow";
+			break;
+		case 34:
+			this.fgcolor = "blue";
+			break;
+		case 35:
+			this.fgcolor = "magenta";
+			break;
+		case 36:
+			this.fgcolor = "cyan";
+			break;
+		case 37:
+			this.fgcolor = "white";
+			break;
+		case 40:
+			this.bgcolor = "black";
+			break;
+		case 41:
+			this.bgcolor = "red";
+			break;
+		case 42:
+			this.bgcolor = "green";
+			break;
+		case 43:
+			this.bgcolor = "yellow";
+			break;
+		case 44:
+			this.bgcolor = "blue";
+			break;
+		case 45:
+			this.bgcolor = "magenta";
+			break;
+		case 46:
+			this.bgcolor = "cyan";
+			break;
+		case 47:
+			this.bgcolor = "white";
+			break;
+		}
+	}
+	toCSS(renderMethod) {
+		if(this.fgcolor != null || this.bgcolor != null || this.bold || this.underline || this.blink) {
+			let sb = new hx_strings_StringBuilder();
+			if(renderMethod == null) {
+				renderMethod = hx_strings_AnsiToHtmlRenderMethod.StyleAttributes;
+			}
+			switch(renderMethod._hx_index) {
+			case 0:
+				if(this.fgcolor != null) {
+					sb.add("color:").add(this.fgcolor).add(";");
+				}
+				if(this.bgcolor != null) {
+					sb.add("background-color:").add(this.bgcolor).add(";");
+				}
+				if(this.bold) {
+					sb.add("font-weight:bold;");
+				}
+				if(this.underline) {
+					sb.add("text-decoration:underline;");
+				}
+				if(this.blink) {
+					sb.add("text-decoration:blink;");
+				}
+				break;
+			case 1:
+				sb.add(hx_strings_AnsiState.defaultCssClassesCallback(this));
+				break;
+			case 2:
+				let func = renderMethod.func;
+				sb.add(func(this));
+				break;
+			}
+			return sb.toString();
+		}
+		return "";
+	}
+	static defaultCssClassesCallback(state) {
+		let classes = [];
+		if(state.fgcolor != null) {
+			classes.push("ansi_fg_" + state.fgcolor);
+		}
+		if(state.bgcolor != null) {
+			classes.push("ansi_bg_" + state.bgcolor);
+		}
+		if(state.bold) {
+			classes.push("ansi_bold");
+		}
+		if(state.underline) {
+			classes.push("ansi_underline");
+		}
+		if(state.blink) {
+			classes.push("ansi_blink");
+		}
+		return classes.join(" ");
+	}
+}
+hx_strings_AnsiState.__name__ = "hx.strings.AnsiState";
+Object.assign(hx_strings_AnsiState.prototype, {
+	__class__: hx_strings_AnsiState
+});
+class hx_strings_internal_Bits {
+	static clearBit(num,bitPos) {
+		return num & ~(1 << bitPos - 1);
+	}
+	static setBit(num,bitPos) {
+		return num | 1 << bitPos - 1;
+	}
+	static toggleBit(num,bitPos) {
+		return num ^ 1 << bitPos - 1;
+	}
+	static getBit(num,bitPos) {
+		return 1 == (num >> bitPos - 1 & 1);
+	}
+}
+hx_strings_internal_Bits.__name__ = "hx.strings.internal.Bits";
+class hx_strings_internal_Either2 {
+	static _new(value) {
+		return value;
+	}
+	static get_value(this1) {
+		return this1;
+	}
+	static fromA(value) {
+		return hx_strings_internal__$Either2__$Either2.a(value);
+	}
+	static fromB(value) {
+		return hx_strings_internal__$Either2__$Either2.b(value);
+	}
+}
+var hx_strings_internal__$Either2__$Either2 = $hxEnums["hx.strings.internal._Either2._Either2"] = { __ename__:true,__constructs__:null
+	,a: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"hx.strings.internal._Either2._Either2",toString:$estr}; },$_._hx_name="a",$_.__params__ = ["v"],$_)
+	,b: ($_=function(v) { return {_hx_index:1,v:v,__enum__:"hx.strings.internal._Either2._Either2",toString:$estr}; },$_._hx_name="b",$_.__params__ = ["v"],$_)
+};
+hx_strings_internal__$Either2__$Either2.__constructs__ = [hx_strings_internal__$Either2__$Either2.a,hx_strings_internal__$Either2__$Either2.b];
+class hx_strings_internal_Either3 {
+	static _new(value) {
+		return value;
+	}
+	static get_value(this1) {
+		return this1;
+	}
+	static fromA(value) {
+		return hx_strings_internal__$Either3__$Either3.a(value);
+	}
+	static fromB(value) {
+		return hx_strings_internal__$Either3__$Either3.b(value);
+	}
+	static fromC(value) {
+		return hx_strings_internal__$Either3__$Either3.c(value);
+	}
+}
+class hx_strings_internal_OneOrMany {
+	static fromSingle(value) {
+		return [value];
+	}
+}
+class hx_strings_internal_RingBuffer {
+	static _new(size) {
+		return new hx_strings_internal__$RingBuffer_RingBufferImpl(size);
+	}
+	static get(this1,index) {
+		return this1.get(index);
+	}
+}
+class hx_strings_internal__$RingBuffer_RingBufferIterator {
+	constructor(buff) {
+		this.idx = -1;
+		this.buff = buff;
+	}
+	hasNext() {
+		return this.idx + 1 < this.buff.length;
+	}
+	next() {
+		this.idx++;
+		return this.buff.get(this.idx);
+	}
+}
+hx_strings_internal__$RingBuffer_RingBufferIterator.__name__ = "hx.strings.internal._RingBuffer.RingBufferIterator";
+Object.assign(hx_strings_internal__$RingBuffer_RingBufferIterator.prototype, {
+	__class__: hx_strings_internal__$RingBuffer_RingBufferIterator
+});
+class js_Browser {
+	static get_supported() {
+		if(typeof(window) != "undefined" && typeof(window.location) != "undefined") {
+			return typeof(window.location.protocol) == "string";
+		} else {
+			return false;
+		}
+	}
+	static createXMLHttpRequest() {
+		if(typeof XMLHttpRequest != "undefined") {
+			return new XMLHttpRequest();
+		}
+		if(typeof ActiveXObject != "undefined") {
+			return new ActiveXObject("Microsoft.XMLHTTP");
+		}
+		throw haxe_Exception.thrown("Unable to create XMLHttpRequest object.");
+	}
+}
+js_Browser.__name__ = "js.Browser";
+class js_lib_HaxeIterator {
+	constructor(jsIterator) {
+		this.jsIterator = jsIterator;
+		this.lastStep = jsIterator.next();
+	}
+	hasNext() {
+		return !this.lastStep.done;
+	}
+	next() {
+		let v = this.lastStep.value;
+		this.lastStep = this.jsIterator.next();
+		return v;
+	}
+}
+js_lib_HaxeIterator.__name__ = "js.lib.HaxeIterator";
+Object.assign(js_lib_HaxeIterator.prototype, {
+	__class__: js_lib_HaxeIterator
+});
+class sha_Hash {
+	constructor(blockSize,finalSize) {
+		if(sha_Hash._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(blockSize,finalSize);
+	}
+	_hx_constructor(blockSize,finalSize) {
+		this.finalSize = finalSize;
+		this.block = new haxe_io_Bytes(new ArrayBuffer(blockSize));
+		this.length = 0;
+	}
+	min(a,b) {
+		if(a < b) {
+			return a;
+		}
+		return b;
+	}
+	writeInt(b,i,pos) {
+		b.b[pos] = i >> 24;
+		b.b[pos + 1] = i >> 16 & 255;
+		b.b[pos + 2] = i >> 8 & 255;
+		b.b[pos + 3] = i & 255;
+	}
+	update(data) {
+		let accum = this.length;
+		let offset = 0;
+		while(offset < data.length) {
+			let assigned = accum % this.block.length;
+			let a = data.length - offset;
+			let b = this.block.length - assigned;
+			let remainder = a < b ? a : b;
+			let _g = 0;
+			let _g1 = remainder;
+			while(_g < _g1) {
+				let i = _g++;
+				this.block.b[assigned + i] = data.b[offset + i];
+			}
+			accum += remainder;
+			offset += remainder;
+			if(accum % this.block.length == 0) {
+				this._update(this.block);
+			}
+		}
+		this.length += data.length;
+		return this;
+	}
+	digest() {
+		let rem = this.length % this.block.length;
+		this.block.b[rem] = 128;
+		this.block.fill(rem + 1,this.block.length - (rem + 1),0);
+		if(rem >= this.finalSize) {
+			this._update(this.block);
+			this.block.fill(0,this.block.length,0);
+		}
+		let bits = this.length * 8;
+		if(bits <= -1) {
+			let b = this.block;
+			let pos = this.block.length - 4;
+			b.b[pos] = bits >> 24;
+			b.b[pos + 1] = bits >> 16 & 255;
+			b.b[pos + 2] = bits >> 8 & 255;
+			b.b[pos + 3] = bits & 255;
+		} else {
+			let lowBits = (bits & -1) >>> 0;
+			let highBits = (bits - lowBits) / 4294967296 | 0;
+			let b = this.block;
+			let pos = this.block.length - 8;
+			b.b[pos] = highBits >> 24;
+			b.b[pos + 1] = highBits >> 16 & 255;
+			b.b[pos + 2] = highBits >> 8 & 255;
+			b.b[pos + 3] = highBits & 255;
+			let b1 = this.block;
+			let pos1 = this.block.length - 4;
+			b1.b[pos1] = lowBits >> 24;
+			b1.b[pos1 + 1] = lowBits >> 16 & 255;
+			b1.b[pos1 + 2] = lowBits >> 8 & 255;
+			b1.b[pos1 + 3] = lowBits & 255;
+		}
+		this._update(this.block);
+		return this._hash();
+	}
+}
+sha_Hash.__name__ = "sha.Hash";
+Object.assign(sha_Hash.prototype, {
+	__class__: sha_Hash
+});
+class sha_SHA256 extends sha_Hash {
+	constructor() {
+		sha_Hash._hx_skip_constructor = true;
+		super();
+		sha_Hash._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this._w = [];
+		this._h = 1541459225;
+		this._g = 528734635;
+		this._f = -1694144372;
+		this._e = 1359893119;
+		this._d = -1521486534;
+		this._c = 1013904242;
+		this._b = -1150833019;
+		this._a = 1779033703;
+		super._hx_constructor(64,56);
+	}
+	sigma0(x) {
+		return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10);
+	}
+	sigma1(x) {
+		return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7);
+	}
+	gamma0(x) {
+		return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ x >>> 3;
+	}
+	gamma1(x) {
+		return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ x >>> 10;
+	}
+	ch(x,y,z) {
+		return z ^ x & (y ^ z);
+	}
+	maj(x,y,z) {
+		return x & y | z & (x | y);
+	}
+	_update(data) {
+		let W = this._w;
+		let a = this._a | 0;
+		let b = this._b | 0;
+		let c = this._c | 0;
+		let d = this._d | 0;
+		let e = this._e | 0;
+		let f = this._f | 0;
+		let g = this._g | 0;
+		let h = this._h | 0;
+		let _g = 0;
+		while(_g < 16) {
+			let i = _g++;
+			W[i] = data.b[i * 4] << 24 | data.b[i * 4 + 1] << 16 | data.b[i * 4 + 2] << 8 | data.b[i * 4 + 3];
+		}
+		let _g1 = 16;
+		while(_g1 < 64) {
+			let i = _g1++;
+			W[i] = this.gamma1(W[i - 2]) + W[i - 7] + this.gamma0(W[i - 15]) + W[i - 16] | 0;
+		}
+		let _g2 = 0;
+		while(_g2 < 64) {
+			let j = _g2++;
+			let T1 = h + this.sigma1(e) + this.ch(e,f,g) + sha_SHA256_K[j] + W[j] | 0;
+			let T2 = this.sigma0(a) + this.maj(a,b,c) | 0;
+			h = g;
+			g = f;
+			f = e;
+			e = d + T1 | 0;
+			d = c;
+			c = b;
+			b = a;
+			a = T1 + T2 | 0;
+		}
+		this._a = a + this._a | 0;
+		this._b = b + this._b | 0;
+		this._c = c + this._c | 0;
+		this._d = d + this._d | 0;
+		this._e = e + this._e | 0;
+		this._f = f + this._f | 0;
+		this._g = g + this._g | 0;
+		this._h = h + this._h | 0;
+	}
+	_hash() {
+		let b = new haxe_io_Bytes(new ArrayBuffer(32));
+		let i = this._a;
+		b.b[0] = i >> 24;
+		b.b[1] = i >> 16 & 255;
+		b.b[2] = i >> 8 & 255;
+		b.b[3] = i & 255;
+		let i1 = this._b;
+		b.b[4] = i1 >> 24;
+		b.b[5] = i1 >> 16 & 255;
+		b.b[6] = i1 >> 8 & 255;
+		b.b[7] = i1 & 255;
+		let i2 = this._c;
+		b.b[8] = i2 >> 24;
+		b.b[9] = i2 >> 16 & 255;
+		b.b[10] = i2 >> 8 & 255;
+		b.b[11] = i2 & 255;
+		let i3 = this._d;
+		b.b[12] = i3 >> 24;
+		b.b[13] = i3 >> 16 & 255;
+		b.b[14] = i3 >> 8 & 255;
+		b.b[15] = i3 & 255;
+		let i4 = this._e;
+		b.b[16] = i4 >> 24;
+		b.b[17] = i4 >> 16 & 255;
+		b.b[18] = i4 >> 8 & 255;
+		b.b[19] = i4 & 255;
+		let i5 = this._f;
+		b.b[20] = i5 >> 24;
+		b.b[21] = i5 >> 16 & 255;
+		b.b[22] = i5 >> 8 & 255;
+		b.b[23] = i5 & 255;
+		let i6 = this._g;
+		b.b[24] = i6 >> 24;
+		b.b[25] = i6 >> 16 & 255;
+		b.b[26] = i6 >> 8 & 255;
+		b.b[27] = i6 & 255;
+		let i7 = this._h;
+		b.b[28] = i7 >> 24;
+		b.b[29] = i7 >> 16 & 255;
+		b.b[30] = i7 >> 8 & 255;
+		b.b[31] = i7 & 255;
+		return b;
+	}
+}
+sha_SHA256.__name__ = "sha.SHA256";
+sha_SHA256.__super__ = sha_Hash;
+Object.assign(sha_SHA256.prototype, {
+	__class__: sha_SHA256
+});
+class snikket_AttachmentSource {
+	static tinkSource(this1) {
+		let options = null;
+		let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+		return new tink_io_js_BlobSource(this1.name,this1,0,chunkSize);
+	}
+}
+class snikket_Autolink {
+	static one(s,start) {
+		let matches = [snikket_Autolink.match(s,start,snikket_Autolink.XMPP_URI,false),snikket_Autolink.match(s,start,snikket_Autolink.TEL_URI,false),snikket_Autolink.match(s,start,snikket_Autolink.SMS_URI,false),snikket_Autolink.match(s,start,snikket_Autolink.AUTOLINK_WEB_URL,true)];
+		matches.sort(function(x,y) {
+			return x.start - y.start;
+		});
+		let tmp = Lambda.find(matches,function(match) {
+			return match.span != null;
+		});
+		if(tmp != null) {
+			return tmp;
+		} else {
+			return matches[0];
+		}
+	}
+	static match(s,start,pattern,addHttps) {
+		let pattern1 = new EReg(pattern,"u");
+		if(pattern1.matchSub(s,start)) {
+			let pos = pattern1.matchedPos();
+			let link = pattern1.matched(0);
+			let uri = !addHttps || link.includes("://") ? link : "https://" + link;
+			return { span : snikket_Node.Element(new snikket_Stanza("a",{ href : uri}).text(link)), start : pos.pos, end : pos.pos + pos.len};
+		} else {
+			return { span : null, start : s.length, end : s.length};
+		}
+	}
+}
+snikket_Autolink.__name__ = "snikket.Autolink";
+class snikket_Caps {
+	constructor(node,identities,features) {
+		this._ver = null;
+		this.node = node;
+		this.identities = identities;
+		this.features = features;
+	}
+	isChannel(chatId) {
+		if(chatId.indexOf("@") < 0) {
+			return false;
+		}
+		if(this.features.includes("http://jabber.org/protocol/muc")) {
+			return Lambda.find(this.identities,function(identity) {
+				return identity.category == "conference";
+			}) != null;
+		} else {
+			return false;
+		}
+	}
+	discoReply() {
+		let query = new snikket_Stanza("query",{ xmlns : "http://jabber.org/protocol/disco#info"});
+		let _g = 0;
+		let _g1 = this.identities;
+		while(_g < _g1.length) {
+			let identity = _g1[_g];
+			++_g;
+			identity.addToDisco(query);
+		}
+		let _g2 = 0;
+		let _g3 = this.features;
+		while(_g2 < _g3.length) {
+			let feature = _g3[_g2];
+			++_g2;
+			query.tag("feature",{ "var" : feature}).up();
+		}
+		return query;
+	}
+	addC(stanza) {
+		stanza.tag("c",{ xmlns : "http://jabber.org/protocol/caps", hash : "sha-1", node : this.node, ver : this.ver()}).up();
+		return stanza;
+	}
+	computeVer() {
+		this.features.sort(function(x,y) {
+			if(x == y) {
+				return 0;
+			} else if(x < y) {
+				return -1;
+			} else {
+				return 1;
+			}
+		});
+		this.identities.sort(function(x,y) {
+			if(x.ver() == y.ver()) {
+				return 0;
+			} else if(x.ver() < y.ver()) {
+				return -1;
+			} else {
+				return 1;
+			}
+		});
+		let s = "";
+		let _g = 0;
+		let _g1 = this.identities;
+		while(_g < _g1.length) {
+			let identity = _g1[_g];
+			++_g;
+			s += identity.ver() + "<";
+		}
+		let _g2 = 0;
+		let _g3 = this.features;
+		while(_g2 < _g3.length) {
+			let feature = _g3[_g2];
+			++_g2;
+			s += feature + "<";
+		}
+		return snikket_Hash.sha1(haxe_io_Bytes.ofString(s));
+	}
+	verRaw() {
+		if(this._ver == null) {
+			this._ver = this.computeVer();
+		}
+		return this._ver;
+	}
+	ver() {
+		return this.verRaw().toBase64();
+	}
+	static withIdentity(caps,category,type) {
+		let result = [];
+		let cap = caps;
+		while(cap.hasNext()) {
+			let cap1 = cap.next();
+			if(cap1.value != null) {
+				let _g = 0;
+				let _g1 = cap1.value.identities;
+				while(_g < _g1.length) {
+					let identity = _g1[_g];
+					++_g;
+					if((category == null || category == identity.category) && (type == null || type == identity.type)) {
+						result.push(cap1.key);
+					}
+				}
+			}
+		}
+		return result;
+	}
+	static withFeature(caps,feature) {
+		let result = [];
+		let cap = caps;
+		while(cap.hasNext()) {
+			let cap1 = cap.next();
+			if(cap1.value != null) {
+				let _g = 0;
+				let _g1 = cap1.value.features;
+				while(_g < _g1.length) {
+					let feat = _g1[_g];
+					++_g;
+					if(feature == feat) {
+						result.push(cap1.key);
+					}
+				}
+			}
+		}
+		return result;
+	}
+}
+$hx_exports["snikket"]["Caps"] = snikket_Caps;
+snikket_Caps.__name__ = "snikket.Caps";
+Object.assign(snikket_Caps.prototype, {
+	__class__: snikket_Caps
+});
+class snikket_Identity {
+	constructor(category,type,name) {
+		this.category = category;
+		this.type = type;
+		this.name = name;
+	}
+	addToDisco(stanza) {
+		stanza.tag("identity",{ category : this.category, type : this.type, name : this.name}).up();
+	}
+	ver() {
+		return this.category + "/" + this.type + "//" + this.name;
+	}
+}
+$hx_exports["snikket"]["Identity"] = snikket_Identity;
+snikket_Identity.__name__ = "snikket.Identity";
+Object.assign(snikket_Identity.prototype, {
+	__class__: snikket_Identity
+});
+class snikket_Chat {
+	constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy) {
+		if(snikket_Chat._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy);
+	}
+	_hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy) {
+		if(isBlocked == null) {
+			isBlocked = false;
+		}
+		if(uiState == null) {
+			uiState = 1;
+		}
+		this.activeThread = null;
+		this.isActive = null;
+		this.typingTimer = null;
+		this.typingThread = null;
+		this.isTyping = false;
+		this._unreadCount = 0;
+		this.isBlocked = false;
+		this.uiState = 1;
+		this.jingleSessions = new Map([]);
+		this.trusted = false;
+		this.presence = new Map([]);
+		this.avatarSha1 = null;
+		this.client = client;
+		this.stream = stream;
+		this.persistence = persistence;
+		this.chatId = chatId;
+		this.uiState = uiState;
+		this.isBlocked = isBlocked;
+		let tmp = extensions;
+		this.extensions = tmp != null ? tmp : new snikket_Stanza("extensions",{ xmlns : "urn:xmpp:bookmarks:1"});
+		this.readUpToId = readUpToId;
+		this.readUpToBy = readUpToBy;
+		this.displayName = chatId;
+	}
+	fetchFromSync(sync,callback) {
+		let _gthis = this;
+		sync.onMessages(function(messageList) {
+			let chatMessages = [];
+			let _g = 0;
+			let _g1 = messageList.messages;
+			while(_g < _g1.length) {
+				let m = _g1[_g];
+				++_g;
+				switch(m._hx_index) {
+				case 1:
+					let message = m.message;
+					chatMessages.push(message);
+					break;
+				case 2:
+					let action = m.action;
+					_gthis.client.moderateMessage(action);
+					break;
+				case 3:
+					let update = m.update;
+					_gthis.persistence.storeReaction(_gthis.client.accountId(),update,function(m) {
+					});
+					break;
+				default:
+				}
+			}
+			_gthis.client.storeMessages(chatMessages,function(chatMessages) {
+				let callback1 = callback;
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = chatMessages;
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(v != null && v.chatId() == _gthis.chatId) {
+						_g.push(v);
+					}
+				}
+				callback1(_g);
+			});
+		});
+		sync.fetchNext();
+	}
+	addReaction(m,reaction) {
+		let toSend = m.reply();
+		toSend.localId = snikket_ID.long();
+		reaction.render(function(text) {
+			toSend.text = StringTools.replace(text,"️","");
+		},function(text,uri) {
+			let hash = snikket_Hash.fromUri(uri);
+			toSend.setHtml("<img alt=\"" + snikket_Util_xmlEscape(text) + "\" src=\"" + snikket_Util_xmlEscape(hash == null ? uri : hash.bobUri()) + "\" />");
+		});
+		this.sendMessage(toSend);
+	}
+	typing(threadId,content) {
+		if(threadId != this.typingThread && this.isTyping) {
+			this.sendChatState("paused",this.typingThread);
+			this.isTyping = false;
+		}
+		this.typingThread = threadId;
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		let _gthis = this;
+		if(content == "") {
+			this.isTyping = false;
+			this.sendChatState("active",this.typingThread);
+			if(this.isActive == null) {
+				this.typingTimer = haxe_Timer.delay(function() {
+					_gthis.sendChatState("inactive",_gthis.typingThread);
+				},30000);
+			}
+			return;
+		}
+		this.typingTimer = haxe_Timer.delay(function() {
+			_gthis.sendChatState("paused",_gthis.typingThread);
+			_gthis.isTyping = false;
+		},10000);
+		if(this.isTyping) {
+			return;
+		}
+		this.isTyping = true;
+		this.sendChatState("composing",this.typingThread);
+	}
+	setActive(active,threadId) {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.isTyping = false;
+		if(this.isActive && active && threadId != this.activeThread) {
+			this.sendChatState("inactive",this.activeThread);
+			this.isActive = false;
+		}
+		if(this.isActive != null) {
+			if(this.isActive && active) {
+				return;
+			}
+			if(!this.isActive && !active) {
+				return;
+			}
+		}
+		this.isActive = active;
+		this.activeThread = threadId;
+		this.sendChatState(active ? "active" : "inactive",this.activeThread);
+	}
+	togglePinned() {
+		this.uiState = this.uiState == 0 ? 1 : 0;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		this.client.sortChats();
+		this.client.trigger("chats/update",[this]);
+	}
+	block(reportSpam,onServer) {
+		if(reportSpam != null && !onServer) {
+			throw haxe_Exception.thrown("Can't report SPAM if not sending to server");
+		}
+		this.isBlocked = true;
+		if(this.uiState == 2) {
+			this.persistence.storeChats(this.client.accountId(),[this]);
+		} else {
+			this.close();
+		}
+		if(onServer) {
+			let iq = new snikket_Stanza("iq",{ type : "set", id : snikket_ID.short()}).tag("block",{ xmlns : "urn:xmpp:blocking"}).tag("item",{ jid : this.chatId});
+			if(reportSpam != null) {
+				iq.tag("report",{ xmlns : "urn:xmpp:reporting:1", reason : "urn:xmpp:reporting:spam"}).tag("stanza-id",{ xmlns : "urn:xmpp:sid:0", by : reportSpam.serverIdBy, id : reportSpam.serverId});
+			}
+			this.stream.sendIq(iq,function(response) {
+			});
+		}
+	}
+	unblock(onServer) {
+		this.isBlocked = false;
+		this.uiState = 1;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		this.client.trigger("chats/update",[this]);
+		if(onServer) {
+			this.stream.sendIq(new snikket_Stanza("iq",{ type : "set", id : snikket_ID.short()}).tag("unblock",{ xmlns : "urn:xmpp:blocking"}).tag("item",{ jid : this.chatId}).up().up(),function(response) {
+			});
+		}
+	}
+	lastMessageTimestamp() {
+		let tmp = this.lastMessage;
+		if(tmp != null) {
+			return tmp.timestamp;
+		} else {
+			return null;
+		}
+	}
+	updateFromBookmark(item) {
+		let conf = item.getChild("conference","urn:xmpp:bookmarks:1");
+		let fn = conf.attr["name"];
+		if(fn != null) {
+			this.displayName = fn;
+		}
+		this.uiState = conf.attr["autojoin"] == "1" || conf.attr["autojoin"] == "true" ? this.uiState == 0 ? 0 : 1 : 2;
+		let tmp = conf.getChild("extensions");
+		this.extensions = tmp != null ? tmp : new snikket_Stanza("extensions",{ xmlns : "urn:xmpp:bookmarks:1"});
+	}
+	updateFromRoster(item) {
+		this.setTrusted(item.subscription == "both" || item.subscription == "from");
+		if(item.fn != null && item.fn != "") {
+			this.displayName = item.fn;
+		}
+	}
+	getPhoto() {
+		if(this.avatarSha1 == null || haxe_io_Bytes.ofData(this.avatarSha1).length < 1) {
+			return null;
+		}
+		return new snikket_Hash("sha-1",this.avatarSha1).toUri();
+	}
+	getPlaceholder() {
+		return snikket_Color.defaultPhoto(this.chatId,this.getDisplayName().charAt(0).toUpperCase());
+	}
+	readUpTo() {
+		return this.readUpToId;
+	}
+	unreadCount() {
+		return this._unreadCount;
+	}
+	setUnreadCount(count) {
+		this._unreadCount = count;
+	}
+	preview() {
+		if(this.lastMessage == null) {
+			return "";
+		}
+		if(this.lastMessage.type == 1) {
+			if(this.lastMessage.isIncoming()) {
+				return "Incoming Call";
+			} else {
+				return "Outgoing Call";
+			}
+		} else {
+			return this.lastMessage.text;
+		}
+	}
+	setLastMessage(message) {
+		this.lastMessage = message;
+	}
+	setDisplayName(fn) {
+		this.displayName = fn;
+		this.bookmark();
+	}
+	getDisplayName() {
+		return this.displayName;
+	}
+	setPresence(resource,presence) {
+		this.presence.set(resource,presence);
+	}
+	setCaps(resource,caps) {
+		let presence = this.presence.get(resource);
+		if(presence != null) {
+			presence.caps = caps;
+			this.setPresence(resource,presence);
+		} else {
+			this.setPresence(resource,new snikket_Presence(caps,null));
+		}
+	}
+	removePresence(resource) {
+		this.presence.delete(resource);
+	}
+	getCaps() {
+		let iter = new snikket_HaxeKVIterator(this.presence.entries());
+		return { hasNext : $bind(iter,iter.hasNext), next : function() {
+			let n = iter.next();
+			return { key : n.key, value : n.value.caps};
+		}};
+	}
+	getResourceCaps(resource) {
+		let tmp = this.presence.get(resource);
+		let tmp1 = tmp != null ? tmp.caps : null;
+		if(tmp1 != null) {
+			return tmp1;
+		} else {
+			return new snikket_Caps("",[],[]);
+		}
+	}
+	setAvatarSha1(sha1) {
+		this.avatarSha1 = sha1;
+	}
+	setTrusted(trusted) {
+		this.trusted = trusted;
+	}
+	isTrusted() {
+		return this.trusted;
+	}
+	livePresence() {
+		return true;
+	}
+	syncing() {
+		return !this.client.inSync;
+	}
+	canAudioCall() {
+		let jsIterator = this.presence.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let resource = _g_key;
+			let p = _g_value;
+			let tmp = p.caps;
+			let tmp1 = tmp != null ? tmp.features : null;
+			let tmp2 = tmp1 != null ? tmp1.includes("urn:xmpp:jingle:apps:rtp:audio") : null;
+			if(tmp2 != null && tmp2) {
+				return true;
+			}
+		}
+		return false;
+	}
+	canVideoCall() {
+		let jsIterator = this.presence.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let resource = _g_key;
+			let p = _g_value;
+			let tmp = p.caps;
+			let tmp1 = tmp != null ? tmp.features : null;
+			let tmp2 = tmp1 != null ? tmp1.includes("urn:xmpp:jingle:apps:rtp:video") : null;
+			if(tmp2 != null && tmp2) {
+				return true;
+			}
+		}
+		return false;
+	}
+	startCall(audio,video) {
+		let session = new snikket_jingle_OutgoingProposedSession(this.client,snikket_JID.parse(this.chatId));
+		this.jingleSessions.set(session.get_sid(),session);
+		session.propose(audio,video);
+	}
+	addMedia(streams) {
+		if(this.callStatus() != "ongoing") {
+			throw haxe_Exception.thrown("cannot add media when no call ongoing");
+		}
+		let jsIterator = this.jingleSessions.values();
+		let inlHaxeIterator_jsIterator = jsIterator;
+		let inlHaxeIterator_lastStep = jsIterator.next();
+		let v = inlHaxeIterator_lastStep.value;
+		inlHaxeIterator_lastStep = inlHaxeIterator_jsIterator.next();
+		v.addMedia(streams);
+	}
+	acceptCall() {
+		let jsIterator = this.jingleSessions.values();
+		let session_jsIterator = jsIterator;
+		let session_lastStep = jsIterator.next();
+		while(!session_lastStep.done) {
+			let v = session_lastStep.value;
+			session_lastStep = session_jsIterator.next();
+			let session = v;
+			session.accept();
+		}
+	}
+	hangup() {
+		let jsIterator = this.jingleSessions.values();
+		let session_jsIterator = jsIterator;
+		let session_lastStep = jsIterator.next();
+		while(!session_lastStep.done) {
+			let v = session_lastStep.value;
+			session_lastStep = session_jsIterator.next();
+			let session = v;
+			session.hangup();
+			this.jingleSessions.delete(session.get_sid());
+		}
+	}
+	callStatus() {
+		let jsIterator = this.jingleSessions.values();
+		let session_jsIterator = jsIterator;
+		let session_lastStep = jsIterator.next();
+		while(!session_lastStep.done) {
+			let v = session_lastStep.value;
+			session_lastStep = session_jsIterator.next();
+			let session = v;
+			return session.callStatus();
+		}
+		return "none";
+	}
+	dtmf() {
+		let jsIterator = this.jingleSessions.values();
+		let session_jsIterator = jsIterator;
+		let session_lastStep = jsIterator.next();
+		while(!session_lastStep.done) {
+			let v = session_lastStep.value;
+			session_lastStep = session_jsIterator.next();
+			let session = v;
+			let dtmf = session.dtmf();
+			if(dtmf != null) {
+				return dtmf;
+			}
+		}
+		return null;
+	}
+	videoTracks() {
+		let this1 = this.jingleSessions;
+		let _g = [];
+		let x = $getIterator({ iterator : function() {
+			return new js_lib_HaxeIterator(this1.values());
+		}});
+		while(x.hasNext()) {
+			let x1 = x.next();
+			_g.push(x1.videoTracks());
+		}
+		let _g1 = [];
+		let e = $getIterator(_g);
+		while(e.hasNext()) {
+			let e1 = e.next();
+			let x = $getIterator(e1);
+			while(x.hasNext()) {
+				let x1 = x.next();
+				_g1.push(x1);
+			}
+		}
+		return _g1;
+	}
+	markReadUpToId(upTo,upToBy,callback) {
+		if(upTo == null) {
+			return;
+		}
+		if(this.readUpTo() == upTo) {
+			return;
+		}
+		this.readUpToId = upTo;
+		this.readUpToBy = upToBy;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		let _gthis = this;
+		this.persistence.getMessagesBefore(this.client.accountId(),this.chatId,null,null,function(messages) {
+			let i = messages.length;
+			while(--i >= 0) if(messages[i].serverId == _gthis.readUpToId || !messages[i].isIncoming()) {
+				break;
+			}
+			_gthis.setUnreadCount(messages.length - (i + 1));
+			if(callback != null) {
+				callback();
+			}
+		});
+	}
+	markReadUpToMessage(message,callback) {
+		if(message.serverId == null || message.chatId() != this.chatId) {
+			return;
+		}
+		if(this.readUpTo() == message.serverId) {
+			return;
+		}
+		let _gthis = this;
+		this.persistence.getMessage(this.client.accountId(),this.chatId,this.readUpTo(),null,function(readMessage) {
+			if(readMessage != null && Reflect.compare(message.timestamp,readMessage.timestamp) <= 0) {
+				return;
+			}
+			_gthis.markReadUpToId(message.serverId,message.serverIdBy,callback);
+		});
+	}
+	publishMds() {
+		let _gthis = this;
+		this.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub"}).tag("publish",{ node : "urn:xmpp:mds:displayed:0"}).tag("item",{ id : this.chatId}).tag("displayed",{ xmlns : "urn:xmpp:mds:displayed:0"}).tag("stanza-id",{ xmlns : "urn:xmpp:sid:0", id : this.readUpTo(), by : this.readUpToBy}).up().up().up().tag("publish-options").tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value","http://jabber.org/protocol/pubsub#publish-options").up().tag("field",{ "var" : "pubsub#persist_items"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#max_items"}).textTag("value","max").up().tag("field",{ "var" : "pubsub#send_last_published_item"}).textTag("value","never").up().tag("field",{ "var" : "pubsub#access_model"}).textTag("value","whitelist").up().up().up(),function(response) {
+			if(response.attr["type"] == "error") {
+				let tmp = response.getChild("error");
+				let preconditionError = tmp != null ? tmp.getChild("precondition-not-met","http://jabber.org/protocol/pubsub#errors") : null;
+				if(preconditionError != null) {
+					_gthis.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub#owner"}).tag("configure",{ node : "urn:xmpp:mds:displayed:0"}).tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value","http://jabber.org/protocol/pubsub#publish-options").up().tag("field",{ "var" : "pubsub#persist_items"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#max_items"}).textTag("value","max").up().tag("field",{ "var" : "pubsub#send_last_published_item"}).textTag("value","never").up().tag("field",{ "var" : "pubsub#access_model"}).textTag("value","whitelist").up().up().up().up(),function(response) {
+						if(response.attr["type"] == "result") {
+							_gthis.publishMds();
+						}
+					});
+				}
+			}
+		});
+	}
+}
+snikket_Chat.__name__ = "snikket.Chat";
+Object.assign(snikket_Chat.prototype, {
+	__class__: snikket_Chat
+});
+class snikket_DirectChat extends snikket_Chat {
+	constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy) {
+		if(isBlocked == null) {
+			isBlocked = false;
+		}
+		if(uiState == null) {
+			uiState = 1;
+		}
+		super(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy);
+	}
+	getParticipants() {
+		return this.chatId.split("\n");
+	}
+	getParticipantDetails(participantId) {
+		let chat = this.client.getDirectChat(participantId);
+		return new snikket_Participant(chat.getDisplayName(),chat.getPhoto(),chat.getPlaceholder(),chat.chatId == this.client.accountId());
+	}
+	getMessagesBefore(beforeId,beforeTime,handler) {
+		let _gthis = this;
+		this.persistence.getMessagesBefore(this.client.accountId(),this.chatId,beforeId,beforeTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				let filter = { 'with' : _gthis.chatId};
+				if(beforeId != null) {
+					filter.page = { before : beforeId};
+				}
+				let sync = new snikket_MessageSync(_gthis.client,_gthis.stream,filter);
+				_gthis.fetchFromSync(sync,handler);
+			}
+		});
+	}
+	getMessagesAfter(afterId,afterTime,handler) {
+		if(afterId == this.lastMessageId() && !this.syncing()) {
+			handler([]);
+			return;
+		}
+		let _gthis = this;
+		this.persistence.getMessagesAfter(this.client.accountId(),this.chatId,afterId,afterTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				let filter = { 'with' : _gthis.chatId};
+				if(afterId != null) {
+					filter.page = { after : afterId};
+				}
+				let sync = new snikket_MessageSync(_gthis.client,_gthis.stream,filter);
+				_gthis.fetchFromSync(sync,handler);
+			}
+		});
+	}
+	getMessagesAround(aroundId,aroundTime,handler) {
+		this.persistence.getMessagesAround(this.client.accountId(),this.chatId,aroundId,aroundTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				handler([]);
+			}
+		});
+	}
+	prepareIncomingMessage(message,stanza) {
+		message.syncPoint = !this.syncing();
+		return message;
+	}
+	prepareOutgoingMessage(message) {
+		let tmp = message.timestamp;
+		message.timestamp = tmp != null ? tmp : snikket_Date.format(new Date());
+		message.direction = 1;
+		message.from = this.client.jid;
+		message.sender = message.from.asBare();
+		message.replyTo = [message.sender];
+		let _this = this.getParticipants();
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = snikket_JID.parse(_this[i]);
+		}
+		message.recipients = result;
+		return message;
+	}
+	correctMessage(localId,message) {
+		let toSendId = message.localId;
+		message = this.prepareOutgoingMessage(message);
+		let tmp = message.build();
+		message.versions = [tmp];
+		message.localId = localId;
+		let _gthis = this;
+		this.client.storeMessages([message.build()],function(corrected) {
+			let tmp = corrected[0].versions[corrected[0].versions.length - 1];
+			let tmp1 = (tmp != null ? tmp.localId : null) == localId ? corrected[0].versions : [message.build()];
+			message.versions = tmp1;
+			message.localId = toSendId;
+			let _g = 0;
+			let _g1 = message.recipients;
+			while(_g < _g1.length) {
+				let recipient = _g1[_g];
+				++_g;
+				message.to = recipient;
+				_gthis.client.sendStanza(message.build().asStanza());
+			}
+			let tmp2 = _gthis.lastMessage;
+			if(localId == (tmp2 != null ? tmp2.localId : null)) {
+				_gthis.setLastMessage(corrected[0]);
+				_gthis.client.trigger("chats/update",[_gthis]);
+			}
+			_gthis.client.notifyMessageHandlers(corrected[0],1);
+		});
+	}
+	sendMessage(message) {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.client.chatActivity(this);
+		message = this.prepareOutgoingMessage(message);
+		message.to = message.recipients[0];
+		let fromStanza = snikket_Message.fromStanza(message.build().asStanza(),this.client.jid).parsed;
+		let _gthis = this;
+		switch(fromStanza._hx_index) {
+		case 1:
+			let _g = fromStanza.message;
+			this.client.storeMessages([message.build()],function(stored) {
+				let _g = 0;
+				let _g1 = message.recipients;
+				while(_g < _g1.length) {
+					let recipient = _g1[_g];
+					++_g;
+					message.to = recipient;
+					let stanza = message.build().asStanza();
+					if(_gthis.isActive != null) {
+						_gthis.isActive = true;
+						_gthis.activeThread = message.threadId;
+						stanza.tag("active",{ xmlns : "http://jabber.org/protocol/chatstates"}).up();
+					}
+					_gthis.client.sendStanza(stanza);
+				}
+				_gthis.setLastMessage(message.build());
+				_gthis.client.trigger("chats/update",[_gthis]);
+				_gthis.client.notifyMessageHandlers(stored[0],stored[0].versions.length > 1 ? 1 : 0);
+			});
+			break;
+		case 3:
+			let update = fromStanza.update;
+			this.persistence.storeReaction(this.client.accountId(),update,function(stored) {
+				let _g = 0;
+				let _g1 = message.recipients;
+				while(_g < _g1.length) {
+					let recipient = _g1[_g];
+					++_g;
+					message.to = recipient;
+					_gthis.client.sendStanza(message.build().asStanza());
+				}
+				if(stored != null) {
+					_gthis.client.notifyMessageHandlers(stored,2);
+				}
+			});
+			break;
+		default:
+			haxe_Log.trace("Invalid message",{ fileName : "snikket/Chat.hx", lineNumber : 797, className : "snikket.DirectChat", methodName : "sendMessage", customParams : [fromStanza]});
+			throw haxe_Exception.thrown("Trying to send invalid message.");
+		}
+	}
+	removeReaction(m,reaction) {
+		if(((reaction) instanceof snikket_CustomEmojiReaction)) {
+			if(reaction.envelopeId == null) {
+				throw haxe_Exception.thrown("Cannot remove custom emoji reaction without envelopeId");
+			}
+			let correct = m.reply();
+			correct.localId = snikket_ID.long();
+			correct.setHtml("");
+			correct.text = null;
+			this.correctMessage(reaction.envelopeId,correct);
+			return;
+		}
+		let reactions = [];
+		let _gthis = this;
+		let jsIterator = m.reactions.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let areaction = _g_key;
+			let reacts = _g_value;
+			if(areaction != reaction.key) {
+				let react = Lambda.find(reacts,function(r) {
+					return r.senderId == _gthis.client.accountId();
+				});
+				if(react != null && !((react) instanceof snikket_CustomEmojiReaction)) {
+					reactions.push(react);
+				}
+			}
+		}
+		let update = new snikket_ReactionUpdate(snikket_ID.long(),null,null,m.localId,m.chatId(),this.client.accountId(),snikket_Date.format(new Date()),reactions,0);
+		this.persistence.storeReaction(this.client.accountId(),update,function(stored) {
+			let stanza = update.asStanza();
+			let _g = 0;
+			let _g1 = _gthis.getParticipants();
+			while(_g < _g1.length) {
+				let recipient = _g1[_g];
+				++_g;
+				stanza.attr["to"] = recipient;
+				_gthis.client.sendStanza(stanza);
+			}
+			if(stored != null) {
+				_gthis.client.notifyMessageHandlers(stored,2);
+			}
+		});
+	}
+	lastMessageId() {
+		let tmp = this.lastMessage;
+		let tmp1 = tmp != null ? tmp.localId : null;
+		if(tmp1 != null) {
+			return tmp1;
+		} else {
+			let tmp = this.lastMessage;
+			if(tmp != null) {
+				return tmp.serverId;
+			} else {
+				return null;
+			}
+		}
+	}
+	markReadUpTo(message) {
+		let _gthis = this;
+		this.markReadUpToMessage(message,function() {
+			if(message.isIncoming() && message.localId != null) {
+				let _g = 0;
+				let _g1 = _gthis.getParticipants();
+				while(_g < _g1.length) {
+					let recipient = _g1[_g];
+					++_g;
+					let stanza = new snikket_Stanza("message",{ to : recipient, id : snikket_ID.long()}).tag("displayed",{ xmlns : "urn:xmpp:chat-markers:0", id : message.localId}).up();
+					if(message.threadId != null) {
+						stanza.textTag("thread",message.threadId);
+					}
+					_gthis.client.sendStanza(stanza);
+				}
+			}
+			_gthis.publishMds();
+			_gthis.client.trigger("chats/update",[_gthis]);
+		});
+	}
+	bookmark() {
+		let attr = { jid : this.chatId};
+		if(this.displayName != null && this.displayName != "" && this.displayName != this.chatId) {
+			attr["name"] = this.displayName;
+		}
+		let _gthis = this;
+		this.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("query",{ xmlns : "jabber:iq:roster"}).tag("item",attr).up().up(),function(response) {
+			if(response.attr["type"] == "error") {
+				return;
+			}
+			_gthis.stream.sendStanza(new snikket_Stanza("presence",{ to : _gthis.chatId, type : "subscribe", id : snikket_ID.short()}));
+			if(_gthis.isTrusted()) {
+				_gthis.stream.sendStanza(new snikket_Stanza("presence",{ to : _gthis.chatId, type : "subscribed", id : snikket_ID.short()}));
+			}
+		});
+	}
+	sendChatState(state,threadId) {
+		let _g = 0;
+		let _g1 = this.getParticipants();
+		while(_g < _g1.length) {
+			let recipient = _g1[_g];
+			++_g;
+			let stanza = new snikket_Stanza("message",{ id : snikket_ID.long(), type : "chat", from : this.client.jid.asString(), to : recipient}).tag(state,{ xmlns : "http://jabber.org/protocol/chatstates"}).up();
+			if(threadId != null) {
+				stanza.textTag("thread",threadId);
+			}
+			this.stream.sendStanza(stanza);
+		}
+	}
+	close() {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.uiState = 2;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		if(!this.isBlocked) {
+			this.sendChatState("gone",null);
+		}
+		this.client.trigger("chats/update",[this]);
+	}
+}
+$hx_exports["snikket"]["DirectChat"] = snikket_DirectChat;
+snikket_DirectChat.__name__ = "snikket.DirectChat";
+snikket_DirectChat.__super__ = snikket_Chat;
+Object.assign(snikket_DirectChat.prototype, {
+	__class__: snikket_DirectChat
+});
+class snikket_Channel extends snikket_Chat {
+	constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy,disco) {
+		snikket_Chat._hx_skip_constructor = true;
+		super();
+		snikket_Chat._hx_skip_constructor = false;
+		this._hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy,disco);
+	}
+	_hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy,disco) {
+		if(isBlocked == null) {
+			isBlocked = false;
+		}
+		if(uiState == null) {
+			uiState = 1;
+		}
+		this._nickInUse = null;
+		this.forceLive = false;
+		this.sync = null;
+		this.inSync = true;
+		this.disco = new snikket_Caps("",[],["http://jabber.org/protocol/muc"]);
+		super._hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy);
+		if(disco != null) {
+			this.disco = disco;
+			if(!disco.features.includes("http://jabber.org/protocol/muc")) {
+				this.forceLive = true;
+			}
+		}
+	}
+	selfPing(refresh) {
+		if(this.uiState == 2) {
+			this.client.sendPresence(this.getFullJid().asString(),function(stanza) {
+				stanza.attr["type"] = "unavailable";
+				return stanza;
+			});
+			return;
+		}
+		let _gthis = this;
+		(refresh ? $bind(this,this.refreshDisco) : function(cb) {
+			cb();
+		})(function() {
+			if(!_gthis.disco.features.includes("http://jabber.org/protocol/muc")) {
+				_gthis.forceLive = true;
+				return;
+			}
+			_gthis.stream.sendIq(new snikket_Stanza("iq",{ type : "get", to : _gthis.getFullJid().asString()}).tag("ping",{ xmlns : "urn:xmpp:ping"}).up(),function(response) {
+				if(response.attr["type"] == "error") {
+					let tmp = response.getChild("error");
+					let err = tmp != null ? tmp.getChild(null,"urn:ietf:params:xml:ns:xmpp-stanzas") : null;
+					if(err.name == "service-unavailable" || err.name == "feature-not-implemented") {
+						_gthis.selfPingSuccess();
+						return;
+					}
+					if(err.name == "remote-server-not-found" || err.name == "remote-server-timeout") {
+						_gthis.selfPingSuccess();
+						return;
+					}
+					if(err.name == "item-not-found") {
+						_gthis.selfPingSuccess();
+						return;
+					}
+					_gthis.presence = new Map([]);
+					_gthis._nickInUse = null;
+					_gthis.inSync = false;
+					_gthis.client.trigger("chats/update",[_gthis]);
+					let desiredFullJid = snikket_JID.parse(_gthis.chatId).withResource(_gthis.client.displayName());
+					_gthis.client.sendPresence(desiredFullJid.asString(),function(stanza) {
+						stanza.tag("x",{ xmlns : "http://jabber.org/protocol/muc"});
+						if(_gthis.disco.features.includes("urn:xmpp:mam:2")) {
+							stanza.tag("history",{ maxchars : "0"}).up();
+						}
+						stanza.up();
+						return stanza;
+					});
+				} else {
+					_gthis.selfPingSuccess();
+				}
+			});
+		});
+	}
+	selfPingSuccess() {
+		if(this.nickInUse() != this.client.displayName()) {
+			let desiredFullJid = snikket_JID.parse(this.chatId).withResource(this.client.displayName());
+			this.client.sendPresence(desiredFullJid.asString());
+		}
+		this.inSync = false;
+		this.persistence.lastId(this.client.accountId(),this.chatId,$bind(this,this.doSync));
+	}
+	setPresence(resource,presence) {
+		let tmp = presence != null ? presence.mucUser : null;
+		let oneTen = tmp != null ? Lambda.find(tmp.allTags("status"),function(status) {
+			return status.attr["code"] == "110";
+		}) : null;
+		if(oneTen != null) {
+			this._nickInUse = resource;
+		} else if(resource == this._nickInUse) {
+			this._nickInUse = null;
+		}
+		if(presence != null && presence.mucUser != null && oneTen == null) {
+			let existing = this.presence.get(resource);
+			let tmp;
+			if(existing != null) {
+				let tmp1 = existing != null ? existing.mucUser : null;
+				tmp = (tmp1 != null ? Lambda.find(tmp1.allTags("status"),function(status) {
+					return status.attr["code"] == "110";
+				}) : null) != null;
+			} else {
+				tmp = false;
+			}
+			if(tmp) {
+				presence.mucUser.tag("status",{ code : "110"});
+				this.setPresence(resource,presence);
+				return;
+			}
+		}
+		super.setPresence(resource,presence);
+		let tmp1 = presence != null ? presence.mucUser : null;
+		let tripleThree = tmp1 != null ? Lambda.find(tmp1.allTags("status"),function(status) {
+			return status.attr["code"] == "333";
+		}) : null;
+		if(!this.inSync && this.sync == null && oneTen != null) {
+			this.persistence.lastId(this.client.accountId(),this.chatId,$bind(this,this.doSync));
+		}
+		if(oneTen != null && tripleThree != null) {
+			this.selfPing(true);
+		}
+	}
+	doSync(lastId) {
+		if(!this.disco.features.includes("urn:xmpp:mam:2")) {
+			this.inSync = true;
+			return;
+		}
+		if(this.sync != null) {
+			return;
+		}
+		let threeDaysAgo = snikket_Date.format(new Date(new Date().getTime() + (-259200000.)));
+		this.sync = new snikket_MessageSync(this.client,this.stream,lastId == null ? { startTime : threeDaysAgo} : { page : { after : lastId}},this.chatId);
+		this.sync.setNewestPageFirst(false);
+		let _gthis = this;
+		this.sync.addContext(function(builder,stanza) {
+			builder = _gthis.prepareIncomingMessage(builder,stanza);
+			builder.syncPoint = true;
+			return builder;
+		});
+		let chatMessages = [];
+		this.sync.onMessages(function(messageList) {
+			let promises = [];
+			let pageChatMessages = [];
+			let _g = 0;
+			let _g1 = messageList.messages;
+			while(_g < _g1.length) {
+				let m = _g1[_g];
+				++_g;
+				switch(m._hx_index) {
+				case 1:
+					let message = m.message;
+					let _g2 = 0;
+					let _g3 = message.inlineHashReferences();
+					while(_g2 < _g3.length) {
+						let hash = _g3[_g2];
+						++_g2;
+						_gthis.client.fetchMediaByHash([hash],[message.from]);
+					}
+					pageChatMessages.push(message);
+					break;
+				case 2:
+					let action = m.action;
+					promises.push(thenshim_Promise._new(function(resolve,reject) {
+						_gthis.client.moderateMessage(action).then(function(_) {
+							resolve(null);
+						});
+					}));
+					break;
+				case 3:
+					let update = m.update;
+					promises.push(thenshim_Promise._new(function(resolve,reject) {
+						_gthis.persistence.storeReaction(_gthis.client.accountId(),update,function(_) {
+							resolve(null);
+						});
+					}));
+					break;
+				default:
+				}
+			}
+			promises.push(thenshim_Promise._new(function(resolve,reject) {
+				_gthis.client.storeMessages(pageChatMessages,resolve);
+			}));
+			thenshim_Promise.then(thenshim_PromiseTools.all(promises),function(stored) {
+				let _g = 0;
+				while(_g < stored.length) {
+					let messages = stored[_g];
+					++_g;
+					if(messages != null) {
+						let _g = 0;
+						while(_g < messages.length) {
+							let message = messages[_g];
+							++_g;
+							_gthis.client.notifySyncMessageHandlers(message);
+							if(message != null && message.chatId() == _gthis.chatId) {
+								chatMessages.push(message);
+							}
+							if(chatMessages.length > 1000) {
+								chatMessages.shift();
+							}
+						}
+					}
+				}
+				if(_gthis.sync.hasMore()) {
+					_gthis.sync.fetchNext();
+				} else {
+					_gthis.inSync = true;
+					_gthis.sync = null;
+					let lastFromSync = chatMessages[chatMessages.length - 1];
+					if(lastFromSync != null && (_gthis.lastMessageTimestamp() == null || Reflect.compare(lastFromSync.timestamp,_gthis.lastMessageTimestamp()) > 0)) {
+						_gthis.setLastMessage(lastFromSync);
+						_gthis.client.sortChats();
+					}
+					let serverIds = new Map([]);
+					let dedupedMessages = [];
+					chatMessages.reverse();
+					let _g = 0;
+					while(_g < chatMessages.length) {
+						let m = chatMessages[_g];
+						++_g;
+						let tmp = serverIds.get(m.serverId);
+						if(!(tmp != null && tmp)) {
+							dedupedMessages.unshift(m);
+							serverIds.set(m.serverId,true);
+						}
+					}
+					let readIndex = Lambda.findIndex(dedupedMessages,function(m) {
+						if(m.serverId != _gthis.readUpTo()) {
+							return !m.isIncoming();
+						} else {
+							return true;
+						}
+					});
+					if(readIndex < 0) {
+						_gthis.setUnreadCount(_gthis.unreadCount() + dedupedMessages.length);
+					} else {
+						_gthis.setUnreadCount(dedupedMessages.length - readIndex - 1);
+					}
+					_gthis.client.trigger("chats/update",[_gthis]);
+				}
+			});
+		});
+		this.sync.onError(function(stanza) {
+			_gthis.sync = null;
+			if(lastId != null) {
+				_gthis.doSync(null);
+			} else {
+				haxe_Log.trace("SYNC failed",{ fileName : "snikket/Chat.hx", lineNumber : 1114, className : "snikket.Channel", methodName : "doSync", customParams : [_gthis.chatId,stanza]});
+			}
+		});
+		this.sync.fetchNext();
+	}
+	isTrusted() {
+		return this.uiState != 2;
+	}
+	refreshDisco(callback) {
+		let discoGet = new snikket_queries_DiscoInfoGet(this.chatId);
+		let _gthis = this;
+		discoGet.onFinished(function() {
+			if(discoGet.getResult() != null) {
+				_gthis.disco = discoGet.getResult();
+				_gthis.persistence.storeCaps(discoGet.getResult());
+				_gthis.persistence.storeChats(_gthis.client.accountId(),[_gthis]);
+			}
+			if(callback != null) {
+				callback();
+			}
+		});
+		this.client.sendQuery(discoGet);
+	}
+	preview() {
+		if(this.lastMessage == null) {
+			return super.preview();
+		}
+		return this.getParticipantDetails(this.lastMessage.senderId).displayName + ": " + super.preview();
+	}
+	livePresence() {
+		if(this.forceLive) {
+			return true;
+		}
+		return this._nickInUse != null;
+	}
+	syncing() {
+		if(this.inSync) {
+			return !this.livePresence();
+		} else {
+			return true;
+		}
+	}
+	canAudioCall() {
+		let tmp = this.disco;
+		let tmp1 = tmp != null ? tmp.features : null;
+		let tmp2 = tmp1 != null ? tmp1.includes("urn:xmpp:jingle:apps:rtp:audio") : null;
+		if(tmp2 != null) {
+			return tmp2;
+		} else {
+			return false;
+		}
+	}
+	canVideoCall() {
+		let tmp = this.disco;
+		let tmp1 = tmp != null ? tmp.features : null;
+		let tmp2 = tmp1 != null ? tmp1.includes("urn:xmpp:jingle:apps:rtp:video") : null;
+		if(tmp2 != null) {
+			return tmp2;
+		} else {
+			return false;
+		}
+	}
+	nickInUse() {
+		let tmp = this._nickInUse;
+		if(tmp != null) {
+			return tmp;
+		} else {
+			return this.client.displayName();
+		}
+	}
+	getFullJid() {
+		return snikket_JID.parse(this.chatId).withResource(this.nickInUse());
+	}
+	getParticipants() {
+		let jid = snikket_JID.parse(this.chatId);
+		let _gthis = this;
+		let _g = [];
+		let inlobj_iterator = function() {
+			return new js_lib_HaxeIterator(_gthis.presence.keys());
+		};
+		let x = inlobj_iterator();
+		while(x.hasNext()) {
+			let x1 = x.next();
+			_g.push(new snikket_JID(jid.node,jid.domain,x1).asString());
+		}
+		return _g;
+	}
+	getParticipantDetails(participantId) {
+		if(participantId == this.getFullJid().asString()) {
+			let chat = this.client.getDirectChat(this.client.accountId(),false);
+			return new snikket_Participant(this.client.displayName(),chat.getPhoto(),chat.getPlaceholder(),true);
+		} else {
+			let nick = snikket_JID.parse(participantId).resource;
+			let placeholderUri = snikket_Color.defaultPhoto(participantId,nick == null ? " " : nick.charAt(0));
+			return new snikket_Participant(nick,null,placeholderUri,false);
+		}
+	}
+	getMessagesBefore(beforeId,beforeTime,handler) {
+		let _gthis = this;
+		this.persistence.getMessagesBefore(this.client.accountId(),this.chatId,beforeId,beforeTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				let filter = { };
+				if(beforeId != null) {
+					filter.page = { before : beforeId};
+				}
+				let sync = new snikket_MessageSync(_gthis.client,_gthis.stream,filter,_gthis.chatId);
+				sync.addContext(function(builder,stanza) {
+					builder = _gthis.prepareIncomingMessage(builder,stanza);
+					builder.syncPoint = false;
+					return builder;
+				});
+				_gthis.fetchFromSync(sync,handler);
+			}
+		});
+	}
+	getMessagesAfter(afterId,afterTime,handler) {
+		if(afterId == this.lastMessageId() && !this.syncing()) {
+			handler([]);
+			return;
+		}
+		let _gthis = this;
+		this.persistence.getMessagesAfter(this.client.accountId(),this.chatId,afterId,afterTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				let filter = { };
+				if(afterId != null) {
+					filter.page = { after : afterId};
+				}
+				let sync = new snikket_MessageSync(_gthis.client,_gthis.stream,filter,_gthis.chatId);
+				sync.addContext(function(builder,stanza) {
+					builder = _gthis.prepareIncomingMessage(builder,stanza);
+					builder.syncPoint = false;
+					return builder;
+				});
+				_gthis.fetchFromSync(sync,handler);
+			}
+		});
+	}
+	getMessagesAround(aroundId,aroundTime,handler) {
+		this.persistence.getMessagesAround(this.client.accountId(),this.chatId,aroundId,aroundTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				handler([]);
+			}
+		});
+	}
+	prepareIncomingMessage(message,stanza) {
+		message.syncPoint = !this.syncing();
+		if(message.type == 0) {
+			message.type = 3;
+		}
+		message.sender = snikket_JID.parse(stanza.attr["from"]);
+		if(message.get_senderId() == this.getFullJid().asString()) {
+			message.recipients = message.replyTo;
+			message.direction = 1;
+		}
+		return message;
+	}
+	prepareOutgoingMessage(message) {
+		message.type = 2;
+		let tmp = message.timestamp;
+		message.timestamp = tmp != null ? tmp : snikket_Date.format(new Date());
+		message.direction = 1;
+		message.from = this.client.jid;
+		message.sender = this.getFullJid();
+		message.replyTo = [message.sender];
+		message.to = snikket_JID.parse(this.chatId);
+		message.recipients = [message.to];
+		return message;
+	}
+	correctMessage(localId,message) {
+		let toSendId = message.localId;
+		message = this.prepareOutgoingMessage(message);
+		let tmp = message.build();
+		message.versions = [tmp];
+		message.localId = localId;
+		let _gthis = this;
+		this.client.storeMessages([message.build()],function(corrected) {
+			let tmp = corrected[0].localId == localId ? corrected[0].versions : [message.build()];
+			message.versions = tmp;
+			message.localId = toSendId;
+			_gthis.client.sendStanza(message.build().asStanza());
+			_gthis.client.notifyMessageHandlers(corrected[0],1);
+			let tmp1 = _gthis.lastMessage;
+			if(localId == (tmp1 != null ? tmp1.localId : null)) {
+				_gthis.setLastMessage(corrected[0]);
+				_gthis.client.trigger("chats/update",[_gthis]);
+			}
+		});
+	}
+	sendMessage(message) {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.client.chatActivity(this);
+		message = this.prepareOutgoingMessage(message);
+		let stanza = message.build().asStanza();
+		stanza.attr["from"] = this.getFullJid().asString();
+		let fromStanza = snikket_Message.fromStanza(stanza,this.client.jid).parsed;
+		stanza.attr["from"] = this.client.jid.asString();
+		let _gthis = this;
+		switch(fromStanza._hx_index) {
+		case 1:
+			let _g = fromStanza.message;
+			if(this.isActive != null) {
+				this.isActive = true;
+				this.activeThread = message.threadId;
+				stanza.tag("active",{ xmlns : "http://jabber.org/protocol/chatstates"}).up();
+			}
+			this.client.storeMessages([message.build()],function(stored) {
+				_gthis.client.sendStanza(stanza);
+				_gthis.setLastMessage(stored[0]);
+				_gthis.client.notifyMessageHandlers(stored[0],stored[0].versions.length > 1 ? 1 : 0);
+				_gthis.client.trigger("chats/update",[_gthis]);
+			});
+			break;
+		case 3:
+			let update = fromStanza.update;
+			this.persistence.storeReaction(this.client.accountId(),update,function(stored) {
+				_gthis.client.sendStanza(stanza);
+				if(stored != null) {
+					_gthis.client.notifyMessageHandlers(stored,2);
+				}
+			});
+			break;
+		default:
+			haxe_Log.trace("Invalid message",{ fileName : "snikket/Chat.hx", lineNumber : 1314, className : "snikket.Channel", methodName : "sendMessage", customParams : [fromStanza]});
+			throw haxe_Exception.thrown("Trying to send invalid message.");
+		}
+	}
+	removeReaction(m,reaction) {
+		if(((reaction) instanceof snikket_CustomEmojiReaction)) {
+			if(reaction.envelopeId == null) {
+				throw haxe_Exception.thrown("Cannot remove custom emoji reaction without envelopeId");
+			}
+			let correct = m.reply();
+			correct.localId = snikket_ID.long();
+			correct.setHtml("");
+			correct.text = null;
+			this.correctMessage(reaction.envelopeId,correct);
+			return;
+		}
+		let reactions = [];
+		let _gthis = this;
+		let jsIterator = m.reactions.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let areaction = _g_key;
+			let reacts = _g_value;
+			if(areaction != reaction.key) {
+				let react = Lambda.find(reacts,function(r) {
+					return r.senderId == _gthis.getFullJid().asString();
+				});
+				if(react != null && !((react) instanceof snikket_CustomEmojiReaction)) {
+					reactions.push(react);
+				}
+			}
+		}
+		let update = new snikket_ReactionUpdate(snikket_ID.long(),m.serverId,m.chatId(),null,m.chatId(),this.getFullJid().asString(),snikket_Date.format(new Date()),reactions,0);
+		this.persistence.storeReaction(this.client.accountId(),update,function(stored) {
+			let stanza = update.asStanza();
+			stanza.attr["to"] = _gthis.chatId;
+			_gthis.client.sendStanza(stanza);
+			if(stored != null) {
+				_gthis.client.notifyMessageHandlers(stored,2);
+			}
+		});
+	}
+	lastMessageId() {
+		let tmp = this.lastMessage;
+		if(tmp != null) {
+			return tmp.serverId;
+		} else {
+			return null;
+		}
+	}
+	markReadUpTo(message) {
+		let _gthis = this;
+		this.markReadUpToMessage(message,function() {
+			let stanza = new snikket_Stanza("message",{ to : _gthis.chatId, id : snikket_ID.long(), type : "groupchat"}).tag("displayed",{ xmlns : "urn:xmpp:chat-markers:0", id : message.serverId}).up();
+			if(message.threadId != null) {
+				stanza.textTag("thread",message.threadId);
+			}
+			_gthis.client.sendStanza(stanza);
+			_gthis.publishMds();
+			_gthis.client.trigger("chats/update",[_gthis]);
+		});
+	}
+	bookmark() {
+		let _gthis = this;
+		this.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub"}).tag("publish",{ node : "urn:xmpp:bookmarks:1"}).tag("item",{ id : this.chatId}).tag("conference",{ xmlns : "urn:xmpp:bookmarks:1", name : this.getDisplayName(), autojoin : this.uiState == 2 ? "false" : "true"}).textTag("nick",this.client.displayName()).addChild(this.extensions).up().up().tag("publish-options").tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value","http://jabber.org/protocol/pubsub#publish-options").up().tag("field",{ "var" : "pubsub#persist_items"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#max_items"}).textTag("value","max").up().tag("field",{ "var" : "pubsub#send_last_published_item"}).textTag("value","never").up().tag("field",{ "var" : "pubsub#access_model"}).textTag("value","whitelist").up().tag("field",{ "var" : "pubsub#notify_delete"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#notify_retract"}).textTag("value","true").up().up().up().up().up(),function(response) {
+			if(response.attr["type"] == "error") {
+				let tmp = response.getChild("error");
+				let preconditionError = tmp != null ? tmp.getChild("precondition-not-met","http://jabber.org/protocol/pubsub#errors") : null;
+				if(preconditionError != null) {
+					_gthis.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub#owner"}).tag("configure",{ node : "urn:xmpp:bookmarks:1"}).tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value","http://jabber.org/protocol/pubsub#publish-options").up().tag("field",{ "var" : "pubsub#persist_items"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#max_items"}).textTag("value","max").up().tag("field",{ "var" : "pubsub#send_last_published_item"}).textTag("value","never").up().tag("field",{ "var" : "pubsub#access_model"}).textTag("value","whitelist").up().tag("field",{ "var" : "pubsub#notify_delete"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#notify_retract"}).textTag("value","true").up().up().up().up(),function(response) {
+						if(response.attr["type"] == "result") {
+							_gthis.bookmark();
+						}
+					});
+				}
+			}
+		});
+	}
+	sendChatState(state,threadId) {
+		let stanza = new snikket_Stanza("message",{ id : snikket_ID.long(), type : "groupchat", from : this.client.jid.asString(), to : this.chatId}).tag(state,{ xmlns : "http://jabber.org/protocol/chatstates"}).up();
+		if(threadId != null) {
+			stanza.textTag("thread",threadId);
+		}
+		this.stream.sendStanza(stanza);
+	}
+	close() {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.uiState = 2;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		this.selfPing(false);
+		this.bookmark();
+		this.sendChatState("gone",null);
+		this.client.trigger("chats/update",[this]);
+	}
+}
+$hx_exports["snikket"]["Channel"] = snikket_Channel;
+snikket_Channel.__name__ = "snikket.Channel";
+snikket_Channel.__super__ = snikket_Chat;
+Object.assign(snikket_Channel.prototype, {
+	__class__: snikket_Channel
+});
+class snikket_AvailableChat {
+	constructor(chatId,displayName,note,caps) {
+		this.chatId = chatId;
+		this.displayName = displayName;
+		this.note = note;
+		this.caps = caps;
+	}
+	isChannel() {
+		return this.caps.isChannel(this.chatId);
+	}
+}
+$hx_exports["snikket"]["AvailableChat"] = snikket_AvailableChat;
+snikket_AvailableChat.__name__ = "snikket.AvailableChat";
+Object.assign(snikket_AvailableChat.prototype, {
+	__class__: snikket_AvailableChat
+});
+class snikket_SerializedChat {
+	constructor(chatId,trusted,avatarSha1,presence,displayName,uiState,isBlocked,extensions,readUpToId,readUpToBy,disco,klass) {
+		this.chatId = chatId;
+		this.trusted = trusted;
+		this.avatarSha1 = avatarSha1;
+		this.presence = presence;
+		this.displayName = displayName;
+		let tmp = uiState;
+		this.uiState = tmp != null ? tmp : 1;
+		let tmp1 = isBlocked;
+		this.isBlocked = tmp1 != null && tmp1;
+		let tmp2 = extensions;
+		this.extensions = tmp2 != null ? tmp2 : "<extensions xmlns='urn:app:bookmarks:1' />";
+		this.readUpToId = readUpToId;
+		this.readUpToBy = readUpToBy;
+		this.disco = disco;
+		this.klass = klass;
+	}
+	toChat(client,stream,persistence) {
+		let extensionsStanza = snikket_Stanza.fromXml(Xml.parse(this.extensions));
+		let chat;
+		if(this.klass == "DirectChat") {
+			chat = new snikket_DirectChat(client,stream,persistence,this.chatId,this.uiState,this.isBlocked,extensionsStanza,this.readUpToId,this.readUpToBy);
+		} else if(this.klass == "Channel") {
+			let channel = new snikket_Channel(client,stream,persistence,this.chatId,this.uiState,this.isBlocked,extensionsStanza,this.readUpToId,this.readUpToBy);
+			let tmp = this.disco;
+			channel.disco = tmp != null ? tmp : new snikket_Caps("",[],["http://jabber.org/protocol/muc"]);
+			chat = channel;
+		} else {
+			throw haxe_Exception.thrown("Unknown class of " + this.chatId + ": " + this.klass);
+		}
+		if(this.displayName != null) {
+			chat.displayName = this.displayName;
+		}
+		if(this.avatarSha1 != null) {
+			chat.setAvatarSha1(this.avatarSha1);
+		}
+		chat.setTrusted(this.trusted);
+		let jsIterator = this.presence.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let resource = _g_key;
+			let p = _g_value;
+			chat.setPresence(resource,p);
+		}
+		return chat;
+	}
+}
+$hx_exports["snikket"]["SerializedChat"] = snikket_SerializedChat;
+snikket_SerializedChat.__name__ = "snikket.SerializedChat";
+Object.assign(snikket_SerializedChat.prototype, {
+	__class__: snikket_SerializedChat
+});
+class snikket_ChatAttachment {
+	constructor(name,mime,size,uris,hashes) {
+		this.name = name;
+		this.mime = mime;
+		this.size = size;
+		this.uris = uris;
+		this.hashes = hashes;
+	}
+}
+$hx_exports["snikket"]["ChatAttachment"] = snikket_ChatAttachment;
+snikket_ChatAttachment.__name__ = "snikket.ChatAttachment";
+Object.assign(snikket_ChatAttachment.prototype, {
+	__class__: snikket_ChatAttachment
+});
+class snikket_ChatMessage {
+	constructor(params) {
+		this.localId = params.localId;
+		this.serverId = params.serverId;
+		this.serverIdBy = params.serverIdBy;
+		let tmp = params.type;
+		this.type = tmp != null ? tmp : 0;
+		let tmp1 = params.syncPoint;
+		this.syncPoint = tmp1 != null && tmp1;
+		this.replyId = params.replyId;
+		this.timestamp = params.timestamp;
+		this.to = params.to;
+		this.from = params.from;
+		this.senderId = params.senderId;
+		let tmp2 = params.recipients;
+		this.recipients = tmp2 != null ? tmp2 : [];
+		let tmp3 = params.replyTo;
+		this.replyTo = tmp3 != null ? tmp3 : [];
+		this.replyToMessage = params.replyToMessage;
+		this.threadId = params.threadId;
+		let tmp4 = params.attachments;
+		this.attachments = tmp4 != null ? tmp4 : [];
+		let tmp5 = params.reactions;
+		this.reactions = tmp5 != null ? tmp5 : new Map([]);
+		this.text = params.text;
+		this.lang = params.lang;
+		let tmp6 = params.direction;
+		this.direction = tmp6 != null ? tmp6 : 1;
+		let tmp7 = params.status;
+		this.status = tmp7 != null ? tmp7 : 0;
+		let tmp8 = params.versions;
+		this.versions = tmp8 != null ? tmp8 : [];
+		let tmp9 = params.payloads;
+		this.payloads = tmp9 != null ? tmp9 : [];
+		this.stanza = params.stanza;
+	}
+	reply() {
+		let m = new snikket_ChatMessageBuilder();
+		m.type = this.type;
+		let tmp = this.threadId;
+		m.threadId = tmp != null ? tmp : snikket_ID.long();
+		m.replyToMessage = this;
+		return m;
+	}
+	getReplyId() {
+		if(this.replyId != null) {
+			return this.replyId;
+		}
+		if(this.type == 2 || this.type == 3) {
+			return this.serverId;
+		} else {
+			return this.localId;
+		}
+	}
+	set_replyToMessage(m) {
+		let rtm = this.replyToMessage;
+		if(rtm == null) {
+			throw haxe_Exception.thrown("Cannot hydrate null replyToMessage");
+		}
+		if(rtm.serverId != null && rtm.serverId != m.serverId) {
+			throw haxe_Exception.thrown("Hydrate serverId mismatch");
+		}
+		if(rtm.localId != null && rtm.localId != m.localId) {
+			throw haxe_Exception.thrown("Hydrate localId mismatch");
+		}
+		return this.replyToMessage = m;
+	}
+	set_reactions(r) {
+		let _gthis = this;
+		if(this.reactions != null && !Lambda.empty({ iterator : function() {
+			return new js_lib_HaxeIterator(_gthis.reactions.keys());
+		}})) {
+			throw haxe_Exception.thrown("Reactions already hydrated");
+		}
+		return this.reactions = r;
+	}
+	inlineHashReferences() {
+		let result = [];
+		let tmp = Lambda.find(this.payloads,function(p) {
+			if(p.attr["xmlns"] == "http://jabber.org/protocol/xhtml-im") {
+				return p.name == "html";
+			} else {
+				return false;
+			}
+		});
+		let htmlBody = tmp != null ? tmp.getChild("body","http://www.w3.org/1999/xhtml") : null;
+		if(htmlBody != null) {
+			htmlBody.traverse(function(child) {
+				if(child.name == "img") {
+					let src = child.attr["src"];
+					if(src != null) {
+						let hash = snikket_Hash.fromUri(src);
+						if(hash != null) {
+							let x = hash;
+							result.push(x);
+						}
+					}
+					return true;
+				}
+				return false;
+			});
+		}
+		return result;
+	}
+	html() {
+		let tmp = Lambda.find(this.payloads,function(p) {
+			if(p.attr["xmlns"] == "http://jabber.org/protocol/xhtml-im") {
+				return p.name == "html";
+			} else {
+				return false;
+			}
+		});
+		let htmlBody = tmp != null ? tmp.getChild("body","http://www.w3.org/1999/xhtml") : null;
+		if(htmlBody != null) {
+			let _this = htmlBody.getChildren();
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].traverse(function(child) {
+					if(child.name == "img") {
+						let src = child.attr["src"];
+						if(src != null) {
+							let hash = snikket_Hash.fromUri(src);
+							if(hash != null) {
+								child.attr["src"] = hash.toUri();
+							}
+						}
+						return true;
+					}
+					return false;
+				}).serialize();
+			}
+			return result.join("");
+		}
+		let tmp1 = this.text;
+		let codepoints = snikket_StringUtil.codepointArray(tmp1 != null ? tmp1 : "");
+		let _gthis = this;
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.payloads;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.attr["xmlns"] == "urn:xmpp:fallback:0" && ((v.attr["for"] == "jabber:x:oob" || v.attr["for"] == "urn:xmpp:sims:1") && _gthis.attachments.length > 0 || _gthis.replyToMessage != null && v.attr["for"] == "urn:xmpp:reply:0" || v.attr["for"] == "http://jabber.org/protocol/address")) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			result[i] = _this[i].getChild("body");
+		}
+		let _this1 = result;
+		let result1 = new Array(_this1.length);
+		let _g5 = 0;
+		let _g6 = _this1.length;
+		while(_g5 < _g6) {
+			let i = _g5++;
+			let b = _this1[i];
+			let fallbacks;
+			if(b == null) {
+				fallbacks = null;
+			} else {
+				let tmp = b.attr["start"];
+				let tmp1 = Std.parseInt(tmp != null ? tmp : "0");
+				let tmp2 = b.attr["end"];
+				let tmp3 = Std.parseInt(tmp2 != null ? tmp2 : codepoints.length == null ? "null" : "" + codepoints.length);
+				fallbacks = { start : tmp1 != null ? tmp1 : 0, end : tmp3 != null ? tmp3 : codepoints.length};
+			}
+			result1[i] = fallbacks;
+		}
+		let _g7 = [];
+		let _g8 = 0;
+		let _g9 = result1;
+		while(_g8 < _g9.length) {
+			let v = _g9[_g8];
+			++_g8;
+			if(v != null) {
+				_g7.push(v);
+			}
+		}
+		let fallbacks = _g7;
+		fallbacks.sort(function(x,y) {
+			return y.start - x.start;
+		});
+		let _g10 = 0;
+		while(_g10 < fallbacks.length) {
+			let fallback = fallbacks[_g10];
+			++_g10;
+			codepoints.splice(fallback.start,fallback.end - fallback.start);
+		}
+		let body = codepoints.join("");
+		if(Lambda.find(this.payloads,function(p) {
+			if(p.attr["xmlns"] == "urn:xmpp:styling:0") {
+				return p.name == "unstyled";
+			} else {
+				return false;
+			}
+		}) == null) {
+			let _g = [];
+			let x = $getIterator(snikket_XEP0393.parse(body));
+			while(x.hasNext()) {
+				let x1 = x.next();
+				_g.push(x1.toString());
+			}
+			return _g.join("");
+		} else {
+			return StringTools.htmlEscape(body);
+		}
+	}
+	chatId() {
+		if(this.isIncoming()) {
+			let _this = this.replyTo;
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].asBare().asString();
+			}
+			return result.join("\n");
+		} else {
+			let _this = this.recipients;
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].asString();
+			}
+			return result.join("\n");
+		}
+	}
+	account() {
+		let tmp;
+		if(!this.isIncoming()) {
+			let tmp1 = this.from;
+			let tmp2 = tmp1 != null ? tmp1.asBare() : null;
+			tmp = tmp2 != null ? tmp2.asString() : null;
+		} else {
+			let tmp1 = this.to;
+			let tmp2 = tmp1 != null ? tmp1.asBare() : null;
+			tmp = tmp2 != null ? tmp2.asString() : null;
+		}
+		if(tmp != null) {
+			return tmp;
+		} else {
+			throw haxe_Exception.thrown("from or to is null");
+		}
+	}
+	isIncoming() {
+		return this.direction == 0;
+	}
+	threadIcon() {
+		if(this.threadId == null) {
+			return null;
+		} else {
+			return snikket_Identicon.svg(this.threadId);
+		}
+	}
+	callStatus() {
+		let tmp = Lambda.find(this.payloads,function(el) {
+			return el.attr["xmlns"] == "urn:xmpp:jingle-message:0";
+		});
+		if(tmp != null) {
+			return tmp.name;
+		} else {
+			return null;
+		}
+	}
+	callSid() {
+		let tmp = Lambda.find(this.payloads,function(el) {
+			return el.attr["xmlns"] == "urn:xmpp:jingle-message:0";
+		});
+		let tmp1 = tmp != null ? tmp.attr : null;
+		if(tmp1 != null) {
+			return tmp1["id"];
+		} else {
+			return null;
+		}
+	}
+	callDuration() {
+		if(this.versions.length < 2) {
+			return null;
+		}
+		let startedStr = this.versions[this.versions.length - 1].timestamp;
+		let _g = this.callStatus();
+		if(_g == null) {
+			return null;
+		} else {
+			switch(_g) {
+			case "finish":
+				let endedStr = this.versions[0].timestamp;
+				if(startedStr == null || endedStr == null) {
+					return null;
+				}
+				let started = datetime_utils_DateTimeUtils.fromString(startedStr);
+				let ended = datetime_utils_DateTimeUtils.fromString(endedStr);
+				let duration = datetime_DateTimeInterval.create(started,ended - 62135596800.0 + 62135596800.0);
+				return datetime_utils_DateTimeIntervalUtils.strftime(duration,"%I:%S");
+			case "proceed":
+				if(startedStr == null) {
+					return null;
+				}
+				let started1 = datetime_utils_DateTimeUtils.fromString(startedStr);
+				let ended1 = Math.floor(new Date().getTime() / 1000) + 62135596800.0;
+				let duration1 = datetime_DateTimeInterval.create(started1,ended1 - 62135596800.0 + 62135596800.0);
+				return datetime_utils_DateTimeIntervalUtils.strftime(duration1,"%I:%S");
+			default:
+				return null;
+			}
+		}
+	}
+	asStanza() {
+		if(this.stanza != null) {
+			return this.stanza;
+		}
+		let body = this.text;
+		let attrs = { type : this.type == 2 ? "groupchat" : "chat"};
+		if(this.from != null) {
+			attrs["from"] = this.from.asString();
+		}
+		if(this.to != null) {
+			attrs["to"] = this.to.asString();
+		}
+		if(this.localId != null) {
+			attrs["id"] = this.localId;
+		}
+		let stanza = new snikket_Stanza("message",attrs);
+		if(this.versions.length > 0 && this.versions[this.versions.length - 1].localId != null) {
+			stanza.tag("replace",{ xmlns : "urn:xmpp:message-correct:0", id : this.versions[this.versions.length - 1].localId}).up();
+		}
+		if(this.threadId != null) {
+			stanza.textTag("thread",this.threadId);
+		}
+		if(this.recipients.length > 1) {
+			let addresses = stanza.tag("addresses",{ xmlns : "http://jabber.org/protocol/address"});
+			let _g = 0;
+			let _g1 = this.recipients;
+			while(_g < _g1.length) {
+				let recipient = _g1[_g];
+				++_g;
+				addresses.tag("address",{ type : "to", jid : recipient.asString(), delivered : "true"}).up();
+			}
+			addresses.up();
+		} else if(this.recipients.length == 1 && this.to == null) {
+			attrs["to"] = this.recipients[0].asString();
+		}
+		let replyToM = this.replyToMessage;
+		let _gthis = this;
+		if(replyToM != null) {
+			let replyId = replyToM.getReplyId();
+			if(body != null) {
+				let tmp = replyToM.text;
+				let tmp1 = tmp != null ? tmp.split("\n") : null;
+				let lines = tmp1 != null ? tmp1 : [];
+				let quoteText = "";
+				let _g = 0;
+				while(_g < lines.length) {
+					let line = lines[_g];
+					++_g;
+					if(!new EReg("^(?:> ?){3,}","").match(line)) {
+						if(line.charAt(0) == ">") {
+							quoteText += ">" + line + "\n";
+						} else {
+							quoteText += "> " + line + "\n";
+						}
+					}
+				}
+				let reaction = snikket_EmojiUtil.isEmoji(StringTools.trim(body)) ? StringTools.trim(body) : null;
+				body = quoteText + body;
+				if(replyId != null) {
+					let codepoints = snikket_StringUtil.codepointArray(quoteText);
+					if(reaction != null) {
+						let addedReactions = new Map([]);
+						stanza.tag("reactions",{ xmlns : "urn:xmpp:reactions:0", id : replyId});
+						stanza.textTag("reaction",reaction);
+						addedReactions.set(reaction,true);
+						let jsIterator = replyToM.reactions.entries();
+						let _g_jsIterator = jsIterator;
+						let _g_lastStep = jsIterator.next();
+						while(!_g_lastStep.done) {
+							let v = _g_lastStep.value;
+							_g_lastStep = _g_jsIterator.next();
+							let _g_key = v[0];
+							let _g_value = v[1];
+							let areaction = _g_key;
+							let reactions = _g_value;
+							let tmp = addedReactions.get(areaction);
+							if(!(tmp != null && tmp) && Lambda.find(reactions,function(r) {
+								return r.senderId == _gthis.senderId;
+							}) != null) {
+								addedReactions.set(areaction,true);
+								stanza.textTag("reaction",areaction);
+							}
+						}
+						stanza.up();
+						stanza.tag("fallback",{ xmlns : "urn:xmpp:fallback:0", "for" : "urn:xmpp:reactions:0"}).tag("body").up().up();
+					}
+					let tmp = codepoints.length == null ? "null" : "" + codepoints.length;
+					stanza.tag("fallback",{ xmlns : "urn:xmpp:fallback:0", "for" : "urn:xmpp:reply:0"}).tag("body",{ start : "0", end : tmp}).up().up();
+				}
+			}
+			if(replyId != null) {
+				let tmp = replyToM.from;
+				stanza.tag("reply",{ xmlns : "urn:xmpp:reply:0", to : tmp != null ? tmp.asString() : null, id : replyId}).up();
+			}
+		}
+		let _g = 0;
+		let _g1 = this.attachments;
+		while(_g < _g1.length) {
+			let attachment = _g1[_g];
+			++_g;
+			stanza.tag("reference",{ xmlns : "urn:xmpp:reference:0", type : "data"}).tag("media-sharing",{ xmlns : "urn:xmpp:sims:1"});
+			stanza.tag("file",{ xmlns : "urn:xmpp:jingle:apps:file-transfer:5"});
+			if(attachment.name != null) {
+				stanza.textTag("name",attachment.name);
+			}
+			stanza.textTag("media-type",attachment.mime);
+			if(attachment.size != null) {
+				stanza.textTag("size",attachment.size == null ? "null" : "" + attachment.size);
+			}
+			let _g2 = 0;
+			let _g3 = attachment.hashes;
+			while(_g2 < _g3.length) {
+				let hash = _g3[_g2];
+				++_g2;
+				stanza.textTag("hash",haxe_crypto_Base64.encode(haxe_io_Bytes.ofData(hash.hash)),{ xmlns : "urn:xmpp:hashes:2", algo : hash.algorithm});
+			}
+			stanza.up();
+			stanza.tag("sources");
+			let _g4 = 0;
+			let _g5 = attachment.uris;
+			while(_g4 < _g5.length) {
+				let uri = _g5[_g4];
+				++_g4;
+				stanza.tag("reference",{ xmlns : "urn:xmpp:reference:0", type : "data", uri : uri}).up();
+			}
+			stanza.up().up().up();
+			if(attachment.uris.length > 0) {
+				stanza.tag("x",{ xmlns : "jabber:x:oob"}).textTag("url",attachment.uris[0]).up();
+				if(body == null) {
+					body = "";
+				}
+				let codepoints = snikket_StringUtil.codepointArray(body);
+				let start = codepoints.length;
+				let end = start + attachment.uris[0].length;
+				if(body != "") {
+					body += "\n";
+					++end;
+				}
+				body += attachment.uris[0];
+				stanza.tag("fallback",{ xmlns : "urn:xmpp:fallback:0", "for" : "jabber:x:oob"}).tag("body",{ start : start == null ? "null" : "" + start, end : end == null ? "null" : "" + end}).up().up();
+			}
+		}
+		if(body != null) {
+			stanza.textTag("body",body);
+		}
+		let _g2 = 0;
+		let _g3 = this.payloads;
+		while(_g2 < _g3.length) {
+			let payload = _g3[_g2];
+			++_g2;
+			stanza.addDirectChild(snikket_Node.Element(payload));
+		}
+		return stanza;
+	}
+	static fromStanza(stanza,localJid,addContext) {
+		let _g = snikket_Message.fromStanza(stanza,localJid,addContext).parsed;
+		if(_g._hx_index == 1) {
+			let message = _g.message;
+			return message;
+		} else {
+			return null;
+		}
+	}
+}
+$hx_exports["snikket"]["ChatMessage"] = snikket_ChatMessage;
+snikket_ChatMessage.__name__ = "snikket.ChatMessage";
+Object.assign(snikket_ChatMessage.prototype, {
+	__class__: snikket_ChatMessage
+});
+class snikket_ChatMessageBuilder {
+	constructor(params) {
+		this.stanza = null;
+		this.payloads = [];
+		this.versions = [];
+		this.status = 0;
+		this.direction = 0;
+		this.lang = null;
+		this.text = null;
+		this.reactions = new Map([]);
+		this.attachments = [];
+		this.threadId = null;
+		this.replyToMessage = null;
+		this.senderId = null;
+		this.replyTo = [];
+		this.recipients = [];
+		this.sender = null;
+		this.from = null;
+		this.to = null;
+		this.timestamp = null;
+		this.replyId = null;
+		this.syncPoint = false;
+		this.type = 0;
+		this.serverIdBy = null;
+		this.serverId = null;
+		this.localId = null;
+		this.localId = params != null ? params.localId : null;
+		this.serverId = params != null ? params.serverId : null;
+		this.serverIdBy = params != null ? params.serverIdBy : null;
+		let tmp = params != null ? params.type : null;
+		this.type = tmp != null ? tmp : 0;
+		let tmp1 = params != null ? params.syncPoint : null;
+		this.syncPoint = tmp1 != null && tmp1;
+		this.replyId = params != null ? params.replyId : null;
+		this.timestamp = params != null ? params.timestamp : null;
+		this.senderId = params != null ? params.senderId : null;
+		this.replyToMessage = params != null ? params.replyToMessage : null;
+		this.threadId = params != null ? params.threadId : null;
+		let tmp2 = params != null ? params.attachments : null;
+		this.attachments = tmp2 != null ? tmp2 : [];
+		let tmp3 = params != null ? params.reactions : null;
+		this.reactions = tmp3 != null ? tmp3 : new Map([]);
+		this.text = params != null ? params.text : null;
+		this.lang = params != null ? params.lang : null;
+		let tmp4 = params != null ? params.direction : null;
+		this.direction = tmp4 != null ? tmp4 : 1;
+		let tmp5 = params != null ? params.status : null;
+		this.status = tmp5 != null ? tmp5 : 0;
+		let tmp6 = params != null ? params.versions : null;
+		this.versions = tmp6 != null ? tmp6 : [];
+		let tmp7 = params != null ? params.payloads : null;
+		this.payloads = tmp7 != null ? tmp7 : [];
+		let html = params != null ? params.html : null;
+		if(html != null) {
+			this.setHtml(html);
+		}
+	}
+	attachSims(sims) {
+		let mime = sims.findText("{urn:xmpp:jingle:apps:file-transfer:5}/media-type#");
+		if(mime == null) {
+			mime = sims.findText("{urn:xmpp:jingle:apps:file-transfer:3}/media-type#");
+		}
+		if(mime == null) {
+			mime = "application/octet-stream";
+		}
+		let name = sims.findText("{urn:xmpp:jingle:apps:file-transfer:5}/name#");
+		if(name == null) {
+			name = sims.findText("{urn:xmpp:jingle:apps:file-transfer:3}/name#");
+		}
+		let size = sims.findText("{urn:xmpp:jingle:apps:file-transfer:5}/size#");
+		if(size == null) {
+			size = sims.findText("{urn:xmpp:jingle:apps:file-transfer:3}/size#");
+		}
+		let tmp = sims.getChild("file","urn:xmpp:jingle:apps:file-transfer:5");
+		let tmp1 = tmp != null ? tmp : sims.getChild("file","urn:xmpp:jingle:apps:file-transfer:3");
+		let tmp2 = tmp1 != null ? tmp1.allTags("hash","urn:xmpp:hashes:2") : null;
+		let _this = tmp2 != null ? tmp2 : [];
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let hash = _this[i];
+			let tmp = hash.attr["algo"];
+			result[i] = new snikket_Hash(tmp != null ? tmp : "",haxe_crypto_Base64.decode(hash.getText()).b.bufferValue);
+		}
+		let hashes = result;
+		let sources = sims.getChild("sources");
+		let tmp3 = sources != null ? sources.allTags("reference","urn:xmpp:reference:0") : null;
+		let _this1 = tmp3 != null ? tmp3 : [];
+		let result1 = new Array(_this1.length);
+		let _g2 = 0;
+		let _g3 = _this1.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			let tmp = _this1[i].attr["uri"];
+			result1[i] = tmp != null ? tmp : "";
+		}
+		let _g4 = [];
+		let _g5 = 0;
+		let _g6 = result1;
+		while(_g5 < _g6.length) {
+			let v = _g6[_g5];
+			++_g5;
+			if(v != "") {
+				_g4.push(v);
+			}
+		}
+		let uris = _g4;
+		if(uris.length > 0) {
+			this.attachments.push(new snikket_ChatAttachment(name,mime,size == null ? null : Std.parseInt(size),uris,hashes));
+		}
+	}
+	addAttachment(attachment) {
+		this.attachments.push(attachment);
+	}
+	setHtml(html) {
+		let htmlEl = new snikket_Stanza("html",{ xmlns : "http://jabber.org/protocol/xhtml-im"});
+		let body = new snikket_Stanza("body",{ xmlns : "http://www.w3.org/1999/xhtml"});
+		htmlEl.addChild(body);
+		let nodes = htmlparser_HtmlParser.run(html,true);
+		let _g = 0;
+		while(_g < nodes.length) {
+			let node = nodes[_g];
+			++_g;
+			let el = snikket_Util_downcast(node,htmlparser_HtmlNodeElement);
+			if(el != null && (el.name == "html" || el.name == "body")) {
+				let _g = 0;
+				let _g1 = el.nodes;
+				while(_g < _g1.length) {
+					let inner = _g1[_g];
+					++_g;
+					body.addDirectChild(this.htmlToNode(inner));
+				}
+			} else {
+				body.addDirectChild(this.htmlToNode(node));
+			}
+		}
+		let htmlIdx = Lambda.findIndex(this.payloads,function(p) {
+			if(p.attr["xmlns"] == "http://jabber.org/protocol/xhtml-im") {
+				return p.name == "html";
+			} else {
+				return false;
+			}
+		});
+		if(htmlIdx >= 0) {
+			this.payloads.splice(htmlIdx,1);
+		}
+		this.payloads.push(htmlEl);
+		this.text = snikket_XEP0393.render(body);
+	}
+	htmlToNode(node) {
+		let txt = snikket_Util_downcast(node,htmlparser_HtmlNodeText);
+		if(txt != null) {
+			return snikket_Node.CData(new snikket_TextNode(txt.toText()));
+		}
+		let el = snikket_Util_downcast(node,htmlparser_HtmlNodeElement);
+		if(el != null) {
+			let s = new snikket_Stanza(el.name,{ });
+			let _g = 0;
+			let _g1 = el.attributes;
+			while(_g < _g1.length) {
+				let attr = _g1[_g];
+				++_g;
+				s.attr[attr.name] = attr.value;
+			}
+			let _g2 = 0;
+			let _g3 = el.nodes;
+			while(_g2 < _g3.length) {
+				let child = _g3[_g2];
+				++_g2;
+				s.addDirectChild(this.htmlToNode(child));
+			}
+			return snikket_Node.Element(s);
+		}
+		throw haxe_Exception.thrown("node was neither text nor element?");
+	}
+	chatId() {
+		if(this.isIncoming()) {
+			let _this = this.replyTo;
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].asBare().asString();
+			}
+			return result.join("\n");
+		} else {
+			let _this = this.recipients;
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].asString();
+			}
+			return result.join("\n");
+		}
+	}
+	get_senderId() {
+		let tmp = this.senderId;
+		let tmp1;
+		if(tmp != null) {
+			tmp1 = tmp;
+		} else {
+			let tmp = this.sender;
+			tmp1 = tmp != null ? tmp.asString() : null;
+		}
+		if(tmp1 != null) {
+			return tmp1;
+		} else {
+			throw haxe_Exception.thrown("sender is null");
+		}
+	}
+	isIncoming() {
+		return this.direction == 0;
+	}
+	build() {
+		if(this.serverId == null && this.localId == null) {
+			throw haxe_Exception.thrown("Cannot build a ChatMessage with no id");
+		}
+		let to = this.to;
+		if(to == null) {
+			throw haxe_Exception.thrown("Cannot build a ChatMessage with no to");
+		}
+		let from = this.from;
+		if(from == null) {
+			throw haxe_Exception.thrown("Cannot build a ChatMessage with no from");
+		}
+		let tmp = this.sender;
+		let sender = tmp != null ? tmp : from.asBare();
+		let tmp1 = this.timestamp;
+		return new snikket_ChatMessage({ localId : this.localId, serverId : this.serverId, serverIdBy : this.serverIdBy, type : this.type, syncPoint : this.syncPoint, replyId : this.replyId, timestamp : tmp1 != null ? tmp1 : snikket_Date.format(new Date()), to : to, from : from, senderId : this.get_senderId(), recipients : this.recipients, replyTo : this.replyTo, replyToMessage : this.replyToMessage, threadId : this.threadId, attachments : this.attachments, reactions : this.reactions, text : this.text, lang : this.lang, direction : this.direction, status : this.status, versions : this.versions, payloads : this.payloads, stanza : this.stanza});
+	}
+	static makeModerated(m,timestamp,moderatorId,reason) {
+		let builder = new snikket_ChatMessageBuilder();
+		builder.localId = m.localId;
+		builder.serverId = m.serverId;
+		builder.serverIdBy = m.serverIdBy;
+		builder.type = m.type;
+		builder.syncPoint = m.syncPoint;
+		builder.replyId = m.replyId;
+		builder.timestamp = m.timestamp;
+		builder.to = m.to;
+		builder.from = m.from;
+		builder.senderId = m.senderId;
+		builder.recipients = Lambda.array(m.recipients);
+		builder.replyTo = Lambda.array(m.replyTo);
+		builder.replyToMessage = m.replyToMessage;
+		builder.threadId = m.threadId;
+		builder.reactions = m.reactions;
+		builder.direction = m.direction;
+		builder.status = m.status;
+		let cleanedStub = builder.build();
+		let payload = new snikket_Stanza("retracted",{ xmlns : "urn:xmpp:message-retract:1", stamp : timestamp});
+		if(reason != null) {
+			payload.textTag("reason",reason);
+		}
+		payload.tag("moderated",{ by : moderatorId, xmlns : "urn:xmpp:message-moderate:1"}).up();
+		builder.payloads.push(payload);
+		builder.timestamp = timestamp;
+		builder.versions = [builder.build(),cleanedStub];
+		builder.timestamp = m.timestamp;
+		return builder.build();
+	}
+}
+$hx_exports["snikket"]["ChatMessageBuilder"] = snikket_ChatMessageBuilder;
+snikket_ChatMessageBuilder.__name__ = "snikket.ChatMessageBuilder";
+Object.assign(snikket_ChatMessageBuilder.prototype, {
+	__class__: snikket_ChatMessageBuilder
+});
+class snikket_EventEmitter {
+	constructor() {
+		if(snikket_EventEmitter._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.eventHandlers = new Map([]);
+	}
+	on(eventName,callback) {
+		let handlers = this.eventHandlers.get(eventName);
+		if(handlers == null) {
+			handlers = [];
+			this.eventHandlers.set(eventName,handlers);
+		}
+		let newHandler = new snikket_EventHandler(handlers,callback);
+		handlers.push(newHandler);
+		return newHandler;
+	}
+	once(eventName,callback) {
+		return this.on(eventName,callback).once();
+	}
+	trigger(eventName,eventData) {
+		let handlers = this.eventHandlers.get(eventName);
+		if(handlers == null || handlers.length == 0) {
+			haxe_Log.trace("no event handlers for " + eventName,{ fileName : "snikket/EventEmitter.hx", lineNumber : 29, className : "snikket.EventEmitter", methodName : "trigger"});
+			return snikket_EventResult.EventUnhandled;
+		}
+		haxe_Log.trace("firing event: " + eventName,{ fileName : "snikket/EventEmitter.hx", lineNumber : 32, className : "snikket.EventEmitter", methodName : "trigger"});
+		let handled = false;
+		let _g = 0;
+		while(_g < handlers.length) {
+			let handler = handlers[_g];
+			++_g;
+			let ret = handler.call(eventData);
+			switch(ret._hx_index) {
+			case 0:
+				handled = true;
+				break;
+			case 1:
+				continue;
+			case 2:
+				return ret;
+			case 3:
+				let _g1 = ret.result;
+				return ret;
+			}
+		}
+		if(handled) {
+			return snikket_EventResult.EventHandled;
+		} else {
+			return snikket_EventResult.EventUnhandled;
+		}
+	}
+}
+snikket_EventEmitter.__name__ = "snikket.EventEmitter";
+Object.assign(snikket_EventEmitter.prototype, {
+	__class__: snikket_EventEmitter
+});
+class snikket_Client extends snikket_EventEmitter {
+	constructor(address,persistence) {
+		snikket_EventEmitter._hx_skip_constructor = true;
+		super();
+		snikket_EventEmitter._hx_skip_constructor = false;
+		this._hx_constructor(address,persistence);
+	}
+	_hx_constructor(address,persistence) {
+		this.inSync = false;
+		this.pendingCaps = new Map([]);
+		this.token = null;
+		this.fastMechanism = null;
+		this.caps = new snikket_Caps("https://sdk.snikket.org",[],["http://jabber.org/protocol/disco#info","http://jabber.org/protocol/caps","urn:xmpp:avatar:metadata+notify","http://jabber.org/protocol/nick+notify","urn:xmpp:bookmarks:1+notify","urn:xmpp:mds:displayed:0+notify","urn:xmpp:jingle-message:0","urn:xmpp:jingle:1","urn:xmpp:jingle:apps:dtls:0","urn:xmpp:jingle:apps:rtp:1","urn:xmpp:jingle:apps:rtp:audio","urn:xmpp:jingle:apps:rtp:video","urn:xmpp:jingle:transports:ice-udp:1"]);
+		this.chats = [];
+		this.chatStateHandlers = [];
+		this.syncMessageHandlers = [];
+		this.chatMessageHandlers = [];
+		this.sendAvailable = true;
+		snikket_Util_setupTrace();
+		super._hx_constructor();
+		this.jid = snikket_JID.parse(address);
+		this._displayName = this.jid.node;
+		this.persistence = persistence;
+		this.stream = new snikket_streams_XmppJsStream();
+		this.stream.on("status/online",$bind(this,this.onConnected));
+		let _gthis = this;
+		this.stream.on("status/offline",function(data) {
+			return _gthis.trigger("status/offline",{ });
+		});
+		this.stream.on("fast-token",function(data) {
+			_gthis.token = data.token;
+			let persistence1 = persistence;
+			let tmp = _gthis.jid.asBare().asString();
+			let tmp1 = _gthis.stream.clientId;
+			persistence1.storeLogin(tmp,tmp1 != null ? tmp1 : _gthis.jid.resource,_gthis.displayName(),_gthis.token);
+			return snikket_EventResult.EventHandled;
+		});
+		this.stream.on("sm/update",function(data) {
+			let anySyncHappening = Lambda.exists(_gthis.chats,function(chat) {
+				if(chat.uiState != 2) {
+					return chat.syncing();
+				} else {
+					return false;
+				}
+			});
+			persistence.storeStreamManagement(_gthis.accountId(),anySyncHappening ? null : data.sm);
+			return snikket_EventResult.EventHandled;
+		});
+		this.stream.on("sm/ack",function(data) {
+			persistence.updateMessageStatus(_gthis.accountId(),data.id,1,function(m) {
+				_gthis.notifyMessageHandlers(m,3);
+			});
+			return snikket_EventResult.EventHandled;
+		});
+		this.stream.on("sm/fail",function(data) {
+			persistence.updateMessageStatus(_gthis.accountId(),data.id,3,function(m) {
+				_gthis.notifyMessageHandlers(m,3);
+			});
+			return snikket_EventResult.EventHandled;
+		});
+		this.stream.on("message",function(event) {
+			let stanza = event.stanza;
+			if(stanza.getChild("result","urn:xmpp:mam:2") != null) {
+				return snikket_EventResult.EventUnhandled;
+			}
+			let from = stanza.attr["from"] == null ? null : snikket_JID.parse(stanza.attr["from"]);
+			if(stanza.attr["type"] == "error" && from != null) {
+				let chat = _gthis.getChat(from.asBare().asString());
+				let channel = ((chat) instanceof snikket_Channel) ? chat : null;
+				if(channel != null) {
+					channel.selfPing(true);
+				}
+			}
+			let fwd = null;
+			if(from != null && from.asBare().asString() == _gthis.accountId()) {
+				let carbon = stanza.getChild("received","urn:xmpp:carbons:2");
+				if(carbon == null) {
+					carbon = stanza.getChild("sent","urn:xmpp:carbons:2");
+				}
+				if(carbon != null) {
+					let tmp = carbon.getChild("forwarded","urn:xmpp:forward:0");
+					fwd = tmp != null ? tmp.getFirstChild() : null;
+				}
+			}
+			let message = snikket_Message.fromStanza(stanza,_gthis.jid,function(builder,stanza) {
+				let chat = _gthis.getChat(builder.chatId());
+				if(chat == null && stanza.attr["type"] != "groupchat") {
+					chat = _gthis.getDirectChat(builder.chatId());
+				}
+				if(chat == null) {
+					return builder;
+				}
+				return chat.prepareIncomingMessage(builder,stanza);
+			});
+			let _g = message.parsed;
+			switch(_g._hx_index) {
+			case 1:
+				let chatMessage = _g.message;
+				let _g1 = 0;
+				let _g2 = chatMessage.inlineHashReferences();
+				while(_g1 < _g2.length) {
+					let hash = _g2[_g1];
+					++_g1;
+					_gthis.fetchMediaByHash([hash],[chatMessage.from]);
+				}
+				let chat = _gthis.getChat(chatMessage.chatId());
+				if(chat != null) {
+					let updateChat = function(chatMessage) {
+						_gthis.notifyMessageHandlers(chatMessage,chatMessage.versions.length > 1 ? 1 : 0);
+						if(chatMessage.versions.length < 1 || chat.lastMessageId() == chatMessage.serverId || chat.lastMessageId() == chatMessage.localId) {
+							chat.setLastMessage(chatMessage);
+							if(chatMessage.versions.length < 1) {
+								chat.setUnreadCount(chatMessage.isIncoming() ? chat.unreadCount() + 1 : 0);
+							}
+							_gthis.chatActivity(chat);
+						}
+					};
+					if(chatMessage.serverId == null) {
+						updateChat(chatMessage);
+					} else {
+						_gthis.storeMessages([chatMessage],function(stored) {
+							updateChat(stored[0]);
+						});
+					}
+				}
+				break;
+			case 2:
+				let action = _g.action;
+				_gthis.moderateMessage(action).then(function(stored) {
+					if(stored != null) {
+						_gthis.notifyMessageHandlers(stored,1);
+					}
+				});
+				break;
+			case 3:
+				let update = _g.update;
+				let _g3 = 0;
+				let _g4 = update.inlineHashReferences();
+				while(_g3 < _g4.length) {
+					let hash = _g4[_g3];
+					++_g3;
+					_gthis.fetchMediaByHash([hash],[from]);
+				}
+				persistence.storeReaction(_gthis.accountId(),update,function(stored) {
+					if(stored != null) {
+						_gthis.notifyMessageHandlers(stored,2);
+					}
+				});
+				break;
+			default:
+			}
+			let jmiP = stanza.getChild("propose","urn:xmpp:jingle-message:0");
+			if(jmiP != null && jmiP.attr["id"] != null) {
+				let session = new snikket_jingle_IncomingProposedSession(_gthis,from,jmiP.attr["id"]);
+				let chat = _gthis.getDirectChat(from.asBare().asString());
+				if(!chat.jingleSessions.has(session.get_sid())) {
+					chat.jingleSessions.set(session.get_sid(),session);
+					_gthis.chatActivity(chat);
+					session.ring();
+				}
+			}
+			let jmiR = stanza.getChild("retract","urn:xmpp:jingle-message:0");
+			if(jmiR != null && jmiR.attr["id"] != null) {
+				let chat = _gthis.getDirectChat(from.asBare().asString());
+				let session = chat.jingleSessions.get(jmiR.attr["id"]);
+				if(session != null) {
+					session.retract();
+					chat.jingleSessions.delete(session.get_sid());
+				}
+			}
+			let jmiProFwd = fwd != null ? fwd.getChild("proceed","urn:xmpp:jingle-message:0") : null;
+			if(jmiProFwd != null && jmiProFwd.attr["id"] != null) {
+				let chat = _gthis.getDirectChat(snikket_JID.parse(fwd.attr["to"]).asBare().asString());
+				let session = chat.jingleSessions.get(jmiProFwd.attr["id"]);
+				if(session != null) {
+					session.retract();
+					chat.jingleSessions.delete(session.get_sid());
+				}
+			}
+			let jmiPro = stanza.getChild("proceed","urn:xmpp:jingle-message:0");
+			if(jmiPro != null && jmiPro.attr["id"] != null) {
+				let chat = _gthis.getDirectChat(from.asBare().asString());
+				let session = chat.jingleSessions.get(jmiPro.attr["id"]);
+				if(session != null) {
+					try {
+						chat.jingleSessions.set(session.get_sid(),session.initiate(stanza));
+					} catch( _g ) {
+						let e = haxe_Exception.caught(_g);
+						haxe_Log.trace("JMI proceed failed",{ fileName : "snikket/Client.hx", lineNumber : 243, className : "snikket.Client", methodName : "new", customParams : [e]});
+					}
+				}
+			}
+			let jmiRej = stanza.getChild("reject","urn:xmpp:jingle-message:0");
+			if(jmiRej != null && jmiRej.attr["id"] != null) {
+				let chat = _gthis.getDirectChat(from.asBare().asString());
+				let session = chat.jingleSessions.get(jmiRej.attr["id"]);
+				if(session != null) {
+					session.retract();
+					chat.jingleSessions.delete(session.get_sid());
+				}
+			}
+			if(stanza.attr["type"] != "error") {
+				let chatState = stanza.getChild(null,"http://jabber.org/protocol/chatstates");
+				let userState;
+				let _g = chatState != null ? chatState.name : null;
+				if(_g == null) {
+					userState = null;
+				} else {
+					switch(_g) {
+					case "active":
+						userState = 2;
+						break;
+					case "composing":
+						userState = 3;
+						break;
+					case "gone":
+						userState = 0;
+						break;
+					case "inactive":
+						userState = 1;
+						break;
+					case "paused":
+						userState = 4;
+						break;
+					default:
+						userState = null;
+					}
+				}
+				if(userState != null) {
+					let chat = _gthis.getChat(from.asBare().asString());
+					if(chat == null || !chat.getParticipantDetails(message.senderId).isSelf) {
+						let _g = 0;
+						let _g1 = _gthis.chatStateHandlers;
+						while(_g < _g1.length) {
+							let handler = _g1[_g];
+							++_g;
+							handler(message.senderId,message.chatId,message.threadId,userState);
+						}
+					}
+				}
+			}
+			let pubsubEvent = snikket_PubsubEvent.fromStanza(stanza);
+			if(pubsubEvent != null && pubsubEvent.getFrom() != null && pubsubEvent.getNode() == "urn:xmpp:avatar:metadata" && pubsubEvent.getItems().length > 0) {
+				let item = pubsubEvent.getItems()[0];
+				let avatarSha1Hex = pubsubEvent.getItems()[0].attr["id"];
+				let tmp = snikket_Hash.fromHex("sha-1",avatarSha1Hex);
+				let avatarSha1 = tmp != null ? tmp.hash : null;
+				let metadata = item.getChild("metadata","urn:xmpp:avatar:metadata");
+				let mime = "image/png";
+				if(metadata != null) {
+					let info = metadata.getChild("info");
+					if(info != null && info.attr["type"] != null) {
+						mime = info.attr["type"];
+					}
+				}
+				if(avatarSha1 != null) {
+					let chat = _gthis.getDirectChat(snikket_JID.parse(pubsubEvent.getFrom()).asBare().asString(),false);
+					chat.setAvatarSha1(avatarSha1);
+					persistence.storeChats(_gthis.accountId(),[chat]);
+					persistence.hasMedia("sha-1",avatarSha1,function(has) {
+						if(has) {
+							_gthis.trigger("chats/update",[chat]);
+						} else {
+							let pubsubGet = new snikket_queries_PubsubGet(pubsubEvent.getFrom(),"urn:xmpp:avatar:data",avatarSha1Hex);
+							pubsubGet.onFinished(function() {
+								let item = pubsubGet.getResult()[0];
+								if(item == null) {
+									return;
+								}
+								let dataNode = item.getChild("data","urn:xmpp:avatar:data");
+								if(dataNode == null) {
+									return;
+								}
+								persistence.storeMedia(mime,haxe_crypto_Base64.decode(StringTools.replace(dataNode.getText(),"\n","")).b.bufferValue,function() {
+									_gthis.trigger("chats/update",[chat]);
+								});
+							});
+							_gthis.sendQuery(pubsubGet);
+						}
+					});
+				}
+			}
+			if(pubsubEvent != null && pubsubEvent.getFrom() != null && snikket_JID.parse(pubsubEvent.getFrom()).asBare().asString() == _gthis.accountId() && pubsubEvent.getNode() == "http://jabber.org/protocol/nick" && pubsubEvent.getItems().length > 0) {
+				_gthis.updateDisplayName(pubsubEvent.getItems()[0].getChildText("nick","http://jabber.org/protocol/nick"));
+			}
+			if(pubsubEvent != null && pubsubEvent.getFrom() != null && snikket_JID.parse(pubsubEvent.getFrom()).asBare().asString() == _gthis.accountId() && pubsubEvent.getNode() == "urn:xmpp:mds:displayed:0" && pubsubEvent.getItems().length > 0) {
+				let _g = 0;
+				let _g1 = pubsubEvent.getItems();
+				while(_g < _g1.length) {
+					let item = _g1[_g];
+					++_g;
+					if(item.attr["id"] != null) {
+						let tmp = item.getChild("displayed","urn:xmpp:mds:displayed:0");
+						let upTo = tmp != null ? tmp.getChild("stanza-id","urn:xmpp:sid:0") : null;
+						let chat = _gthis.getChat(item.attr["id"]);
+						if(chat == null) {
+							_gthis.startChatWith(item.attr["id"],function(caps) {
+								return 2;
+							},function(chat) {
+								chat.markReadUpToId(upTo.attr["id"],upTo.attr["by"]);
+							});
+						} else {
+							chat.markReadUpToId(upTo.attr["id"],upTo.attr["by"],function() {
+								persistence.storeChats(_gthis.accountId(),[chat]);
+								_gthis.trigger("chats/update",[chat]);
+							});
+						}
+					}
+				}
+			}
+			return snikket_EventResult.EventUnhandled;
+		});
+		this.stream.onIq(snikket_IqRequestType.Set,"jingle","urn:xmpp:jingle:1",function(stanza) {
+			let from = stanza.attr["from"] == null ? null : snikket_JID.parse(stanza.attr["from"]);
+			let jingle = stanza.getChild("jingle","urn:xmpp:jingle:1");
+			let chat = _gthis.getDirectChat(from.asBare().asString());
+			let session = chat.jingleSessions.get(jingle.attr["sid"]);
+			if(jingle.attr["action"] == "session-initiate") {
+				if(session != null) {
+					try {
+						chat.jingleSessions.set(session.get_sid(),session.initiate(stanza));
+					} catch( _g ) {
+						let e = haxe_Exception.caught(_g);
+						haxe_Log.trace("Bad session-inititate",{ fileName : "snikket/Client.hx", lineNumber : 350, className : "snikket.Client", methodName : "new", customParams : [e]});
+						chat.jingleSessions.delete(session.get_sid());
+					}
+				} else {
+					let newSession = snikket_jingle_InitiatedSession.fromSessionInitiate(_gthis,stanza);
+					chat.jingleSessions.set(newSession.get_sid(),newSession);
+					_gthis.chatActivity(chat);
+					newSession.ring();
+				}
+			}
+			if(session != null && jingle.attr["action"] == "session-accept") {
+				try {
+					chat.jingleSessions.set(session.get_sid(),session.initiate(stanza));
+				} catch( _g ) {
+					let e = haxe_Exception.caught(_g);
+					haxe_Log.trace("session-accept failed",{ fileName : "snikket/Client.hx", lineNumber : 365, className : "snikket.Client", methodName : "new", customParams : [e]});
+				}
+			}
+			if(session != null && jingle.attr["action"] == "session-terminate") {
+				session.terminate();
+				chat.jingleSessions.delete(jingle.attr["sid"]);
+			}
+			if(session != null && jingle.attr["action"] == "content-add") {
+				session.contentAdd(stanza);
+			}
+			if(session != null && jingle.attr["action"] == "content-accept") {
+				session.contentAccept(stanza);
+			}
+			if(session != null && jingle.attr["action"] == "transport-info") {
+				session.transportInfo(stanza);
+			}
+			return snikket_IqResult.IqResult;
+		});
+		this.stream.onIq(snikket_IqRequestType.Get,"query","http://jabber.org/protocol/disco#info",function(stanza) {
+			return snikket_IqResult.IqResultElement(_gthis.caps.discoReply());
+		});
+		this.stream.onIq(snikket_IqRequestType.Set,"query","jabber:iq:roster",function(stanza) {
+			if(stanza.attr["from"] != null && stanza.attr["from"] != _gthis.jid.domain) {
+				return snikket_IqResult.IqNoResult;
+			}
+			let roster = new snikket_queries_RosterGet();
+			roster.handleResponse(stanza);
+			let items = roster.getResult();
+			if(items.length == 0) {
+				return snikket_IqResult.IqNoResult;
+			}
+			let chatsToUpdate = [];
+			let _g = 0;
+			while(_g < items.length) {
+				let item = items[_g];
+				++_g;
+				if(item.subscription != "remove") {
+					let chat = _gthis.getDirectChat(item.jid,false);
+					chat.updateFromRoster(item);
+					chatsToUpdate.push(js_Boot.__cast(chat , snikket_Chat));
+				}
+			}
+			persistence.storeChats(_gthis.accountId(),chatsToUpdate);
+			_gthis.trigger("chats/update",chatsToUpdate);
+			return snikket_IqResult.IqResult;
+		});
+		this.stream.onIq(snikket_IqRequestType.Set,"block","urn:xmpp:blocking",function(stanza) {
+			if(stanza.attr["from"] != null && stanza.attr["from"] != _gthis.jid.domain) {
+				return snikket_IqResult.IqNoResult;
+			}
+			let _g = 0;
+			let tmp = stanza.getChild("block","urn:xmpp:blocking");
+			let tmp1 = tmp != null ? tmp.allTags("item") : null;
+			let _g1 = tmp1 != null ? tmp1 : [];
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				if(item.attr["jid"] != null) {
+					_gthis.serverBlocked(item.attr["jid"]);
+				}
+			}
+			return snikket_IqResult.IqResult;
+		});
+		this.stream.onIq(snikket_IqRequestType.Set,"unblock","urn:xmpp:blocking",function(stanza) {
+			if(stanza.attr["from"] != null && stanza.attr["from"] != _gthis.jid.domain) {
+				return snikket_IqResult.IqNoResult;
+			}
+			let tmp = stanza.getChild("unblock","urn:xmpp:blocking");
+			let unblocks = tmp != null ? tmp.allTags("item") : null;
+			if(unblocks == null) {
+				let _g = 0;
+				let _g1 = _gthis.chats;
+				while(_g < _g1.length) {
+					let chat = _g1[_g];
+					++_g;
+					if(chat.isBlocked) {
+						chat.unblock(false);
+					}
+				}
+			} else {
+				let _g = 0;
+				while(_g < unblocks.length) {
+					let item = unblocks[_g];
+					++_g;
+					if(item.attr["jid"] != null) {
+						let tmp = _gthis.getChat(item.attr["jid"]);
+						if(tmp != null) {
+							tmp.unblock(false);
+						}
+					}
+				}
+			}
+			return snikket_IqResult.IqResult;
+		});
+		this.stream.on("presence",function(event) {
+			let stanza = event.stanza;
+			let c = stanza.getChild("c","http://jabber.org/protocol/caps");
+			let mucUser = stanza.getChild("x","http://jabber.org/protocol/muc#user");
+			if(stanza.attr["from"] != null && stanza.attr["type"] == null) {
+				let from = snikket_JID.parse(stanza.attr["from"]);
+				let chat = _gthis.getChat(from.asBare().asString());
+				if(chat == null) {
+					haxe_Log.trace("Presence for unknown JID: " + stanza.attr["from"],{ fileName : "snikket/Client.hx", lineNumber : 467, className : "snikket.Client", methodName : "new"});
+					return snikket_EventResult.EventUnhandled;
+				}
+				if(c == null) {
+					chat.setPresence(snikket_JID.parse(stanza.attr["from"]).resource,new snikket_Presence(null,mucUser));
+					persistence.storeChats(_gthis.accountId(),[chat]);
+					if(chat.livePresence()) {
+						_gthis.trigger("chats/update",[chat]);
+					}
+				} else {
+					let handleCaps = function(caps) {
+						chat.setPresence(snikket_JID.parse(stanza.attr["from"]).resource,new snikket_Presence(caps,mucUser));
+						if(mucUser == null || chat.livePresence()) {
+							persistence.storeChats(_gthis.accountId(),[chat]);
+						}
+						return chat;
+					};
+					persistence.getCaps(c.attr["ver"],function(caps) {
+						if(caps == null) {
+							let pending = _gthis.pendingCaps.get(c.attr["ver"]);
+							if(pending == null) {
+								_gthis.pendingCaps.set(c.attr["ver"],[handleCaps]);
+								let discoGet = new snikket_queries_DiscoInfoGet(stanza.attr["from"],c.attr["node"] + "#" + c.attr["ver"]);
+								discoGet.onFinished(function() {
+									let chatsToUpdate = new Map([]);
+									let tmp = _gthis.pendingCaps.get(c.attr["ver"]);
+									let handlers = tmp != null ? tmp : [];
+									_gthis.pendingCaps.delete(c.attr["ver"]);
+									if(discoGet.getResult() != null) {
+										persistence.storeCaps(discoGet.getResult());
+									}
+									let _g = 0;
+									while(_g < handlers.length) {
+										let handler = handlers[_g];
+										++_g;
+										let c = handler(discoGet.getResult());
+										if(c.livePresence()) {
+											chatsToUpdate.set(c.chatId,c);
+										}
+									}
+									_gthis.trigger("chats/update",Lambda.array({ iterator : function() {
+										return new js_lib_HaxeIterator(chatsToUpdate.values());
+									}}));
+								});
+								_gthis.sendQuery(discoGet);
+							} else {
+								pending.push(handleCaps);
+							}
+						} else {
+							handleCaps(caps);
+						}
+					});
+				}
+				if(from.isBare()) {
+					let avatarSha1Hex = stanza.findText("{vcard-temp:x:update}x/photo#");
+					if(avatarSha1Hex != null) {
+						let tmp = snikket_Hash.fromHex("sha-1",avatarSha1Hex);
+						let avatarSha1 = tmp != null ? tmp.hash : null;
+						chat.setAvatarSha1(avatarSha1);
+						persistence.storeChats(_gthis.accountId(),[chat]);
+						persistence.hasMedia("sha-1",avatarSha1,function(has) {
+							if(has) {
+								if(chat.livePresence()) {
+									_gthis.trigger("chats/update",[chat]);
+								}
+							} else {
+								let vcardGet = new snikket_queries_VcardTempGet(from);
+								vcardGet.onFinished(function() {
+									let vcard = vcardGet.getResult();
+									if(vcard.photo == null) {
+										return;
+									}
+									persistence.storeMedia(vcard.photo.mime,vcard.photo.data.b.bufferValue,function() {
+										_gthis.trigger("chats/update",[chat]);
+									});
+								});
+								_gthis.sendQuery(vcardGet);
+							}
+						});
+					}
+				}
+				return snikket_EventResult.EventHandled;
+			}
+			if(stanza.attr["from"] != null && stanza.attr["type"] == "unavailable") {
+				let chat = _gthis.getChat(snikket_JID.parse(stanza.attr["from"]).asBare().asString());
+				if(chat == null) {
+					haxe_Log.trace("Presence for unknown JID: " + stanza.attr["from"],{ fileName : "snikket/Client.hx", lineNumber : 536, className : "snikket.Client", methodName : "new"});
+					return snikket_EventResult.EventUnhandled;
+				}
+				chat.removePresence(snikket_JID.parse(stanza.attr["from"]).resource);
+				persistence.storeChats(_gthis.accountId(),[chat]);
+				_gthis.trigger("chats/update",[chat]);
+			}
+			return snikket_EventResult.EventUnhandled;
+		});
+	}
+	start() {
+		let _gthis = this;
+		this.persistence.getLogin(this.accountId(),function(clientId,loadedToken,fastCount,displayName) {
+			_gthis.token = loadedToken;
+			_gthis.persistence.getStreamManagement(_gthis.accountId(),function(sm) {
+				let tmp = clientId;
+				let tmp1 = tmp != null ? tmp : snikket_ID.long();
+				_gthis.stream.clientId = tmp1;
+				_gthis.jid = _gthis.jid.withResource(_gthis.stream.clientId);
+				if(!_gthis.updateDisplayName(displayName) && clientId == null) {
+					_gthis.persistence.storeLogin(_gthis.jid.asBare().asString(),_gthis.stream.clientId,_gthis.displayName(),null);
+				}
+				_gthis.persistence.getChats(_gthis.accountId(),function(protoChats) {
+					let _g = 0;
+					while(_g < protoChats.length) {
+						let protoChat = protoChats[_g];
+						++_g;
+						_gthis.chats.push(protoChat.toChat(_gthis,_gthis.stream,_gthis.persistence));
+					}
+					_gthis.persistence.getChatsUnreadDetails(_gthis.accountId(),_gthis.chats,function(details) {
+						let _g = 0;
+						while(_g < details.length) {
+							let detail = details[_g];
+							++_g;
+							let chat = _gthis.getChat(detail.chatId);
+							if(chat != null) {
+								chat.setLastMessage(detail.message);
+								chat.setUnreadCount(detail.unreadCount);
+							}
+						}
+						_gthis.sortChats();
+						_gthis.trigger("chats/update",_gthis.chats);
+						_gthis.stream.on("auth/password-needed",function(data) {
+							let tmp = data.mechanisms;
+							let tmp1 = tmp != null ? tmp.find(function(mech) {
+								return mech.canFast;
+							}) : null;
+							_gthis.fastMechanism = tmp1 != null ? tmp1.name : null;
+							if(_gthis.token == null || _gthis.fastMechanism == null && data.mechanimsms != null) {
+								return _gthis.trigger("auth/password-needed",{ accountId : _gthis.accountId()});
+							} else {
+								return _gthis.stream.trigger("auth/password",{ password : _gthis.token, mechanism : _gthis.fastMechanism, fastCount : fastCount});
+							}
+						});
+						_gthis.stream.on("auth/fail",function(data) {
+							if(_gthis.token != null) {
+								_gthis.token = null;
+								_gthis.stream.connect(_gthis.jid.asString(),sm);
+							} else {
+								_gthis.stream.connect(_gthis.jid.asString(),sm);
+							}
+							return snikket_EventResult.EventHandled;
+						});
+						_gthis.stream.connect(_gthis.jid.asString(),sm);
+					});
+				});
+			});
+		});
+	}
+	logout(completely) {
+		this.persistence.removeAccount(this.accountId(),completely);
+		let disable = new snikket_queries_Push2Disable(this.jid.asBare().asString());
+		let _gthis = this;
+		disable.onFinished(function() {
+			_gthis.stream.disconnect();
+		});
+		this.sendQuery(disable);
+	}
+	usePassword(password) {
+		this.stream.trigger("auth/password",{ password : password, requestToken : this.fastMechanism});
+	}
+	accountId() {
+		return this.jid.asBare().asString();
+	}
+	displayName() {
+		return this._displayName;
+	}
+	setDisplayName(displayName) {
+		if(displayName == null || displayName == "" || displayName == this.displayName()) {
+			return;
+		}
+		this.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub"}).tag("publish",{ node : "http://jabber.org/protocol/nick"}).tag("item").textTag("nick",displayName,{ xmlns : "http://jabber.org/protocol/nick"}).up().up().up(),function(response) {
+		});
+	}
+	updateDisplayName(fn) {
+		if(fn == null || fn == "" || fn == this.displayName()) {
+			return false;
+		}
+		this._displayName = fn;
+		let tmp = this.persistence;
+		let tmp1 = this.jid.asBare().asString();
+		let tmp2 = this.stream.clientId;
+		tmp.storeLogin(tmp1,tmp2 != null ? tmp2 : this.jid.resource,fn,null);
+		this.pingAllChannels(false);
+		return true;
+	}
+	onConnected(data) {
+		if(data != null && data.jid != null) {
+			this.jid = snikket_JID.parse(data.jid);
+			if(this.stream.clientId == null && !this.jid.isBare()) {
+				this.persistence.storeLogin(this.jid.asBare().asString(),this.jid.resource,this.displayName(),null);
+			}
+		}
+		if(data.resumed) {
+			this.inSync = true;
+			this.trigger("status/online",{ });
+			return snikket_EventResult.EventHandled;
+		}
+		let _gthis = this;
+		this.discoverServices(new snikket_JID(null,this.jid.domain),null,function(service,caps) {
+			_gthis.persistence.storeService(_gthis.accountId(),service.jid.asString(),service.name,service.node,caps);
+		});
+		this.rosterGet();
+		haxe_Log.trace("SYNC: bookmarks",{ fileName : "snikket/Client.hx", lineNumber : 687, className : "snikket.Client", methodName : "onConnected"});
+		this.bookmarksGet(function() {
+			haxe_Log.trace("SYNC: MAM",{ fileName : "snikket/Client.hx", lineNumber : 689, className : "snikket.Client", methodName : "onConnected"});
+			_gthis.sync(function(syncFinished) {
+				if(!syncFinished) {
+					haxe_Log.trace("SYNC: failed",{ fileName : "snikket/Client.hx", lineNumber : 692, className : "snikket.Client", methodName : "onConnected"});
+					_gthis.inSync = false;
+					_gthis.stream.disconnect();
+					return;
+				}
+				haxe_Log.trace("SYNC: details",{ fileName : "snikket/Client.hx", lineNumber : 699, className : "snikket.Client", methodName : "onConnected"});
+				_gthis.inSync = true;
+				_gthis.persistence.getChatsUnreadDetails(_gthis.accountId(),_gthis.chats,function(details) {
+					let _g = 0;
+					while(_g < details.length) {
+						let detail = details[_g];
+						++_g;
+						let tmp = _gthis.getChat(detail.chatId);
+						let chat = tmp != null ? tmp : _gthis.getDirectChat(detail.chatId,false);
+						let initialLastId = chat.lastMessageId();
+						chat.setLastMessage(detail.message);
+						chat.setUnreadCount(detail.unreadCount);
+						if(detail.unreadCount > 0 && initialLastId != chat.lastMessageId()) {
+							_gthis.chatActivity(chat,false);
+						}
+					}
+					_gthis.sortChats();
+					_gthis.trigger("chats/update",_gthis.chats);
+					if(_gthis.sendAvailable) {
+						_gthis.sendStanza(new snikket_Stanza("iq",{ type : "set", id : snikket_ID.short()}).tag("enable",{ xmlns : "urn:xmpp:carbons:2"}).up());
+						_gthis.sendPresence();
+						_gthis.pingAllChannels(true);
+					}
+					_gthis.trigger("status/online",{ });
+					haxe_Log.trace("SYNC: done",{ fileName : "snikket/Client.hx", lineNumber : 725, className : "snikket.Client", methodName : "onConnected"});
+				});
+			});
+		});
+		this.trigger("session-started",{ });
+		return snikket_EventResult.EventHandled;
+	}
+	prepareAttachment(source,callback) {
+		let _gthis = this;
+		this.persistence.findServicesWithFeature(this.accountId(),"urn:xmpp:http:upload:0",function(services) {
+			let sha256 = new sha_SHA256();
+			let options = null;
+			let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+			tink_io_Source.chunked(new tink_io_js_BlobSource(source.name,source,0,chunkSize)).forEach(tink_streams_Handler.ofSafeSync(function(chunk) {
+				sha256.update(chunk.toBytes());
+				return tink_streams_Handled.Resume;
+			})).handle(function(o) {
+				if(o._hx_index == 3) {
+					_gthis.prepareAttachmentFor(source,services,[new snikket_Hash("sha-256",sha256.digest().b.bufferValue)],callback);
+				} else {
+					haxe_Log.trace("Error computing attachment hash",{ fileName : "snikket/Client.hx", lineNumber : 748, className : "snikket.Client", methodName : "prepareAttachment", customParams : [o]});
+					callback(null);
+				}
+			});
+		});
+	}
+	prepareAttachmentFor(source,services,hashes,callback) {
+		if(services.length < 1) {
+			callback(null);
+			return;
+		}
+		let httpUploadSlot = new snikket_queries_HttpUploadSlot(services[0].serviceId,source.name,source.size,source.type,hashes);
+		let _gthis = this;
+		httpUploadSlot.onFinished(function() {
+			let slot = httpUploadSlot.getResult();
+			if(slot == null) {
+				_gthis.prepareAttachmentFor(source,services.slice(1),hashes,callback);
+			} else {
+				let url = tink_Url.fromString(slot.put);
+				let options = null;
+				let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+				tink_http_FetchResponse.all(tink_http_Fetch.fetch(url,{ method : "PUT", headers : slot.putHeaders, body : tink_io_RealSourceTools.idealize(new tink_io_js_BlobSource(source.name,source,0,chunkSize),function(e) {
+					throw haxe_Exception.thrown(e);
+				})})).handle(function(o) {
+					if(o._hx_index == 0) {
+						let res = o.data;
+						if(res.header.statusCode == 201) {
+							callback(new snikket_ChatAttachment(source.name,source.type,source.size,[slot.get],hashes));
+						} else {
+							_gthis.prepareAttachmentFor(source,services.slice(1),hashes,callback);
+						}
+					} else {
+						_gthis.prepareAttachmentFor(source,services.slice(1),hashes,callback);
+					}
+				});
+			}
+		});
+		this.sendQuery(httpUploadSlot);
+	}
+	getChats() {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.chats;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.uiState != 2) {
+				_g.push(v);
+			}
+		}
+		return _g;
+	}
+	findAvailableChats(q,callback) {
+		let results = [];
+		let query = StringTools.trim(q);
+		let _gthis = this;
+		let checkAndAdd = function(jid,prepend) {
+			if(prepend == null) {
+				prepend = false;
+			}
+			let add = function(item) {
+				if(prepend) {
+					results.unshift(item);
+				} else {
+					results.push(item);
+				}
+			};
+			let discoGet = new snikket_queries_DiscoInfoGet(jid.asString());
+			discoGet.onFinished(function() {
+				let resultCaps = discoGet.getResult();
+				if(resultCaps == null) {
+					let tmp = discoGet.responseStanza;
+					let tmp1 = tmp != null ? tmp.getChild("error") : null;
+					let err = tmp1 != null ? tmp1.getChild(null,"urn:ietf:params:xml:ns:xmpp-stanzas") : null;
+					if(err == null || (err != null ? err.name : null) == "service-unavailable" || (err != null ? err.name : null) == "feature-not-implemented") {
+						add(new snikket_AvailableChat(jid.asString(),query,jid.asString(),new snikket_Caps("",[],[])));
+					}
+				} else {
+					_gthis.persistence.storeCaps(resultCaps);
+					let identity = resultCaps.identities[0];
+					let tmp = identity != null ? identity.name : null;
+					let displayName = tmp != null ? tmp : query;
+					let note = jid.asString() + (identity == null ? "" : " (" + identity.type + ")");
+					add(new snikket_AvailableChat(jid.asString(),displayName,note,resultCaps));
+				}
+				callback(q,results);
+			});
+			_gthis.sendQuery(discoGet);
+		};
+		let jid = query.startsWith("xmpp:") ? snikket_JID.parse(HxOverrides.substr(query,5,null)) : snikket_JID.parse(query);
+		if(jid.isValid()) {
+			checkAndAdd(jid,true);
+		}
+		let _g = 0;
+		let _g1 = this.chats;
+		while(_g < _g1.length) {
+			let chat = _g1[_g];
+			++_g;
+			if(chat.chatId != jid.asBare().asString()) {
+				if(chat.chatId.includes(query.toLowerCase()) || chat.getDisplayName().toLowerCase().includes(query.toLowerCase())) {
+					let channel = snikket_Util_downcast(chat,snikket_Channel);
+					results.push(new snikket_AvailableChat(chat.chatId,chat.getDisplayName(),chat.chatId,channel == null || channel.disco == null ? new snikket_Caps("",[],[]) : channel.disco));
+				}
+			}
+			if(chat.isTrusted()) {
+				let resources = new Map([]);
+				let _g = 0;
+				let _g1 = snikket_Caps.withIdentity(chat.getCaps(),"gateway",null);
+				while(_g < _g1.length) {
+					let resource = _g1[_g];
+					++_g;
+					resources.set(resource,true);
+				}
+				let _g2 = 0;
+				let _g3 = snikket_Caps.withFeature(chat.getCaps(),"jabber:iq:gateway");
+				while(_g2 < _g3.length) {
+					let resource = _g3[_g2];
+					++_g2;
+					resources.set(resource,true);
+				}
+				if(!this.sendAvailable && snikket_JID.parse(chat.chatId).isDomain()) {
+					resources.set(null,true);
+				}
+				let jsIterator = resources.keys();
+				let _g_jsIterator = jsIterator;
+				let _g_lastStep = jsIterator.next();
+				while(!_g_lastStep.done) {
+					let v = _g_lastStep.value;
+					_g_lastStep = _g_jsIterator.next();
+					let resource = v;
+					let bareJid = snikket_JID.parse(chat.chatId);
+					let fullJid = new snikket_JID(bareJid.node,bareJid.domain,resource);
+					let jigGet = new snikket_queries_JabberIqGatewayGet(fullJid.asString(),query);
+					jigGet.onFinished(function() {
+						if(jigGet.getResult() == null) {
+							let caps = chat.getResourceCaps(resource);
+							if(bareJid.isDomain() && caps.features.includes("jid\\20escaping")) {
+								checkAndAdd(new snikket_JID(query,bareJid.domain));
+							} else if(bareJid.isDomain()) {
+								checkAndAdd(new snikket_JID(StringTools.replace(query,"@","%"),bareJid.domain));
+							}
+						} else {
+							let _g = jigGet.getResult();
+							switch(_g._hx_index) {
+							case 0:
+								let error = _g.v;
+								return;
+							case 1:
+								let result = _g.v;
+								checkAndAdd(snikket_JID.parse(result));
+								break;
+							}
+						}
+					});
+					this.sendQuery(jigGet);
+				}
+			}
+		}
+		if(!jid.isValid() && results.length > 0) {
+			callback(q,results);
+		}
+	}
+	startChat(availableChat) {
+		let existingChat = this.getChat(availableChat.chatId);
+		if(existingChat != null) {
+			let channel = ((existingChat) instanceof snikket_Channel) ? existingChat : null;
+			if(channel == null && availableChat.isChannel() || channel != null && !availableChat.isChannel()) {
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = this.chats;
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(v.chatId != availableChat.chatId) {
+						_g.push(v);
+					}
+				}
+				this.chats = _g;
+			} else {
+				if(existingChat.uiState == 2) {
+					existingChat.uiState = 1;
+				}
+				if(channel != null) {
+					channel.selfPing(true);
+				}
+				this.persistence.storeChats(this.accountId(),[existingChat]);
+				this.trigger("chats/update",[existingChat]);
+				return existingChat;
+			}
+		}
+		let chat;
+		if(availableChat.isChannel()) {
+			let channel = new snikket_Channel(this,this.stream,this.persistence,availableChat.chatId,1,false,null,null,null,availableChat.caps);
+			this.chats.unshift(channel);
+			channel.selfPing(false);
+			chat = channel;
+		} else {
+			chat = this.getDirectChat(availableChat.chatId,false);
+		}
+		this.persistence.storeChats(this.accountId(),[chat]);
+		this.trigger("chats/update",[chat]);
+		return chat;
+	}
+	getChat(chatId) {
+		return Lambda.find(this.chats,function(chat) {
+			return chat.chatId == chatId;
+		});
+	}
+	moderateMessage(action) {
+		let _gthis = this;
+		return thenshim_Promise._new(function(resolve,reject) {
+			_gthis.persistence.getMessage(_gthis.accountId(),action.chatId,action.moderateServerId,null,function(moderateMessage) {
+				if(moderateMessage == null) {
+					resolve(null);
+					return;
+				}
+				let _g = 0;
+				let _g1 = moderateMessage.attachments;
+				while(_g < _g1.length) {
+					let attachment = _g1[_g];
+					++_g;
+					let _g2 = 0;
+					let _g3 = attachment.hashes;
+					while(_g2 < _g3.length) {
+						let hash = _g3[_g2];
+						++_g2;
+						_gthis.persistence.removeMedia(hash.algorithm,hash.hash);
+					}
+				}
+				moderateMessage = snikket_ChatMessageBuilder.makeModerated(moderateMessage,action.timestamp,action.moderatorId,action.reason);
+				_gthis.persistence.updateMessage(_gthis.accountId(),moderateMessage);
+				resolve(moderateMessage);
+			});
+		});
+	}
+	getDirectChat(chatId,triggerIfNew) {
+		if(triggerIfNew == null) {
+			triggerIfNew = true;
+		}
+		let _g = 0;
+		let _g1 = this.chats;
+		while(_g < _g1.length) {
+			let chat = _g1[_g];
+			++_g;
+			if(((chat) instanceof snikket_DirectChat) && chat.chatId == chatId) {
+				if(((chat) instanceof snikket_DirectChat)) {
+					return chat;
+				} else {
+					return null;
+				}
+			}
+		}
+		let chat = new snikket_DirectChat(this,this.stream,this.persistence,chatId);
+		this.persistence.storeChats(this.accountId(),[chat]);
+		this.chats.unshift(chat);
+		if(triggerIfNew) {
+			this.trigger("chats/update",[chat]);
+		}
+		return chat;
+	}
+	subscribePush(reg,push_service,vapid_key) {
+		let _gthis = this;
+		window.crypto.subtle.exportKey("raw",vapid_key.publicKey).then(function(vapid_public_raw) {
+			return reg.pushManager.subscribe({ userVisibleOnly : true, applicationServerKey : vapid_public_raw}).then(function(pushSubscription) {
+				if(pushSubscription == null) {
+					haxe_Log.trace("WebPush subscription failed",{ fileName : "snikket/Client.hx", lineNumber : 950, className : "snikket.Client", methodName : "subscribePush"});
+					return;
+				}
+				_gthis.enablePush(push_service,vapid_key.privateKey,pushSubscription.endpoint,pushSubscription.getKey("p256dh"),pushSubscription.getKey("auth"));
+			});
+		});
+	}
+	enablePush(push_service,vapid_private_key,endpoint,p256dh,auth) {
+		let _gthis = this;
+		window.crypto.subtle.exportKey("pkcs8",vapid_private_key).then(function(vapid_private_pkcs8) {
+			let _gthis1 = _gthis;
+			let tmp = _gthis.jid.asBare().asString();
+			let push_service1 = push_service;
+			let endpoint1 = endpoint;
+			let tmp1 = haxe_io_Bytes.ofData(p256dh);
+			let tmp2 = haxe_io_Bytes.ofData(auth);
+			let tmp3 = haxe_io_Bytes.ofData(vapid_private_pkcs8);
+			let _g = new haxe_ds_StringMap();
+			let value = new URL(endpoint).origin;
+			_g.h["aud"] = value;
+			_gthis1.sendQuery(new snikket_queries_Push2Enable(tmp,push_service1,endpoint1,tmp1,tmp2,"ES256",tmp3,snikket_Map.fromMap(_g)));
+		});
+	}
+	addPasswordNeededListener(handler) {
+		let _gthis = this;
+		this.on("auth/password-needed",function(data) {
+			handler(_gthis);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addStatusOnlineListener(handler) {
+		this.on("status/online",function(data) {
+			handler();
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addStatusOfflineListener(handler) {
+		this.on("status/offline",function(data) {
+			handler();
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addConnectionFailedListener(handler) {
+		this.stream.on("status/error",function(data) {
+			handler();
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addUserStateListener(handler) {
+		this.chatStateHandlers.push(handler);
+	}
+	addChatMessageListener(handler) {
+		this.chatMessageHandlers.push(handler);
+	}
+	addSyncMessageListener(handler) {
+		this.syncMessageHandlers.push(handler);
+	}
+	addChatsUpdatedListener(handler) {
+		this.on("chats/update",function(data) {
+			handler(data);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallRingListener(handler) {
+		this.on("call/ring",function(data) {
+			handler(data.session,data.chatId);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallRetractListener(handler) {
+		this.on("call/retract",function(data) {
+			handler(data.chatId);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallRingingListener(handler) {
+		this.on("call/ringing",function(data) {
+			handler(data.chatId);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallMediaListener(handler) {
+		this.on("call/media",function(data) {
+			handler(data.session,data.audio,data.video);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallTrackListener(handler) {
+		this.on("call/track",function(data) {
+			handler(data.chatId,data.track,data.streams);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	setInForeground() {
+		if(!this.stream.csi) {
+			return;
+		}
+		this.stream.sendStanza(new snikket_Stanza("active",{ xmlns : "urn:xmpp:csi:0"}));
+	}
+	setNotInForeground() {
+		if(!this.stream.csi) {
+			return;
+		}
+		this.stream.sendStanza(new snikket_Stanza("inactive",{ xmlns : "urn:xmpp:csi:0"}));
+	}
+	fetchMediaByHash(hashes,counterparts) {
+		if(hashes.length < 1 || counterparts.length < 1) {
+			return thenshim_Promise.reject("no counterparts left");
+		}
+		let _gthis = this;
+		return thenshim_Promise.then(this.fetchMediaByHashOneCounterpart(hashes,counterparts[0]),function(x) {
+			return x;
+		},function(_) {
+			return _gthis.fetchMediaByHash(hashes,counterparts.slice(1));
+		});
+	}
+	fetchMediaByHashOneCounterpart(hashes,counterpart) {
+		if(hashes.length < 1) {
+			return thenshim_Promise.reject("no hashes left");
+		}
+		let _gthis = this;
+		return thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+			_gthis.persistence.hasMedia(hashes[0].algorithm,hashes[0].hash,resolve);
+		}),function(has) {
+			if(has) {
+				return thenshim_Promise.resolve(null);
+			}
+			return thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+				let q = snikket_queries_BoB.forHash(counterpart.asString(),hashes[0]);
+				q.onFinished(function() {
+					let r = q.getResult();
+					if(r == null) {
+						reject("bad or no result from BoB query");
+					} else {
+						_gthis.persistence.storeMedia(r.type,r.bytes.b.bufferValue,function() {
+							resolve(null);
+						});
+					}
+				});
+				_gthis.sendQuery(q);
+			}),function(x) {
+				return x;
+			},function(_) {
+				return _gthis.fetchMediaByHashOneCounterpart(hashes.slice(1),counterpart);
+			});
+		});
+	}
+	chatActivity(chat,trigger) {
+		if(trigger == null) {
+			trigger = true;
+		}
+		if(chat.isBlocked) {
+			return;
+		}
+		if(chat.uiState == 2) {
+			chat.uiState = 1;
+			this.persistence.storeChats(this.accountId(),[chat]);
+		}
+		let pinnedCount = chat.uiState == 0 ? 0 : Lambda.fold(this.chats,function(item,result) {
+			return result + (item.uiState == 0 ? 1 : 0);
+		},0);
+		let idx = this.chats.indexOf(chat);
+		if(idx > pinnedCount) {
+			this.chats.splice(idx,1);
+			this.chats.splice(pinnedCount,0,chat);
+		}
+		if(trigger) {
+			this.trigger("chats/update",[chat]);
+		}
+	}
+	sortChats() {
+		this.chats.sort(function(a,b) {
+			if(a.uiState == 0 && b.uiState != 0) {
+				return -1;
+			}
+			if(b.uiState == 0 && a.uiState != 0) {
+				return 1;
+			}
+			let tmp = a.lastMessageTimestamp();
+			let tmp1 = b.lastMessageTimestamp();
+			return -Reflect.compare(tmp != null ? tmp : "0",tmp1 != null ? tmp1 : "0");
+		});
+	}
+	storeMessages(messages,callback) {
+		let tmp = callback;
+		this.persistence.storeMessages(this.accountId(),messages,tmp != null ? tmp : function(_) {
+		});
+	}
+	sendQuery(query) {
+		this.stream.sendIq(query.getQueryStanza(),$bind(query,query.handleResponse));
+	}
+	sendStanza(stanza) {
+		if(stanza.attr["id"] == null) {
+			stanza.attr["id"] = snikket_ID.long();
+		}
+		this.stream.sendStanza(stanza);
+	}
+	sendPresence(to,augment) {
+		let tmp = augment;
+		this.sendStanza((tmp != null ? tmp : function(s) {
+			return s;
+		})(this.caps.addC(new snikket_Stanza("presence",to == null ? { } : { to : to})).textTag("nick",this.displayName(),{ xmlns : "http://jabber.org/protocol/nick"})));
+	}
+	getIceServers(callback) {
+		let extDiscoGet = new snikket_queries_ExtDiscoGet(this.jid.domain);
+		extDiscoGet.onFinished(function() {
+			let didUrl = new Map([]);
+			let servers = [];
+			let _g = 0;
+			let tmp = extDiscoGet.getResult();
+			let _g1 = tmp != null ? tmp : [];
+			while(_g < _g1.length) {
+				let service = _g1[_g];
+				++_g;
+				if(!["stun","stuns","turn","turns"].includes(service.attr["type"])) {
+					continue;
+				}
+				let host = service.attr["host"];
+				if(host == null || host == "") {
+					continue;
+				}
+				let port = Std.parseInt(service.attr["port"]);
+				if(port == null || port < 1 || port > 65535) {
+					continue;
+				}
+				let isTurn = ["turn","turns"].includes(service.attr["type"]);
+				let url = service.attr["type"] + ":" + (host.indexOf(":") >= 0 ? "[" + host + "]" : host) + ":" + port + (isTurn ? "?transport=" + service.attr["transport"] : "");
+				if(!didUrl.has(url)) {
+					servers.push({ username : service.attr["username"], credential : service.attr["password"], urls : [url]});
+					didUrl.set(url,true);
+				}
+			}
+			callback(servers);
+		});
+		this.sendQuery(extDiscoGet);
+	}
+	discoverServices(target,node,callback) {
+		let itemsGet = new snikket_queries_DiscoItemsGet(target.asString(),node);
+		let _gthis = this;
+		itemsGet.onFinished(function() {
+			let _g = 0;
+			let tmp = itemsGet.getResult();
+			let _g1 = tmp != null ? tmp : [];
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				let infoGet = new snikket_queries_DiscoInfoGet(item.jid.asString(),item.node);
+				infoGet.onFinished(function() {
+					callback(item,infoGet.getResult());
+				});
+				_gthis.sendQuery(infoGet);
+			}
+		});
+		this.sendQuery(itemsGet);
+	}
+	notifyMessageHandlers(message,event) {
+		let chat = this.getChat(message.chatId());
+		if(chat != null && chat.isBlocked) {
+			return;
+		}
+		let _g = 0;
+		let _g1 = this.chatMessageHandlers;
+		while(_g < _g1.length) {
+			let handler = _g1[_g];
+			++_g;
+			handler(message,event);
+		}
+	}
+	notifySyncMessageHandlers(message) {
+		if(message == null || message.versions.length > 1) {
+			return;
+		}
+		let chat = this.getChat(message.chatId());
+		if(chat != null && chat.isBlocked) {
+			return;
+		}
+		let _g = 0;
+		let _g1 = this.syncMessageHandlers;
+		while(_g < _g1.length) {
+			let handler = _g1[_g];
+			++_g;
+			handler(message);
+		}
+	}
+	rosterGet() {
+		let rosterGet = new snikket_queries_RosterGet();
+		let _gthis = this;
+		rosterGet.onFinished(function() {
+			let chatsToUpdate = [];
+			let _g = 0;
+			let _g1 = rosterGet.getResult();
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				let chat = _gthis.getDirectChat(item.jid,false);
+				chat.updateFromRoster(item);
+				chatsToUpdate.push(js_Boot.__cast(chat , snikket_Chat));
+			}
+			_gthis.persistence.storeChats(_gthis.accountId(),chatsToUpdate);
+			_gthis.trigger("chats/update",chatsToUpdate);
+		});
+		this.sendQuery(rosterGet);
+	}
+	startChatWith(jid,handleCaps,handleChat) {
+		let discoGet = new snikket_queries_DiscoInfoGet(jid);
+		let _gthis = this;
+		discoGet.onFinished(function() {
+			let resultCaps = discoGet.getResult();
+			if(resultCaps == null) {
+				let tmp = discoGet.responseStanza;
+				let tmp1 = tmp != null ? tmp.getChild("error") : null;
+				let err = tmp1 != null ? tmp1.getChild(null,"urn:ietf:params:xml:ns:xmpp-stanzas") : null;
+				if(err == null || (err != null ? err.name : null) == "service-unavailable" || (err != null ? err.name : null) == "feature-not-implemented") {
+					let chat = _gthis.getDirectChat(jid,false);
+					handleChat(chat);
+					_gthis.persistence.storeChats(_gthis.accountId(),[chat]);
+				}
+			} else {
+				_gthis.persistence.storeCaps(resultCaps);
+				let uiState = handleCaps(resultCaps);
+				if(resultCaps.isChannel(jid)) {
+					let chat = new snikket_Channel(_gthis,_gthis.stream,_gthis.persistence,jid,uiState,false,null,null,null,resultCaps);
+					handleChat(chat);
+					_gthis.chats.unshift(chat);
+					_gthis.persistence.storeChats(_gthis.accountId(),[chat]);
+				} else {
+					let chat = _gthis.getDirectChat(jid,false);
+					handleChat(chat);
+					_gthis.persistence.storeChats(_gthis.accountId(),[chat]);
+				}
+			}
+		});
+		this.sendQuery(discoGet);
+	}
+	serverBlocked(blocked) {
+		let tmp = this.getChat(blocked);
+		let chat = tmp != null ? tmp : this.getDirectChat(blocked,false);
+		chat.block(null,false);
+	}
+	bookmarksGet(callback) {
+		let blockingGet = new snikket_queries_BlocklistGet();
+		let _gthis = this;
+		blockingGet.onFinished(function() {
+			let _g = 0;
+			let _g1 = blockingGet.getResult();
+			while(_g < _g1.length) {
+				let blocked = _g1[_g];
+				++_g;
+				_gthis.serverBlocked(blocked);
+			}
+		});
+		this.sendQuery(blockingGet);
+		let mdsGet = new snikket_queries_PubsubGet(null,"urn:xmpp:mds:displayed:0");
+		mdsGet.onFinished(function() {
+			let chatsToUpdate = [];
+			let _g = 0;
+			let _g1 = mdsGet.getResult();
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				if(item.attr["id"] != null) {
+					let tmp = item.getChild("displayed","urn:xmpp:mds:displayed:0");
+					let upTo = tmp != null ? tmp.getChild("stanza-id","urn:xmpp:sid:0") : null;
+					let chat = _gthis.getChat(item.attr["id"]);
+					if(chat == null) {
+						_gthis.startChatWith(item.attr["id"],function(caps) {
+							return 2;
+						},function(chat) {
+							chat.markReadUpToId(upTo.attr["id"],upTo.attr["by"]);
+						});
+					} else {
+						chat.markReadUpToId(upTo.attr["id"],upTo.attr["by"]);
+						chatsToUpdate.push(chat);
+					}
+				}
+			}
+			_gthis.persistence.storeChats(_gthis.accountId(),chatsToUpdate);
+		});
+		this.sendQuery(mdsGet);
+		let pubsubGet = new snikket_queries_PubsubGet(null,"urn:xmpp:bookmarks:1");
+		pubsubGet.onFinished(function() {
+			let chatsToUpdate = [];
+			let _g = 0;
+			let _g1 = pubsubGet.getResult();
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				if(item.attr["id"] != null) {
+					let chat = _gthis.getChat(item.attr["id"]);
+					if(chat == null) {
+						_gthis.startChatWith(item.attr["id"],function(caps) {
+							let identity = caps.identities[0];
+							let conf = item.getChild("conference","urn:xmpp:bookmarks:1");
+							if(conf.attr["name"] == null) {
+								conf.attr["name"] = identity != null ? identity.name : null;
+							}
+							if(conf.attr["autojoin"] == "1" || conf.attr["autojoin"] == "true" || !caps.isChannel(item.attr["id"])) {
+								return 1;
+							} else {
+								return 2;
+							}
+						},function(chat) {
+							chat.updateFromBookmark(item);
+						});
+					} else {
+						chat.updateFromBookmark(item);
+						chatsToUpdate.push(chat);
+					}
+				}
+			}
+			_gthis.persistence.storeChats(_gthis.accountId(),chatsToUpdate);
+			callback();
+		});
+		this.sendQuery(pubsubGet);
+	}
+	sync(callback) {
+		let _gthis = this;
+		if(((this.persistence) instanceof snikket_persistence_Dummy)) {
+			callback(true);
+		} else {
+			this.persistence.lastId(this.accountId(),null,function(lastId) {
+				_gthis.doSync(callback,lastId);
+			});
+		}
+	}
+	onMAMJMI(sid,stanza) {
+		if(stanza.attr["from"] == null) {
+			return;
+		}
+		let from = snikket_JID.parse(stanza.attr["from"]);
+		let chat = this.getDirectChat(from.asBare().asString());
+		if(chat.jingleSessions.has(sid)) {
+			return;
+		}
+		let jmiP = stanza.getChild("propose","urn:xmpp:jingle-message:0");
+		if(jmiP == null) {
+			return;
+		}
+		let session = new snikket_jingle_IncomingProposedSession(this,from,sid);
+		chat.jingleSessions.set(session.get_sid(),session);
+		this.chatActivity(chat);
+		session.ring();
+	}
+	doSync(callback,lastId) {
+		let thirtyDaysAgo = snikket_Date.format(new Date(new Date().getTime() + (-2592000000.)));
+		let sync = new snikket_MessageSync(this,this.stream,lastId == null ? { startTime : thirtyDaysAgo} : { page : { after : lastId}});
+		sync.setNewestPageFirst(false);
+		sync.addContext(function(builder,stanza) {
+			builder.syncPoint = true;
+			return builder;
+		});
+		let _gthis = this;
+		sync.onMessages(function(messageList) {
+			let promises = [];
+			let chatMessages = [];
+			let _g = 0;
+			let _g1 = messageList.messages;
+			while(_g < _g1.length) {
+				let m = _g1[_g];
+				++_g;
+				switch(m._hx_index) {
+				case 1:
+					let message = m.message;
+					chatMessages.push(message);
+					break;
+				case 2:
+					let action = m.action;
+					promises.push(thenshim_Promise._new(function(resolve,reject) {
+						_gthis.moderateMessage(action).then(function(_) {
+							resolve(null);
+						});
+					}));
+					break;
+				case 3:
+					let update = m.update;
+					promises.push(thenshim_Promise._new(function(resolve,reject) {
+						_gthis.persistence.storeReaction(_gthis.accountId(),update,function(_) {
+							resolve(null);
+						});
+					}));
+					break;
+				default:
+				}
+			}
+			promises.push(thenshim_Promise._new(function(resolve,reject) {
+				_gthis.persistence.storeMessages(_gthis.accountId(),chatMessages,resolve);
+			}));
+			haxe_Log.trace("SYNC: MAM page wait for writes",{ fileName : "snikket/Client.hx", lineNumber : 1467, className : "snikket.Client", methodName : "doSync"});
+			thenshim_Promise.then(thenshim_PromiseTools.all(promises),function(results) {
+				if(_gthis.syncMessageHandlers.length > 0) {
+					let _g = 0;
+					while(_g < results.length) {
+						let messages = results[_g];
+						++_g;
+						if(messages != null) {
+							let _g = 0;
+							while(_g < messages.length) {
+								let message = messages[_g];
+								++_g;
+								_gthis.notifySyncMessageHandlers(message);
+							}
+						}
+					}
+				}
+				if(sync.hasMore()) {
+					sync.fetchNext();
+				} else {
+					let jsIterator = sync.jmi.entries();
+					let _g_jsIterator = jsIterator;
+					let _g_lastStep = jsIterator.next();
+					while(!_g_lastStep.done) {
+						let v = _g_lastStep.value;
+						_g_lastStep = _g_jsIterator.next();
+						let _g_key = v[0];
+						let _g_value = v[1];
+						let sid = _g_key;
+						let stanza = _g_value;
+						_gthis.onMAMJMI(sid,stanza);
+					}
+					if(callback != null) {
+						callback(true);
+					}
+				}
+			},function(e) {
+				haxe_Log.trace("SYNC: error",{ fileName : "snikket/Client.hx", lineNumber : 1489, className : "snikket.Client", methodName : "doSync", customParams : [e == null ? "null" : Std.string(e)]});
+				callback(false);
+			});
+		});
+		sync.onError(function(stanza) {
+			if(lastId != null) {
+				_gthis.doSync(callback,null);
+			} else {
+				haxe_Log.trace("SYNC: error",{ fileName : "snikket/Client.hx", lineNumber : 1498, className : "snikket.Client", methodName : "doSync", customParams : [stanza]});
+				if(callback != null) {
+					callback(false);
+				}
+			}
+		});
+		sync.fetchNext();
+	}
+	pingAllChannels(refresh) {
+		let _g = 0;
+		let _g1 = this.getChats();
+		while(_g < _g1.length) {
+			let chat = _g1[_g];
+			++_g;
+			let channel = ((chat) instanceof snikket_Channel) ? chat : null;
+			if(channel != null) {
+				channel.selfPing(refresh || (channel != null ? channel.disco : null) == null);
+			}
+		}
+	}
+}
+$hx_exports["snikket"]["Client"] = snikket_Client;
+snikket_Client.__name__ = "snikket.Client";
+snikket_Client.__super__ = snikket_EventEmitter;
+Object.assign(snikket_Client.prototype, {
+	__class__: snikket_Client
+});
+class snikket_Color {
+	static forString(s) {
+		let hash = haxe_crypto_Sha1.make(haxe_io_Bytes.ofString(s));
+		let hue = hash.getUInt16(0) / 65536.0 * 360;
+		let color = new hsluv_Hsluv();
+		color.hsluv_h = hue;
+		color.hsluv_s = 100;
+		color.hsluv_l = 50;
+		color.hsluvToHex();
+		return color.hex;
+	}
+	static defaultPhoto(input,letter) {
+		let hex = HxOverrides.substr(snikket_Color.forString(input),1,null);
+		return "data:image/svg+xml,<svg%20xmlns=\"http://www.w3.org/2000/svg\"%20version=\"1.1\"%20width=\"15\"%20height=\"15\"%20viewBox=\"0%200%2015%2015\">" + "<rect%20style=\"fill:%23" + hex + ";\"%20width=\"15\"%20height=\"15\"%20x=\"0\"%20y=\"0\"%20/>" + "<text%20style=\"fill:%23ffffff;font-size:8px;font-family:sans-serif;\"%20text-anchor=\"middle\"%20dominant-baseline=\"central\"%20x=\"50%25\"%20y=\"50%25\">" + encodeURIComponent(letter) + "</text>" + "</svg>";
+	}
+}
+snikket_Color.__name__ = "snikket.Color";
+class snikket_Config {
+}
+$hx_exports["snikket"]["Config"] = snikket_Config;
+snikket_Config.__name__ = "snikket.Config";
+class snikket_Date {
+	static format(d) {
+		let millis = d.getTime();
+		let frac = millis - (millis / 1000 | 0) * 1000.0 | 0;
+		return Std.string(d.getUTCFullYear()) + "-" + StringTools.lpad(Std.string(d.getUTCMonth() + 1),"0",2) + "-" + StringTools.lpad(Std.string(d.getUTCDate()),"0",2) + "T" + StringTools.lpad(Std.string(d.getUTCHours()),"0",2) + ":" + StringTools.lpad(Std.string(d.getUTCMinutes()),"0",2) + ":" + StringTools.lpad(Std.string(d.getUTCSeconds()),"0",2) + "." + StringTools.lpad(frac == null ? "null" : "" + frac,"0",3) + "Z";
+	}
+}
+snikket_Date.__name__ = "snikket.Date";
+class snikket_UnicodeSet {
+}
+snikket_UnicodeSet.__name__ = "snikket.UnicodeSet";
+snikket_UnicodeSet.__isInterface__ = true;
+Object.assign(snikket_UnicodeSet.prototype, {
+	__class__: snikket_UnicodeSet
+});
+class snikket_UnicodeList {
+	constructor(...codes) {
+		this.list = codes.slice();
+	}
+	contains(codepoint) {
+		return this.list.includes(codepoint);
+	}
+}
+snikket_UnicodeList.__name__ = "snikket.UnicodeList";
+snikket_UnicodeList.__interfaces__ = [snikket_UnicodeSet];
+Object.assign(snikket_UnicodeList.prototype, {
+	__class__: snikket_UnicodeList
+});
+class snikket_UnicodeRange {
+	constructor(lower,upper) {
+		this.lower = lower;
+		this.upper = upper;
+	}
+	contains(codePoint) {
+		if(codePoint >= this.lower) {
+			return codePoint <= this.upper;
+		} else {
+			return false;
+		}
+	}
+}
+snikket_UnicodeRange.__name__ = "snikket.UnicodeRange";
+snikket_UnicodeRange.__interfaces__ = [snikket_UnicodeSet];
+Object.assign(snikket_UnicodeRange.prototype, {
+	__class__: snikket_UnicodeRange
+});
+class snikket_UnicodeBlocks {
+	constructor(...sets) {
+		this.unicodeSets = sets.slice();
+	}
+	contains(codepoint) {
+		let _g = 0;
+		let _g1 = this.unicodeSets;
+		while(_g < _g1.length) {
+			let unicodeSet = _g1[_g];
+			++_g;
+			if(unicodeSet.contains(codepoint)) {
+				return true;
+			}
+		}
+		return false;
+	}
+}
+snikket_UnicodeBlocks.__name__ = "snikket.UnicodeBlocks";
+snikket_UnicodeBlocks.__interfaces__ = [snikket_UnicodeSet];
+Object.assign(snikket_UnicodeBlocks.prototype, {
+	__class__: snikket_UnicodeBlocks
+});
+class snikket_EmojiUtil {
+	static parse(str) {
+		let symbols = [];
+		let builder = new snikket_Builder();
+		let needsFinalBuild = false;
+		let input = snikket_StringUtil.rawCodepointArray(str);
+		let _g = 0;
+		let _g1 = input.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let cp = input[i];
+			if(builder.offer(cp)) {
+				needsFinalBuild = true;
+			} else {
+				symbols.push(builder.build());
+				builder = new snikket_Builder();
+				if(builder.offer(cp)) {
+					needsFinalBuild = true;
+				}
+			}
+		}
+		if(needsFinalBuild) {
+			symbols.push(builder.build());
+		}
+		return symbols;
+	}
+	static isEmoji(input) {
+		let symbols = snikket_EmojiUtil.parse(input);
+		if(symbols.length == 1) {
+			return symbols[0].isEmoji();
+		} else {
+			return false;
+		}
+	}
+	static isOnlyEmoji(input) {
+		let symbols = snikket_EmojiUtil.parse(input);
+		let _g = 0;
+		while(_g < symbols.length) {
+			let symbol = symbols[_g];
+			++_g;
+			if(!symbol.isEmoji()) {
+				return false;
+			}
+		}
+		return symbols.length > 0;
+	}
+}
+snikket_EmojiUtil.__name__ = "snikket.EmojiUtil";
+class snikket_Symbol {
+	constructor(codepoints) {
+		let builder_b = "";
+		let _g = 0;
+		while(_g < codepoints.length) {
+			let codepoint = codepoints[_g];
+			++_g;
+			builder_b += String.fromCodePoint(codepoint);
+		}
+		this.value = builder_b;
+	}
+	toString() {
+		return this.value;
+	}
+}
+snikket_Symbol.__name__ = "snikket.Symbol";
+Object.assign(snikket_Symbol.prototype, {
+	__class__: snikket_Symbol
+});
+class snikket_Emoji extends snikket_Symbol {
+	constructor(codepoints) {
+		super(codepoints);
+	}
+	isEmoji() {
+		return true;
+	}
+}
+snikket_Emoji.__name__ = "snikket.Emoji";
+snikket_Emoji.__super__ = snikket_Symbol;
+Object.assign(snikket_Emoji.prototype, {
+	__class__: snikket_Emoji
+});
+class snikket_Other extends snikket_Symbol {
+	constructor(codepoints) {
+		super(codepoints);
+	}
+	isEmoji() {
+		return false;
+	}
+}
+snikket_Other.__name__ = "snikket.Other";
+snikket_Other.__super__ = snikket_Symbol;
+Object.assign(snikket_Other.prototype, {
+	__class__: snikket_Other
+});
+class snikket_Builder {
+	constructor() {
+		this.codepoints = [];
+	}
+	offer(codepoint) {
+		let add = false;
+		if(this.codepoints.length == 0) {
+			if(snikket_EmojiUtil.SYMBOLIZE.contains(codepoint)) {
+				add = true;
+			} else if(snikket_EmojiUtil.REGIONAL_INDICATORS.contains(codepoint)) {
+				add = true;
+			} else if(snikket_EmojiUtil.EMOJIS.contains(codepoint) && !snikket_EmojiUtil.FITZPATRICK.contains(codepoint) && codepoint != snikket_EmojiUtil.ZWJ) {
+				add = true;
+			}
+		} else {
+			let previous = this.codepoints[this.codepoints.length - 1];
+			if(this.codepoints[0] == snikket_EmojiUtil.BLACK_FLAG) {
+				add = snikket_EmojiUtil.TAGS.contains(codepoint);
+			} else if(snikket_EmojiUtil.COMBINING_ENCLOSING_KEYCAP == codepoint) {
+				add = snikket_EmojiUtil.KEYCAP_COMBINEABLE.contains(previous) || previous == snikket_EmojiUtil.VARIATION_16;
+			} else if(snikket_EmojiUtil.SYMBOLIZE.contains(previous)) {
+				add = codepoint == snikket_EmojiUtil.VARIATION_16;
+			} else if(snikket_EmojiUtil.REGIONAL_INDICATORS.contains(previous) && snikket_EmojiUtil.REGIONAL_INDICATORS.contains(codepoint)) {
+				add = this.codepoints.length == 1;
+			} else if(previous == snikket_EmojiUtil.VARIATION_16) {
+				add = snikket_Builder.isMerger(codepoint) || codepoint == snikket_EmojiUtil.VARIATION_16;
+			} else if(snikket_EmojiUtil.FITZPATRICK.contains(previous)) {
+				add = codepoint == snikket_EmojiUtil.ZWJ;
+			} else if(snikket_EmojiUtil.ZWJ == previous) {
+				add = snikket_EmojiUtil.EMOJIS.contains(codepoint);
+			} else if(snikket_Builder.isMerger(codepoint)) {
+				add = true;
+			} else if(codepoint == snikket_EmojiUtil.VARIATION_16 && snikket_EmojiUtil.EMOJIS.contains(previous)) {
+				add = true;
+			}
+		}
+		if(add) {
+			this.codepoints.push(codepoint);
+			return true;
+		} else {
+			return false;
+		}
+	}
+	build() {
+		if(this.codepoints.length > 0 && snikket_EmojiUtil.SYMBOLIZE.contains(this.codepoints[this.codepoints.length - 1])) {
+			return new snikket_Other(this.codepoints);
+		} else if(this.codepoints.length > 1 && snikket_EmojiUtil.KEYCAP_COMBINEABLE.contains(this.codepoints[0]) && this.codepoints[this.codepoints.length - 1] != snikket_EmojiUtil.COMBINING_ENCLOSING_KEYCAP) {
+			return new snikket_Other(this.codepoints);
+		}
+		if(this.codepoints.length == 0) {
+			return new snikket_Other(this.codepoints);
+		} else {
+			return new snikket_Emoji(this.codepoints);
+		}
+	}
+	static isMerger(codepoint) {
+		if(codepoint != snikket_EmojiUtil.ZWJ) {
+			return snikket_EmojiUtil.FITZPATRICK.contains(codepoint);
+		} else {
+			return true;
+		}
+	}
+}
+snikket_Builder.__name__ = "snikket.Builder";
+Object.assign(snikket_Builder.prototype, {
+	__class__: snikket_Builder
+});
+var snikket_EventResult = $hxEnums["snikket.EventResult"] = { __ename__:true,__constructs__:null
+	,EventHandled: {_hx_name:"EventHandled",_hx_index:0,__enum__:"snikket.EventResult",toString:$estr}
+	,EventUnhandled: {_hx_name:"EventUnhandled",_hx_index:1,__enum__:"snikket.EventResult",toString:$estr}
+	,EventStop: {_hx_name:"EventStop",_hx_index:2,__enum__:"snikket.EventResult",toString:$estr}
+	,EventValue: ($_=function(result) { return {_hx_index:3,result:result,__enum__:"snikket.EventResult",toString:$estr}; },$_._hx_name="EventValue",$_.__params__ = ["result"],$_)
+};
+snikket_EventResult.__constructs__ = [snikket_EventResult.EventHandled,snikket_EventResult.EventUnhandled,snikket_EventResult.EventStop,snikket_EventResult.EventValue];
+class snikket_EventHandler {
+	constructor(handlers,callback,onlyOnce) {
+		this.onlyOnce = false;
+		this.callback = null;
+		this.handlers = null;
+		this.handlers = handlers;
+		this.callback = callback;
+		if(onlyOnce != null) {
+			this.onlyOnce = onlyOnce;
+		}
+	}
+	call(data) {
+		if(this.onlyOnce) {
+			this.unsubscribe();
+		}
+		return this.callback(data);
+	}
+	once() {
+		this.onlyOnce = true;
+		return this;
+	}
+	unsubscribe() {
+		HxOverrides.remove(this.handlers,this);
+	}
+}
+snikket_EventHandler.__name__ = "snikket.EventHandler";
+Object.assign(snikket_EventHandler.prototype, {
+	__class__: snikket_EventHandler
+});
+class snikket_FSM extends snikket_EventEmitter {
+	constructor(desc,initialState,initialAttr) {
+		snikket_EventEmitter._hx_skip_constructor = true;
+		super();
+		snikket_EventEmitter._hx_skip_constructor = false;
+		this._hx_constructor(desc,initialState,initialAttr);
+	}
+	_hx_constructor(desc,initialState,initialAttr) {
+		this.currentStateAttributes = null;
+		this.currentState = null;
+		this.states = new Map([]);
+		super._hx_constructor();
+		let _g = 0;
+		let _g1 = desc.transitions;
+		while(_g < _g1.length) {
+			let transition = _g1[_g];
+			++_g;
+			let from_states = transition.from;
+			let _g2 = 0;
+			while(_g2 < from_states.length) {
+				let from_state = from_states[_g2];
+				++_g2;
+				let from_state_def = this.states.get(from_state);
+				if(from_state_def == null) {
+					from_state_def = new Map([]);
+					this.states.set(from_state,from_state_def);
+				}
+				let to_state_def = this.states.get(transition.to);
+				if(to_state_def == null) {
+					to_state_def = new Map([]);
+					this.states.set(transition.to,to_state_def);
+				}
+				if(this.states.get(from_state).get(transition.name) != null) {
+					throw new haxe_Exception("Duplicate transition in FSM specification: " + transition.name + " from " + from_state);
+				}
+				this.states.get(from_state).set(transition.name,transition.to);
+			}
+		}
+		if(desc.state_handlers != null) {
+			let jsIterator = desc.state_handlers.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let state = _g_key;
+				let handler = _g_value;
+				this.on("enter/" + state,function(data) {
+					handler(data);
+					return snikket_EventResult.EventHandled;
+				});
+			}
+		}
+		if(desc.transition_handlers != null) {
+			let jsIterator = desc.transition_handlers.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let transition = _g_key;
+				let handler = _g_value;
+				this.on("transition/" + transition,function(data) {
+					if(handler(data) == false) {
+						return snikket_EventResult.EventStop;
+					}
+					return snikket_EventResult.EventHandled;
+				});
+			}
+		}
+		this.currentState = initialState;
+		this.currentStateAttributes = initialAttr;
+		let initialEvent = { fsm : this, to : initialState, toAttr : initialAttr};
+		this.notifyTransitioned(initialEvent,true);
+	}
+	can(name) {
+		return this.states.get(this.currentState).get(name) != null;
+	}
+	getState() {
+		return this.currentState;
+	}
+	event(name,attr) {
+		let newState = this.states.get(this.currentState).get(name);
+		if(newState == null) {
+			throw new haxe_Exception("Invalid state transition: " + this.currentState + " cannot " + name);
+		}
+		let event = { fsm : this, name : name, to : newState, toAttr : attr, from : this.currentState, fromAttr : this.currentStateAttributes};
+		if(this.notifyTransition(event) == false) {
+			return false;
+		}
+		this.currentState = newState;
+		this.currentStateAttributes = attr;
+		this.notifyTransitioned(event,false);
+		return true;
+	}
+	notifyTransition(event) {
+		let ret = this.trigger("transition",event);
+		if(ret == snikket_EventResult.EventStop) {
+			return false;
+		}
+		if(event.to != event.from) {
+			ret = this.trigger("leave/" + event.from,event);
+			if(ret == snikket_EventResult.EventStop) {
+				return false;
+			}
+		}
+		ret = this.trigger("transition/" + event.name,event);
+		if(ret == snikket_EventResult.EventStop) {
+			return false;
+		}
+		return true;
+	}
+	notifyTransitioned(event,isInitial) {
+		if(event.to != event.from) {
+			this.trigger("enter/" + event.to,event);
+		}
+		if(isInitial == false) {
+			if(event.name != null) {
+				this.trigger("transitioned/" + event.name,event);
+			}
+			this.trigger("transitioned",event);
+		}
+	}
+}
+snikket_FSM.__name__ = "snikket.FSM";
+snikket_FSM.__super__ = snikket_EventEmitter;
+Object.assign(snikket_FSM.prototype, {
+	__class__: snikket_FSM
+});
+var snikket_IqResult = $hxEnums["snikket.IqResult"] = { __ename__:true,__constructs__:null
+	,IqResultElement: ($_=function(element) { return {_hx_index:0,element:element,__enum__:"snikket.IqResult",toString:$estr}; },$_._hx_name="IqResultElement",$_.__params__ = ["element"],$_)
+	,IqResult: {_hx_name:"IqResult",_hx_index:1,__enum__:"snikket.IqResult",toString:$estr}
+	,IqNoResult: {_hx_name:"IqNoResult",_hx_index:2,__enum__:"snikket.IqResult",toString:$estr}
+};
+snikket_IqResult.__constructs__ = [snikket_IqResult.IqResultElement,snikket_IqResult.IqResult,snikket_IqResult.IqNoResult];
+class snikket_GenericStream extends snikket_EventEmitter {
+	constructor() {
+		if(snikket_EventEmitter._hx_skip_constructor) {
+			super();
+			return;
+		}
+		snikket_EventEmitter._hx_skip_constructor = true;
+		super();
+		snikket_EventEmitter._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.csi = false;
+		this.clientId = null;
+		super._hx_constructor();
+	}
+	sendIq(stanza,callback) {
+		let id = this.newId();
+		stanza.attr["id"] = id;
+		this.once("iq-response/" + id,function(event) {
+			callback(event.stanza);
+			return snikket_EventResult.EventHandled;
+		});
+		this.sendStanza(stanza);
+	}
+	onStanza(stanza) {
+		haxe_Log.trace("stanza received!",{ fileName : "snikket/GenericStream.hx", lineNumber : 40, className : "snikket.GenericStream", methodName : "onStanza"});
+		let xmlns = stanza.attr["xmlns"];
+		if(xmlns == "jabber:client") {
+			let name = stanza.name;
+			if(name == "iq") {
+				let type = stanza.attr["type"];
+				haxe_Log.trace("type: " + type,{ fileName : "snikket/GenericStream.hx", lineNumber : 46, className : "snikket.GenericStream", methodName : "onStanza"});
+				if(type == "result" || type == "error") {
+					let id = stanza.attr["id"];
+					this.trigger("iq-response/" + id,{ stanza : stanza});
+				}
+			} else if(name == "message" || name == "presence") {
+				this.trigger(name,{ stanza : stanza});
+			}
+		}
+	}
+}
+snikket_GenericStream.__name__ = "snikket.GenericStream";
+snikket_GenericStream.__super__ = snikket_EventEmitter;
+Object.assign(snikket_GenericStream.prototype, {
+	__class__: snikket_GenericStream
+});
+class snikket_Hash {
+	constructor(algorithm,hash) {
+		this.algorithm = algorithm;
+		this.hash = hash;
+	}
+	toUri() {
+		if(snikket_Config.relativeHashUri) {
+			let s = this.algorithm;
+			return "/.well-known/ni/" + encodeURIComponent(s) + "/" + this.toBase64Url();
+		} else {
+			return this.serializeUri();
+		}
+	}
+	bobUri() {
+		let tmp;
+		if(this.algorithm == "sha-1") {
+			tmp = "sha1";
+		} else {
+			let s = this.algorithm;
+			tmp = encodeURIComponent(s);
+		}
+		return "cid:" + tmp + "+" + this.toHex() + "@bob.xmpp.org";
+	}
+	serializeUri() {
+		let s = this.algorithm;
+		return "ni:///" + encodeURIComponent(s) + ";" + this.toBase64Url();
+	}
+	toHex() {
+		return haxe_io_Bytes.ofData(this.hash).toHex();
+	}
+	toBase64() {
+		return haxe_crypto_Base64.encode(haxe_io_Bytes.ofData(this.hash),true);
+	}
+	toBase64Url() {
+		return haxe_crypto_Base64.urlEncode(haxe_io_Bytes.ofData(this.hash));
+	}
+	static fromHex(algorithm,hash) {
+		try {
+			return new snikket_Hash(algorithm,haxe_io_Bytes.ofHex(hash).b.bufferValue);
+		} catch( _g ) {
+			return null;
+		}
+	}
+	static fromUri(uri) {
+		if(uri.startsWith("cid:") && uri.endsWith("@bob.xmpp.org") && uri.includes("+")) {
+			let parts = HxOverrides.substr(uri,4,null).split("@")[0].split("+");
+			let algo = parts[0] == "sha1" ? "sha-1" : parts[0];
+			return snikket_Hash.fromHex(algo,parts[1]);
+		}
+		if(uri.startsWith("ni:///") && uri.includes(";")) {
+			let parts = uri.substring(6).split(";");
+			return new snikket_Hash(parts[0],haxe_crypto_Base64.urlDecode(parts[1]).b.bufferValue);
+		} else if(uri.startsWith("/.well-known/ni/")) {
+			let parts = uri.substring(16).split("/");
+			return new snikket_Hash(parts[0],haxe_crypto_Base64.urlDecode(parts[1]).b.bufferValue);
+		}
+		return null;
+	}
+	static sha1(bytes) {
+		return new snikket_Hash("sha-1",haxe_crypto_Sha1.make(bytes).b.bufferValue);
+	}
+	static sha256(bytes) {
+		return new snikket_Hash("sha-256",haxe_crypto_Sha256.make(bytes).b.bufferValue);
+	}
+}
+$hx_exports["snikket"]["Hash"] = snikket_Hash;
+snikket_Hash.__name__ = "snikket.Hash";
+Object.assign(snikket_Hash.prototype, {
+	__class__: snikket_Hash
+});
+class snikket_ID {
+	static tiny() {
+		return hx_strings_RandomStrings.random(6,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC));
+	}
+	static short() {
+		return hx_strings_RandomStrings.random(18,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC));
+	}
+	static medium() {
+		return hx_strings_RandomStrings.random(32,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC));
+	}
+	static long() {
+		return hx_strings_RandomStrings.randomUUIDv4();
+	}
+}
+snikket_ID.__name__ = "snikket.ID";
+class snikket_Identicon {
+	static svg(source) {
+		let sha = haxe_crypto_Sha1.make(haxe_io_Bytes.ofString(source));
+		let input = new haxe_io_BytesInput(sha);
+		input.set_bigEndian(true);
+		let hash = input.readInt32();
+		let uri = "data:image/svg+xml,<svg%20xmlns=\"http://www.w3.org/2000/svg\"%20version=\"1.1\"%20width=\"5\"%20height=\"5\"%20viewBox=\"0%200%205%205\">";
+		uri += "<style>rect{fill:%23" + HxOverrides.substr(snikket_Color.forString(source),1,null) + ";}</style>";
+		let i = 0;
+		let value = hash >> i++;
+		if(value % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 0 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 0 + "\"/>";
+		}
+		let value1 = hash >> i++;
+		if(value1 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 1 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 1 + "\"/>";
+		}
+		let value2 = hash >> i++;
+		if(value2 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 2 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 2 + "\"/>";
+		}
+		let value3 = hash >> i++;
+		if(value3 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 3 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 3 + "\"/>";
+		}
+		let value4 = hash >> i++;
+		if(value4 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 4 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 4 + "\"/>";
+		}
+		let value5 = hash >> i++;
+		if(value5 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 0 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 0 + "\"/>";
+		}
+		let value6 = hash >> i++;
+		if(value6 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 1 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 1 + "\"/>";
+		}
+		let value7 = hash >> i++;
+		if(value7 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 2 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 2 + "\"/>";
+		}
+		let value8 = hash >> i++;
+		if(value8 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 3 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 3 + "\"/>";
+		}
+		let value9 = hash >> i++;
+		if(value9 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 4 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 4 + "\"/>";
+		}
+		let value10 = hash >> i++;
+		if(value10 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 0 + "\"/>";
+		}
+		let value11 = hash >> i++;
+		if(value11 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 1 + "\"/>";
+		}
+		let value12 = hash >> i++;
+		if(value12 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 2 + "\"/>";
+		}
+		let value13 = hash >> i++;
+		if(value13 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 3 + "\"/>";
+		}
+		let value14 = hash >> i++;
+		if(value14 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 4 + "\"/>";
+		}
+		return uri + "</svg>";
+	}
+}
+$hx_exports["snikket"]["Identicon"] = snikket_Identicon;
+snikket_Identicon.__name__ = "snikket.Identicon";
+class snikket_JID {
+	constructor(node,domain,resource) {
+		this.node = node == null ? null : StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.trim(node),"\\5c","\\5c5c"),"\\20","\\5c20"),"\\22","\\5c22"),"\\26","\\5c26"),"\\27","\\5c27"),"\\2f","\\5c2f"),"\\3a","\\5c3a"),"\\3c","\\5c3c"),"\\3e","\\5c3e"),"\\40","\\5c40")," ","\\20"),"\"","\\22"),"&","\\26"),"'","\\27"),"/","\\2f"),":","\\3a"),"<","\\3c"),">","\\3e"),"@","\\40");
+		this.domain = domain;
+		this.resource = resource;
+	}
+	asBare() {
+		return new snikket_JID(this.node,this.domain);
+	}
+	withResource(resource) {
+		return new snikket_JID(this.node,this.domain,resource);
+	}
+	isValid() {
+		return this.domain.indexOf(".") >= 0;
+	}
+	isDomain() {
+		return this.node == null;
+	}
+	isBare() {
+		return this.resource == null;
+	}
+	equals(rhs) {
+		if(this.node == rhs.node && this.domain == rhs.domain) {
+			return this.resource == rhs.resource;
+		} else {
+			return false;
+		}
+	}
+	asString() {
+		return (this.node != null ? this.node + "@" : "") + this.domain + (this.resource != null ? "/" + this.resource : "");
+	}
+	static parse(jid) {
+		let resourceDelimiter = jid.indexOf("/");
+		let nodeDelimiter = jid.indexOf("@");
+		if(resourceDelimiter > 0 && nodeDelimiter >= resourceDelimiter) {
+			nodeDelimiter = -1;
+		}
+		return new snikket_JID(nodeDelimiter > 0 ? HxOverrides.substr(jid,0,nodeDelimiter) : null,jid.substring(nodeDelimiter == -1 ? 0 : nodeDelimiter + 1,resourceDelimiter == -1 ? jid.length + 1 : resourceDelimiter),resourceDelimiter == -1 ? null : jid.substring(resourceDelimiter + 1));
+	}
+}
+$hx_exports["snikket"]["JID"] = snikket_JID;
+snikket_JID.__name__ = "snikket.JID";
+Object.assign(snikket_JID.prototype, {
+	__class__: snikket_JID
+});
+class snikket_Map {
+	static set(this1,k,v) {
+		this1.set(k,v);
+	}
+	static get(this1,k) {
+		return this1.get(k);
+	}
+	static exists(this1,k) {
+		return this1.has(k);
+	}
+	static remove(this1,k) {
+		return this1.delete(k);
+	}
+	static keys(this1) {
+		return new js_lib_HaxeIterator(this1.keys());
+	}
+	static iterator(this1) {
+		return new js_lib_HaxeIterator(this1.values());
+	}
+	static keyValueIterator(this1) {
+		return new snikket_HaxeKVIterator(this1.entries());
+	}
+	static flatMap(this1,f) {
+		let _g = [];
+		let x = $getIterator({ iterator : function() {
+			return new js_lib_HaxeIterator(this1.values());
+		}});
+		while(x.hasNext()) {
+			let x1 = x.next();
+			_g.push(f(x1));
+		}
+		let _g1 = [];
+		let e = $getIterator(_g);
+		while(e.hasNext()) {
+			let e1 = e.next();
+			let x = $getIterator(e1);
+			while(x.hasNext()) {
+				let x1 = x.next();
+				_g1.push(x1);
+			}
+		}
+		return _g1;
+	}
+	static arrayRead(this1,k) {
+		return this1.get(k);
+	}
+	static arrayWrite(this1,k,v) {
+		this1.set(k,v);
+		return v;
+	}
+	static fromMap(map) {
+		let result = new Map();
+		let _g = map.keyValueIterator();
+		while(_g.hasNext()) {
+			let _g1 = _g.next();
+			let k = _g1.key;
+			let v = _g1.value;
+			result.set(k,v);
+		}
+		return result;
+	}
+	static fromArray(iterable) {
+		return new Map(iterable);
+	}
+}
+class snikket_HaxeKVIterator {
+	constructor(jsIterator) {
+		this.jsIterator = jsIterator;
+		this.lastStep = jsIterator.next();
+	}
+	hasNext() {
+		return !this.lastStep.done;
+	}
+	next() {
+		let v = this.lastStep.value;
+		this.lastStep = this.jsIterator.next();
+		return { key : v[0], value : v[1]};
+	}
+}
+snikket_HaxeKVIterator.__name__ = "snikket.HaxeKVIterator";
+Object.assign(snikket_HaxeKVIterator.prototype, {
+	__class__: snikket_HaxeKVIterator
+});
+var snikket_MessageStanza = $hxEnums["snikket.MessageStanza"] = { __ename__:true,__constructs__:null
+	,ErrorMessageStanza: ($_=function(stanza) { return {_hx_index:0,stanza:stanza,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="ErrorMessageStanza",$_.__params__ = ["stanza"],$_)
+	,ChatMessageStanza: ($_=function(message) { return {_hx_index:1,message:message,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="ChatMessageStanza",$_.__params__ = ["message"],$_)
+	,ModerateMessageStanza: ($_=function(action) { return {_hx_index:2,action:action,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="ModerateMessageStanza",$_.__params__ = ["action"],$_)
+	,ReactionUpdateStanza: ($_=function(update) { return {_hx_index:3,update:update,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="ReactionUpdateStanza",$_.__params__ = ["update"],$_)
+	,UnknownMessageStanza: ($_=function(stanza) { return {_hx_index:4,stanza:stanza,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="UnknownMessageStanza",$_.__params__ = ["stanza"],$_)
+};
+snikket_MessageStanza.__constructs__ = [snikket_MessageStanza.ErrorMessageStanza,snikket_MessageStanza.ChatMessageStanza,snikket_MessageStanza.ModerateMessageStanza,snikket_MessageStanza.ReactionUpdateStanza,snikket_MessageStanza.UnknownMessageStanza];
+class snikket_Message {
+	constructor(chatId,senderId,threadId,parsed) {
+		this.chatId = chatId;
+		this.senderId = senderId;
+		this.threadId = threadId;
+		this.parsed = parsed;
+	}
+	static fromStanza(stanza,localJid,addContext) {
+		let fromAttr = stanza.attr["from"];
+		let from = fromAttr == null ? localJid.domain : fromAttr;
+		if(stanza.attr["type"] == "error") {
+			return new snikket_Message(from,from,null,snikket_MessageStanza.ErrorMessageStanza(stanza));
+		}
+		let msg = new snikket_ChatMessageBuilder();
+		msg.stanza = stanza;
+		msg.timestamp = stanza.findText("{urn:xmpp:delay}delay@stamp");
+		msg.threadId = stanza.getChildText("thread");
+		msg.lang = stanza.attr["xml:lang"];
+		msg.text = stanza.getChildText("body");
+		if(msg.text != null && (msg.lang == null || msg.lang == "")) {
+			let tmp = stanza.getChild("body");
+			msg.lang = tmp != null ? tmp.attr["xml:lang"] : null;
+		}
+		msg.from = snikket_JID.parse(from);
+		let isGroupchat = stanza.attr["type"] == "groupchat";
+		msg.type = isGroupchat ? 2 : 0;
+		let tmp;
+		if(isGroupchat) {
+			tmp = msg.from;
+		} else {
+			let tmp1 = msg.from;
+			tmp = tmp1 != null ? tmp1.asBare() : null;
+		}
+		msg.senderId = tmp != null ? tmp.asString() : null;
+		let localJidBare = localJid.asBare();
+		let domain = localJid.domain;
+		let to = stanza.attr["to"];
+		msg.to = to == null ? localJid : snikket_JID.parse(to);
+		if(msg.from != null && msg.from.equals(localJidBare)) {
+			let carbon = stanza.getChild("received","urn:xmpp:carbons:2");
+			if(carbon == null) {
+				carbon = stanza.getChild("sent","urn:xmpp:carbons:2");
+			}
+			if(carbon != null) {
+				let fwd = carbon.getChild("forwarded","urn:xmpp:forward:0");
+				if(fwd != null) {
+					return snikket_Message.fromStanza(fwd.getFirstChild(),localJid);
+				}
+			}
+		}
+		let localId = stanza.attr["id"];
+		if(localId != null) {
+			msg.localId = localId;
+		}
+		let altServerId = null;
+		let _g = 0;
+		let _g1 = stanza.allTags("stanza-id","urn:xmpp:sid:0");
+		while(_g < _g1.length) {
+			let stanzaId = _g1[_g];
+			++_g;
+			let id = stanzaId.attr["id"];
+			if((stanzaId.attr["by"] == domain || stanzaId.attr["by"] == localJidBare.asString()) && id != null) {
+				msg.serverIdBy = localJidBare.asString();
+				msg.serverId = id;
+				break;
+			}
+			altServerId = stanzaId;
+		}
+		if(msg.serverId == null && altServerId != null && stanza.attr["type"] != "error") {
+			let id = altServerId.attr["id"];
+			if(id != null) {
+				msg.serverId = id;
+				msg.serverIdBy = altServerId.attr["by"];
+			}
+		}
+		if(msg.serverIdBy != null && msg.serverIdBy != localJid.asBare().asString()) {
+			msg.replyId = msg.serverId;
+		} else if(msg.serverIdBy == localJid.asBare().asString()) {
+			msg.replyId = msg.localId;
+		}
+		msg.direction = msg.to == null || msg.to.asBare().equals(localJidBare) ? 0 : 1;
+		if(msg.from != null && msg.from.asBare().equals(localJidBare)) {
+			msg.direction = 1;
+		}
+		msg.status = msg.direction == 0 ? 2 : 1;
+		let recipients = new Map([]);
+		let replyTo = new Map([]);
+		if(msg.to != null) {
+			let k = msg.to.asBare().asString();
+			recipients.set(k,true);
+		}
+		let from1 = msg.from;
+		if(msg.direction == 0 && from1 != null) {
+			let k = isGroupchat ? from1.asBare().asString() : from1.asString();
+			replyTo.set(k,true);
+		} else if(msg.to != null) {
+			let k = msg.to.asString();
+			replyTo.set(k,true);
+		}
+		let addresses = stanza.getChild("addresses","http://jabber.org/protocol/address");
+		let anyExtendedReplyTo = false;
+		if(addresses != null) {
+			let _g = 0;
+			let _g1 = addresses.allTags("address");
+			while(_g < _g1.length) {
+				let address = _g1[_g];
+				++_g;
+				let jid = address.attr["jid"];
+				if(address.attr["type"] == "noreply") {
+					replyTo.clear();
+				} else if(jid == null) {
+					haxe_Log.trace("No support for addressing to non-jid",{ fileName : "snikket/Message.hx", lineNumber : 128, className : "snikket.Message", methodName : "fromStanza", customParams : [address]});
+					return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.UnknownMessageStanza(stanza));
+				} else if(address.attr["type"] == "to" || address.attr["type"] == "cc") {
+					let k = snikket_JID.parse(jid).asBare().asString();
+					recipients.set(k,true);
+					if(!anyExtendedReplyTo) {
+						let k = snikket_JID.parse(jid).asString();
+						replyTo.set(k,true);
+					}
+				} else if(address.attr["type"] == "replyto" || address.attr["type"] == "replyroom") {
+					if(!anyExtendedReplyTo) {
+						replyTo.clear();
+						anyExtendedReplyTo = true;
+					}
+					let k = snikket_JID.parse(jid).asString();
+					replyTo.set(k,true);
+				} else if(address.attr["type"] == "ofrom") {
+					let tmp = msg.from;
+					let tmp1 = tmp != null ? tmp.domain : null;
+					if(snikket_JID.parse(jid).domain == tmp1) {
+						msg.senderId = snikket_JID.parse(jid).asBare().asString();
+					}
+				}
+			}
+		}
+		let _g2 = [];
+		let inlobj_iterator = function() {
+			return new js_lib_HaxeIterator(recipients.keys());
+		};
+		let x = inlobj_iterator();
+		while(x.hasNext()) {
+			let x1 = x.next();
+			_g2.push(snikket_JID.parse(x1));
+		}
+		msg.recipients = _g2;
+		msg.recipients.sort(function(x,y) {
+			return Reflect.compare(x.asString(),y.asString());
+		});
+		let _g3 = [];
+		let inlobj_iterator1 = function() {
+			return new js_lib_HaxeIterator(replyTo.keys());
+		};
+		let x1 = inlobj_iterator1();
+		while(x1.hasNext()) {
+			let x = x1.next();
+			_g3.push(snikket_JID.parse(x));
+		}
+		msg.replyTo = _g3;
+		msg.replyTo.sort(function(x,y) {
+			return Reflect.compare(x.asString(),y.asString());
+		});
+		let msgFrom = msg.from;
+		if(msg.direction == 0 && msgFrom != null && Lambda.find(msg.replyTo,function(r) {
+			return r.asBare().equals(msgFrom.asBare());
+		}) == null) {
+			haxe_Log.trace("Don't know what chat message without from in replyTo belongs in",{ fileName : "snikket/Message.hx", lineNumber : 155, className : "snikket.Message", methodName : "fromStanza", customParams : [stanza]});
+			return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.UnknownMessageStanza(stanza));
+		}
+		if(addContext != null) {
+			msg = addContext(msg,stanza);
+		}
+		let tmp1 = msg.timestamp;
+		let timestamp = tmp1 != null ? tmp1 : snikket_Date.format(new Date());
+		msg.timestamp = timestamp;
+		let reactionsEl = stanza.getChild("reactions","urn:xmpp:reactions:0");
+		if(reactionsEl != null) {
+			let _this = reactionsEl.allTags("reaction");
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].getText();
+			}
+			let reactions = result;
+			let reactionId = reactionsEl.attr["id"];
+			if(reactionId != null) {
+				let tmp = msg.chatId();
+				let tmp1 = msg.get_senderId();
+				let msg1 = msg.threadId;
+				let tmp2 = stanza.attr["id"];
+				let tmp3 = tmp2 != null ? tmp2 : snikket_ID.long();
+				let tmp4 = isGroupchat ? reactionId : null;
+				let tmp5 = isGroupchat ? msg.chatId() : null;
+				let tmp6 = isGroupchat ? null : reactionId;
+				let tmp7 = msg.chatId();
+				let tmp8 = msg.get_senderId();
+				let result = new Array(reactions.length);
+				let _g = 0;
+				let _g1 = reactions.length;
+				while(_g < _g1) {
+					let i = _g++;
+					result[i] = new snikket_Reaction(msg.get_senderId(),timestamp,reactions[i],msg.localId);
+				}
+				return new snikket_Message(tmp,tmp1,msg1,snikket_MessageStanza.ReactionUpdateStanza(new snikket_ReactionUpdate(tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,timestamp,result,0)));
+			}
+		}
+		let _g4 = 0;
+		let _g5 = stanza.allTags("reference","urn:xmpp:reference:0");
+		while(_g4 < _g5.length) {
+			let ref = _g5[_g4];
+			++_g4;
+			if(ref.attr["begin"] == null && ref.attr["end"] == null) {
+				let sims = ref.getChild("media-sharing","urn:xmpp:sims:1");
+				if(sims != null) {
+					msg.attachSims(sims);
+				}
+			}
+		}
+		let _g6 = 0;
+		let _g7 = stanza.allTags("media-sharing","urn:xmpp:sims:1");
+		while(_g6 < _g7.length) {
+			let sims = _g7[_g6];
+			++_g6;
+			msg.attachSims(sims);
+		}
+		let jmi = stanza.getChild(null,"urn:xmpp:jingle-message:0");
+		if(jmi != null) {
+			msg.type = 1;
+			msg.payloads.push(jmi);
+			if(msg.text == null) {
+				msg.text = "call " + jmi.name;
+			}
+			if(jmi.name != "propose") {
+				msg.versions = [msg.build()];
+			}
+			msg.localId = jmi.attr["id"];
+		}
+		let retract = stanza.getChild("replace","urn:xmpp:message-retract:1");
+		let fasten = stanza.getChild("apply-to","urn:xmpp:fasten:0");
+		let tmp2 = retract != null ? retract.getChild("moderated","urn:xmpp:message-retract:1") : null;
+		let moderated = tmp2 != null ? tmp2 : fasten != null ? fasten.getChild("moderated","urn:xmpp:message-moderate:0") : null;
+		let moderateServerId;
+		let tmp3 = retract != null ? retract.attr : null;
+		let tmp4 = tmp3 != null ? tmp3["id"] : null;
+		if(tmp4 != null) {
+			moderateServerId = tmp4;
+		} else {
+			let tmp = fasten != null ? fasten.attr : null;
+			moderateServerId = tmp != null ? tmp["id"] : null;
+		}
+		if(moderated != null && moderateServerId != null && isGroupchat && msg.from != null && msg.from.isBare() && msg.from.asString() == msg.chatId()) {
+			let tmp = retract != null ? retract.getChildText("reason") : null;
+			let reason = tmp != null ? tmp : moderated != null ? moderated.getChildText("reason") : null;
+			let by = moderated.attr["by"];
+			return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.ModerateMessageStanza(new snikket_ModerationAction(msg.chatId(),moderateServerId,timestamp,by,reason)));
+		}
+		let replace = stanza.getChild("replace","urn:xmpp:message-correct:0");
+		let tmp5 = replace != null ? replace.attr : null;
+		let replaceId = tmp5 != null ? tmp5["id"] : null;
+		if(msg.text == null && msg.attachments.length < 1 && replaceId == null) {
+			return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.UnknownMessageStanza(stanza));
+		}
+		let _g8 = 0;
+		let _g9 = stanza.allTags("fallback","urn:xmpp:fallback:0");
+		while(_g8 < _g9.length) {
+			let fallback = _g9[_g8];
+			++_g8;
+			msg.payloads.push(fallback);
+		}
+		let unstyled = stanza.getChild("unstyled","urn:xmpp:styling:0");
+		if(unstyled != null) {
+			msg.payloads.push(unstyled);
+		}
+		let html = stanza.getChild("html","http://jabber.org/protocol/xhtml-im");
+		if(html != null) {
+			msg.payloads.push(html);
+		}
+		let reply = stanza.getChild("reply","urn:xmpp:reply:0");
+		if(reply != null) {
+			let replyToJid = reply.attr["to"];
+			let replyToID = reply.attr["id"];
+			let text = msg.text;
+			if(text != null && snikket_EmojiUtil.isOnlyEmoji(StringTools.trim(text))) {
+				let tmp = msg.chatId();
+				let tmp1 = msg.get_senderId();
+				let msg1 = msg.threadId;
+				let tmp2 = stanza.attr["id"];
+				let tmp3 = tmp2 != null ? tmp2 : snikket_ID.long();
+				let tmp4 = isGroupchat ? msg.chatId() : null;
+				let tmp5 = msg.chatId();
+				let tmp6 = msg.get_senderId();
+				return new snikket_Message(tmp,tmp1,msg1,snikket_MessageStanza.ReactionUpdateStanza(new snikket_ReactionUpdate(tmp3,isGroupchat ? replyToID : null,tmp4,isGroupchat ? null : replyToID,tmp5,tmp6,timestamp,[new snikket_Reaction(msg.get_senderId(),timestamp,StringTools.trim(text),msg.localId)],1)));
+			}
+			if(html != null) {
+				let body = html.getChild("body","http://www.w3.org/1999/xhtml");
+				if(body != null) {
+					let els = body.allTags();
+					if(els.length == 1 && els[0].name == "img") {
+						let tmp = els[0].attr["src"];
+						let hash = snikket_Hash.fromUri(tmp != null ? tmp : "");
+						if(hash != null) {
+							let tmp = msg.chatId();
+							let tmp1 = msg.get_senderId();
+							let msg1 = msg.threadId;
+							let tmp2 = stanza.attr["id"];
+							let tmp3 = tmp2 != null ? tmp2 : snikket_ID.long();
+							let tmp4 = isGroupchat ? msg.chatId() : null;
+							let tmp5 = msg.chatId();
+							let tmp6 = msg.get_senderId();
+							let tmp7 = msg.get_senderId();
+							let tmp8 = els[0].attr["alt"];
+							return new snikket_Message(tmp,tmp1,msg1,snikket_MessageStanza.ReactionUpdateStanza(new snikket_ReactionUpdate(tmp3,isGroupchat ? replyToID : null,tmp4,isGroupchat ? null : replyToID,tmp5,tmp6,timestamp,[new snikket_CustomEmojiReaction(tmp7,timestamp,tmp8 != null ? tmp8 : "",hash.serializeUri(),msg.localId)],1)));
+						}
+					}
+				}
+			}
+			if(replyToID != null) {
+				let replyToMessage = new snikket_ChatMessageBuilder();
+				replyToMessage.to = replyToJid == msg.get_senderId() ? msg.to : msg.from;
+				replyToMessage.from = replyToJid == null ? null : snikket_JID.parse(replyToJid);
+				let tmp = replyToMessage.from;
+				replyToMessage.senderId = tmp != null ? tmp.asString() : null;
+				replyToMessage.replyId = replyToID;
+				if(msg.serverIdBy != null && msg.serverIdBy != localJid.asBare().asString()) {
+					replyToMessage.serverId = replyToID;
+				} else {
+					replyToMessage.localId = replyToID;
+				}
+				msg.replyToMessage = replyToMessage.build();
+			}
+		}
+		if(replaceId != null) {
+			msg.versions = [msg.build()];
+			msg.localId = replaceId;
+		}
+		return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.ChatMessageStanza(msg.build()));
+	}
+}
+snikket_Message.__name__ = "snikket.Message";
+Object.assign(snikket_Message.prototype, {
+	__class__: snikket_Message
+});
+class snikket_MessageSync {
+	constructor(client,stream,filter,serviceJID) {
+		this.jmi = new Map([]);
+		this.newestPageFirst = true;
+		this.complete = false;
+		this.progress = 0;
+		this.contextHandler = function(b,_) {
+			return b;
+		};
+		this.client = client;
+		this.stream = stream;
+		this.filter = Reflect.copy(filter);
+		this.serviceJID = serviceJID != null ? serviceJID : client.accountId();
+	}
+	fetchNext() {
+		if(this.handler == null) {
+			throw new haxe_Exception("Attempt to fetch messages, but no handler has been set");
+		}
+		if(this.complete) {
+			throw new haxe_Exception("Attempt to fetch messages, but already complete");
+		}
+		let messages = [];
+		if(this.lastPage == null) {
+			if(this.newestPageFirst == true && (this.filter.page == null || this.filter.page.before == null && this.filter.page.after == null)) {
+				if(this.filter.page == null) {
+					this.filter.page = { };
+				}
+				this.filter.page.before = "";
+			}
+		} else {
+			if(this.filter.page == null) {
+				this.filter.page = { };
+			}
+			if(this.newestPageFirst == true) {
+				this.filter.page.before = this.lastPage.first;
+			} else {
+				this.filter.page.after = this.lastPage.last;
+			}
+		}
+		let query = new snikket_queries_MAMQuery(this.filter,this.serviceJID);
+		let _gthis = this;
+		let resultHandler = this.stream.on("message",function(event) {
+			_gthis.progress++;
+			let message = event.stanza;
+			let from = Object.prototype.hasOwnProperty.call(message.attr,"from") ? message.attr["from"] : _gthis.client.accountId();
+			if(from != _gthis.serviceJID) {
+				return snikket_EventResult.EventUnhandled;
+			}
+			let result = message.getChild("result",query.xmlns);
+			if(result == null || result.attr["queryid"] != query.queryId) {
+				return snikket_EventResult.EventUnhandled;
+			}
+			let originalMessage = result.findChild("{urn:xmpp:forward:0}forwarded/{jabber:client}message");
+			if(originalMessage == null) {
+				return snikket_EventResult.EventHandled;
+			}
+			let timestamp = result.findText("{urn:xmpp:forward:0}forwarded/{urn:xmpp:delay}delay@stamp");
+			let jmiChildren = originalMessage.allTags(null,"urn:xmpp:jingle-message:0");
+			if(jmiChildren.length > 0) {
+				_gthis.jmi.set(jmiChildren[0].attr["id"],originalMessage);
+			}
+			let msg = snikket_Message.fromStanza(originalMessage,_gthis.client.jid,function(builder,stanza) {
+				builder.serverId = result.attr["id"];
+				builder.serverIdBy = _gthis.serviceJID;
+				if(timestamp != null && builder.timestamp == null) {
+					builder.timestamp = timestamp;
+				}
+				return _gthis.contextHandler(builder,stanza);
+			}).parsed;
+			messages.push(msg);
+			return snikket_EventResult.EventHandled;
+		});
+		query.onFinished(function() {
+			resultHandler.unsubscribe();
+			let result = query.getResult();
+			if(result == null) {
+				haxe_Log.trace("Error from MAM, stopping sync",{ fileName : "snikket/MessageSync.hx", lineNumber : 101, className : "snikket.MessageSync", methodName : "fetchNext"});
+				_gthis.complete = true;
+				if(_gthis.errorHandler != null) {
+					_gthis.errorHandler(query.responseStanza);
+				}
+			} else {
+				_gthis.complete = result.complete;
+				_gthis.lastPage = result.page;
+			}
+			if(result != null || _gthis.errorHandler == null) {
+				_gthis.handler({ sync : _gthis, messages : messages});
+			}
+		});
+		this.client.sendQuery(query);
+	}
+	hasMore() {
+		return !this.complete;
+	}
+	addContext(handler) {
+		this.contextHandler = handler;
+	}
+	onMessages(handler) {
+		this.handler = handler;
+	}
+	onError(handler) {
+		this.errorHandler = handler;
+	}
+	setNewestPageFirst(newestPageFirst) {
+		this.newestPageFirst = newestPageFirst;
+	}
+}
+snikket_MessageSync.__name__ = "snikket.MessageSync";
+Object.assign(snikket_MessageSync.prototype, {
+	__class__: snikket_MessageSync
+});
+class snikket_ModerationAction {
+	constructor(chatId,moderateServerId,timestamp,moderatorId,reason) {
+		this.chatId = chatId;
+		this.moderateServerId = moderateServerId;
+		this.timestamp = timestamp;
+		this.moderatorId = moderatorId;
+		this.reason = reason;
+	}
+}
+snikket_ModerationAction.__name__ = "snikket.ModerationAction";
+Object.assign(snikket_ModerationAction.prototype, {
+	__class__: snikket_ModerationAction
+});
+class snikket_Notification {
+	constructor(title,body,accountId,chatId,messageId,type,callStatus,callSid,imageUri,lang,timestamp) {
+		this.title = title;
+		this.body = body;
+		this.accountId = accountId;
+		this.chatId = chatId;
+		this.messageId = messageId;
+		this.type = type;
+		this.callStatus = callStatus;
+		this.callSid = callSid;
+		this.imageUri = imageUri;
+		this.lang = lang;
+		this.timestamp = timestamp;
+	}
+	static fromChatMessage(m) {
+		let imageUri = null;
+		let attachment = m.attachments[0];
+		if(attachment != null) {
+			imageUri = attachment.uris[0];
+		}
+		return new snikket_Notification(m.type == 1 ? "Incoming Call" : "New Message",m.text,m.account(),m.chatId(),m.serverId,m.type,m.callStatus(),m.callSid(),imageUri,m.lang,m.timestamp);
+	}
+	static fromThinStanza(stanza) {
+		return new snikket_Notification("New Message","",snikket_JID.parse(stanza.attr["to"]).asBare().asString(),snikket_JID.parse(stanza.attr["from"]).asBare().asString(),stanza.getChildText("stanza-id","urn:xmpp:sid:0"),0,null,null,null,null,null);
+	}
+}
+$hx_exports["snikket"]["Notification"] = snikket_Notification;
+snikket_Notification.__name__ = "snikket.Notification";
+Object.assign(snikket_Notification.prototype, {
+	__class__: snikket_Notification
+});
+class snikket_Participant {
+	constructor(displayName,photoUri,placeholderUri,isSelf) {
+		this.displayName = displayName;
+		this.photoUri = photoUri;
+		this.placeholderUri = placeholderUri;
+		this.isSelf = isSelf;
+	}
+}
+$hx_exports["snikket"]["Participant"] = snikket_Participant;
+snikket_Participant.__name__ = "snikket.Participant";
+Object.assign(snikket_Participant.prototype, {
+	__class__: snikket_Participant
+});
+class snikket_Persistence {
+}
+snikket_Persistence.__name__ = "snikket.Persistence";
+snikket_Persistence.__isInterface__ = true;
+Object.assign(snikket_Persistence.prototype, {
+	__class__: snikket_Persistence
+});
+class snikket_Presence {
+	constructor(caps,mucUser) {
+		this.caps = caps;
+		this.mucUser = mucUser;
+	}
+}
+$hx_exports["snikket"]["Presence"] = snikket_Presence;
+snikket_Presence.__name__ = "snikket.Presence";
+Object.assign(snikket_Presence.prototype, {
+	__class__: snikket_Presence
+});
+class snikket_PubsubEvent {
+	constructor(from,to,node,items) {
+		this.from = from;
+		this.to = to;
+		this.node = node;
+		this.items = items;
+	}
+	getFrom() {
+		return this.from;
+	}
+	getNode() {
+		return this.node;
+	}
+	getItems() {
+		return this.items;
+	}
+	static fromStanza(stanza) {
+		let event = stanza.getChild("event","http://jabber.org/protocol/pubsub#event");
+		if(event == null) {
+			return null;
+		}
+		let items = event.getChild("items");
+		if(items == null) {
+			return null;
+		}
+		return new snikket_PubsubEvent(stanza.attr["from"],stanza.attr["to"],items.attr["node"],items.allTags("item"));
+	}
+}
+snikket_PubsubEvent.__name__ = "snikket.PubsubEvent";
+Object.assign(snikket_PubsubEvent.prototype, {
+	__class__: snikket_PubsubEvent
+});
+function snikket_Push_receive(data,persistence) {
+	let stanza = snikket_Stanza.parse(data);
+	if(stanza == null) {
+		return null;
+	}
+	if(stanza.name == "envelope" && stanza.attr["xmlns"] == "urn:xmpp:sce:1") {
+		stanza = stanza.getChild("content").getFirstChild();
+	}
+	if(stanza.name == "forwarded" && stanza.attr["xmlns"] == "urn:xmpp:forward:0") {
+		stanza = stanza.getChild("message","jabber:client");
+	}
+	if(stanza.attr["to"] == null) {
+		return null;
+	}
+	let message = snikket_ChatMessage.fromStanza(stanza,snikket_JID.parse(stanza.attr["to"]).asBare());
+	if(message != null) {
+		return snikket_Notification.fromChatMessage(message);
+	} else {
+		return snikket_Notification.fromThinStanza(stanza);
+	}
+}
+$hx_exports["snikket"]["Push"]["receive"] = snikket_Push_receive;
+class snikket_Reaction {
+	constructor(senderId,timestamp,text,envelopeId,key) {
+		this.senderId = senderId;
+		this.timestamp = timestamp;
+		this.text = StringTools.replace(text,"️","");
+		this.envelopeId = envelopeId;
+		let tmp = key;
+		this.key = tmp != null ? tmp : this.text;
+	}
+	render(forText,forImage) {
+		return forText(this.text + "️");
+	}
+}
+$hx_exports["snikket"]["Reaction"] = snikket_Reaction;
+snikket_Reaction.__name__ = "snikket.Reaction";
+Object.assign(snikket_Reaction.prototype, {
+	__class__: snikket_Reaction
+});
+class snikket_CustomEmojiReaction extends snikket_Reaction {
+	constructor(senderId,timestamp,text,uri,envelopeId) {
+		super(senderId,timestamp,text,envelopeId,uri);
+		this.uri = uri;
+	}
+	render(forText,forImage) {
+		let hash = snikket_Hash.fromUri(this.uri);
+		let tmp = this.text;
+		let tmp1 = hash != null ? hash.toUri() : null;
+		return forImage(tmp,tmp1 != null ? tmp1 : this.uri);
+	}
+}
+$hx_exports["snikket"]["CustomEmojiReaction"] = snikket_CustomEmojiReaction;
+snikket_CustomEmojiReaction.__name__ = "snikket.CustomEmojiReaction";
+snikket_CustomEmojiReaction.__super__ = snikket_Reaction;
+Object.assign(snikket_CustomEmojiReaction.prototype, {
+	__class__: snikket_CustomEmojiReaction
+});
+class snikket_ReactionUpdate {
+	constructor(updateId,serverId,serverIdBy,localId,chatId,senderId,timestamp,reactions,kind) {
+		if(serverId == null && localId == null) {
+			throw haxe_Exception.thrown("ReactionUpdate serverId and localId cannot both be null");
+		}
+		if(serverId != null && serverIdBy == null) {
+			throw haxe_Exception.thrown("serverId requires serverIdBy");
+		}
+		this.updateId = updateId;
+		this.serverId = serverId;
+		this.serverIdBy = serverIdBy;
+		this.localId = localId;
+		this.chatId = chatId;
+		this.senderId = senderId;
+		this.timestamp = timestamp;
+		this.reactions = reactions;
+		this.kind = kind;
+	}
+	getReactions(existingReactions) {
+		if(this.kind == 1) {
+			let set = new Map([]);
+			let list = [];
+			let _g = 0;
+			let tmp = existingReactions;
+			let _g1 = tmp != null ? tmp : [];
+			while(_g < _g1.length) {
+				let r = _g1[_g];
+				++_g;
+				if(!set.has(r.key)) {
+					list.push(r);
+				}
+				set.set(r.key,true);
+			}
+			let _g2 = 0;
+			let _g3 = this.reactions;
+			while(_g2 < _g3.length) {
+				let r = _g3[_g2];
+				++_g2;
+				if(!set.has(r.key)) {
+					list.push(r);
+				}
+				set.set(r.key,true);
+			}
+			return list;
+		} else if(this.kind == 0) {
+			let list = Lambda.array(this.reactions);
+			let _g = 0;
+			let tmp = existingReactions;
+			let _g1 = tmp != null ? tmp : [];
+			while(_g < _g1.length) {
+				let r = _g1[_g];
+				++_g;
+				let custom = snikket_Util_downcast(r,snikket_CustomEmojiReaction);
+				if(custom != null) {
+					list.push(custom);
+				}
+			}
+			return list;
+		} else if(this.kind == 2) {
+			return this.reactions;
+		}
+		throw haxe_Exception.thrown("Unknown kind of reaction update");
+	}
+	inlineHashReferences() {
+		let hashes = [];
+		let _g = 0;
+		let _g1 = this.reactions;
+		while(_g < _g1.length) {
+			let r = _g1[_g];
+			++_g;
+			let custom = snikket_Util_downcast(r,snikket_CustomEmojiReaction);
+			if(custom != null) {
+				let hash = snikket_Hash.fromUri(custom.uri);
+				if(hash != null) {
+					hashes.push(hash);
+				}
+			}
+		}
+		return hashes;
+	}
+	asStanza() {
+		if(this.kind != 0) {
+			throw haxe_Exception.thrown("Cannot make a reaction XEP stanza for this kind");
+		}
+		let attrs = { type : this.serverId == null ? "chat" : "groupchat", id : this.updateId};
+		let stanza = new snikket_Stanza("message",attrs);
+		let tmp = this.localId;
+		stanza.tag("reactions",{ xmlns : "urn:xmpp:reactions:0", id : tmp != null ? tmp : this.serverId});
+		let _g = 0;
+		let _g1 = this.reactions;
+		while(_g < _g1.length) {
+			let reaction = _g1[_g];
+			++_g;
+			if(!((reaction) instanceof snikket_CustomEmojiReaction)) {
+				stanza.textTag("reaction",reaction.text);
+			}
+		}
+		stanza.up();
+		return stanza;
+	}
+}
+$hx_exports["snikket"]["ReactionUpdate"] = snikket_ReactionUpdate;
+snikket_ReactionUpdate.__name__ = "snikket.ReactionUpdate";
+Object.assign(snikket_ReactionUpdate.prototype, {
+	__class__: snikket_ReactionUpdate
+});
+var snikket_Node = $hxEnums["snikket.Node"] = { __ename__:true,__constructs__:null
+	,Element: ($_=function(stanza) { return {_hx_index:0,stanza:stanza,__enum__:"snikket.Node",toString:$estr}; },$_._hx_name="Element",$_.__params__ = ["stanza"],$_)
+	,CData: ($_=function(textNode) { return {_hx_index:1,textNode:textNode,__enum__:"snikket.Node",toString:$estr}; },$_._hx_name="CData",$_.__params__ = ["textNode"],$_)
+};
+snikket_Node.__constructs__ = [snikket_Node.Element,snikket_Node.CData];
+class snikket__$Stanza_NodeInterface {
+}
+snikket__$Stanza_NodeInterface.__name__ = "snikket._Stanza.NodeInterface";
+snikket__$Stanza_NodeInterface.__isInterface__ = true;
+Object.assign(snikket__$Stanza_NodeInterface.prototype, {
+	__class__: snikket__$Stanza_NodeInterface
+});
+class snikket_TextNode {
+	constructor(content) {
+		this.content = "";
+		this.content = content;
+	}
+	serialize() {
+		return snikket_Util_xmlEscape(this.content);
+	}
+	clone() {
+		return new snikket_TextNode(this.content);
+	}
+	traverse(f) {
+		return this;
+	}
+}
+snikket_TextNode.__name__ = "snikket.TextNode";
+snikket_TextNode.__interfaces__ = [snikket__$Stanza_NodeInterface];
+Object.assign(snikket_TextNode.prototype, {
+	__class__: snikket_TextNode
+});
+class snikket_StanzaError {
+	constructor(type_,condition_,text_) {
+		this.type = type_;
+		this.condition = condition_;
+		this.text = text_;
+	}
+}
+snikket_StanzaError.__name__ = "snikket.StanzaError";
+Object.assign(snikket_StanzaError.prototype, {
+	__class__: snikket_StanzaError
+});
+class snikket_Stanza {
+	constructor(name,attr) {
+		this.last_added_stack = [];
+		this.children = [];
+		this.attr = { };
+		this.name = null;
+		this.name = name;
+		if(attr != null) {
+			this.attr = attr;
+		}
+		this.last_added = this;
+	}
+	serialize() {
+		let el = Xml.createElement(this.name);
+		let _g = 0;
+		let _g1 = Reflect.fields(this.attr);
+		while(_g < _g1.length) {
+			let attr_k = _g1[_g];
+			++_g;
+			el.set(attr_k,this.attr[attr_k]);
+		}
+		if(this.children.length == 0) {
+			return haxe_xml_Printer.print(el);
+		}
+		let serialized = haxe_xml_Printer.print(el);
+		let buffer = [serialized.substring(0,serialized.length - 2) + ">"];
+		let _g2 = 0;
+		let _g3 = this.children;
+		while(_g2 < _g3.length) {
+			let child = _g3[_g2];
+			++_g2;
+			let tmp;
+			switch(child._hx_index) {
+			case 0:
+				let c = child.stanza;
+				tmp = c.serialize();
+				break;
+			case 1:
+				let c1 = child.textNode;
+				tmp = c1.serialize();
+				break;
+			}
+			buffer.push(tmp);
+		}
+		buffer.push("</" + this.name + ">");
+		return buffer.join("");
+	}
+	toString() {
+		return this.serialize();
+	}
+	tag(name,attr) {
+		let child = new snikket_Stanza(name,attr);
+		this.last_added.addDirectChild(snikket_Node.Element(child));
+		this.last_added_stack.push(this.last_added);
+		this.last_added = child;
+		return this;
+	}
+	text(content) {
+		this.last_added.addDirectChild(snikket_Node.CData(new snikket_TextNode(content)));
+		return this;
+	}
+	textTag(tagName,textContent,attr) {
+		let tmp = attr;
+		this.last_added.addDirectChild(snikket_Node.Element(new snikket_Stanza(tagName,tmp != null ? tmp : { }).text(textContent)));
+		return this;
+	}
+	up() {
+		if(this.last_added != this) {
+			this.last_added = this.last_added_stack.pop();
+		}
+		return this;
+	}
+	reset() {
+		this.last_added = this;
+		return this;
+	}
+	addChildren(children) {
+		let child = $getIterator(children);
+		while(child.hasNext()) {
+			let child1 = child.next();
+			this.addChild(child1);
+		}
+		return this;
+	}
+	addChildNodes(children) {
+		let child = $getIterator(children);
+		while(child.hasNext()) {
+			let child1 = child.next();
+			this.addDirectChild(child1);
+		}
+		return this;
+	}
+	addChild(stanza) {
+		this.last_added.children.push(snikket_Node.Element(stanza));
+		return this;
+	}
+	addDirectChild(child) {
+		this.children.push(child);
+		return this;
+	}
+	clone() {
+		let clone = new snikket_Stanza(this.name,this.attr);
+		let _g = 0;
+		let _g1 = this.children;
+		while(_g < _g1.length) {
+			let child = _g1[_g];
+			++_g;
+			let tmp;
+			switch(child._hx_index) {
+			case 0:
+				let c = child.stanza;
+				tmp = snikket_Node.Element(c.clone());
+				break;
+			case 1:
+				let c1 = child.textNode;
+				tmp = snikket_Node.CData(c1.clone());
+				break;
+			}
+			clone.addDirectChild(tmp);
+		}
+		return clone;
+	}
+	allTags(name,xmlns) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.children;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			let tmp;
+			if(v._hx_index == 0) {
+				let _g = v.stanza;
+				tmp = true;
+			} else {
+				tmp = false;
+			}
+			if(tmp) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			let child = _this[i];
+			let tmp;
+			if(child._hx_index == 0) {
+				let c = child.stanza;
+				tmp = c;
+			} else {
+				tmp = null;
+			}
+			result[i] = tmp;
+		}
+		let tags = result;
+		if(name != null || xmlns != null) {
+			let ourXmlns = this.attr["xmlns"];
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = tags;
+			while(_g1 < _g2.length) {
+				let v = _g2[_g1];
+				++_g1;
+				let childXmlns = v.attr["xmlns"];
+				if((name == null || v.name == name) && (xmlns == null && (ourXmlns == childXmlns || childXmlns == null) || childXmlns == xmlns)) {
+					_g.push(v);
+				}
+			}
+			tags = _g;
+		}
+		return tags;
+	}
+	allText() {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.children;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			let tmp;
+			if(v._hx_index == 1) {
+				let _g = v.textNode;
+				tmp = true;
+			} else {
+				tmp = false;
+			}
+			if(tmp) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			let child = _this[i];
+			let tmp;
+			if(child._hx_index == 1) {
+				let c = child.textNode;
+				tmp = c.content;
+			} else {
+				tmp = null;
+			}
+			result[i] = tmp;
+		}
+		return result;
+	}
+	getFirstChild() {
+		return this.allTags()[0];
+	}
+	getChildren() {
+		let _this = this.children;
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let child = _this[i];
+			let tmp;
+			switch(child._hx_index) {
+			case 0:
+				let el = child.stanza;
+				tmp = el;
+				break;
+			case 1:
+				let text = child.textNode;
+				tmp = text;
+				break;
+			}
+			result[i] = tmp;
+		}
+		return result;
+	}
+	getChild(name,xmlns) {
+		let ourXmlns = this.attr["xmlns"];
+		let tags = this.allTags(name,xmlns);
+		if(tags.length == 0) {
+			return null;
+		}
+		return tags[0];
+	}
+	getChildText(name,xmlns) {
+		let child = this.getChild(name,xmlns);
+		if(child == null) {
+			return null;
+		}
+		return child.getText();
+	}
+	getText() {
+		return this.allText().join("");
+	}
+	find(path) {
+		let pos = 0;
+		let len = path.length;
+		let cursor = this;
+		do {
+			let xmlns = null;
+			let name = null;
+			let text = null;
+			let char = path.charAt(pos);
+			if(char == "@") {
+				return snikket_Node.CData(new snikket_TextNode(cursor.attr[HxOverrides.substr(path,pos + 1,null)]));
+			} else if(char == "{") {
+				xmlns = path.substring(pos + 1,path.indexOf("}",pos + 1));
+				pos += xmlns.length + 2;
+			}
+			let reName = new EReg("([^@/#]*)([/#]?)","");
+			if(!reName.matchSub(path,pos)) {
+				throw new haxe_Exception("Invalid path to Stanza.find(): " + path);
+			}
+			let name1 = reName.matched(1);
+			let text1 = reName.matched(2);
+			pos = reName.matchedPos().pos + reName.matchedPos().len;
+			if(name1 == "") {
+				name1 = null;
+			}
+			if(pos == len) {
+				if(text1 == "#") {
+					let text = cursor.getChildText(name1,xmlns);
+					if(text == null) {
+						return null;
+					}
+					return snikket_Node.CData(new snikket_TextNode(text));
+				}
+				return snikket_Node.Element(cursor.getChild(name1,xmlns));
+			}
+			cursor = cursor.getChild(name1,xmlns);
+		} while(cursor != null);
+		return null;
+	}
+	findChild(path) {
+		let result = this.find(path);
+		if(result == null) {
+			return null;
+		}
+		if(result == null) {
+			return null;
+		} else if(result._hx_index == 0) {
+			let stanza = result.stanza;
+			return stanza;
+		} else {
+			return null;
+		}
+	}
+	findText(path) {
+		let result = this.find(path);
+		if(result == null) {
+			return null;
+		}
+		if(result == null) {
+			return null;
+		} else if(result._hx_index == 1) {
+			let textNode = result.textNode;
+			return textNode.content;
+		} else {
+			return null;
+		}
+	}
+	traverse(f) {
+		if(!f(this)) {
+			let _g = 0;
+			let _g1 = this.allTags();
+			while(_g < _g1.length) {
+				let child = _g1[_g];
+				++_g;
+				child.traverse(f);
+			}
+		}
+		return this;
+	}
+	getError() {
+		let errorTag = this.getChild("error");
+		if(errorTag == null) {
+			return null;
+		}
+		let errorTag1 = errorTag.attr["type"];
+		let tmp = errorTag.getChild(null,"urn:ietf:params:xml:ns:xmpp-stanzas");
+		return new snikket_StanzaError(errorTag1,tmp != null ? tmp.name : null,errorTag.getChildText("text","urn:ietf:params:xml:ns:xmpp-stanzas"));
+	}
+	removeChildren(name,xmlns_) {
+		let tmp = xmlns_;
+		let xmlns = tmp != null ? tmp : this.attr["xmlns"];
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.children;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			let tmp;
+			if(v._hx_index == 0) {
+				let c = v.stanza;
+				let tmp1;
+				if(name == null || c.name == name) {
+					let tmp = c.attr["xmlns"];
+					tmp1 = (tmp != null ? tmp : xmlns) == xmlns;
+				} else {
+					tmp1 = false;
+				}
+				tmp = !tmp1;
+			} else {
+				tmp = true;
+			}
+			if(tmp) {
+				_g.push(v);
+			}
+		}
+		this.children = _g;
+	}
+	static parse(s) {
+		return snikket_Stanza.fromXml(Xml.parse(s));
+	}
+	static fromXml(el) {
+		if(el.nodeType == 6) {
+			return snikket_Stanza.fromXml(el.firstElement());
+		}
+		let attrs = { };
+		let a = el.attributes();
+		while(a.hasNext()) {
+			let a1 = a.next();
+			attrs[a1] = el.get(a1);
+		}
+		if(el.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (el.nodeType == null ? "null" : XmlType.toString(el.nodeType)));
+		}
+		let stanza = new snikket_Stanza(el.nodeName,attrs);
+		if(el.nodeType != Xml.Document && el.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (el.nodeType == null ? "null" : XmlType.toString(el.nodeType)));
+		}
+		let _g_current = 0;
+		let _g_array = el.children;
+		while(_g_current < _g_array.length) {
+			let child = _g_array[_g_current++];
+			if(child.nodeType == 0) {
+				stanza.addChild(snikket_Stanza.fromXml(child));
+			} else if(!(child.nodeType == 5 || child.nodeType == 4 || child.nodeType == 3)) {
+				if(child.nodeType == Xml.Document || child.nodeType == Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, unexpected " + (child.nodeType == null ? "null" : XmlType.toString(child.nodeType)));
+				}
+				stanza.text(child.nodeValue);
+			}
+		}
+		return stanza;
+	}
+	static parseXmlBool(x) {
+		if(x != "true") {
+			return x == "1";
+		} else {
+			return true;
+		}
+	}
+}
+$hx_exports["snikket"]["Stanza"] = snikket_Stanza;
+snikket_Stanza.__name__ = "snikket.Stanza";
+snikket_Stanza.__interfaces__ = [snikket__$Stanza_NodeInterface];
+Object.assign(snikket_Stanza.prototype, {
+	__class__: snikket_Stanza
+});
+var snikket_IqRequestType = $hxEnums["snikket.IqRequestType"] = { __ename__:true,__constructs__:null
+	,Get: {_hx_name:"Get",_hx_index:0,__enum__:"snikket.IqRequestType",toString:$estr}
+	,Set: {_hx_name:"Set",_hx_index:1,__enum__:"snikket.IqRequestType",toString:$estr}
+};
+snikket_IqRequestType.__constructs__ = [snikket_IqRequestType.Get,snikket_IqRequestType.Set];
+class snikket_StringUtil {
+	static codepointArray(s) {
+		let result = [];
+		let offset = 0;
+		while(offset < s.length) {
+			let c = s.charCodeAt(offset);
+			if(c >= 55296 && c <= 56319) {
+				c = c - 55232 << 10 | s.charCodeAt(offset + 1) & 1023;
+			}
+			let c1 = c;
+			if(c1 >= 65536) {
+				result.push(HxOverrides.substr(s,offset,2));
+				++offset;
+			} else {
+				result.push(HxOverrides.substr(s,offset,1));
+			}
+			++offset;
+		}
+		return result;
+	}
+	static rawCodepointArray(s) {
+		let result = [];
+		let offset = 0;
+		while(offset < s.length) {
+			let c = s.charCodeAt(offset);
+			if(c >= 55296 && c <= 56319) {
+				c = c - 55232 << 10 | s.charCodeAt(offset + 1) & 1023;
+			}
+			let c1 = c;
+			if(c1 >= 65536) {
+				result.push(c1);
+				++offset;
+			} else {
+				result.push(c1);
+			}
+			++offset;
+		}
+		return result;
+	}
+}
+snikket_StringUtil.__name__ = "snikket.StringUtil";
+function snikket_Util_setupTrace() {
+	haxe_Log.trace = function(v,infos) {
+		if(typeof(console) != "undefined" && console.debug != null) {
+			let tmp = infos.customParams;
+			let params = tmp != null ? tmp : [];
+			infos.customParams = [];
+			let str = haxe_Log.formatOutput(v,infos);
+			let tmp1 = [str].concat(params);
+			console.debug.apply(null,tmp1);
+		} else if(typeof(console) != "undefined" && console.log != null) {
+			let str = haxe_Log.formatOutput(v,infos);
+			console.log(str);
+		}
+	};
+}
+function snikket_Util_downcast(value,c) {
+	let value1 = value;
+	return js_Boot.__downcastCheck(value1,c) ? value1 : null;
+}
+function snikket_Util_xmlEscape(s) {
+	return StringTools.replace(StringTools.replace(StringTools.replace(s,"&","&amp;"),"<","&lt;"),">","&gt;");
+}
+class snikket_Version {
+}
+$hx_exports["snikket"]["Version"] = snikket_Version;
+snikket_Version.__name__ = "snikket.Version";
+class snikket_XEP0393 {
+	static parse(styled) {
+		let blocks = [];
+		while(styled.length > 0) {
+			let result = snikket_XEP0393.parseBlock(styled);
+			styled = result.rest;
+			blocks.push(result.block);
+		}
+		return blocks;
+	}
+	static render(xhtml) {
+		if(xhtml.name == "br") {
+			return "\n";
+		}
+		if(xhtml.name == "img") {
+			let tmp = xhtml.attr["alt"];
+			if(tmp != null) {
+				return tmp;
+			} else {
+				return "";
+			}
+		}
+		let s_b = "";
+		if(xhtml.name == "pre") {
+			s_b += "\n```\n";
+		}
+		if(xhtml.name == "b" || xhtml.name == "strong") {
+			s_b += "*";
+		}
+		if(xhtml.name == "i" || xhtml.name == "em") {
+			s_b += "_";
+		}
+		if(xhtml.name == "s" || xhtml.name == "del") {
+			s_b += "~";
+		}
+		if(xhtml.name == "tt") {
+			s_b += "`";
+		}
+		let _g = 0;
+		let _g1 = xhtml.children;
+		while(_g < _g1.length) {
+			let child = _g1[_g];
+			++_g;
+			s_b += Std.string(snikket_XEP0393.renderNode(child));
+		}
+		if(xhtml.name == "b" || xhtml.name == "strong") {
+			s_b += "*";
+		}
+		if(xhtml.name == "i" || xhtml.name == "em") {
+			s_b += "_";
+		}
+		if(xhtml.name == "s" || xhtml.name == "del") {
+			s_b += "~";
+		}
+		if(xhtml.name == "tt") {
+			s_b += "`";
+		}
+		if(xhtml.name == "blockquote" || xhtml.name == "p" || xhtml.name == "div" || xhtml.name == "pre") {
+			s_b += "\n";
+		}
+		if(xhtml.name == "pre") {
+			s_b += "```\n";
+		}
+		if(xhtml.name == "blockquote") {
+			let _this_r = new RegExp("^","gm".split("u").join(""));
+			return s_b.replace(_this_r,"> ");
+		}
+		return s_b;
+	}
+	static renderNode(xhtml) {
+		switch(xhtml._hx_index) {
+		case 0:
+			let c = xhtml.stanza;
+			return snikket_XEP0393.render(c);
+		case 1:
+			let c1 = xhtml.textNode;
+			return c1.content;
+		}
+	}
+	static parseSpans(styled) {
+		let spans = [];
+		let start = 0;
+		let nextLink = null;
+		while(start < styled.length) if(StringTools.isSpace(styled,start + 1)) {
+			spans.push(snikket_Node.CData(new snikket_TextNode(HxOverrides.substr(styled,start,2))));
+			start += 2;
+		} else if(start != 0 && !StringTools.isSpace(styled,start - 1)) {
+			spans.push(snikket_Node.CData(new snikket_TextNode(styled.charAt(start))));
+			++start;
+		} else if(styled.charAt(start) == "*") {
+			let parsed = snikket_XEP0393.parseSpan("strong","*",styled,start);
+			spans.push(parsed.span);
+			start = parsed.end;
+		} else if(styled.charAt(start) == "_") {
+			let parsed = snikket_XEP0393.parseSpan("em","_",styled,start);
+			spans.push(parsed.span);
+			start = parsed.end;
+		} else if(styled.charAt(start) == "~") {
+			let parsed = snikket_XEP0393.parseSpan("s","~",styled,start);
+			spans.push(parsed.span);
+			start = parsed.end;
+		} else if(styled.charAt(start) == "`") {
+			let parsed = snikket_XEP0393.parseSpan("tt","`",styled,start);
+			spans.push(parsed.span);
+			start = parsed.end;
+		} else {
+			if(nextLink == null || start > nextLink.start) {
+				nextLink = snikket_Autolink.one(styled,start);
+			}
+			if(nextLink != null && nextLink.start == start && nextLink.span != null) {
+				spans.push(nextLink.span);
+				start = nextLink.end;
+			} else {
+				spans.push(snikket_Node.CData(new snikket_TextNode(styled.charAt(start))));
+				++start;
+			}
+		}
+		return spans;
+	}
+	static parseSpan(tagName,marker,styled,start) {
+		let end = start + 1;
+		while(end < styled.length && styled.charAt(end) != marker) {
+			if(StringTools.isSpace(styled,end)) {
+				++end;
+			}
+			++end;
+		}
+		if(end == start + 1) {
+			return { span : snikket_Node.CData(new snikket_TextNode(HxOverrides.substr(styled,start,2))), end : end + 1};
+		} else if(styled.charAt(end) != marker) {
+			return { span : snikket_Node.CData(new snikket_TextNode(HxOverrides.substr(styled,start,end - start))), end : end};
+		} else if(marker == "`") {
+			return { span : snikket_Node.Element(new snikket_Stanza(tagName).text(HxOverrides.substr(styled,start + 1,end - start - 1))), end : end + 1};
+		} else {
+			return { span : snikket_Node.Element(new snikket_Stanza(tagName).addChildNodes(snikket_XEP0393.parseSpans(HxOverrides.substr(styled,start + 1,end - start - 1)))), end : end + 1};
+		}
+	}
+	static parseBlock(styled) {
+		if(styled.charAt(0) == ">") {
+			return snikket_XEP0393.parseQuote(styled);
+		} else if(HxOverrides.substr(styled,0,3) == "```") {
+			return snikket_XEP0393.parsePreformatted(styled);
+		} else {
+			let end = 0;
+			while(end < styled.length && styled.charAt(end) != "\n") ++end;
+			if(end < styled.length && styled.charAt(end) == "\n") {
+				++end;
+			}
+			return { block : new snikket_Stanza("div").addChildNodes(snikket_XEP0393.parseSpans(HxOverrides.substr(styled,0,end))), rest : HxOverrides.substr(styled,end,null)};
+		}
+	}
+	static parseQuote(styled) {
+		let lines = [];
+		let line = "";
+		let end = 1;
+		let spaceAfter = 0;
+		while(end < styled.length) {
+			if(styled.charAt(end) != "\n" && StringTools.isSpace(styled,end)) {
+				++end;
+			}
+			while(end < styled.length && styled.charAt(end) != "\n") {
+				line += styled.charAt(end);
+				++end;
+			}
+			if(end < styled.length && styled.charAt(end) == "\n") {
+				++end;
+			}
+			lines.push(line + "\n");
+			line = "";
+			if(styled.charAt(end) == ">") {
+				++end;
+			} else {
+				break;
+			}
+		}
+		return { block : new snikket_Stanza("blockquote").addChildren(snikket_XEP0393.parse(lines.join(""))), rest : HxOverrides.substr(styled,end,null)};
+	}
+	static parsePreformatted(styled) {
+		let lines = [];
+		let line = null;
+		let end = 0;
+		while(end < styled.length) {
+			while(end < styled.length && styled.charAt(end) != "\n") {
+				if(line != null) {
+					line += styled.charAt(end);
+				}
+				++end;
+			}
+			if(end < styled.length && styled.charAt(end) == "\n") {
+				++end;
+			}
+			if(line != null) {
+				lines.push(line + "\n");
+			}
+			line = "";
+			if(HxOverrides.substr(styled,end,4) == "```\n" || HxOverrides.substr(styled,end,null) == "```") {
+				end += 4;
+				break;
+			}
+		}
+		return { block : new snikket_Stanza("pre").text(lines.join("")), rest : HxOverrides.substr(styled,end,null)};
+	}
+}
+snikket_XEP0393.__name__ = "snikket.XEP0393";
+class snikket_jingle_Group {
+	constructor(semantics,identificationTags) {
+		this.semantics = semantics;
+		this.identificationTags = identificationTags;
+	}
+	toSdp() {
+		if(this.semantics.indexOf(" ") >= 0) {
+			throw haxe_Exception.thrown("Group semantics cannot contain a space in SDP");
+		}
+		return this.semantics + " " + this.identificationTags.join(" ");
+	}
+	toElement() {
+		let group = new snikket_Stanza("group",{ xmlns : "urn:xmpp:jingle:apps:grouping:0", semantics : this.semantics});
+		let _g = 0;
+		let _g1 = this.identificationTags;
+		while(_g < _g1.length) {
+			let tag = _g1[_g];
+			++_g;
+			group.tag("content",{ name : tag}).up();
+		}
+		return group;
+	}
+	static parse(input) {
+		let segments = input.split(" ");
+		if(segments.length < 2) {
+			return null;
+		}
+		return new snikket_jingle_Group(segments[0],segments.slice(1));
+	}
+	static fromElement(el) {
+		let idTags = [];
+		let _g = 0;
+		let _g1 = el.allTags("content");
+		while(_g < _g1.length) {
+			let content = _g1[_g];
+			++_g;
+			if(content.attr["name"] != null) {
+				idTags.push(content.attr["name"]);
+			}
+		}
+		return new snikket_jingle_Group(el.attr["semantics"],idTags);
+	}
+}
+snikket_jingle_Group.__name__ = "snikket.jingle.Group";
+Object.assign(snikket_jingle_Group.prototype, {
+	__class__: snikket_jingle_Group
+});
+class snikket_jingle_Session {
+}
+snikket_jingle_Session.__name__ = "snikket.jingle.Session";
+snikket_jingle_Session.__isInterface__ = true;
+Object.assign(snikket_jingle_Session.prototype, {
+	__class__: snikket_jingle_Session
+});
+class snikket_jingle_IncomingProposedSession {
+	constructor(client,from,sid) {
+		this.accepted = false;
+		this.client = client;
+		this.from = from;
+		this._sid = sid;
+	}
+	ring() {
+		let event = new snikket_Stanza("ringing",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.from,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+		});
+		this.client.trigger("call/ring",{ chatId : this.from.asBare().asString(), session : this});
+	}
+	hangup() {
+		let event = new snikket_Stanza("reject",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.from,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+		});
+		this.client.getDirectChat(this.from.asBare().asString(),false).jingleSessions.delete(this.get_sid());
+	}
+	retract() {
+		this.client.trigger("call/retract",{ chatId : this.from.asBare().asString()});
+	}
+	terminate() {
+		haxe_Log.trace("Tried to terminate before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 102, className : "snikket.jingle.IncomingProposedSession", methodName : "terminate", customParams : [this]});
+	}
+	contentAdd(_) {
+		haxe_Log.trace("Got content-add before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 106, className : "snikket.jingle.IncomingProposedSession", methodName : "contentAdd", customParams : [this]});
+	}
+	contentAccept(_) {
+		haxe_Log.trace("Got content-accept before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 110, className : "snikket.jingle.IncomingProposedSession", methodName : "contentAccept", customParams : [this]});
+	}
+	transportInfo(_) {
+		haxe_Log.trace("Got transport-info before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 114, className : "snikket.jingle.IncomingProposedSession", methodName : "transportInfo", customParams : [this]});
+		return Promise.resolve(null);
+	}
+	accept() {
+		if(this.accepted) {
+			return;
+		}
+		this.accepted = true;
+		this.client.sendPresence(this.from.asString());
+		let event = new snikket_Stanza("proceed",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.from,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+			_gthis.client.sendStanza(new snikket_Stanza("message",{ to : _gthis.from.asString(), type : "chat", id : msg.versions[0].localId}).addChild(event).tag("store",{ xmlns : "urn:xmpp:hints"}));
+		});
+	}
+	initiate(stanza) {
+		let session = snikket_jingle_InitiatedSession.fromSessionInitiate(this.client,stanza);
+		if(session.get_sid() != this.get_sid()) {
+			throw haxe_Exception.thrown("id mismatch");
+		}
+		if(!this.accepted) {
+			throw haxe_Exception.thrown("trying to initiate unaccepted session");
+		}
+		session.accept();
+		return session;
+	}
+	addMedia(_) {
+		throw haxe_Exception.thrown("Cannot add media before call starts");
+	}
+	callStatus() {
+		return "incoming";
+	}
+	videoTracks() {
+		return [];
+	}
+	dtmf() {
+		return null;
+	}
+	get_sid() {
+		return this._sid;
+	}
+}
+snikket_jingle_IncomingProposedSession.__name__ = "snikket.jingle.IncomingProposedSession";
+snikket_jingle_IncomingProposedSession.__interfaces__ = [snikket_jingle_Session];
+Object.assign(snikket_jingle_IncomingProposedSession.prototype, {
+	__class__: snikket_jingle_IncomingProposedSession
+});
+class snikket_jingle_OutgoingProposedSession {
+	constructor(client,to) {
+		this.video = false;
+		this.audio = false;
+		this.client = client;
+		this.to = to;
+		this._sid = snikket_ID.long();
+	}
+	propose(audio,video) {
+		this.audio = audio;
+		this.video = video;
+		let event = new snikket_Stanza("propose",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		if(audio) {
+			event.tag("description",{ xmlns : "urn:xmpp:jingle:apps:rtp:1", media : "audio"}).up();
+		}
+		if(video) {
+			event.tag("description",{ xmlns : "urn:xmpp:jingle:apps:rtp:1", media : "video"}).up();
+		}
+		let msg = snikket_jingle_Session_mkCallMessage(this.to,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			let stanza = new snikket_Stanza("message",{ to : _gthis.to.asString(), type : "chat", id : msg.localId}).addChild(event).tag("store",{ xmlns : "urn:xmpp:hints"});
+			_gthis.client.sendStanza(stanza);
+			_gthis.client.notifyMessageHandlers(stored[0],0);
+			_gthis.client.trigger("call/ringing",{ chatId : _gthis.to.asBare().asString()});
+		});
+	}
+	ring() {
+		haxe_Log.trace("Tried to accept before initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 200, className : "snikket.jingle.OutgoingProposedSession", methodName : "ring", customParams : [this]});
+	}
+	hangup() {
+		let event = new snikket_Stanza("retract",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.to,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.sendStanza(new snikket_Stanza("message",{ to : _gthis.to.asString(), type : "chat", id : msg.versions[0].localId}).addChild(event).tag("store",{ xmlns : "urn:xmpp:hints"}));
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+		});
+		this.client.getDirectChat(this.to.asBare().asString(),false).jingleSessions.delete(this.get_sid());
+	}
+	retract() {
+		this.client.trigger("call/retract",{ chatId : this.to.asBare().asString()});
+	}
+	terminate() {
+		haxe_Log.trace("Tried to terminate before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 223, className : "snikket.jingle.OutgoingProposedSession", methodName : "terminate", customParams : [this]});
+	}
+	contentAdd(_) {
+		haxe_Log.trace("Got content-add before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 227, className : "snikket.jingle.OutgoingProposedSession", methodName : "contentAdd", customParams : [this]});
+	}
+	contentAccept(_) {
+		haxe_Log.trace("Got content-accept before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 231, className : "snikket.jingle.OutgoingProposedSession", methodName : "contentAccept", customParams : [this]});
+	}
+	transportInfo(_) {
+		haxe_Log.trace("Got transport-info before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 235, className : "snikket.jingle.OutgoingProposedSession", methodName : "transportInfo", customParams : [this]});
+		return Promise.resolve(null);
+	}
+	accept() {
+		haxe_Log.trace("Tried to accept before initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 240, className : "snikket.jingle.OutgoingProposedSession", methodName : "accept", customParams : [this]});
+	}
+	initiate(stanza) {
+		let jmi = stanza.getChild("proceed","urn:xmpp:jingle-message:0");
+		if(jmi == null) {
+			throw haxe_Exception.thrown("no jmi: " + Std.string(stanza));
+		}
+		if(jmi.attr["id"] != this.get_sid()) {
+			throw haxe_Exception.thrown("sid doesn't match: " + jmi.attr["id"] + " vs " + this.get_sid());
+		}
+		this.client.sendPresence(this.to.asString());
+		let session = new snikket_jingle_OutgoingSession(this.client,snikket_JID.parse(stanza.attr["from"]),this.get_sid());
+		this.client.trigger("call/media",{ session : session, audio : this.audio, video : this.video});
+		return session;
+	}
+	addMedia(_) {
+		throw haxe_Exception.thrown("Cannot add media before call starts");
+	}
+	callStatus() {
+		return "outgoing";
+	}
+	videoTracks() {
+		return [];
+	}
+	dtmf() {
+		return null;
+	}
+	get_sid() {
+		return this._sid;
+	}
+}
+snikket_jingle_OutgoingProposedSession.__name__ = "snikket.jingle.OutgoingProposedSession";
+snikket_jingle_OutgoingProposedSession.__interfaces__ = [snikket_jingle_Session];
+Object.assign(snikket_jingle_OutgoingProposedSession.prototype, {
+	__class__: snikket_jingle_OutgoingProposedSession
+});
+class snikket_jingle_InitiatedSession {
+	constructor(client,counterpart,sid,remoteDescription) {
+		this.candidatesDone = null;
+		this.afterMedia = null;
+		this.accepted = false;
+		this.queuedOutboundCandidate = [];
+		this.queuedInboundTransportInfo = [];
+		this.peerDtlsSetup = "actpass";
+		this.pc = null;
+		this.localDescription = null;
+		this.remoteDescription = null;
+		this.client = client;
+		this.counterpart = counterpart;
+		this._sid = sid;
+		this.remoteDescription = remoteDescription;
+		this.initiator = remoteDescription == null;
+	}
+	get_sid() {
+		return this._sid;
+	}
+	ring() {
+		this.client.trigger("call/ring",{ chatId : this.counterpart.asBare().asString(), session : this});
+	}
+	retract() {
+		haxe_Log.trace("Tried to retract session in wrong state: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 327, className : "snikket.jingle.InitiatedSession", methodName : "retract", customParams : [this]});
+	}
+	accept() {
+		if(this.accepted || this.remoteDescription == null) {
+			return;
+		}
+		this.accepted = true;
+		let audio = Lambda.find(this.remoteDescription.media,function(m) {
+			return m.media == "audio";
+		}) != null;
+		let video = Lambda.find(this.remoteDescription.media,function(m) {
+			return m.media == "video";
+		}) != null;
+		this.client.trigger("call/media",{ session : this, audio : audio, video : video});
+	}
+	hangup() {
+		this.client.sendStanza(new snikket_Stanza("iq",{ to : this.counterpart.asString(), type : "set", id : snikket_ID.medium()}).tag("jingle",{ xmlns : "urn:xmpp:jingle:1", action : "session-terminate", sid : this.get_sid()}).tag("reason").tag("success").up().up().up());
+		this.terminate();
+	}
+	initiate(stanza) {
+		haxe_Log.trace("Trying to initiate already initiated session: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 350, className : "snikket.jingle.InitiatedSession", methodName : "initiate"});
+		throw haxe_Exception.thrown("already initiated");
+	}
+	terminate() {
+		if(this.pc == null) {
+			return;
+		}
+		this.pc.close();
+		let _g = 0;
+		let _g1 = this.pc.getTransceivers();
+		while(_g < _g1.length) {
+			let tranceiver = _g1[_g];
+			++_g;
+			if(tranceiver.sender != null && tranceiver.sender.track != null) {
+				tranceiver.sender.track.stop();
+			}
+		}
+		this.pc = null;
+		this.client.trigger("call/retract",{ chatId : this.counterpart.asBare().asString()});
+		let event = new snikket_Stanza("finish",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.counterpart,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+			_gthis.client.sendStanza(new snikket_Stanza("message",{ to : _gthis.counterpart.asString(), type : "chat", id : msg.versions[0].localId}).addChild(event).tag("store",{ xmlns : "urn:xmpp:hints"}));
+		});
+	}
+	contentAdd(stanza) {
+		if(this.remoteDescription == null) {
+			throw haxe_Exception.thrown("Got content-add before session-accept");
+		}
+		let addThis = snikket_jingle_SessionDescription.fromStanza(stanza,this.initiator,this.remoteDescription);
+		let video = false;
+		let audio = false;
+		let _g = 0;
+		let _g1 = addThis.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			if(Lambda.exists(m.attributes,function(attr) {
+				if(attr.key != "sendrecv") {
+					return attr.key == "sendonly";
+				} else {
+					return true;
+				}
+			})) {
+				if(m.media == "video") {
+					video = true;
+				}
+				if(m.media == "audio") {
+					audio = true;
+				}
+			}
+			m.attributes.push(new snikket_jingle_Attribute("setup",this.peerDtlsSetup));
+		}
+		this.remoteDescription = this.remoteDescription.addContent(addThis);
+		let _gthis = this;
+		this.pc.setRemoteDescription({ type : "offer", sdp : this.remoteDescription.toSdp()}).then(function(_) {
+			_gthis.afterMedia = function() {
+				let _gthis1 = _gthis;
+				let _this = addThis.media;
+				let result = new Array(_this.length);
+				let _g = 0;
+				let _g1 = _this.length;
+				while(_g < _g1) {
+					let i = _g++;
+					result[i] = _this[i].mid;
+				}
+				_gthis1.setupLocalDescription("content-accept",result,false,function(gonnaAccept) {
+					if(Lambda.find(gonnaAccept.media,function(m) {
+						return m.contentElement(false).attr["senders"] != Lambda.find(addThis.media,function(addM) {
+							return addM.mid == m.mid;
+						}).contentElement(false).attr["senders"];
+					}) != null) {
+						let modify = gonnaAccept.toStanza("content-modify",_gthis.get_sid(),_gthis.initiator);
+						modify.attr["to"] = _gthis.counterpart.asString();
+						modify.attr["id"] = snikket_ID.medium();
+						_gthis.client.sendStanza(modify);
+					}
+				});
+				_gthis.afterMedia = null;
+			};
+			return _gthis.client.trigger("call/media",{ session : _gthis, audio : audio, video : video});
+		});
+	}
+	contentAccept(stanza) {
+		if(this.remoteDescription == null) {
+			throw haxe_Exception.thrown("Got content-accept before session-accept");
+		}
+		let addThis = snikket_jingle_SessionDescription.fromStanza(stanza,!this.initiator,this.remoteDescription);
+		let _g = 0;
+		let _g1 = addThis.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			m.attributes.push(new snikket_jingle_Attribute("setup",this.peerDtlsSetup));
+		}
+		this.remoteDescription = this.remoteDescription.addContent(addThis);
+		this.pc.setRemoteDescription({ type : "answer", sdp : this.remoteDescription.toSdp()});
+	}
+	transportInfo(stanza) {
+		if(this.pc == null || this.remoteDescription == null) {
+			this.queuedInboundTransportInfo.push(stanza);
+			return Promise.resolve(null);
+		}
+		let _gthis = this;
+		let _this = snikket_jingle_IceCandidate.fromStanza(stanza);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let candidate = _this[i];
+			let index = _gthis.remoteDescription.identificationTags.indexOf(candidate.sdpMid);
+			result[i] = _gthis.pc.addIceCandidate({ candidate : candidate.toSdp(), sdpMid : candidate.sdpMid, sdpMLineIndex : index < 0 ? null : index, usernameFragment : candidate.ufrag});
+		}
+		return thenshim_Promise.then(thenshim_PromiseTools.all(result),function(_) {
+			return;
+		});
+	}
+	addMedia(streams) {
+		if(this.pc == null) {
+			throw haxe_Exception.thrown("tried to add media before PeerConnection exists");
+		}
+		let _this = this.localDescription.media;
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = _this[i].mid;
+		}
+		let oldMids = result;
+		let _g2 = 0;
+		while(_g2 < streams.length) {
+			let stream = streams[_g2];
+			++_g2;
+			let _g = 0;
+			let _g1 = stream.getTracks();
+			while(_g < _g1.length) {
+				let track = _g1[_g];
+				++_g;
+				this.pc.addTrack(track,stream);
+			}
+		}
+		this.setupLocalDescription("content-add",oldMids,true);
+	}
+	callStatus() {
+		return "ongoing";
+	}
+	videoTracks() {
+		if(this.pc == null) {
+			return [];
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.pc.getTransceivers();
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.receiver != null && v.receiver.track != null && v.receiver.track.kind == "video" && !v.receiver.track.muted) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			result[i] = _this[i].receiver.track;
+		}
+		return result;
+	}
+	dtmf() {
+		if(this.pc == null) {
+			return null;
+		}
+		let transceiver = Lambda.find(this.pc.getTransceivers(),function(t) {
+			if(t.sender != null && t.sender.track != null && t.sender.track.kind == "audio") {
+				return !t.sender.track.muted;
+			} else {
+				return false;
+			}
+		});
+		if(transceiver == null) {
+			return null;
+		}
+		return transceiver.sender.dtmf;
+	}
+	sendIceCandidate(candidate) {
+		if(candidate == null || candidate.candidate == "") {
+			if(this.candidatesDone != null) {
+				this.candidatesDone();
+			}
+			return;
+		}
+		if(this.candidatesDone != null) {
+			return;
+		}
+		if(this.localDescription == null) {
+			this.queuedOutboundCandidate.push(candidate);
+			return;
+		}
+		let media = Lambda.find(this.localDescription.media,function(media) {
+			return media.mid == candidate.sdpMid;
+		});
+		if(media == null) {
+			throw haxe_Exception.thrown("Unknown media: " + candidate.sdpMid);
+		}
+		let media1 = media.mid;
+		let media2 = media.media;
+		let media3 = media.connectionData;
+		let media4 = media.port;
+		let media5 = media.protocol;
+		let transportInfo = snikket_jingle_Attribute.parse(candidate.candidate);
+		let transportInfo1 = new snikket_jingle_Attribute("ice-ufrag",candidate.usernameFragment);
+		let tmp = Lambda.find(media.attributes,function(attr) {
+			return attr.key == "ice-pwd";
+		});
+		let transportInfo2 = new snikket_jingle_TransportInfo(new snikket_jingle_Media(media1,media2,media3,media4,media5,[transportInfo,transportInfo1,tmp != null ? tmp : Lambda.find(this.localDescription.attributes,function(attr) {
+			return attr.key == "ice-pwd";
+		})],media.formats),this.get_sid()).toStanza(this.initiator);
+		transportInfo2.attr["to"] = this.counterpart.asString();
+		transportInfo2.attr["id"] = snikket_ID.medium();
+		this.client.sendStanza(transportInfo2);
+	}
+	supplyMedia(streams) {
+		let _gthis = this;
+		this.setupPeerConnection(function() {
+			let _g = 0;
+			while(_g < streams.length) {
+				let stream = streams[_g];
+				++_g;
+				let _g1 = 0;
+				let _g2 = stream.getTracks();
+				while(_g1 < _g2.length) {
+					let track = _g2[_g1];
+					++_g1;
+					_gthis.pc.addTrack(track,stream);
+				}
+			}
+			if(_gthis.afterMedia == null) {
+				_gthis.onPeerConnection().catch(function(e) {
+					haxe_Log.trace("supplyMedia error",{ fileName : "snikket/jingle/Session.hx", lineNumber : 523, className : "snikket.jingle.InitiatedSession", methodName : "supplyMedia", customParams : [e]});
+					_gthis.pc.close();
+				});
+			} else {
+				_gthis.afterMedia();
+			}
+		});
+	}
+	setupPeerConnection(callback) {
+		if(this.pc != null) {
+			callback();
+			return;
+		}
+		let _gthis = this;
+		this.client.getIceServers(function(servers) {
+			_gthis.pc = new RTCPeerConnection({ iceServers : servers},null);
+			_gthis.pc.addEventListener("track",function(event) {
+				return _gthis.client.trigger("call/track",{ chatId : _gthis.counterpart.asBare().asString(), track : event.track, streams : event.streams});
+			});
+			_gthis.pc.addEventListener("negotiationneeded",function(event) {
+				haxe_Log.trace("renegotiate",{ fileName : "snikket/jingle/Session.hx", lineNumber : 542, className : "snikket.jingle.InitiatedSession", methodName : "setupPeerConnection", customParams : [event]});
+			});
+			_gthis.pc.addEventListener("icecandidate",function(event) {
+				_gthis.sendIceCandidate(event.candidate);
+			});
+			_gthis.pc.addEventListener("connectionstatechange",function(event) {
+				if(_gthis.pc != null && (_gthis.pc.connectionState == "closed" || _gthis.pc.connectionState == "failed")) {
+					_gthis.terminate();
+				}
+			});
+			callback();
+		});
+	}
+	setupLocalDescription(type,filterMedia,filterOut,beforeSend) {
+		if(filterOut == null) {
+			filterOut = false;
+		}
+		let _gthis = this;
+		return this.pc.setLocalDescription(null).then(function(_) {
+			let caps = _gthis.client.getDirectChat(_gthis.counterpart.asBare().asString()).getResourceCaps(_gthis.counterpart.resource);
+			if((type == "session-initiate" || type == "session-accept") && caps.features.includes("urn:ietf:rfc:3264")) {
+				return new Promise(function(resolve,reject) {
+					let timeout = haxe_Timer.delay(function() {
+						_gthis.candidatesDone = function() {
+						};
+						resolve(false);
+					},3000);
+					_gthis.candidatesDone = function() {
+						timeout.stop();
+						resolve(true);
+					};
+				});
+			} else {
+				return null;
+			}
+		}).then(function(_) {
+			_gthis.localDescription = snikket_jingle_SessionDescription.parse(_gthis.pc.localDescription.sdp);
+			let descriptionToSend = _gthis.localDescription;
+			if(filterMedia != null) {
+				let descriptionToSend1 = descriptionToSend.version;
+				let descriptionToSend2 = descriptionToSend.name;
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = descriptionToSend.media;
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(filterOut ? !filterMedia.includes(v.mid) : filterMedia.includes(v.mid)) {
+						_g.push(v);
+					}
+				}
+				descriptionToSend = new snikket_jingle_SessionDescription(descriptionToSend1,descriptionToSend2,_g,descriptionToSend.attributes,descriptionToSend.identificationTags);
+			}
+			if(beforeSend != null) {
+				beforeSend(descriptionToSend);
+			}
+			let sessionAccept = descriptionToSend.toStanza(type,_gthis.get_sid(),_gthis.initiator);
+			sessionAccept.attr["to"] = _gthis.counterpart.asString();
+			sessionAccept.attr["id"] = snikket_ID.medium();
+			_gthis.client.sendStanza(sessionAccept);
+			let outboundCandidate = _gthis.queuedOutboundCandidate.slice();
+			_gthis.queuedOutboundCandidate.length = 0;
+			let _g = 0;
+			while(_g < outboundCandidate.length) {
+				let candidate = outboundCandidate[_g];
+				++_g;
+				_gthis.sendIceCandidate(candidate);
+			}
+		});
+	}
+	onPeerConnection() {
+		let _gthis = this;
+		return this.pc.setRemoteDescription({ type : "offer", sdp : this.remoteDescription.toSdp()}).then(function(_) {
+			let inboundTransportInfo = _gthis.queuedInboundTransportInfo.slice();
+			_gthis.queuedInboundTransportInfo.length = 0;
+			let f = $bind(_gthis,_gthis.transportInfo);
+			let result = new Array(inboundTransportInfo.length);
+			let _g = 0;
+			let _g1 = inboundTransportInfo.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = f(inboundTransportInfo[i]);
+			}
+			return result;
+		}).then(function(_) {
+			return _gthis.setupLocalDescription("session-accept");
+		}).then(function(_) {
+			let tmp = _gthis.localDescription.getDtlsSetup() == "active" ? "passive" : "active";
+			return _gthis.peerDtlsSetup = tmp;
+		});
+	}
+	static fromSessionInitiate(client,stanza) {
+		let jingle = stanza.getChild("jingle","urn:xmpp:jingle:1");
+		let session = new snikket_jingle_InitiatedSession(client,snikket_JID.parse(stanza.attr["from"]),jingle.attr["sid"],snikket_jingle_SessionDescription.fromStanza(stanza,false));
+		session.transportInfo(stanza);
+		return session;
+	}
+}
+snikket_jingle_InitiatedSession.__name__ = "snikket.jingle.InitiatedSession";
+snikket_jingle_InitiatedSession.__interfaces__ = [snikket_jingle_Session];
+Object.assign(snikket_jingle_InitiatedSession.prototype, {
+	__class__: snikket_jingle_InitiatedSession
+});
+class snikket_jingle_OutgoingSession extends snikket_jingle_InitiatedSession {
+	constructor(client,counterpart,sid) {
+		super(client,counterpart,sid,null);
+	}
+	onPeerConnection() {
+		return this.setupLocalDescription("session-initiate");
+	}
+	initiate(stanza) {
+		this.remoteDescription = snikket_jingle_SessionDescription.fromStanza(stanza,true);
+		this.peerDtlsSetup = this.remoteDescription.getDtlsSetup();
+		let _gthis = this;
+		this.pc.setRemoteDescription({ type : "answer", sdp : this.remoteDescription.toSdp()}).then(function(_) {
+			return _gthis.transportInfo(stanza);
+		});
+		return this;
+	}
+}
+snikket_jingle_OutgoingSession.__name__ = "snikket.jingle.OutgoingSession";
+snikket_jingle_OutgoingSession.__super__ = snikket_jingle_InitiatedSession;
+Object.assign(snikket_jingle_OutgoingSession.prototype, {
+	__class__: snikket_jingle_OutgoingSession
+});
+function snikket_jingle_Session_mkCallMessage(to,from,event) {
+	let m = new snikket_ChatMessageBuilder();
+	m.type = 1;
+	m.to = to;
+	m.recipients = [to.asBare()];
+	m.from = from;
+	m.sender = m.from.asBare();
+	m.replyTo = [m.sender];
+	m.direction = 1;
+	m.text = "call " + event.name;
+	m.timestamp = snikket_Date.format(new Date());
+	m.payloads.push(event);
+	m.localId = snikket_ID.long();
+	if(event.name != "propose") {
+		m.versions = [m.build()];
+	}
+	m.localId = event.attr["id"];
+	return m.build();
+}
+class snikket_jingle_SessionDescription {
+	constructor(version,name,media,attributes,identificationTags) {
+		this.version = version;
+		this.name = name;
+		this.media = media;
+		this.attributes = attributes;
+		this.identificationTags = identificationTags;
+	}
+	getUfragPwd() {
+		let ufragPwd = null;
+		let _g = 0;
+		let _g1 = this.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			let mUfragPwd = m.getUfragPwd();
+			if(ufragPwd != null && mUfragPwd.ufrag != ufragPwd.ufrag) {
+				throw haxe_Exception.thrown("ufrag not unique");
+			}
+			if(ufragPwd != null && mUfragPwd.pwd != ufragPwd.pwd) {
+				throw haxe_Exception.thrown("pwd not unique");
+			}
+			ufragPwd = mUfragPwd;
+		}
+		if(ufragPwd == null) {
+			throw haxe_Exception.thrown("no ufrag or pwd found");
+		}
+		return ufragPwd;
+	}
+	getFingerprint() {
+		let fingerprint = Lambda.find(this.attributes,function(attr) {
+			return attr.key == "fingerprint";
+		});
+		if(fingerprint != null) {
+			return fingerprint;
+		}
+		let _g = 0;
+		let _g1 = this.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			let mFingerprint = Lambda.find(m.attributes,function(attr) {
+				return attr.key == "fingerprint";
+			});
+			if(fingerprint != null && mFingerprint != null && fingerprint.value != mFingerprint.value) {
+				throw haxe_Exception.thrown("fingerprint not unique");
+			}
+			fingerprint = mFingerprint;
+		}
+		if(fingerprint == null) {
+			throw haxe_Exception.thrown("no fingerprint found");
+		}
+		return fingerprint;
+	}
+	getDtlsSetup() {
+		let setup = Lambda.find(this.attributes,function(attr) {
+			return attr.key == "setup";
+		});
+		if(setup != null) {
+			return setup.value;
+		}
+		let _g = 0;
+		let _g1 = this.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			let mSetup = Lambda.find(m.attributes,function(attr) {
+				return attr.key == "setup";
+			});
+			if(setup != null && mSetup != null && setup.value != mSetup.value) {
+				throw haxe_Exception.thrown("setup not unique");
+			}
+			setup = mSetup;
+		}
+		if(setup == null) {
+			throw haxe_Exception.thrown("no setup found");
+		}
+		return setup.value;
+	}
+	addContent(newDescription) {
+		let _g = 0;
+		let _g1 = newDescription.media;
+		while(_g < _g1.length) {
+			let newM = _g1[_g];
+			++_g;
+			if(Lambda.find(this.media,function(m) {
+				return m.mid == newM.mid;
+			}) != null) {
+				throw haxe_Exception.thrown("Media with id " + newM.mid + " already exists!");
+			}
+		}
+		let tmp = this.version;
+		let tmp1 = this.name;
+		let tmp2 = this.media.concat(newDescription.media);
+		let _g2 = [];
+		let _g3 = 0;
+		let _g4 = this.attributes;
+		while(_g3 < _g4.length) {
+			let v = _g4[_g3];
+			++_g3;
+			if(v.key != "group") {
+				_g2.push(v);
+			}
+		}
+		let tmp3 = _g2;
+		let _g5 = [];
+		let _g6 = 0;
+		let _g7 = newDescription.attributes;
+		while(_g6 < _g7.length) {
+			let v = _g7[_g6];
+			++_g6;
+			if(v.key == "group") {
+				_g5.push(v);
+			}
+		}
+		return new snikket_jingle_SessionDescription(tmp,tmp1,tmp2,tmp3.concat(_g5),newDescription.identificationTags);
+	}
+	toSdp() {
+		let tmp = "v=" + this.version + "\r\n" + "o=- 8770656990916039506 2 IN IP4 127.0.0.1\r\n" + "s=" + this.name + "\r\n" + "t=0 0\r\n";
+		let _this = this.attributes;
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = _this[i].toSdp();
+		}
+		let tmp1 = tmp + result.join("");
+		let _this1 = this.media;
+		let result1 = new Array(_this1.length);
+		let _g2 = 0;
+		let _g3 = _this1.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			result1[i] = _this1[i].toSdp();
+		}
+		return tmp1 + result1.join("");
+	}
+	toStanza(action,sid,initiator) {
+		let iq = new snikket_Stanza("iq",{ type : "set"});
+		let jingle = iq.tag("jingle",{ xmlns : "urn:xmpp:jingle:1", action : action, sid : sid});
+		let group = Lambda.find(this.attributes,function(attr) {
+			return attr.key == "group";
+		});
+		if(group != null) {
+			jingle.addChild(snikket_jingle_Group.parse(group.value).toElement());
+		}
+		let _g = 0;
+		let _g1 = this.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			jingle.addChild(m.toElement(this.attributes,initiator));
+		}
+		jingle.up();
+		return iq;
+	}
+	static parse(input) {
+		let version = 0;
+		let name = "-";
+		let attributes = [];
+		let media = [];
+		let currentAttributes = [];
+		let currentMedia = null;
+		let _g = 0;
+		let _g1 = input.split("\r\n");
+		while(_g < _g1.length) {
+			let line = _g1[_g];
+			++_g;
+			if(line.indexOf("=") != 1) {
+				continue;
+			}
+			let value = HxOverrides.substr(line,2,null);
+			switch(line.charAt(0)) {
+			case "a":
+				currentAttributes.push(snikket_jingle_Attribute.parse(value));
+				break;
+			case "c":
+				if(currentMedia != null) {
+					currentMedia.connectionData = value;
+				}
+				break;
+			case "m":
+				if(currentMedia == null) {
+					attributes = currentAttributes;
+				} else {
+					let mid = Lambda.find(currentAttributes,function(attr) {
+						return attr.key == "mid";
+					});
+					media.push(new snikket_jingle_Media(mid == null ? null : mid.value,currentMedia.media,currentMedia.connectionData,currentMedia.port,currentMedia.protocol,currentAttributes,currentMedia.formats));
+				}
+				currentAttributes = [];
+				let segments = value.split(" ");
+				if(segments.length >= 3) {
+					let segments1 = segments[0];
+					let segments2 = segments[1];
+					let segments3 = segments[2];
+					let _this = segments.slice(3);
+					let result = new Array(_this.length);
+					let _g = 0;
+					let _g1 = _this.length;
+					while(_g < _g1) {
+						let i = _g++;
+						result[i] = Std.parseInt(_this[i]);
+					}
+					currentMedia = { media : segments1, port : segments2, protocol : segments3, formats : result};
+				} else {
+					currentMedia = { };
+				}
+				break;
+			case "s":
+				name = value;
+				break;
+			case "v":
+				version = Std.parseInt(value);
+				break;
+			}
+		}
+		if(currentMedia != null) {
+			let mid = Lambda.find(currentAttributes,function(attr) {
+				return attr.key == "mid";
+			});
+			media.push(new snikket_jingle_Media(mid == null ? null : mid.value,currentMedia.media,currentMedia.connectionData,currentMedia.port,currentMedia.protocol,currentAttributes,currentMedia.formats));
+		} else {
+			attributes = currentAttributes;
+		}
+		let tags;
+		let group = Lambda.find(attributes,function(attr) {
+			return attr.key == "group";
+		});
+		if(group != null) {
+			tags = snikket_jingle_Group.parse(group.value).identificationTags;
+		} else {
+			let result = new Array(media.length);
+			let _g = 0;
+			let _g1 = media.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = media[i].mid;
+			}
+			tags = result;
+		}
+		return new snikket_jingle_SessionDescription(version,name,media,attributes,tags);
+	}
+	static fromStanza(iq,initiator,existingDescription) {
+		let attributes = [];
+		let jingle = iq.getChild("jingle","urn:xmpp:jingle:1");
+		let group = jingle.getChild("group","urn:xmpp:jingle:apps:grouping:0");
+		let _this = jingle.allTags("content");
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = snikket_jingle_Media.fromElement(_this[i],initiator,group != null,existingDescription);
+		}
+		let media = result;
+		let tags;
+		if(group != null) {
+			let group1 = snikket_jingle_Group.fromElement(group);
+			attributes.push(new snikket_jingle_Attribute("group",group1.toSdp()));
+			tags = group1.identificationTags;
+		} else {
+			let result = new Array(media.length);
+			let _g = 0;
+			let _g1 = media.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = media[i].mid;
+			}
+			tags = result;
+		}
+		attributes.push(new snikket_jingle_Attribute("msid-semantic","WMS my-media-stream"));
+		return new snikket_jingle_SessionDescription(0,"-",media,attributes,tags);
+	}
+}
+snikket_jingle_SessionDescription.__name__ = "snikket.jingle.SessionDescription";
+Object.assign(snikket_jingle_SessionDescription.prototype, {
+	__class__: snikket_jingle_SessionDescription
+});
+class snikket_jingle_TransportInfo {
+	constructor(media,sid) {
+		this.media = media;
+		this.sid = sid;
+	}
+	toStanza(initiator) {
+		let iq = new snikket_Stanza("iq",{ type : "set"});
+		let jingle = iq.tag("jingle",{ xmlns : "urn:xmpp:jingle:1", action : "transport-info", sid : this.sid});
+		jingle.addChild(this.media.contentElement(initiator).addChild(this.media.toTransportElement([])).up());
+		jingle.up();
+		return iq;
+	}
+}
+snikket_jingle_TransportInfo.__name__ = "snikket.jingle.TransportInfo";
+Object.assign(snikket_jingle_TransportInfo.prototype, {
+	__class__: snikket_jingle_TransportInfo
+});
+class snikket_jingle_Media {
+	constructor(mid,media,connectionData,port,protocol,attributes,formats) {
+		this.mid = mid;
+		this.media = media;
+		this.connectionData = connectionData;
+		this.port = port;
+		this.protocol = protocol;
+		this.attributes = attributes;
+		this.formats = formats;
+	}
+	toSdp() {
+		let tmp = "m=" + this.media + " " + this.port + " " + this.protocol + " " + this.formats.join(" ") + "\r\n" + "c=" + this.connectionData + "\r\n";
+		let _this = this.attributes;
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = _this[i].toSdp();
+		}
+		return tmp + result.join("");
+	}
+	contentElement(initiator) {
+		let attrs = { xmlns : "urn:xmpp:jingle:1", creator : "initiator", name : this.mid};
+		if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "inactive";
+		})) {
+			attrs["senders"] = "none";
+		} else if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "sendonly";
+		})) {
+			attrs["senders"] = initiator ? "initiator" : "responder";
+		} else if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "recvonly";
+		})) {
+			attrs["senders"] = initiator ? "responder" : "initiator";
+		}
+		return new snikket_Stanza("content",attrs);
+	}
+	toElement(sessionAttributes,initiator) {
+		let content = this.contentElement(initiator);
+		let description = content.tag("description",{ xmlns : "urn:xmpp:jingle:apps:rtp:1", media : this.media});
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.attributes;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.key == "rtcp-fb") {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			let segments = _this[i].value.split(" ");
+			let segments1 = segments[0];
+			let tmp;
+			if(segments[1] == "trr-int") {
+				tmp = new snikket_Stanza("rtcp-fb-trr-int",{ xmlns : "urn:xmpp:jingle:apps:rtp:rtcp-fb:0", value : segments[2]});
+			} else {
+				let fbattrs = { xmlns : "urn:xmpp:jingle:apps:rtp:rtcp-fb:0", type : segments[1]};
+				if(segments.length >= 3) {
+					fbattrs["subtype"] = segments[2];
+				}
+				tmp = new snikket_Stanza("rtcp-fb",fbattrs);
+			}
+			result[i] = { id : segments1, el : tmp};
+		}
+		let fbs = result;
+		let ssrc = new Map([]);
+		let fmtp = new Map([]);
+		let _g5 = 0;
+		let _g6 = this.attributes;
+		while(_g5 < _g6.length) {
+			let attr = _g6[_g5];
+			++_g5;
+			if(attr.key == "fmtp") {
+				let pos = attr.value.indexOf(" ");
+				if(pos < 0) {
+					continue;
+				}
+				let k = HxOverrides.substr(attr.value,0,pos);
+				let _this = HxOverrides.substr(attr.value,pos + 1,null).split(";");
+				let result = new Array(_this.length);
+				let _g = 0;
+				let _g1 = _this.length;
+				while(_g < _g1) {
+					let i = _g++;
+					let param = _this[i];
+					let eqPos = param.indexOf("=");
+					let attrs = { value : eqPos > 0 ? HxOverrides.substr(param,eqPos + 1,null) : param};
+					if(eqPos > 0) {
+						attrs["name"] = HxOverrides.substr(param,0,eqPos);
+					}
+					result[i] = new snikket_Stanza("parameter",attrs);
+				}
+				fmtp.set(k,result);
+			} else if(attr.key == "ssrc") {
+				let pos = attr.value.indexOf(" ");
+				if(pos < 0) {
+					continue;
+				}
+				let id = HxOverrides.substr(attr.value,0,pos);
+				if(ssrc.get(id) == null) {
+					ssrc.set(id,[]);
+				}
+				let param = HxOverrides.substr(attr.value,pos + 1,null);
+				let colonPos = param.indexOf(":");
+				let attrs = { name : colonPos > 0 ? HxOverrides.substr(param,0,colonPos) : param};
+				if(colonPos > 0) {
+					attrs["value"] = HxOverrides.substr(param,colonPos + 1,null);
+				}
+				ssrc.get(id).push(new snikket_Stanza("parameter",attrs));
+			} else if(attr.key == "extmap") {
+				let pos = attr.value.indexOf(" ");
+				if(pos < 0) {
+					continue;
+				}
+				description.tag("rtp-hdrext",{ xmlns : "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0", id : HxOverrides.substr(attr.value,0,pos), uri : HxOverrides.substr(attr.value,pos + 1,null)}).up();
+			} else if(attr.key == "ssrc-group") {
+				let segments = attr.value.split(" ");
+				if(segments.length < 2) {
+					continue;
+				}
+				let group = description.tag("ssrc-group",{ xmlns : "urn:xmpp:jingle:apps:rtp:ssma:0", semantics : segments[0]});
+				let _g = 0;
+				let _g1 = segments.slice(1);
+				while(_g < _g1.length) {
+					let seg = _g1[_g];
+					++_g;
+					group.tag("source",{ ssrc : seg}).up();
+				}
+				group.up();
+			}
+		}
+		let _g7 = [];
+		let _g8 = 0;
+		let _g9 = fbs;
+		while(_g8 < _g9.length) {
+			let v = _g9[_g8];
+			++_g8;
+			if(v.id == "*") {
+				_g7.push(v);
+			}
+		}
+		let _this1 = _g7;
+		let result1 = new Array(_this1.length);
+		let _g10 = 0;
+		let _g11 = _this1.length;
+		while(_g10 < _g11) {
+			let i = _g10++;
+			result1[i] = _this1[i].el;
+		}
+		description.addChildren(result1);
+		let _g12 = [];
+		let _g13 = 0;
+		let _g14 = this.attributes;
+		while(_g13 < _g14.length) {
+			let v = _g14[_g13];
+			++_g13;
+			if(v.key == "rtpmap") {
+				_g12.push(v);
+			}
+		}
+		let _this2 = _g12;
+		let result2 = new Array(_this2.length);
+		let _g15 = 0;
+		let _g16 = _this2.length;
+		while(_g15 < _g16) {
+			let i = _g15++;
+			let rtpmap = _this2[i];
+			let pos = rtpmap.value.indexOf(" ");
+			if(pos < 0) {
+				throw haxe_Exception.thrown("invalid rtpmap");
+			}
+			let id = HxOverrides.substr(rtpmap.value,0,pos);
+			let segments = HxOverrides.substr(rtpmap.value,pos + 1,null).split("/");
+			let attrs = { id : id};
+			if(segments.length > 0) {
+				attrs["name"] = segments[0];
+			}
+			if(segments.length > 1) {
+				attrs["clockrate"] = segments[1];
+			}
+			if(segments.length > 2 && segments[2] != "" && segments[2] != "1") {
+				attrs["channels"] = segments[2];
+			}
+			let tmp = new snikket_Stanza("payload-type",attrs);
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = fbs;
+			while(_g1 < _g2.length) {
+				let v = _g2[_g1];
+				++_g1;
+				if(v.id == id) {
+					_g.push(v);
+				}
+			}
+			let _this = _g;
+			let result = new Array(_this.length);
+			let _g3 = 0;
+			let _g4 = _this.length;
+			while(_g3 < _g4) {
+				let i = _g3++;
+				result[i] = _this[i].el;
+			}
+			let tmp1 = fmtp.get(id) == null ? [] : fmtp.get(id);
+			result2[i] = tmp.addChildren(result).addChildren(tmp1);
+		}
+		description.addChildren(result2);
+		if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "extmap-allow-mixed";
+		}) || Lambda.exists(sessionAttributes,function(attr) {
+			return attr.key == "extmap-allow-mixed";
+		})) {
+			description.tag("extmap-allow-mixed",{ xmlns : "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"}).up();
+		}
+		let jsIterator = ssrc.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let entry_key = v[0];
+			let entry_value = v[1];
+			let msid = Lambda.find(this.attributes,function(attr) {
+				return attr.key == "msid";
+			});
+			if(msid != null && !Lambda.exists(entry_value,function(param) {
+				return param.attr["name"] == "msid";
+			})) {
+				entry_value.push(new snikket_Stanza("parameter",{ name : "msid", value : msid.value}));
+			}
+			description.tag("source",{ xmlns : "urn:xmpp:jingle:apps:rtp:ssma:0", ssrc : entry_key}).addChildren(entry_value).up();
+		}
+		if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "rtcp-mux";
+		})) {
+			description.tag("rtcp-mux").up();
+		}
+		if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "ice-lite";
+		})) {
+			description.tag("ice-lite").up();
+		}
+		description.up();
+		content.addChild(this.toTransportElement(sessionAttributes)).up();
+		return content;
+	}
+	getUfragPwd(sessionAttributes) {
+		let tmp = sessionAttributes;
+		let allAttributes = this.attributes.concat(tmp != null ? tmp : []);
+		let ufrag = Lambda.find(allAttributes,function(attr) {
+			return attr.key == "ice-ufrag";
+		});
+		let pwd = Lambda.find(allAttributes,function(attr) {
+			return attr.key == "ice-pwd";
+		});
+		if(ufrag == null || pwd == null) {
+			throw haxe_Exception.thrown("transport is missing ufrag or pwd");
+		}
+		return { ufrag : ufrag.value, pwd : pwd.value};
+	}
+	toTransportElement(sessionAttributes) {
+		let transportAttr = { xmlns : "urn:xmpp:jingle:transports:ice-udp:1"};
+		let ufragPwd = this.getUfragPwd(sessionAttributes);
+		transportAttr["ufrag"] = ufragPwd.ufrag;
+		transportAttr["pwd"] = ufragPwd.pwd;
+		let transport = new snikket_Stanza("transport",transportAttr);
+		let fingerprint = Lambda.find(this.attributes.concat(sessionAttributes),function(attr) {
+			return attr.key == "fingerprint";
+		});
+		let setup = Lambda.find(this.attributes.concat(sessionAttributes),function(attr) {
+			return attr.key == "setup";
+		});
+		if(fingerprint != null && setup != null && fingerprint.value.indexOf(" ") > 0) {
+			let pos = fingerprint.value.indexOf(" ");
+			transport.textTag("fingerprint",HxOverrides.substr(fingerprint.value,pos + 1,null),{ xmlns : "urn:xmpp:jingle:apps:dtls:0", hash : HxOverrides.substr(fingerprint.value,0,pos), setup : setup.value});
+		}
+		let _gthis = this;
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.attributes;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.key == "candidate") {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			result[i] = snikket_jingle_IceCandidate.parse(_this[i].value,_gthis.mid,ufragPwd.ufrag).toElement();
+		}
+		transport.addChildren(result);
+		transport.up();
+		return transport;
+	}
+	static fromElement(content,initiator,hasGroup,existingDescription) {
+		let mediaAttributes = [];
+		let mediaFormats = [];
+		let mid = content.attr["name"];
+		let transport = content.getChild("transport","urn:xmpp:jingle:transports:ice-udp:1");
+		if(transport == null) {
+			throw haxe_Exception.thrown("ice-udp transport is missing");
+		}
+		let ufrag = transport.attr["ufrag"];
+		let pwd = transport.attr["pwd"];
+		if((ufrag == null || pwd == null) && existingDescription != null) {
+			let ufragPwd = existingDescription.getUfragPwd();
+			ufrag = ufragPwd.ufrag;
+			pwd = ufragPwd.pwd;
+		}
+		if(ufrag == null) {
+			throw haxe_Exception.thrown("transport is missing ufrag");
+		}
+		mediaAttributes.push(new snikket_jingle_Attribute("ice-ufrag",ufrag));
+		if(pwd == null) {
+			throw haxe_Exception.thrown("transport is missing pwd");
+		}
+		mediaAttributes.push(new snikket_jingle_Attribute("ice-pwd",pwd));
+		mediaAttributes.push(new snikket_jingle_Attribute("ice-options","trickle"));
+		let fingerprint = transport.getChild("fingerprint","urn:xmpp:jingle:apps:dtls:0");
+		if(fingerprint == null) {
+			if(existingDescription != null) {
+				mediaAttributes.push(existingDescription.getFingerprint());
+			}
+		} else {
+			mediaAttributes.push(new snikket_jingle_Attribute("fingerprint",fingerprint.attr["hash"] + " " + fingerprint.getText()));
+			if(fingerprint.attr["setup"] != null) {
+				mediaAttributes.push(new snikket_jingle_Attribute("setup",fingerprint.attr["setup"]));
+			}
+		}
+		let description = content.getChild("description","urn:xmpp:jingle:apps:rtp:1");
+		let _g = 0;
+		let _g1 = description.allTags("payload-type");
+		while(_g < _g1.length) {
+			let payloadType = _g1[_g];
+			++_g;
+			let id = Std.parseInt(payloadType.attr["id"]);
+			if(payloadType.attr["id"] == null) {
+				throw haxe_Exception.thrown("payload-type missing or invalid id");
+			}
+			mediaFormats.push(id);
+			let clockRate = Std.parseInt(payloadType.attr["clockrate"]);
+			let channels = Std.parseInt(payloadType.attr["channels"]);
+			mediaAttributes.push(new snikket_jingle_Attribute("rtpmap",id + " " + payloadType.attr["name"] + "/" + (clockRate == null ? 0 : clockRate) + (channels == null || channels == 1 ? "" : "/" + channels)));
+			let _this = payloadType.allTags("parameter");
+			let result = new Array(_this.length);
+			let _g2 = 0;
+			let _g3 = _this.length;
+			while(_g2 < _g3) {
+				let i = _g2++;
+				let el = _this[i];
+				result[i] = (el.attr["name"] == null ? "" : el.attr["name"] + "=") + el.attr["value"];
+			}
+			let parameters = result;
+			if(parameters.length > 0) {
+				mediaAttributes.push(new snikket_jingle_Attribute("fmtp",id + " " + parameters.join(";")));
+			}
+			let _g4 = 0;
+			let _g5 = payloadType.allTags("rtcp-fb","urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
+			while(_g4 < _g5.length) {
+				let feedbackNegotiation = _g5[_g4];
+				++_g4;
+				let subtype = feedbackNegotiation.attr["subtype"];
+				mediaAttributes.push(new snikket_jingle_Attribute("rtcp-fb",id + " " + feedbackNegotiation.attr["type"] + (subtype == null || subtype == "" ? "" : " " + subtype)));
+			}
+			let _g6 = 0;
+			let _g7 = payloadType.allTags("rtcp-fb-trr-int","urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
+			while(_g6 < _g7.length) {
+				let trrInt = _g7[_g6];
+				++_g6;
+				mediaAttributes.push(new snikket_jingle_Attribute("rtcp-fb",id + " trr-int " + trrInt.attr["value"]));
+			}
+		}
+		let _g2 = 0;
+		let _g3 = description.allTags("rtcp-fb","urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
+		while(_g2 < _g3.length) {
+			let feedbackNegotiation = _g3[_g2];
+			++_g2;
+			let subtype = feedbackNegotiation.attr["subtype"];
+			mediaAttributes.push(new snikket_jingle_Attribute("rtcp-fb","* " + feedbackNegotiation.attr["type"] + (subtype == null || subtype == "" ? "" : " " + subtype)));
+		}
+		let _g4 = 0;
+		let _g5 = description.allTags("rtcp-fb-trr-int","urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
+		while(_g4 < _g5.length) {
+			let trrInt = _g5[_g4];
+			++_g4;
+			mediaAttributes.push(new snikket_jingle_Attribute("rtcp-fb","* trr-int " + trrInt.attr["value"]));
+		}
+		let _g6 = 0;
+		let _g7 = description.allTags("rtp-hdrext","urn:xmpp:jingle:apps:rtp:rtp-hdrext:0");
+		while(_g6 < _g7.length) {
+			let headerExtension = _g7[_g6];
+			++_g6;
+			mediaAttributes.push(new snikket_jingle_Attribute("extmap",headerExtension.attr["id"] + " " + headerExtension.attr["uri"]));
+		}
+		if(description.getChild("extmap-allow-mixed","urn:xmpp:jingle:apps:rtp:rtp-hdrext:0") != null) {
+			mediaAttributes.push(new snikket_jingle_Attribute("extmap-allow-mixed",""));
+		}
+		let _g8 = 0;
+		let _g9 = description.allTags("ssrc-group","urn:xmpp:jingle:apps:rtp:ssma:0");
+		while(_g8 < _g9.length) {
+			let sourceGroup = _g9[_g8];
+			++_g8;
+			let tmp = sourceGroup.attr["semantics"] + " ";
+			let _this = sourceGroup.allTags("source");
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].attr["ssrc"];
+			}
+			mediaAttributes.push(new snikket_jingle_Attribute("ssrc-group",tmp + result.join(" ")));
+		}
+		let _g10 = 0;
+		let _g11 = description.allTags("source","urn:xmpp:jingle:apps:rtp:ssma:0");
+		while(_g10 < _g11.length) {
+			let source = _g11[_g10];
+			++_g10;
+			let _g = 0;
+			let _g1 = source.allTags("parameter");
+			while(_g < _g1.length) {
+				let parameter = _g1[_g];
+				++_g;
+				mediaAttributes.push(new snikket_jingle_Attribute("ssrc",source.attr["ssrc"] + " " + parameter.attr["name"] + ":" + parameter.attr["value"]));
+			}
+		}
+		mediaAttributes.push(new snikket_jingle_Attribute("mid",mid));
+		let _g12 = content.attr["senders"];
+		if(_g12 == null) {
+			mediaAttributes.push(new snikket_jingle_Attribute("sendrecv",""));
+		} else {
+			switch(_g12) {
+			case "initiator":
+				if(initiator) {
+					mediaAttributes.push(new snikket_jingle_Attribute("sendonly",""));
+				} else {
+					mediaAttributes.push(new snikket_jingle_Attribute("recvonly",""));
+				}
+				break;
+			case "none":
+				mediaAttributes.push(new snikket_jingle_Attribute("inactive",""));
+				break;
+			case "responder":
+				if(initiator) {
+					mediaAttributes.push(new snikket_jingle_Attribute("recvonly",""));
+				} else {
+					mediaAttributes.push(new snikket_jingle_Attribute("sendonly",""));
+				}
+				break;
+			default:
+				mediaAttributes.push(new snikket_jingle_Attribute("sendrecv",""));
+			}
+		}
+		if(hasGroup || description.getChild("rtcp-mux") != null) {
+			mediaAttributes.push(new snikket_jingle_Attribute("rtcp-mux",""));
+		}
+		if(description.getChild("ice-lite") != null) {
+			mediaAttributes.push(new snikket_jingle_Attribute("ice-lite",""));
+		}
+		mediaAttributes.push(new snikket_jingle_Attribute("rtcp","9 IN IP4 0.0.0.0"));
+		return new snikket_jingle_Media(mid,description == null ? "" : description.attr["media"],"IN IP4 0.0.0.0","9","UDP/TLS/RTP/SAVPF",mediaAttributes,mediaFormats);
+	}
+}
+snikket_jingle_Media.__name__ = "snikket.jingle.Media";
+Object.assign(snikket_jingle_Media.prototype, {
+	__class__: snikket_jingle_Media
+});
+class snikket_jingle_IceCandidate {
+	constructor(sdpMid,ufrag,foundation,component,transport,priority,connectionAddress,port,parameters) {
+		this.sdpMid = sdpMid;
+		this.ufrag = ufrag;
+		this.foundation = foundation;
+		this.component = component;
+		this.transport = transport;
+		this.priority = priority;
+		this.connectionAddress = connectionAddress;
+		this.port = port;
+		this.parameters = parameters;
+	}
+	toElement() {
+		let tmp = this.parameters.get("generation");
+		let attrs = { xmlns : this.parameters.get("tcptype") == null ? "urn:xmpp:jingle:transports:ice-udp:1" : "urn:xmpp:jingle:transports:ice:0", foundation : this.foundation, component : this.component, protocol : this.transport.toLowerCase(), priority : this.priority, ip : this.connectionAddress, port : this.port, generation : tmp != null ? tmp : "0"};
+		if(this.parameters.get("typ") != null) {
+			attrs["type"] = this.parameters.get("typ");
+		}
+		if(this.parameters.get("raddr") != null) {
+			attrs["rel-addr"] = this.parameters.get("raddr");
+		}
+		if(this.parameters.get("rport") != null) {
+			attrs["rel-port"] = this.parameters.get("rport");
+		}
+		if(this.parameters.get("tcptype") != null) {
+			attrs["tcptype"] = this.parameters.get("tcptype");
+		}
+		return new snikket_Stanza("candidate",attrs);
+	}
+	toSdp() {
+		let result = "candidate:" + this.foundation + " " + this.component + " " + this.transport + " " + this.priority + " " + this.connectionAddress + " " + this.port;
+		if(this.parameters.has("typ")) {
+			result += " typ " + this.parameters.get("typ");
+		}
+		if(this.parameters.has("raddr")) {
+			result += " raddr " + this.parameters.get("raddr");
+		}
+		if(this.parameters.has("rport")) {
+			result += " rport " + this.parameters.get("rport");
+		}
+		let jsIterator = this.parameters.entries();
+		let entry_jsIterator = jsIterator;
+		let entry_lastStep = jsIterator.next();
+		while(!entry_lastStep.done) {
+			let v = entry_lastStep.value;
+			entry_lastStep = entry_jsIterator.next();
+			let entry_key = v[0];
+			let entry_value = v[1];
+			if(entry_key != "typ" && entry_key != "raddr" && entry_key != "rport") {
+				result += " " + entry_key + " " + entry_value;
+			}
+		}
+		return result;
+	}
+	static fromElement(candidate,sdpMid,ufrag) {
+		let parameters = new Map([]);
+		if(candidate.attr["type"] != null) {
+			parameters.set("typ",candidate.attr["type"]);
+		}
+		if(candidate.attr["rel-addr"] != null) {
+			parameters.set("raddr",candidate.attr["rel-addr"]);
+		}
+		if(candidate.attr["rel-port"] != null) {
+			parameters.set("rport",candidate.attr["rel-port"]);
+		}
+		if(candidate.attr["generation"] != null) {
+			parameters.set("generation",candidate.attr["generation"]);
+		}
+		if(candidate.attr["tcptype"] != null) {
+			parameters.set("tcptype",candidate.attr["tcptype"]);
+		}
+		if(ufrag != null) {
+			parameters.set("ufrag",ufrag);
+		}
+		return new snikket_jingle_IceCandidate(sdpMid,ufrag,candidate.attr["foundation"],candidate.attr["component"],candidate.attr["protocol"].toLowerCase(),candidate.attr["priority"],candidate.attr["ip"],candidate.attr["port"],parameters);
+	}
+	static fromTransport(transport,sdpMid) {
+		let _this = transport.allTags("candidate");
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = snikket_jingle_IceCandidate.fromElement(_this[i],sdpMid,transport.attr["ufrag"]);
+		}
+		return result;
+	}
+	static fromStanza(iq) {
+		let jingle = iq.getChild("jingle","urn:xmpp:jingle:1");
+		let _g = [];
+		let x = $getIterator(jingle.allTags("content"));
+		while(x.hasNext()) {
+			let x1 = x.next();
+			let transport = x1.getChild("transport","urn:xmpp:jingle:transports:ice-udp:1");
+			_g.push(snikket_jingle_IceCandidate.fromTransport(transport,x1.attr["name"]));
+		}
+		let _g1 = [];
+		let e = $getIterator(_g);
+		while(e.hasNext()) {
+			let e1 = e.next();
+			let x = $getIterator(e1);
+			while(x.hasNext()) {
+				let x1 = x.next();
+				_g1.push(x1);
+			}
+		}
+		return _g1;
+	}
+	static parse(input,sdpMid,ufrag) {
+		if(HxOverrides.substr(input,0,10) == "candidate:") {
+			input = HxOverrides.substr(input,11,null);
+		}
+		let segments = input.split(" ");
+		let paramSegs = segments.slice(6);
+		let paramLength = paramSegs.length / 2 | 0;
+		let parameters = new Map([]);
+		let _g = 0;
+		let _g1 = paramLength;
+		while(_g < _g1) {
+			let i = _g++;
+			parameters.set(paramSegs[i * 2],paramSegs[i * 2 + 1]);
+		}
+		if(ufrag != null) {
+			parameters.set("ufrag",ufrag);
+		}
+		return new snikket_jingle_IceCandidate(sdpMid,ufrag,segments[0],segments[1],segments[2],segments[3],segments[4],segments[5],parameters);
+	}
+}
+snikket_jingle_IceCandidate.__name__ = "snikket.jingle.IceCandidate";
+Object.assign(snikket_jingle_IceCandidate.prototype, {
+	__class__: snikket_jingle_IceCandidate
+});
+class snikket_jingle_Attribute {
+	constructor(key,value) {
+		this.key = key;
+		this.value = value;
+	}
+	toSdp() {
+		return "a=" + this.key + (this.value == null || this.value == "" ? "" : ":" + this.value) + "\r\n";
+	}
+	toString() {
+		return this.toSdp();
+	}
+	static parse(input) {
+		let pos = input.indexOf(":");
+		if(pos < 0) {
+			return new snikket_jingle_Attribute(input,"");
+		} else {
+			return new snikket_jingle_Attribute(HxOverrides.substr(input,0,pos),HxOverrides.substr(input,pos + 1,null));
+		}
+	}
+}
+snikket_jingle_Attribute.__name__ = "snikket.jingle.Attribute";
+Object.assign(snikket_jingle_Attribute.prototype, {
+	__class__: snikket_jingle_Attribute
+});
+class snikket_persistence_Dummy {
+	constructor() {
+	}
+	lastId(accountId,chatId,callback) {
+		callback(null);
+	}
+	storeChats(accountId,chat) {
+	}
+	getChats(accountId,callback) {
+		callback([]);
+	}
+	storeMessages(accountId,messages,callback) {
+		callback(messages);
+	}
+	updateMessage(accountId,message) {
+	}
+	getMessage(accountId,chatId,serverId,localId,callback) {
+		callback(null);
+	}
+	getMessagesBefore(accountId,chatId,beforeId,beforeTime,callback) {
+		callback([]);
+	}
+	getMessagesAfter(accountId,chatId,afterId,afterTime,callback) {
+		callback([]);
+	}
+	getMessagesAround(accountId,chatId,aroundId,aroundTime,callback) {
+		callback([]);
+	}
+	getChatsUnreadDetails(accountId,chats,callback) {
+		callback([]);
+	}
+	storeReaction(accountId,update,callback) {
+		callback(null);
+	}
+	updateMessageStatus(accountId,localId,status,callback) {
+		callback(null);
+	}
+	getMediaUri(hashAlgorithm,hash,callback) {
+		callback(null);
+	}
+	hasMedia(hashAlgorithm,hash,callback) {
+		callback(false);
+	}
+	storeMedia(mime,bd,callback) {
+		callback();
+	}
+	removeMedia(hashAlgorithm,hash) {
+	}
+	storeCaps(caps) {
+	}
+	getCaps(ver,callback) {
+		callback(null);
+	}
+	storeLogin(login,clientId,displayName,token) {
+	}
+	getLogin(login,callback) {
+		callback(null,null,0,null);
+	}
+	removeAccount(accountId,completely) {
+	}
+	storeStreamManagement(accountId,sm) {
+	}
+	getStreamManagement(accountId,callback) {
+		callback(null);
+	}
+	storeService(accountId,serviceId,name,node,caps) {
+	}
+	findServicesWithFeature(accountId,feature,callback) {
+		callback([]);
+	}
+}
+$hx_exports["snikket"]["persistence"]["Dummy"] = snikket_persistence_Dummy;
+snikket_persistence_Dummy.__name__ = "snikket.persistence.Dummy";
+snikket_persistence_Dummy.__interfaces__ = [snikket_Persistence];
+Object.assign(snikket_persistence_Dummy.prototype, {
+	__class__: snikket_persistence_Dummy
+});
+class snikket_persistence_KeyValueStore {
+}
+snikket_persistence_KeyValueStore.__name__ = "snikket.persistence.KeyValueStore";
+snikket_persistence_KeyValueStore.__isInterface__ = true;
+Object.assign(snikket_persistence_KeyValueStore.prototype, {
+	__class__: snikket_persistence_KeyValueStore
+});
+class snikket_persistence_MediaStore {
+}
+snikket_persistence_MediaStore.__name__ = "snikket.persistence.MediaStore";
+snikket_persistence_MediaStore.__isInterface__ = true;
+Object.assign(snikket_persistence_MediaStore.prototype, {
+	__class__: snikket_persistence_MediaStore
+});
+class snikket_persistence_Sqlite {
+	constructor(dbfile,media) {
+		this.smStoreNext = null;
+		this.smStoreInProgress = false;
+		this.storeChatTimer = null;
+		this.storeChatBuffer = new Map([]);
+		this.media = media;
+		media.setKV(this);
+		this.db = new snikket_persistence_SqliteDriver(dbfile);
+		let _gthis = this;
+		let version = thenshim_Promise.then(this.db.exec("PRAGMA user_version;"),function(iter) {
+			let tmp = iter.array[iter.current++];
+			let tmp1 = Std.parseInt(tmp != null ? tmp.user_version : null);
+			let version = tmp1 != null ? tmp1 : 0;
+			if(version < 1) {
+				_gthis.db.exec("CREATE TABLE messages (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tmam_id TEXT,\n\t\t\t\t\tmam_by TEXT,\n\t\t\t\t\tstanza_id TEXT,\n\t\t\t\t\tcorrection_id TEXT NOT NULL,\n\t\t\t\t\tsync_point INTEGER NOT NULL,\n\t\t\t\t\tchat_id TEXT NOT NULL,\n\t\t\t\t\tsender_id TEXT NOT NULL,\n\t\t\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\t\t\tstatus INTEGER NOT NULL,\n\t\t\t\t\tdirection INTEGER NOT NULL,\n\t\t\t\t\ttype INTEGER NOT NULL,\n\t\t\t\t\tstanza TEXT NOT NULL,\n\t\t\t\t\tPRIMARY KEY (account_id, mam_id, mam_by, stanza_id)\n\t\t\t\t);\n\t\t\t\tCREATE INDEX messages_created_at ON messages (account_id, chat_id, created_at);\n\t\t\t\tCREATE INDEX messages_correction_id ON messages (correction_id);\n\t\t\t\tCREATE TABLE chats (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tchat_id TEXT NOT NULL,\n\t\t\t\t\ttrusted INTEGER NOT NULL,\n\t\t\t\t\tavatar_sha1 BLOB,\n\t\t\t\t\tfn TEXT,\n\t\t\t\t\tui_state INTEGER NOT NULL,\n\t\t\t\t\tblocked INTEGER NOT NULL,\n\t\t\t\t\textensions TEXT,\n\t\t\t\t\tread_up_to_id TEXT,\n\t\t\t\t\tread_up_to_by TEXT,\n\t\t\t\t\tcaps_ver BLOB,\n\t\t\t\t\tpresence BLOB NOT NULL,\n\t\t\t\t\tclass TEXT NOT NULL,\n\t\t\t\t\tPRIMARY KEY (account_id, chat_id)\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE keyvaluepairs (\n\t\t\t\t\tk TEXT NOT NULL PRIMARY KEY,\n\t\t\t\t\tv TEXT NOT NULL\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE caps (\n\t\t\t\t\tsha1 BLOB NOT NULL PRIMARY KEY,\n\t\t\t\t\tcaps BLOB NOT NULL\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE services (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tservice_id TEXT NOT NULL,\n\t\t\t\t\tname TEXT,\n\t\t\t\t\tnode TEXT,\n\t\t\t\t\tcaps BLOB NOT NULL,\n\t\t\t\t\tPRIMARY KEY (account_id, service_id)\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE accounts (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tclient_id TEXT NOT NULL,\n\t\t\t\t\tdisplay_name TEXT,\n\t\t\t\t\ttoken TEXT,\n\t\t\t\t\tfast_count INTEGER NOT NULL DEFAULT 0,\n\t\t\t\t\tsm_state BLOB,\n\t\t\t\t\tPRIMARY KEY (account_id)\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE reactions (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tupdate_id TEXT NOT NULL,\n\t\t\t\t\tmam_id TEXT,\n\t\t\t\t\tmam_by TEXT,\n\t\t\t\t\tstanza_id TEXT,\n\t\t\t\t\tchat_id TEXT NOT NULL,\n\t\t\t\t\tsender_id TEXT NOT NULL,\n\t\t\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\t\t\treactions BLOB NOT NULL,\n\t\t\t\t\tkind INTEGER NOT NULL,\n\t\t\t\t\tPRIMARY KEY (account_id, chat_id, sender_id, update_id)\n\t\t\t\t) STRICT;\n\t\t\t\tPRAGMA user_version = 1;");
+			}
+		});
+	}
+	get(k,callback) {
+		thenshim_Promise.then(this.db.exec("SELECT v FROM keyvaluepairs WHERE k=? LIMIT 1",[k]),function(iter) {
+			let _g = iter;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				callback(row.v);
+				return;
+			}
+			callback(null);
+		});
+	}
+	set(k,v,callback) {
+		if(v == null) {
+			thenshim_Promise.then(this.db.exec("DELETE FROM keyvaluepairs WHERE k=?",[k]),function(_) {
+				callback();
+			});
+		} else {
+			thenshim_Promise.then(this.db.exec("INSERT OR REPLACE INTO keyvaluepairs VALUES (?,?)",[k,v]),function(_) {
+				callback();
+			});
+		}
+	}
+	lastId(accountId,chatId,callback) {
+		let params = [accountId];
+		let q = "SELECT mam_id FROM messages WHERE mam_id IS NOT NULL AND sync_point AND account_id=?";
+		if(chatId == null) {
+			q += " AND mam_by=?";
+			params.push(accountId);
+		} else {
+			q += " AND chat_id=?";
+			params.push(chatId);
+		}
+		q += " ORDER BY ROWID DESC LIMIT 1";
+		thenshim_Promise.then(this.db.exec(q,params),function(iter) {
+			let callback1 = callback;
+			let tmp = iter.array[iter.current++];
+			callback1(tmp != null ? tmp.mam_id : null);
+		},function(_) {
+			callback(null);
+		});
+	}
+	storeChats(accountId,chats) {
+		if(this.storeChatTimer != null) {
+			this.storeChatTimer.stop();
+		}
+		let _g = 0;
+		while(_g < chats.length) {
+			let chat = chats[_g];
+			++_g;
+			this.storeChatBuffer.set(accountId + "\n" + chat.chatId,chat);
+		}
+		let _gthis = this;
+		this.storeChatTimer = haxe_Timer.delay(function() {
+			let mapPresence = function(chat) {
+				let storePresence = { };
+				let jsIterator = chat.presence.entries();
+				let _g_jsIterator = jsIterator;
+				let _g_lastStep = jsIterator.next();
+				while(!_g_lastStep.done) {
+					let v = _g_lastStep.value;
+					_g_lastStep = _g_jsIterator.next();
+					let _g_key = v[0];
+					let _g_value = v[1];
+					let resource = _g_key;
+					let presence = _g_value;
+					storePresence[resource] = { };
+					if(presence.caps != null) {
+						_gthis.storeCaps(presence.caps);
+						storePresence[resource].caps = presence.caps.ver();
+					}
+					if(presence.mucUser != null) {
+						storePresence[resource].mucUser = presence.mucUser.toString();
+					}
+				}
+				return storePresence;
+			};
+			let q_b = "";
+			q_b += "INSERT OR REPLACE INTO chats VALUES ";
+			let first = true;
+			let jsIterator = _gthis.storeChatBuffer.values();
+			let __jsIterator = jsIterator;
+			let __lastStep = jsIterator.next();
+			while(!__lastStep.done) {
+				let v = __lastStep.value;
+				__lastStep = __jsIterator.next();
+				let _ = v;
+				if(!first) {
+					q_b += ",";
+				}
+				first = false;
+				q_b += "(?,?,?,?,?,?,?,?,?,?,?,jsonb(?),?)";
+			}
+			let _gthis1 = _gthis.db;
+			let this1 = _gthis.storeChatBuffer;
+			let _g = [];
+			let x = $getIterator({ iterator : function() {
+				return new js_lib_HaxeIterator(this1.values());
+			}});
+			while(x.hasNext()) {
+				let x1 = x.next();
+				let channel = ((x1) instanceof snikket_Channel) ? x1 : null;
+				if(channel != null) {
+					_gthis.storeCaps(channel.disco);
+				}
+				let accountId1 = accountId;
+				let x2 = x1.chatId;
+				let row = x1.isTrusted();
+				let x3 = x1.avatarSha1;
+				let row1 = x1.getDisplayName();
+				let x4 = x1.uiState;
+				let x5 = x1.isBlocked;
+				let row2 = x1.extensions.toString();
+				let row3 = x1.readUpTo();
+				let x6 = x1.readUpToBy;
+				let tmp = channel != null ? channel.disco : null;
+				let row4 = tmp != null ? tmp.verRaw().hash : null;
+				let row5 = JSON.stringify(mapPresence(x1));
+				let c = js_Boot.getClass(x1);
+				let row6 = [accountId1,x2,row,x3,row1,x4,x5,row2,row3,x6,row4,row5,c.__name__.split(".").pop()];
+				_g.push(row6);
+			}
+			let _g1 = [];
+			let e = $getIterator(_g);
+			while(e.hasNext()) {
+				let e1 = e.next();
+				let x = $getIterator(e1);
+				while(x.hasNext()) {
+					let x1 = x.next();
+					_g1.push(x1);
+				}
+			}
+			_gthis1.exec(q_b,_g1);
+			_gthis.storeChatTimer = null;
+			_gthis.storeChatBuffer.clear();
+		},100);
+	}
+	getChats(accountId,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(this.db.exec("SELECT chat_id, trusted, avatar_sha1, fn, ui_state, blocked, extensions, read_up_to_id, read_up_to_by, json(caps) AS caps, json(presence) AS presence, class FROM chats LEFT JOIN caps ON chats.caps_ver=caps.sha1 WHERE account_id=?",[accountId]),function(result) {
+			let fetchCaps = new Map([]);
+			let chats = [];
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let capsJson = row.caps == null ? null : JSON.parse(row.caps);
+				row.capsObj = capsJson == null ? null : new snikket_Caps(capsJson.node,capsJson.identities.map(function(i) {
+					return new snikket_Identity(i.category,i.type,i.name);
+				}),capsJson.features);
+				let presenceJson = JSON.parse(row.presence);
+				row.presenceJson = presenceJson;
+				let access = presenceJson;
+				let _g_access = access;
+				let _g_keys = Reflect.fields(access);
+				let _g_index = 0;
+				while(_g_index < _g_keys.length) {
+					let key = _g_keys[_g_index++];
+					let _g_value = _g_access[key];
+					let _g_key = key;
+					let resource = _g_key;
+					let presence = _g_value;
+					if(presence.caps) {
+						let k = haxe_crypto_Base64.decode(presence.caps).b.bufferValue;
+						fetchCaps.set(k,true);
+					}
+				}
+				chats.push(row);
+			}
+			let fetchCapsSha1s = Lambda.array({ iterator : function() {
+				return new js_lib_HaxeIterator(fetchCaps.keys());
+			}});
+			let _gthis1 = _gthis.db;
+			let result1 = new Array(fetchCapsSha1s.length);
+			let _g1 = 0;
+			let _g2 = fetchCapsSha1s.length;
+			while(_g1 < _g2) {
+				let i = _g1++;
+				result1[i] = "?";
+			}
+			return thenshim_Promise.then(_gthis1.exec("SELECT sha1, json(caps) AS caps FROM caps WHERE sha1 IN (" + result1.join(",") + ")",fetchCapsSha1s),function(capsResult) {
+				return { chats : chats, caps : capsResult};
+			});
+		}),function(result) {
+			let capsMap = new Map([]);
+			let _g = result.caps;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let json = JSON.parse(row.caps);
+				let k = haxe_crypto_Base64.encode(haxe_io_Bytes.ofData(row.sha1));
+				let v = new snikket_Caps(json.node,json.identities.map(function(i) {
+					return new snikket_Identity(i.category,i.type,i.name);
+				}),json.features);
+				capsMap.set(k,v);
+			}
+			let chats = [];
+			let _g1 = 0;
+			let _g2 = result.chats;
+			while(_g1 < _g2.length) {
+				let row = _g2[_g1];
+				++_g1;
+				let presenceMap = new Map([]);
+				let presenceJson = row.presenceJson;
+				let access = presenceJson;
+				let _g_access = access;
+				let _g_keys = Reflect.fields(access);
+				let _g_index = 0;
+				while(_g_index < _g_keys.length) {
+					let key = _g_keys[_g_index++];
+					let _g_value = _g_access[key];
+					let _g_key = key;
+					let resource = _g_key;
+					let presence = _g_value;
+					let v = new snikket_Presence(presence.caps == null ? null : capsMap.get(presence.caps),presence.mucUser == null ? null : snikket_Stanza.parse(presence.mucUser));
+					presenceMap.set(resource,v);
+				}
+				chats.push(new snikket_SerializedChat(row.chat_id,row.trusted,row.avatar_sha1,presenceMap,row.fn,row.ui_state,row.blocked,row.extensions,row.read_up_to_id,row.read_up_to_by,row.capsObj,Reflect.field(row,"class")));
+			}
+			callback(chats);
+		});
+	}
+	storeMessages(accountId,messages,callback) {
+		if(messages.length < 1) {
+			callback(messages);
+			return;
+		}
+		let chatIds = [];
+		let localIds = [];
+		let replyTos = [];
+		let _g = 0;
+		while(_g < messages.length) {
+			let message = messages[_g];
+			++_g;
+			if(message.serverId == null && message.localId == null) {
+				throw haxe_Exception.thrown("Cannot store a message with no id");
+			}
+			if(message.serverId == null && message.isIncoming()) {
+				throw haxe_Exception.thrown("Cannot store an incoming message with no server id");
+			}
+			if(message.serverId != null && message.serverIdBy == null) {
+				throw haxe_Exception.thrown("Cannot store a message with a server id and no by");
+			}
+			if(!message.isIncoming() && message.versions.length < 1) {
+				chatIds.push(message.chatId());
+				localIds.push(message.localId);
+			}
+			if(message.replyToMessage != null && message.replyToMessage.serverIdBy == null) {
+				replyTos.push({ chatId : message.chatId(), serverId : message.replyToMessage.serverId, localId : message.replyToMessage.localId});
+			}
+		}
+		let _gthis = this;
+		let tmp;
+		if(chatIds.length > 0 && localIds.length > 0) {
+			let q_b = "";
+			q_b += "DELETE FROM messages WHERE account_id=? AND direction=? AND chat_id IN (";
+			let result = new Array(chatIds.length);
+			let _g = 0;
+			let _g1 = chatIds.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = "?";
+			}
+			q_b += Std.string(result.join(","));
+			q_b += ") AND stanza_id IN (";
+			let result1 = new Array(localIds.length);
+			let _g2 = 0;
+			let _g3 = localIds.length;
+			while(_g2 < _g3) {
+				let i = _g2++;
+				result1[i] = "?";
+			}
+			q_b += Std.string(result1.join(","));
+			q_b += ")";
+			tmp = this.db.exec(q_b,[accountId,1].concat(chatIds).concat(localIds));
+		} else {
+			tmp = thenshim_Promise.resolve(null);
+		}
+		thenshim_Promise.then(thenshim_Promise.then(tmp,function(_) {
+			let _gthis1 = _gthis.db;
+			let result = new Array(messages.length);
+			let _g = 0;
+			let _g1 = messages.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = "(?,?,?,?,?,?,?,?,CAST(unixepoch(?, 'subsec') * 1000 AS INTEGER),?,?,?,?)";
+			}
+			let tmp = "INSERT OR REPLACE INTO messages VALUES " + result.join(",");
+			let _g2 = [];
+			let _g_current = 0;
+			let _g_array = messages;
+			while(_g_current < _g_array.length) {
+				let x = _g_array[_g_current++];
+				let correctable = x;
+				let message = x.versions.length == 1 ? x.versions[0] : x;
+				let tmp = correctable.localId;
+				_g2.push([accountId,message.serverId,message.serverIdBy,message.localId,tmp != null ? tmp : correctable.serverId,correctable.syncPoint,correctable.chatId(),correctable.senderId,message.timestamp,message.status,message.direction,message.type,message.asStanza().toString()]);
+			}
+			let _g3 = [];
+			let e = $getIterator(_g2);
+			while(e.hasNext()) {
+				let e1 = e.next();
+				let x = $getIterator(e1);
+				while(x.hasNext()) {
+					let x1 = x.next();
+					_g3.push(x1);
+				}
+			}
+			return _gthis1.exec(tmp,_g3);
+		}),function(_) {
+			return thenshim_Promise.then(thenshim_Promise.then(_gthis.hydrateReplyTo(accountId,messages,replyTos),function(ms) {
+				return _gthis.hydrateReactions(accountId,ms);
+			}),callback);
+		});
+	}
+	updateMessage(accountId,message) {
+		this.storeMessages(accountId,[message],function(_) {
+		});
+	}
+	getMessage(accountId,chatId,serverId,localId,callback) {
+		let q = "SELECT stanza, direction, type, strftime('%FT%H:%M:%fZ', created_at / 1000.0, 'unixepoch') AS timestamp, sender_id, mam_id, mam_by, sync_point FROM messages WHERE account_id=? AND chat_id=?";
+		let params = [accountId,chatId];
+		if(serverId != null) {
+			q += " AND mam_id=?";
+			params.push(serverId);
+		} else if(localId != null) {
+			q += " AND stanza_id=?";
+			params.push(localId);
+		}
+		q += "LIMIT 1";
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(this.db.exec(q,params),function(result) {
+			return _gthis.hydrateMessages(accountId,result);
+		}),function(messages) {
+			let _g = 0;
+			while(_g < messages.length) {
+				let message = messages[_g];
+				++_g;
+				thenshim_Promise.then(thenshim_Promise.then(message.replyToMessage != null ? _gthis.hydrateReplyTo(accountId,[message],[{ chatId : chatId, serverId : message.replyToMessage.serverId, localId : message.replyToMessage.localId}]) : thenshim_Promise.resolve([message]),function(messages) {
+					return _gthis.hydrateReactions(accountId,messages);
+				}),function(hydrated) {
+					callback(hydrated[0]);
+				});
+				return;
+			}
+			callback(null);
+		});
+	}
+	getMessages(accountId,chatId,time,op) {
+		let q = "SELECT\n\t\t\tcorrection_id AS stanza_id,\n\t\t\tversions.stanza,\n\t\t\tjson_group_object(COALESCE(versions.mam_id, versions.stanza_id), strftime('%FT%H:%M:%fZ', versions.created_at / 1000.0, 'unixepoch')) AS version_times,\n\t\t\tjson_group_object(COALESCE(versions.mam_id, versions.stanza_id), versions.stanza) AS versions,\n\t\t\tmessages.direction,\n\t\t\tmessages.type,\n\t\t\tstrftime('%FT%H:%M:%fZ', messages.created_at / 1000.0, 'unixepoch') AS timestamp,\n\t\t\tmessages.sender_id,\n\t\t\tmessages.mam_id,\n\t\t\tmessages.mam_by,\n\t\t\tmessages.sync_point,\n\t\t\tMAX(versions.created_at)\n\t\t\tFROM messages INNER JOIN messages versions USING (correction_id) WHERE messages.stanza_id=correction_id AND messages.account_id=? AND messages.chat_id=?";
+		let params = [accountId,chatId];
+		if(time != null) {
+			q += " AND messages.created_at " + op + "CAST(unixepoch(?, 'subsec') * 1000 AS INTEGER)";
+			params.push(time);
+		}
+		q += " GROUP BY correction_id ORDER BY messages.created_at";
+		if(op == "<" || op == "<=") {
+			q += " DESC";
+		}
+		q += ", messages.ROWID";
+		if(op == "<" || op == "<=") {
+			q += " DESC";
+		}
+		q += " LIMIT 50";
+		let _gthis = this;
+		return thenshim_Promise.then(thenshim_Promise.then(thenshim_Promise.then(this.db.exec(q,params),function(result) {
+			return _gthis.hydrateMessages(accountId,result);
+		}),function(iter) {
+			let arr = [];
+			let replyTos = [];
+			let _g = 0;
+			while(_g < iter.length) {
+				let message = iter[_g];
+				++_g;
+				arr.push(message);
+				if(message.replyToMessage != null && message.replyToMessage.serverIdBy == null) {
+					replyTos.push({ chatId : message.chatId(), serverId : message.replyToMessage.serverId, localId : message.replyToMessage.localId});
+				}
+			}
+			if(op == "<" || op == "<=") {
+				arr.reverse();
+			}
+			return _gthis.hydrateReplyTo(accountId,arr,replyTos);
+		}),function(messages) {
+			return _gthis.hydrateReactions(accountId,messages);
+		});
+	}
+	getMessagesBefore(accountId,chatId,beforeId,beforeTime,callback) {
+		thenshim_Promise.then(this.getMessages(accountId,chatId,beforeTime,"<"),callback);
+	}
+	getMessagesAfter(accountId,chatId,afterId,afterTime,callback) {
+		thenshim_Promise.then(this.getMessages(accountId,chatId,afterTime,">"),callback);
+	}
+	getMessagesAround(accountId,chatId,aroundId,aroundTime,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(aroundTime == null ? thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+			_gthis.getMessage(accountId,chatId,aroundId,null,resolve);
+		}),function(m) {
+			if(m != null) {
+				return thenshim_Promise.resolve(m.timestamp);
+			} else {
+				return thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+					_gthis.getMessage(accountId,chatId,null,aroundId,resolve);
+				}),function(m) {
+					if(m != null) {
+						return m.timestamp;
+					} else {
+						return null;
+					}
+				});
+			}
+		}) : thenshim_Promise.resolve(aroundTime),function(aroundTime) {
+			return thenshim_PromiseTools.all([_gthis.getMessages(accountId,chatId,aroundTime,"<"),_gthis.getMessages(accountId,chatId,aroundTime,">=")]);
+		}),function(results) {
+			let callback1 = callback;
+			let _g = [];
+			let _g_current = 0;
+			let _g_array = results;
+			while(_g_current < _g_array.length) {
+				let x = _g_array[_g_current++];
+				_g.push(x);
+			}
+			let _g1 = [];
+			let e = $getIterator(_g);
+			while(e.hasNext()) {
+				let e1 = e.next();
+				let x = $getIterator(e1);
+				while(x.hasNext()) {
+					let x1 = x.next();
+					_g1.push(x1);
+				}
+			}
+			callback1(_g1);
+		});
+	}
+	getChatsUnreadDetails(accountId,chats,callback) {
+		if(chats == null || chats.length < 1) {
+			callback([]);
+			return;
+		}
+		let params = [accountId];
+		let subq_b = "";
+		subq_b += "SELECT chat_id, MAX(created_at) AS created_at FROM messages WHERE account_id=?";
+		subq_b += " AND chat_id IN (";
+		let _g_current = 0;
+		let _g_array = chats;
+		while(_g_current < _g_array.length) {
+			let _g_value = _g_array[_g_current];
+			let _g_key = _g_current++;
+			let i = _g_key;
+			let chat = _g_value;
+			if(i != 0) {
+				subq_b += ",";
+			}
+			subq_b += "?";
+			params.push(chat.chatId);
+		}
+		subq_b += ") AND (mam_id IN (";
+		let didOne = false;
+		let _g = 0;
+		while(_g < chats.length) {
+			let chat = chats[_g];
+			++_g;
+			if(chat.readUpTo() != null) {
+				if(didOne) {
+					subq_b += ",";
+				}
+				subq_b += "?";
+				params.push(chat.readUpTo());
+				didOne = true;
+			}
+		}
+		subq_b += ") OR direction=?) GROUP BY chat_id";
+		params.push(1);
+		let q_b = "";
+		q_b += "SELECT chat_id AS chatId, stanza, direction, type, sender_id, mam_id, mam_by, sync_point, CASE WHEN subq.created_at IS NULL THEN COUNT(*) ELSE COUNT(*) - 1 END AS unreadCount, strftime('%FT%H:%M:%fZ', MAX(messages.created_at) / 1000.0, 'unixepoch') AS timestamp FROM messages LEFT JOIN (";
+		q_b += Std.string(subq_b);
+		q_b += ") subq USING (chat_id) WHERE account_id=? AND chat_id IN (";
+		params.push(accountId);
+		let _g_current1 = 0;
+		let _g_array1 = chats;
+		while(_g_current1 < _g_array1.length) {
+			let _g_value = _g_array1[_g_current1];
+			let _g_key = _g_current1++;
+			let i = _g_key;
+			let chat = _g_value;
+			if(i != 0) {
+				q_b += ",";
+			}
+			q_b += "?";
+			params.push(chat.chatId);
+		}
+		q_b += ") AND (subq.created_at IS NULL OR messages.created_at >= subq.created_at) GROUP BY chat_id;";
+		let _gthis = this;
+		thenshim_Promise.then(this.db.exec(q_b,params),function(result) {
+			let details = [];
+			let rows = Lambda.array({ iterator : function() {
+				return result;
+			}});
+			return thenshim_Promise.then(thenshim_Promise.resolve(_gthis.hydrateMessages(accountId,new haxe_iterators_ArrayIterator(rows))),function(messages) {
+				let _g_current = 0;
+				let _g_array = messages;
+				while(_g_current < _g_array.length) {
+					let _g_value = _g_array[_g_current];
+					let _g_key = _g_current++;
+					let i = _g_key;
+					let m = _g_value;
+					details.push({ unreadCount : rows[i].unreadCount, chatId : rows[i].chatId, message : m});
+				}
+				callback(details);
+			});
+		});
+	}
+	storeReaction(accountId,update,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(this.db.exec("INSERT OR REPLACE INTO reactions VALUES (?,?,?,?,?,?,?,CAST(unixepoch(?, 'subsec') * 1000 AS INTEGER),jsonb(?),?)",[accountId,update.updateId,update.serverId,update.serverIdBy,update.localId,update.chatId,update.senderId,update.timestamp,JSON.stringify(update.reactions),update.kind]),function(_) {
+			_gthis.getMessage(accountId,update.chatId,update.serverId,update.localId,callback);
+		});
+	}
+	updateMessageStatus(accountId,localId,status,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(thenshim_Promise.then(this.db.exec("UPDATE messages SET status=? WHERE account_id=? AND stanza_id=? AND direction=? AND status <> ?",[status,accountId,localId,1,2]),function(_) {
+			return _gthis.db.exec("SELECT stanza, direction, type, strftime('%FT%H:%M:%fZ', created_at / 1000.0, 'unixepoch') AS timestamp, sender_id, mam_id, mam_by, sync_point FROM messages WHERE account_id=? AND stanza_id=? AND direction=?",[accountId,localId,1]);
+		}),function(result) {
+			return _gthis.hydrateMessages(accountId,result);
+		}),function(messages) {
+			let _g = 0;
+			while(_g < messages.length) {
+				let message = messages[_g];
+				++_g;
+				thenshim_Promise.then(thenshim_Promise.then(message.replyToMessage != null ? _gthis.hydrateReplyTo(accountId,[message],[{ chatId : message.chatId(), serverId : message.replyToMessage.serverId, localId : message.replyToMessage.localId}]) : thenshim_Promise.resolve([message]),function(messages) {
+					return _gthis.hydrateReactions(accountId,messages);
+				}),function(hydrated) {
+					callback(hydrated[0]);
+				});
+				return;
+			}
+		});
+	}
+	hasMedia(hashAlgorithm,hash,callback) {
+		this.media.hasMedia(hashAlgorithm,hash,callback);
+	}
+	removeMedia(hashAlgorithm,hash) {
+		this.media.removeMedia(hashAlgorithm,hash);
+	}
+	storeMedia(mime,bd,callback) {
+		this.media.storeMedia(mime,bd,callback);
+	}
+	storeCaps(caps) {
+		this.db.exec("INSERT OR IGNORE INTO caps VALUES (?,jsonb(?))",[caps.verRaw().hash,JSON.stringify({ node : caps.node, identities : caps.identities, features : caps.features})]);
+	}
+	getCaps(ver,callback) {
+		let verData;
+		try {
+			verData = haxe_crypto_Base64.decode(ver).b.bufferValue;
+		} catch( _g ) {
+			callback(null);
+			return;
+		}
+		thenshim_Promise.then(this.db.exec("SELECT json(caps) AS caps FROM caps WHERE sha1=? LIMIT 1",[verData]),function(result) {
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let json = JSON.parse(row.caps);
+				callback(new snikket_Caps(json.node,json.identities.map(function(i) {
+					return new snikket_Identity(i.category,i.type,i.name);
+				}),json.features));
+				return;
+			}
+			callback(null);
+		});
+	}
+	storeLogin(accountId,clientId,displayName,token) {
+		let params = [accountId,clientId,displayName];
+		let q_b = "";
+		q_b += "INSERT INTO accounts (account_id, client_id, display_name";
+		if(token != null) {
+			q_b += ", token, fast_count";
+		}
+		q_b += ") VALUES (?,?,?";
+		if(token != null) {
+			q_b += ",?";
+			params.push(token);
+			q_b += ",0";
+		}
+		q_b += ") ON CONFLICT DO UPDATE SET client_id=?";
+		params.push(clientId);
+		q_b += ", display_name=?";
+		params.push(displayName);
+		if(token != null) {
+			q_b += ", token=?";
+			params.push(token);
+			q_b += ", fast_count=0";
+		}
+		this.db.exec(q_b,params);
+	}
+	getLogin(accountId,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(this.db.exec("SELECT client_id, display_name, token, fast_count FROM accounts WHERE account_id=? LIMIT 1",[accountId]),function(result) {
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				if(row.token != null) {
+					_gthis.db.exec("UPDATE accounts SET fast_count=fast_count+1 WHERE account_id=?",[accountId]);
+				}
+				let tmp = row.fast_count;
+				callback(row.client_id,row.token,tmp != null ? tmp : 0,row.display_name);
+				return;
+			}
+			callback(null,null,0,null);
+		});
+	}
+	removeAccount(accountId,completely) {
+		this.db.exec("DELETE FROM accounts WHERE account_id=?",[accountId]);
+		if(!completely) {
+			return;
+		}
+		this.db.exec("DELETE FROM messages WHERE account_id=?",[accountId]);
+		this.db.exec("DELETE FROM chats WHERE account_id=?",[accountId]);
+		this.db.exec("DELETE FROM services WHERE account_id=?",[accountId]);
+	}
+	storeStreamManagement(accountId,sm) {
+		this.smStoreNext = sm;
+		let _gthis = this;
+		if(!this.smStoreInProgress) {
+			this.smStoreInProgress = true;
+			thenshim_Promise.then(this.db.exec("UPDATE accounts SET sm_state=? WHERE account_id=?",[sm,accountId]),function(_) {
+				_gthis.smStoreInProgress = false;
+				if(_gthis.smStoreNext != sm) {
+					_gthis.storeStreamManagement(accountId,sm);
+				}
+			});
+		}
+	}
+	getStreamManagement(accountId,callback) {
+		thenshim_Promise.then(this.db.exec("SELECT sm_state FROM accounts  WHERE account_id=?",[accountId]),function(result) {
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				callback(row.sm_state);
+				return;
+			}
+			callback(null);
+		});
+	}
+	storeService(accountId,serviceId,name,node,caps) {
+		this.storeCaps(caps);
+		this.db.exec("INSERT OR REPLACE INTO services VALUES (?,?,?,?,?)",[accountId,serviceId,name,node,caps.verRaw().hash]);
+	}
+	findServicesWithFeature(accountId,feature,callback) {
+		thenshim_Promise.then(this.db.exec("SELECT service_id, name, node, json(caps.caps) AS caps FROM services INNER JOIN caps ON services.caps=caps.sha1 WHERE account_id=?",[accountId]),function(result) {
+			let services = [];
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let json = JSON.parse(row.caps);
+				let features = json.features;
+				if(features.contains(feature)) {
+					let json1 = json.node;
+					let tmp = json.identities.map(function(i) {
+						return new snikket_Identity(i.category,i.type,i.name);
+					});
+					let tmp1 = features.array();
+					row.set("caps",new snikket_Caps(json1,tmp,tmp1));
+					services.push(row);
+				}
+			}
+			callback(services);
+		});
+	}
+	hydrateReactions(accountId,messages) {
+		let result = new Array(messages.length);
+		let _g = 0;
+		let _g1 = messages.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let m = messages[i];
+			result[i] = { chatId : m.chatId(), serverId : m.serverId, serverIdBy : m.serverIdBy, localId : m.localId};
+		}
+		return thenshim_Promise.then(this.fetchReactions(accountId,result),function(result) {
+			let jsIterator = result.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let id = _g_key;
+				let reactions = _g_value;
+				let m = Lambda.find(messages,function(m) {
+					return (m.serverId == null ? m.localId : m.serverId + "\n" + m.serverIdBy) + "\n" + m.chatId() == id;
+				});
+				if(m != null) {
+					m.set_reactions(reactions);
+				}
+			}
+			return messages;
+		});
+	}
+	fetchReactions(accountId,ids) {
+		let q_b = "";
+		q_b += "SELECT kind, chat_id, mam_id, mam_by, stanza_id, sender_id, json(reactions) AS reactions FROM reactions WHERE 1=0";
+		let params = [];
+		let _g = 0;
+		while(_g < ids.length) {
+			let item = ids[_g];
+			++_g;
+			if(item.serverId != null) {
+				q_b += " OR (mam_id=? AND mam_by=?)";
+				params.push(item.serverId);
+				params.push(item.serverIdBy);
+			} else {
+				q_b += " OR stanza_id=?";
+				params.push(item.localId);
+			}
+		}
+		q_b += " ORDER BY created_at, ROWID";
+		return thenshim_Promise.then(this.db.exec(q_b,params),function(rows) {
+			let agg = new Map([]);
+			let _g = rows;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let reactions = JSON.parse(row.reactions);
+				let mapId = (row.mam_id == null ? row.stanza_id : row.mam_id + "\n" + row.mam_by) + "\n" + row.chat_id;
+				if(!agg.has(mapId)) {
+					agg.set(mapId,new Map([]));
+				}
+				let map = agg.get(mapId);
+				if(!map.has(row.sender_id)) {
+					let v = [];
+					map.set(row.sender_id,v);
+				}
+				if(row.kind == 1) {
+					let _g = 0;
+					while(_g < reactions.length) {
+						let reaction = reactions[_g];
+						++_g;
+						map.get(row.sender_id).push(reaction);
+					}
+				} else if(row.kind == 0) {
+					let k = row.sender_id;
+					let _g = [];
+					let _g1 = 0;
+					let _g2 = map.get(row.sender_id);
+					while(_g1 < _g2.length) {
+						let v = _g2[_g1];
+						++_g1;
+						if(v.uri != null) {
+							_g.push(v);
+						}
+					}
+					let v = reactions.concat(_g);
+					map.set(k,v);
+				} else if(row.kind == 2) {
+					map.set(row.sender_id,reactions);
+				}
+			}
+			let result = new Map([]);
+			let jsIterator = agg.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let id = _g_key;
+				let reactions = _g_value;
+				let map = new Map([]);
+				let jsIterator = reactions.values();
+				let _g_jsIterator1 = jsIterator;
+				let _g_lastStep1 = jsIterator.next();
+				while(!_g_lastStep1.done) {
+					let v = _g_lastStep1.value;
+					_g_lastStep1 = _g_jsIterator1.next();
+					let reactionsBySender = v;
+					let _g = 0;
+					while(_g < reactionsBySender.length) {
+						let reactionD = reactionsBySender[_g];
+						++_g;
+						let reaction = reactionD.uri == null ? new snikket_Reaction(reactionD.senderId,reactionD.timestamp,reactionD.text,reactionD.envelopeId,reactionD.key) : new snikket_CustomEmojiReaction(reactionD.senderId,reactionD.timestamp,reactionD.text,reactionD.uri,reactionD.envelopeId);
+						if(!map.has(reaction.key)) {
+							let v = [];
+							map.set(reaction.key,v);
+						}
+						map.get(reaction.key).push(reaction);
+					}
+				}
+				result.set(id,map);
+			}
+			return result;
+		});
+	}
+	hydrateReplyTo(accountId,messages,replyTos) {
+		let _gthis = this;
+		let tmp;
+		if(replyTos.length < 1) {
+			tmp = thenshim_Promise.resolve(null);
+		} else {
+			let params = [accountId];
+			let q_b = "";
+			q_b += "SELECT chat_id, stanza_id, stanza, direction, type, strftime('%FT%H:%M:%fZ', created_at / 1000.0, 'unixepoch') AS timestamp, sender_id, mam_id, mam_by, sync_point FROM messages WHERE account_id=? AND (";
+			let result = new Array(replyTos.length);
+			let _g = 0;
+			let _g1 = replyTos.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let parent = replyTos[i];
+				let x;
+				if(parent.serverId != null) {
+					params.push(parent.chatId);
+					params.push(parent.serverId);
+					x = " (chat_id=? AND mam_id=?)";
+				} else {
+					params.push(parent.chatId);
+					params.push(parent.localId);
+					x = " (chat_id=? AND stanza_id=?)";
+				}
+				result[i] = x;
+			}
+			q_b += Std.string(result.join(" OR "));
+			q_b += ")";
+			tmp = this.db.exec(q_b,params);
+		}
+		return thenshim_Promise.then(tmp,function(iter) {
+			if(iter != null) {
+				let parents = Lambda.array({ iterator : function() {
+					return iter;
+				}});
+				let _g = 0;
+				while(_g < messages.length) {
+					let message = messages[_g];
+					++_g;
+					if(message.replyToMessage != null) {
+						let found = Lambda.find(parents,function(p) {
+							if(p.chat_id == message.chatId() && (message.replyToMessage.serverId == null || p.mam_id == message.replyToMessage.serverId)) {
+								if(message.replyToMessage.localId != null) {
+									return p.stanza_id == message.replyToMessage.localId;
+								} else {
+									return true;
+								}
+							} else {
+								return false;
+							}
+						});
+						if(found != null) {
+							message.set_replyToMessage(_gthis.hydrateMessages(accountId,new haxe_iterators_ArrayIterator([found]))[0]);
+						}
+					}
+				}
+			}
+			return messages;
+		});
+	}
+	hydrateMessages(accountId,rows) {
+		let accountJid = snikket_JID.parse(accountId);
+		let _g = [];
+		let inlobj_iterator = function() {
+			return rows;
+		};
+		let x = inlobj_iterator();
+		while(x.hasNext()) {
+			let x1 = x.next();
+			let row = x1;
+			_g.push(snikket_ChatMessage.fromStanza(snikket_Stanza.parse(row.stanza),accountJid,function(builder,_) {
+				builder.syncPoint = row.sync_point;
+				builder.timestamp = row.timestamp;
+				builder.direction = row.direction;
+				builder.type = row.type;
+				builder.senderId = row.sender_id;
+				builder.serverId = row.mam_id;
+				builder.serverIdBy = row.mam_by;
+				if(row.stanza_id != null) {
+					builder.localId = row.stanza_id;
+				}
+				if(row.versions != null) {
+					let versionTimes = JSON.parse(row.version_times);
+					let versions = JSON.parse(row.versions);
+					if(Reflect.fields(versions).length > 1) {
+						let access = versions;
+						let _g_access = access;
+						let _g_keys = Reflect.fields(access);
+						let _g_index = 0;
+						while(_g_index < _g_keys.length) {
+							let version = _g_access[_g_keys[_g_index++]];
+							let versionM = snikket_ChatMessage.fromStanza(snikket_Stanza.parse(version),accountJid,function(toPushB,_) {
+								let tmp = toPushB.serverId;
+								toPushB.timestamp = versionTimes[tmp != null ? tmp : toPushB.localId];
+								return toPushB;
+							});
+							let toPush = versionM == null || versionM.versions.length < 1 ? versionM : versionM.versions[0];
+							if(toPush != null) {
+								builder.versions.push(toPush);
+							}
+						}
+						builder.versions.sort(function(a,b) {
+							return Reflect.compare(b.timestamp,a.timestamp);
+						});
+					}
+				}
+				return builder;
+			}));
+		}
+		return _g;
+	}
+}
+$hx_exports["snikket"]["persistence"]["Sqlite"] = snikket_persistence_Sqlite;
+snikket_persistence_Sqlite.__name__ = "snikket.persistence.Sqlite";
+snikket_persistence_Sqlite.__interfaces__ = [snikket_persistence_KeyValueStore,snikket_Persistence];
+Object.assign(snikket_persistence_Sqlite.prototype, {
+	__class__: snikket_persistence_Sqlite
+});
+class snikket_persistence_SqliteDriver {
+	constructor(dbfile) {
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(snikket_persistence_Worker1.v2({ worker : function() {
+			return new Worker(new URL("sqlite-worker1.mjs",import.meta.url),{ type : "module"});
+		}}),function(promiser) {
+			_gthis.sqlite = promiser;
+			return _gthis.sqlite("open",{ filename : dbfile, vfs : "opfs-sahpool"});
+		}),function(openResult) {
+			return _gthis.dbId = openResult.dbId;
+		});
+	}
+	exec(sql,params) {
+		let _gthis = this;
+		if(this.sqlite == null || this.dbId == null) {
+			return thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+				haxe_Timer.delay(function() {
+					resolve(null);
+				},100);
+			}),function(_) {
+				return _gthis.exec(sql,params);
+			});
+		}
+		let items = [];
+		let signalAllDone;
+		let allDone = thenshim_Promise._new(function(resolve,reject) {
+			signalAllDone = resolve;
+		});
+		return thenshim_Promise.then(thenshim_Promise.then(this.sqlite("exec",{ dbId : this.dbId, sql : sql, bind : params, rowMode : "object", callback : function(r) {
+			if(r.rowNumber == null) {
+				signalAllDone(null);
+			} else {
+				items.push(r.row);
+			}
+			return null;
+		}}),function(_) {
+			return allDone;
+		}),function(_) {
+			return new haxe_iterators_ArrayIterator(items);
+		});
+	}
+}
+snikket_persistence_SqliteDriver.__name__ = "snikket.persistence.SqliteDriver";
+Object.assign(snikket_persistence_SqliteDriver.prototype, {
+	__class__: snikket_persistence_SqliteDriver
+});
+class snikket_queries_GenericQuery {
+	constructor() {
+		if(snikket_queries_GenericQuery._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.isFinished = false;
+	}
+	getQueryStanza() {
+		if(this.queryStanza == null) {
+			throw new haxe_Exception("Query has not been initialized");
+		}
+		return this.queryStanza;
+	}
+	finish() {
+		this.isFinished = true;
+		if(this.handleFinished != null) {
+			this.handleFinished();
+		}
+	}
+	onFinished(handler) {
+		this.handleFinished = handler;
+		if(this.isFinished) {
+			this.handleFinished();
+		}
+	}
+}
+snikket_queries_GenericQuery.__name__ = "snikket.queries.GenericQuery";
+Object.assign(snikket_queries_GenericQuery.prototype, {
+	__class__: snikket_queries_GenericQuery
+});
+class snikket_queries_BlocklistGet extends snikket_queries_GenericQuery {
+	constructor() {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:blocking";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ type : "get", id : this.queryId}).tag("blocklist",{ xmlns : this.xmlns}).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return [];
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("blocklist",this.xmlns);
+			if(q == null) {
+				return [];
+			}
+			let _this = q.allTags("item");
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].attr["jid"];
+			}
+			this.result = result;
+		}
+		return this.result;
+	}
+}
+snikket_queries_BlocklistGet.__name__ = "snikket.queries.BlocklistGet";
+snikket_queries_BlocklistGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_BlocklistGet.prototype, {
+	__class__: snikket_queries_BlocklistGet
+});
+class snikket_queries_BoB extends snikket_queries_GenericQuery {
+	constructor(to,uri) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,uri);
+	}
+	_hx_constructor(to,uri) {
+		this.xmlns = "urn:xmpp:bob";
+		super._hx_constructor();
+		if(!uri.startsWith("cid:") || !uri.endsWith("@bob.xmpp.org") || !uri.includes("+")) {
+			throw haxe_Exception.thrown("invalid BoB URI");
+		}
+		this.queryId = snikket_ID.short();
+		let tmp = HxOverrides.substr(uri,4,null);
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("data",{ xmlns : this.xmlns, cid : tmp}).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let data = this.responseStanza.getChild("data",this.xmlns);
+			if(data == null) {
+				return null;
+			}
+			let maxAge = data.attr["max-age"];
+			this.result = { bytes : haxe_crypto_Base64.decode(StringTools.replace(data.getText(),"\n","")), type : data.attr["type"], maxAge : maxAge == null ? null : Std.parseInt(maxAge)};
+		}
+		return this.result;
+	}
+	static uri(hash) {
+		let algo = hash.algorithm == "sha-1" ? "sha1" : hash.algorithm;
+		return "cid:" + encodeURIComponent(algo) + "+" + hash.toHex() + "@bob.xmpp.org";
+	}
+	static forHash(to,hash) {
+		let algo = hash.algorithm == "sha-1" ? "sha1" : hash.algorithm;
+		return new snikket_queries_BoB(to,"cid:" + encodeURIComponent(algo) + "+" + hash.toHex() + "@bob.xmpp.org");
+	}
+}
+snikket_queries_BoB.__name__ = "snikket.queries.BoB";
+snikket_queries_BoB.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_BoB.prototype, {
+	__class__: snikket_queries_BoB
+});
+class snikket_queries_DiscoInfoGet extends snikket_queries_GenericQuery {
+	constructor(to,node) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,node);
+	}
+	_hx_constructor(to,node) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "http://jabber.org/protocol/disco#info";
+		super._hx_constructor();
+		let attr = { xmlns : this.xmlns};
+		if(node != null) {
+			attr["node"] = node;
+		}
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("query",attr).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("query",this.xmlns);
+			if(q == null) {
+				return null;
+			}
+			let identities = q.allTags("identity");
+			let features = q.allTags("feature");
+			let q1 = q.attr["node"];
+			let result = new Array(identities.length);
+			let _g = 0;
+			let _g1 = identities.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let identity = identities[i];
+				result[i] = new snikket_Identity(identity.attr["category"],identity.attr["type"],identity.attr["name"]);
+			}
+			let tmp = result;
+			let result1 = new Array(features.length);
+			let _g2 = 0;
+			let _g3 = features.length;
+			while(_g2 < _g3) {
+				let i = _g2++;
+				result1[i] = features[i].attr["var"];
+			}
+			this.result = new snikket_Caps(q1,tmp,result1);
+		}
+		return this.result;
+	}
+}
+snikket_queries_DiscoInfoGet.__name__ = "snikket.queries.DiscoInfoGet";
+snikket_queries_DiscoInfoGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_DiscoInfoGet.prototype, {
+	__class__: snikket_queries_DiscoInfoGet
+});
+class snikket_queries_DiscoItemsGet extends snikket_queries_GenericQuery {
+	constructor(to,node) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,node);
+	}
+	_hx_constructor(to,node) {
+		this.queryId = null;
+		this.xmlns = "http://jabber.org/protocol/disco#items";
+		super._hx_constructor();
+		let attr = { xmlns : this.xmlns};
+		if(node != null) {
+			attr["node"] = node;
+		}
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("query",attr).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("query",this.xmlns);
+			if(q == null) {
+				return null;
+			}
+			this.result = [];
+			let _g = 0;
+			let _g1 = q.allTags("item");
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				let jid = item.attr["jid"];
+				if(jid != null) {
+					this.result.push({ jid : snikket_JID.parse(jid), name : item.attr["name"], node : item.attr["node"]});
+				}
+			}
+		}
+		return this.result;
+	}
+}
+snikket_queries_DiscoItemsGet.__name__ = "snikket.queries.DiscoItemsGet";
+snikket_queries_DiscoItemsGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_DiscoItemsGet.prototype, {
+	__class__: snikket_queries_DiscoItemsGet
+});
+class snikket_queries_ExtDiscoGet extends snikket_queries_GenericQuery {
+	constructor(to) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to);
+	}
+	_hx_constructor(to) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:extdisco:2";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("services",{ xmlns : this.xmlns}).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("services",this.xmlns);
+			if(q == null) {
+				return null;
+			}
+			this.result = q.allTags("service");
+		}
+		return this.result;
+	}
+}
+snikket_queries_ExtDiscoGet.__name__ = "snikket.queries.ExtDiscoGet";
+snikket_queries_ExtDiscoGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_ExtDiscoGet.prototype, {
+	__class__: snikket_queries_ExtDiscoGet
+});
+class snikket_queries_HttpUploadSlot extends snikket_queries_GenericQuery {
+	constructor(to,filename,size,mime,hashes) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,filename,size,mime,hashes);
+	}
+	_hx_constructor(to,filename,size,mime,hashes) {
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:http:upload:0";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("request",{ xmlns : this.xmlns, filename : filename, size : size == null ? "null" : "" + size, "content-type" : mime});
+		let _g = 0;
+		while(_g < hashes.length) {
+			let hash = hashes[_g];
+			++_g;
+			this.queryStanza.textTag("hash",haxe_crypto_Base64.encode(haxe_io_Bytes.ofData(hash.hash)),{ xmlns : "urn:xmpp:hashes:2", algo : hash.algorithm});
+		}
+		this.queryStanza.up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("slot",this.xmlns);
+			if(q == null) {
+				return null;
+			}
+			let get = q.findText("get@url");
+			if(get == null) {
+				return null;
+			}
+			let put = q.findText("put@url");
+			if(put == null) {
+				return null;
+			}
+			let headers = [];
+			let _g = 0;
+			let _g1 = q.getChild("put").allTags("header");
+			while(_g < _g1.length) {
+				let header = _g1[_g];
+				++_g;
+				headers.push(new tink_http_HeaderField(header.attr["name"].toLowerCase(),header.getText()));
+			}
+			this.result = { get : get, put : put, putHeaders : headers};
+		}
+		return this.result;
+	}
+}
+snikket_queries_HttpUploadSlot.__name__ = "snikket.queries.HttpUploadSlot";
+snikket_queries_HttpUploadSlot.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_HttpUploadSlot.prototype, {
+	__class__: snikket_queries_HttpUploadSlot
+});
+class snikket_queries_JabberIqGatewayGet extends snikket_queries_GenericQuery {
+	constructor(to,prompt) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,prompt);
+	}
+	_hx_constructor(to,prompt) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "jabber:iq:gateway";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : prompt == null ? "get" : "set", id : this.queryId});
+		let query = this.queryStanza.tag("query",{ xmlns : this.xmlns});
+		if(prompt != null) {
+			query.textTag("prompt",prompt,{ });
+		}
+		query.up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let error = this.responseStanza.getChild("error");
+			if(error == null) {
+				let q = this.responseStanza.getChild("query",this.xmlns);
+				if(q == null) {
+					return null;
+				}
+				let prompt = q.getChild("prompt");
+				if(prompt == null) {
+					let jid = q.getChild("jid");
+					if(jid == null) {
+						return null;
+					}
+					this.result = haxe_ds_Either.Right(jid.getText());
+				} else {
+					this.result = haxe_ds_Either.Right(prompt.getText());
+				}
+			} else {
+				if(error.getChild("service-unavailable","urn:ietf:params:xml:ns:xmpp-stanzas") != null) {
+					return null;
+				}
+				if(error.getChild("feature-not-implemented","urn:ietf:params:xml:ns:xmpp-stanzas") != null) {
+					return null;
+				}
+				this.result = haxe_ds_Either.Left(error.getText());
+			}
+		}
+		return this.result;
+	}
+}
+snikket_queries_JabberIqGatewayGet.__name__ = "snikket.queries.JabberIqGatewayGet";
+snikket_queries_JabberIqGatewayGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_JabberIqGatewayGet.prototype, {
+	__class__: snikket_queries_JabberIqGatewayGet
+});
+class snikket_queries_MAMQuery extends snikket_queries_GenericQuery {
+	constructor(params,jid) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(params,jid);
+	}
+	_hx_constructor(params,jid) {
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:mam:2";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ type : "set", to : jid}).tag("query",{ xmlns : this.xmlns, queryid : this.queryId}).tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value",this.xmlns).up();
+		this.addStringField("start",params.startTime);
+		this.addStringField("end",params.endTime);
+		this.addStringField("with",params.with);
+		this.addStringField("before-id",params.beforeId);
+		this.addStringField("after-id",params.afterId);
+		this.addArrayField("ids",params.ids);
+		this.queryStanza.up();
+		if(params.page != null) {
+			let page = params.page;
+			this.queryStanza.tag("set",{ xmlns : "http://jabber.org/protocol/rsm"});
+			if(page.limit != null) {
+				this.queryStanza.textTag("max",page.limit == null ? "null" : "" + page.limit);
+			}
+			if(page.before != null && page.after != null) {
+				throw new haxe_Exception("It is not allowed to request a page before AND a page after");
+			}
+			if(page.before != null) {
+				this.queryStanza.textTag("before",page.before);
+			} else if(page.after != null) {
+				this.queryStanza.textTag("after",page.after);
+			}
+			this.queryStanza.up();
+		}
+	}
+	addStringField(name,value) {
+		if(value == null) {
+			return;
+		}
+		this.queryStanza.tag("field",{ "var" : name}).textTag("value",value).up();
+	}
+	addArrayField(name,values) {
+		if(values == null) {
+			return;
+		}
+		this.queryStanza.tag("field",{ "var" : name});
+		let _g = 0;
+		while(_g < values.length) {
+			let value = values[_g];
+			++_g;
+			this.queryStanza.textTag("value",value);
+		}
+		this.queryStanza.up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let fin = this.responseStanza.getFirstChild();
+			if(fin == null || fin.name != "fin" || fin.attr["xmlns"] != this.xmlns) {
+				return null;
+			}
+			let rsmInfo = fin.getChild("set","http://jabber.org/protocol/rsm");
+			let count = rsmInfo.getChildText("count");
+			this.result = { complete : fin.attr["complete"] == "true" || fin.attr["complete"] == "1", page : { first : rsmInfo.getChildText("first"), last : rsmInfo.getChildText("last"), count : count == null ? null : Std.parseInt(count)}};
+		}
+		return this.result;
+	}
+}
+snikket_queries_MAMQuery.__name__ = "snikket.queries.MAMQuery";
+snikket_queries_MAMQuery.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_MAMQuery.prototype, {
+	__class__: snikket_queries_MAMQuery
+});
+class snikket_queries_PubsubGet extends snikket_queries_GenericQuery {
+	constructor(to,node,itemId) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,node,itemId);
+	}
+	_hx_constructor(to,node,itemId) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "http://jabber.org/protocol/pubsub";
+		super._hx_constructor();
+		let attr = { node : node};
+		if(this.ver != null) {
+			attr["ver"] = this.ver;
+		}
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId});
+		let items = this.queryStanza.tag("pubsub",{ xmlns : this.xmlns}).tag("items",{ node : node});
+		if(itemId != null) {
+			items.tag("item",{ id : itemId}).up();
+		}
+		this.queryStanza.up().up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return [];
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("pubsub",this.xmlns);
+			if(q == null) {
+				return [];
+			}
+			let items = q.getChild("items");
+			if(items == null) {
+				return [];
+			}
+			if(items.attr["xmlns"] == null) {
+				items.attr["xmlns"] = this.xmlns;
+			}
+			this.result = items.allTags("item");
+		}
+		return this.result;
+	}
+}
+snikket_queries_PubsubGet.__name__ = "snikket.queries.PubsubGet";
+snikket_queries_PubsubGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_PubsubGet.prototype, {
+	__class__: snikket_queries_PubsubGet
+});
+class snikket_queries_Push2Disable extends snikket_queries_GenericQuery {
+	constructor(to) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to);
+	}
+	_hx_constructor(to) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:push2:0";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "set", id : this.queryId});
+		this.queryStanza.tag("disable",{ xmlns : this.xmlns});
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		return { type : this.responseStanza.attr["type"]};
+	}
+}
+snikket_queries_Push2Disable.__name__ = "snikket.queries.Push2Disable";
+snikket_queries_Push2Disable.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_Push2Disable.prototype, {
+	__class__: snikket_queries_Push2Disable
+});
+class snikket_queries_Push2Enable extends snikket_queries_GenericQuery {
+	constructor(to,service,client,ua_public,auth_secret,jwt_alg,jwt_key,jwt_claims) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,service,client,ua_public,auth_secret,jwt_alg,jwt_key,jwt_claims);
+	}
+	_hx_constructor(to,service,client,ua_public,auth_secret,jwt_alg,jwt_key,jwt_claims) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:push2:0";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "set", id : this.queryId});
+		let enable = this.queryStanza.tag("enable",{ xmlns : this.xmlns});
+		enable.textTag("service",service);
+		enable.textTag("client",client);
+		let match = enable.tag("match",{ profile : "urn:xmpp:push2:match:important"});
+		let send = match.tag("send",{ xmlns : "urn:xmpp:push2:send:sce+rfc8291+rfc8292:0"});
+		send.textTag("ua-public",haxe_crypto_Base64.encode(ua_public));
+		send.textTag("auth-secret",haxe_crypto_Base64.encode(auth_secret));
+		if(jwt_alg != null) {
+			send.textTag("jwt-alg",jwt_alg);
+			send.textTag("jwt-key",haxe_crypto_Base64.encode(jwt_key));
+			let jsIterator = jwt_claims.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let key = _g_key;
+				let value = _g_value;
+				send.textTag("jwt-claim",value,{ name : key});
+			}
+		}
+		enable.up().up().up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		return { type : this.responseStanza.attr["type"]};
+	}
+}
+snikket_queries_Push2Enable.__name__ = "snikket.queries.Push2Enable";
+snikket_queries_Push2Enable.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_Push2Enable.prototype, {
+	__class__: snikket_queries_Push2Enable
+});
+class snikket_queries_RosterGet extends snikket_queries_GenericQuery {
+	constructor(ver) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(ver);
+	}
+	_hx_constructor(ver) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "jabber:iq:roster";
+		super._hx_constructor();
+		let attr = { xmlns : this.xmlns};
+		if(ver != null) {
+			attr["ver"] = ver;
+		}
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ type : "get"}).tag("query",attr).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return [];
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("query","jabber:iq:roster");
+			if(q == null) {
+				return [];
+			}
+			this.ver = q.attr["ver"];
+			let _this = q.allTags("item");
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let item = _this[i];
+				result[i] = { jid : item.attr["jid"], fn : item.attr["name"], subscription : item.attr["subscription"]};
+			}
+			this.result = result;
+		}
+		return this.result;
+	}
+}
+snikket_queries_RosterGet.__name__ = "snikket.queries.RosterGet";
+snikket_queries_RosterGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_RosterGet.prototype, {
+	__class__: snikket_queries_RosterGet
+});
+class snikket_queries_VcardTempGet extends snikket_queries_GenericQuery {
+	constructor(to) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to);
+	}
+	_hx_constructor(to) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "vcard-temp";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to.asString(), type : "get", id : this.queryId});
+		this.queryStanza.tag("vCard",{ xmlns : this.xmlns}).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return { photo : null};
+		}
+		if(this.result == null) {
+			let vcard = this.responseStanza.getChild("vCard",this.xmlns);
+			if(vcard == null) {
+				return { photo : null};
+			}
+			let photoMime = vcard.findText("PHOTO/TYPE#");
+			let photoBinval = vcard.findText("PHOTO/BINVAL#");
+			if(photoMime != null && photoBinval != null) {
+				this.result = { photo : { mime : photoMime, data : haxe_crypto_Base64.decode(StringTools.replace(photoBinval,"\n",""))}};
+			} else {
+				this.result = { photo : null};
+			}
+		}
+		return this.result;
+	}
+}
+snikket_queries_VcardTempGet.__name__ = "snikket.queries.VcardTempGet";
+snikket_queries_VcardTempGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_VcardTempGet.prototype, {
+	__class__: snikket_queries_VcardTempGet
+});
+class snikket_streams_XmppJsStream extends snikket_GenericStream {
+	constructor() {
+		snikket_EventEmitter._hx_skip_constructor = true;
+		super();
+		snikket_EventEmitter._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.everConnected = false;
+		this.resumed = false;
+		this.initialSM = null;
+		this.pendingOnIq = [];
+		this.pending = [];
+		this.debug = true;
+		super._hx_constructor();
+		let _g = new haxe_ds_StringMap();
+		_g.h["online"] = $bind(this,this.onOnline);
+		_g.h["offline"] = $bind(this,this.onOffline);
+		let tmp = snikket_Map.fromMap(_g);
+		let _g1 = new haxe_ds_StringMap();
+		_g1.h["connection-error"] = $bind(this,this.onError);
+		this.state = new snikket_FSM({ transitions : [{ name : "connect-requested", from : ["offline"], to : "connecting"},{ name : "connection-success", from : ["connecting"], to : "online"},{ name : "connection-error", from : ["connecting"], to : "offline"},{ name : "connection-closed", from : ["connecting","online"], to : "offline"}], state_handlers : tmp, transition_handlers : snikket_Map.fromMap(_g1)},"offline");
+	}
+	connectWithURI(uri) {
+		haxe_Log.trace("Got connection URI: " + uri,{ fileName : "snikket/streams/XmppJsStream.hx", lineNumber : 165, className : "snikket.streams.XmppJsStream", methodName : "connectWithURI"});
+		if(uri == null) {
+			this.state.event("connection-error");
+			return;
+		}
+		this.connectionURI = uri;
+		let _gthis = this;
+		let waitForCreds = new Promise(function(resolve,reject) {
+			_gthis.on("auth/password",function(event) {
+				if(event.username == null) {
+					event.username = _gthis.jid.local;
+				}
+				resolve(event);
+				return snikket_EventResult.EventHandled;
+			});
+		});
+		let clientId = this.jid.resource;
+		let xmpp = new snikket_streams_XmppJsClient({ service : this.connectionURI, domain : this.jid.domain, resource : this.jid.resource, credentials : function(callback,mechanisms,fast) {
+			_gthis.everConnected = true;
+			_gthis.clientId = ((mechanisms) instanceof Array) ? clientId : null;
+			let mechs = fast == null ? [] : [{ name : fast.mechanism, canFast : true, canOther : false}];
+			let _this = ((mechanisms) instanceof Array) ? mechanisms : [mechanisms];
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = { name : _this[i], canFast : false, canOther : true};
+			}
+			let mechs1 = mechs.concat(result);
+			let tmp = Lambda.find(mechs1,function(m) {
+				return m.canOther;
+			});
+			let mech = tmp != null ? tmp.name : null;
+			_gthis.trigger("auth/password-needed",{ mechanisms : mechs1});
+			return waitForCreds.then(function(creds) {
+				creds.username = _gthis.jid.local;
+				if(creds.fastCount != null) {
+					try {
+						creds = { username : _gthis.jid.local, token : JSON.parse(creds.password), mechanism : null};
+					} catch( _g ) {
+						creds = { password : null, fastCount : null, username : _gthis.jid.local, token : { token : "fail", mechanism : creds.mechanism}, mechanism : null};
+					}
+				}
+				let tmp = creds.mechanism;
+				return callback(creds,tmp != null ? tmp : mech,snikket_streams_XmppJsXml("user-agent",{ id : clientId}));
+			});
+		}});
+		snikket_streams_XmppJsScramSha1(xmpp.saslFactory);
+		xmpp.jid = this.jid;
+		xmpp.streamFeatures.use("csi","urn:xmpp:csi:0",function(ctx,next,feature) {
+			_gthis.csi = true;
+			next();
+		});
+		if(this.debug) {
+			snikket_streams_XmppJsDebug(xmpp,true);
+		}
+		if(this.initialSM != null) {
+			let parsedSM = JSON.parse(haxe_io_Bytes.ofData(this.initialSM).toString());
+			let parsedPending = parsedSM.pending;
+			if(parsedPending != null) {
+				let _g = 0;
+				while(_g < parsedPending.length) {
+					let item = parsedPending[_g];
+					++_g;
+					this.pending.push(snikket_streams_XmppJsLtx.parse(item));
+				}
+			}
+			xmpp.streamManagement.id = parsedSM.id;
+			xmpp.streamManagement.outbound = parsedSM.outbound;
+			xmpp.streamManagement.inbound = parsedSM.inbound;
+			let tmp = parsedSM.outbound_q;
+			let _this = tmp != null ? tmp : [];
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let item = _this[i];
+				result[i] = { stanza : snikket_streams_XmppJsLtx.parse(item.stanza), stamp : item.stamp};
+			}
+			xmpp.streamManagement.outbound_q = result;
+			this.initialSM = null;
+		}
+		this.client = xmpp;
+		this.processPendingOnIq();
+		xmpp.on("online",function(jid) {
+			_gthis.resumed = false;
+			_gthis.jid = jid;
+			_gthis.state.event("connection-success");
+		});
+		xmpp.on("offline",function(data) {
+			_gthis.state.event("connection-closed");
+		});
+		xmpp.streamManagement.on("resumed",function(_) {
+			_gthis.resumed = true;
+			if(xmpp.jid == null) {
+				xmpp.jid = _gthis.jid;
+			} else {
+				_gthis.jid = xmpp.jid;
+			}
+			_gthis.state.event("connection-success");
+		});
+		xmpp.on("stanza",function(stanza) {
+			_gthis.onStanza(snikket_streams_XmppJsStream.convertToStanza(stanza));
+			_gthis.triggerSMupdate();
+		});
+		xmpp.streamManagement.on("ack",function(stanza) {
+			let tmp;
+			if((stanza != null ? stanza.name : null) == "message") {
+				let tmp1 = stanza != null ? stanza.attrs : null;
+				tmp = (tmp1 != null ? tmp1.id : null) != null;
+			} else {
+				tmp = false;
+			}
+			if(tmp) {
+				_gthis.trigger("sm/ack",{ id : stanza.attrs.id});
+			}
+			_gthis.triggerSMupdate();
+		});
+		xmpp.streamManagement.on("fail",function(stanza) {
+			if(stanza.name == "message" && stanza.attrs.id != null) {
+				_gthis.trigger("sm/fail",{ id : stanza.attrs.id});
+			}
+			_gthis.triggerSMupdate();
+		});
+		xmpp.fast.saveToken = function(token) {
+			token.token = JSON.stringify(token);
+			_gthis.trigger("fast-token",token);
+			return Promise.resolve(null);
+		};
+		xmpp.on("status",function(status) {
+			if(status == "disconnect") {
+				if(_gthis.state.can("connection-closed")) {
+					_gthis.state.event("connection-closed");
+				}
+			} else if(status == "connecting") {
+				if(_gthis.state.can("connect-requested")) {
+					_gthis.state.event("connect-requested");
+				}
+			}
+		});
+		this.resumed = false;
+		xmpp.start().catch(function(err) {
+			if(_gthis.state.can("connection-error")) {
+				_gthis.state.event("connection-error");
+			}
+			let xmppError = ((err) instanceof snikket_streams_XmppJsError) ? err : null;
+			if((xmppError != null ? xmppError.name : null) == "SASLError") {
+				_gthis.trigger("auth/fail",xmppError);
+			} else {
+				haxe_Log.trace(err,{ fileName : "snikket/streams/XmppJsStream.hx", lineNumber : 298, className : "snikket.streams.XmppJsStream", methodName : "connectWithURI"});
+			}
+		});
+	}
+	connect(jid,sm) {
+		this.state.event("connect-requested");
+		this.jid = new snikket_streams_XmppJsJID(jid);
+		this.initialSM = sm;
+		snikket_streams_XmppJsStream.resolveConnectionURI(this.jid.domain,$bind(this,this.connectWithURI));
+	}
+	disconnect() {
+		if(this.client == null) {
+			return;
+		}
+		this.client.stop();
+	}
+	convertFromStanza(el) {
+		let xml = snikket_streams_XmppJsXml(el.name,el.attr);
+		if(el.children.length > 0) {
+			let _g = 0;
+			let _g1 = el.children;
+			while(_g < _g1.length) {
+				let child = _g1[_g];
+				++_g;
+				switch(child._hx_index) {
+				case 0:
+					let stanza = child.stanza;
+					xml.append(this.convertFromStanza(stanza));
+					break;
+				case 1:
+					let text = child.textNode;
+					xml.append(text.content);
+					break;
+				}
+			}
+		}
+		return xml;
+	}
+	sendStanza(stanza) {
+		if(this.client == null || this.client.status != "online") {
+			this.pending.push(this.convertFromStanza(stanza));
+		} else {
+			this.client.send(this.convertFromStanza(stanza));
+		}
+		this.triggerSMupdate();
+	}
+	newId() {
+		return snikket_streams_XmppJsId();
+	}
+	triggerSMupdate() {
+		if(this.client == null || !this.client.streamManagement.enabled) {
+			return;
+		}
+		let _this = this.client.streamManagement.id;
+		let _this1 = this.client.streamManagement.outbound;
+		let _this2 = this.client.streamManagement.inbound;
+		let tmp = this.client.streamManagement.outbound_q;
+		let _this3 = tmp != null ? tmp : [];
+		let result = new Array(_this3.length);
+		let _g = 0;
+		let _g1 = _this3.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let item = _this3[i];
+			result[i] = { stanza : item.stanza.toString(), stamp : item.stamp};
+		}
+		let _this4 = result;
+		let _this5 = this.pending;
+		let result1 = new Array(_this5.length);
+		let _g2 = 0;
+		let _g3 = _this5.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			result1[i] = _this5[i].toString();
+		}
+		this.trigger("sm/update",{ sm : haxe_io_Bytes.ofString(JSON.stringify({ id : _this, outbound : _this1, inbound : _this2, outbound_q : _this4, pending : result1})).b.bufferValue});
+	}
+	fromIqResult(result) {
+		switch(result._hx_index) {
+		case 0:
+			let el = result.element;
+			return this.convertFromStanza(el);
+		case 1:
+			return true;
+		case 2:
+			return false;
+		}
+	}
+	onIq(type,tag,xmlns,handler) {
+		let _gthis = this;
+		if(this.client == null) {
+			this.pendingOnIq.push({ type : type, tag : tag, xmlns : xmlns, handler : handler});
+		} else {
+			switch(type._hx_index) {
+			case 0:
+				this.client.iqCallee.get(xmlns,tag,function(el) {
+					return _gthis.fromIqResult(handler(snikket_streams_XmppJsStream.convertToStanza(el.stanza)));
+				});
+				break;
+			case 1:
+				this.client.iqCallee.set(xmlns,tag,function(el) {
+					return _gthis.fromIqResult(handler(snikket_streams_XmppJsStream.convertToStanza(el.stanza)));
+				});
+				break;
+			}
+		}
+	}
+	processPendingOnIq() {
+		let item;
+		while(true) {
+			item = this.pendingOnIq.shift();
+			if(!(item != null)) {
+				break;
+			}
+			this.onIq(item.type,item.tag,item.xmlns,item.handler);
+		}
+	}
+	onOnline(event) {
+		this.everConnected = true;
+		let item;
+		while(true) {
+			item = this.pending.shift();
+			if(!(item != null)) {
+				break;
+			}
+			this.client.send(item);
+		}
+		this.triggerSMupdate();
+		this.trigger("status/online",{ jid : this.jid.toString(), resumed : this.resumed});
+	}
+	onOffline(event) {
+		this.trigger("status/offline",{ });
+	}
+	onError(event) {
+		if(!this.everConnected) {
+			this.trigger("status/error",{ });
+		}
+		return true;
+	}
+	static resolveConnectionURI(domain,callback) {
+		let request = new haxe_http_HttpJs("https://" + domain + "/.well-known/host-meta.json");
+		request.onData = function(data) {
+			let parsed = JSON.parse(data);
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = parsed.links;
+			while(_g1 < _g2.length) {
+				let v = _g2[_g1];
+				++_g1;
+				if(HxOverrides.substr(v.href,0,6) == "wss://") {
+					_g.push(v);
+				}
+			}
+			let links = _g;
+			if(links.length > 0) {
+				callback(links[0].href);
+				return;
+			}
+			callback(null);
+		};
+		request.onError = function(msg) {
+			callback(null);
+		};
+		request.request(false);
+	}
+	static convertToStanza(el) {
+		let stanza = new snikket_Stanza(el.name,el.attrs);
+		let _g = 0;
+		let _g1 = el.children;
+		while(_g < _g1.length) {
+			let child = _g1[_g];
+			++_g;
+			if(snikket_streams_XmppJsLtx.isText(child)) {
+				stanza.text(js_Boot.__cast(child , String));
+			} else {
+				stanza.addChild(snikket_streams_XmppJsStream.convertToStanza(child));
+			}
+		}
+		return stanza;
+	}
+	static parse(input) {
+		return snikket_streams_XmppJsStream.convertToStanza(snikket_streams_XmppJsLtx.parse(input));
+	}
+}
+snikket_streams_XmppJsStream.__name__ = "snikket.streams.XmppJsStream";
+snikket_streams_XmppJsStream.__super__ = snikket_GenericStream;
+Object.assign(snikket_streams_XmppJsStream.prototype, {
+	__class__: snikket_streams_XmppJsStream
+});
+class thenshim_PromiseFactory {
+}
+thenshim_PromiseFactory.__name__ = "thenshim.PromiseFactory";
+thenshim_PromiseFactory.__isInterface__ = true;
+Object.assign(thenshim_PromiseFactory.prototype, {
+	__class__: thenshim_PromiseFactory
+});
+class thenshim_js_JSPromiseFactory {
+	constructor() {
+	}
+	make(executor) {
+		return new Promise(executor);
+	}
+	asResolved(object) {
+		return Promise.resolve(object);
+	}
+	asRejected(reason) {
+		return Promise.reject(reason);
+	}
+}
+thenshim_js_JSPromiseFactory.__name__ = "thenshim.js.JSPromiseFactory";
+thenshim_js_JSPromiseFactory.__interfaces__ = [thenshim_PromiseFactory];
+Object.assign(thenshim_js_JSPromiseFactory.prototype, {
+	__class__: thenshim_js_JSPromiseFactory
+});
+class thenshim_Promise {
+	static _new(executor) {
+		return thenshim_Promise.factory.make(executor);
+	}
+	static resolve(object) {
+		return thenshim_Promise.factory.asResolved(object);
+	}
+	static reject(reason) {
+		return thenshim_Promise.factory.asRejected(reason);
+	}
+	static then(this1,onFulfilled,onRejected) {
+		return this1.then(onFulfilled,onRejected);
+	}
+}
+class thenshim_PromiseTools {
+	static all(promises) {
+		return Promise.all(Lambda.array(promises));
+	}
+	static allSettled(promises) {
+		return Promise.allSettled(Lambda.array(promises));
+	}
+	static race(promises) {
+		return Promise.race(Lambda.array(promises));
+	}
+	static catch_(promise,onRejected) {
+		return promise.catch(onRejected);
+	}
+	static catchError(promise,onRejected) {
+		return thenshim_PromiseTools.catch_(promise,onRejected);
+	}
+	static finally(promise,onFinally) {
+		return promise.finally(onFinally);
+	}
+}
+thenshim_PromiseTools.__name__ = "thenshim.PromiseTools";
+class thenshim_Thenable {
+}
+thenshim_Thenable.__name__ = "thenshim.Thenable";
+thenshim_Thenable.__isInterface__ = true;
+Object.assign(thenshim_Thenable.prototype, {
+	__class__: thenshim_Thenable
+});
+class thenshim_ThenableCallback {
+	static toJSPromiseHandler(this1) {
+		return this1;
+	}
+}
+class tink_Anon {
+	static getExistentFields(o) {
+		let ret = { };
+		let _g = 0;
+		let _g1 = Reflect.fields(o);
+		while(_g < _g1.length) {
+			let f = _g1[_g];
+			++_g;
+			ret[f] = true;
+		}
+		return ret;
+	}
+}
+tink_Anon.__name__ = "tink.Anon";
+class tink_chunk_ChunkBase {
+	getCursor() {
+		if(this.flattened == null) {
+			this.flatten(this.flattened = []);
+		}
+		return tink_chunk_ChunkCursor.create(this.flattened.slice());
+	}
+	flatten(into) {
+	}
+}
+tink_chunk_ChunkBase.__name__ = "tink.chunk.ChunkBase";
+Object.assign(tink_chunk_ChunkBase.prototype, {
+	__class__: tink_chunk_ChunkBase
+});
+class tink_chunk_ChunkObject {
+}
+tink_chunk_ChunkObject.__name__ = "tink.chunk.ChunkObject";
+tink_chunk_ChunkObject.__isInterface__ = true;
+Object.assign(tink_chunk_ChunkObject.prototype, {
+	__class__: tink_chunk_ChunkObject
+});
+class tink__$Chunk_EmptyChunk extends tink_chunk_ChunkBase {
+	constructor() {
+		super();
+	}
+	getByte(i) {
+		return 0;
+	}
+	getLength() {
+		return 0;
+	}
+	slice(from,to) {
+		return this;
+	}
+	blitTo(target,offset) {
+	}
+	toString() {
+		return "";
+	}
+	toBytes() {
+		return tink__$Chunk_EmptyChunk.EMPTY;
+	}
+}
+tink__$Chunk_EmptyChunk.__name__ = "tink._Chunk.EmptyChunk";
+tink__$Chunk_EmptyChunk.__interfaces__ = [tink_chunk_ChunkObject];
+tink__$Chunk_EmptyChunk.__super__ = tink_chunk_ChunkBase;
+Object.assign(tink__$Chunk_EmptyChunk.prototype, {
+	__class__: tink__$Chunk_EmptyChunk
+});
+class tink_Chunk {
+	static get_length(this1) {
+		return this1.getLength();
+	}
+	static getByte(this1,i) {
+		return this1.getByte(i);
+	}
+	static concat(this1,that) {
+		return tink_chunk_CompoundChunk.cons(this1,that);
+	}
+	static cursor(this1) {
+		return this1.getCursor();
+	}
+	static iterator(this1) {
+		return new tink_chunk_ChunkIterator(this1.getCursor());
+	}
+	static sub(this1,pos,len) {
+		return this1.slice(pos,pos + len);
+	}
+	static slice(this1,from,to) {
+		return this1.slice(from,to);
+	}
+	static blitTo(this1,target,offset) {
+		this1.blitTo(target,offset);
+	}
+	static toHex(this1) {
+		return this1.toBytes().toHex();
+	}
+	static toString(this1) {
+		return this1.toString();
+	}
+	static toBytes(this1) {
+		return this1.toBytes();
+	}
+	static castToBlob(this1) {
+		return new Blob([this1.toBytes().b.bufferValue],null);
+	}
+	static toBlob(this1,opt) {
+		return new Blob([this1.toBytes().b.bufferValue],opt);
+	}
+	static join(chunks) {
+		if(chunks == null) {
+			return tink_Chunk.EMPTY;
+		} else {
+			switch(chunks.length) {
+			case 0:
+				return tink_Chunk.EMPTY;
+			case 1:
+				let v = chunks[0];
+				return v;
+			default:
+				let v1 = chunks;
+				let ret = tink_Chunk.concat(v1[0],v1[1]);
+				let _g = 2;
+				let _g1 = v1.length;
+				while(_g < _g1) {
+					let i = _g++;
+					ret = tink_Chunk.concat(ret,v1[i]);
+				}
+				return ret;
+			}
+		}
+	}
+	static ofBytes(b) {
+		return tink_chunk_ByteChunk.of(b);
+	}
+	static ofString(s) {
+		return tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(s));
+	}
+	static ofUint8Array(b) {
+		return tink_chunk_ByteChunk.of(haxe_io_Bytes.ofData(b.buffer.slice(b.byteOffset,b.byteOffset + b.byteLength)));
+	}
+	static ofByte(byte) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(1));
+		bytes.b[0] = byte;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static ofHex(s) {
+		let length = s.length >> 1;
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(length));
+		let _g = 0;
+		let _g1 = length;
+		while(_g < _g1) {
+			let i = _g++;
+			bytes.b[i] = Std.parseInt("0x" + HxOverrides.substr(s,i * 2,2));
+		}
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static parseHex(v) {
+		return Std.parseInt("0x" + v);
+	}
+	static catChunk(a,b) {
+		return tink_Chunk.concat(a,b);
+	}
+	static rcatString(a,b) {
+		return tink_Chunk.concat(a,tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(b)));
+	}
+	static lcatString(a,b) {
+		return tink_Chunk.concat(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(a)),b);
+	}
+	static lcatBytes(a,b) {
+		return tink_Chunk.concat(tink_chunk_ByteChunk.of(a),b);
+	}
+	static rcatBytes(a,b) {
+		return tink_Chunk.concat(a,tink_chunk_ByteChunk.of(b));
+	}
+	static eqChunk(a,b) {
+		return a.toString() == b.toString();
+	}
+	static reqString(a,b) {
+		return a.toString() == b.toString();
+	}
+	static leqString(a,b) {
+		return a.toString() == b.toString();
+	}
+	static leqBytes(a,b) {
+		return a.toString() == b.toString();
+	}
+	static reqBytes(a,b) {
+		return a.toString() == b.toString();
+	}
+}
+class tink_Stringly {
+	static isNumber(s,allowFloat) {
+		if(s.length == 0) {
+			return false;
+		}
+		let pos = 0;
+		let max = s.length;
+		if(pos < max && s.charCodeAt(pos) == 45) {
+			++pos;
+		}
+		if(!allowFloat) {
+			if(pos < max && s.charCodeAt(pos) == 48 && pos++ > -1) {
+				if(pos < max && s.charCodeAt(pos) == 120) {
+					++pos;
+				}
+			}
+		}
+		while(pos < max && (s.charCodeAt(pos) ^ 48) < 10) ++pos;
+		if(allowFloat && pos < max) {
+			if(pos < max && s.charCodeAt(pos) == 46 && pos++ > -1) {
+				while(pos < max && (s.charCodeAt(pos) ^ 48) < 10) ++pos;
+			}
+			if(pos < max && s.charCodeAt(pos) == 101 && pos++ > -1 || pos < max && s.charCodeAt(pos) == 69 && pos++ > -1) {
+				if(!(pos < max && s.charCodeAt(pos) == 43 && pos++ > -1)) {
+					if(pos < max && s.charCodeAt(pos) == 45) {
+						++pos;
+					}
+				}
+				while(pos < max && (s.charCodeAt(pos) ^ 48) < 10) ++pos;
+			}
+		}
+		return pos == max;
+	}
+	static toBool(this1) {
+		if(this1 != null) {
+			switch(StringTools.trim(this1).toLowerCase()) {
+			case "0":case "false":case "no":
+				return false;
+			default:
+				return true;
+			}
+		} else {
+			return false;
+		}
+	}
+	static isFloat(this1) {
+		return tink_Stringly.isNumber(StringTools.trim(this1),true);
+	}
+	static parseFloat(this1) {
+		let _g = StringTools.trim(this1);
+		let v = _g;
+		if(tink_Stringly.isNumber(v,true)) {
+			return tink_core_Outcome.Success(parseFloat(v));
+		} else {
+			let v = _g;
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"" + v + " (encoded as " + this1 + ") is not a valid float",{ fileName : "tink/Stringly.hx", lineNumber : 65, className : "tink._Stringly.Stringly_Impl_", methodName : "parseFloat"}));
+		}
+	}
+	static toFloat(this1) {
+		return tink_core_OutcomeTools.sure(tink_Stringly.parseFloat(this1));
+	}
+	static isInt(this1) {
+		return tink_Stringly.isNumber(StringTools.trim(this1),false);
+	}
+	static parseInt(this1) {
+		let _g = StringTools.trim(this1);
+		let v = _g;
+		if(tink_Stringly.isNumber(v,false)) {
+			return tink_core_Outcome.Success(Std.parseInt(v));
+		} else {
+			let v = _g;
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"" + v + " (encoded as " + this1 + ") is not a valid integer",{ fileName : "tink/Stringly.hx", lineNumber : 80, className : "tink._Stringly.Stringly_Impl_", methodName : "parseInt"}));
+		}
+	}
+	static toInt(this1) {
+		return tink_core_OutcomeTools.sure(tink_Stringly.parseInt(this1));
+	}
+	static parseDate(this1) {
+		let _g = tink_Stringly.parseFloat(this1);
+		switch(_g._hx_index) {
+		case 0:
+			let f = _g.data;
+			return tink_core_Outcome.Success(new Date(f));
+		case 1:
+			let _g1 = _g.failure;
+			if(!tink_Stringly.SUPPORTED_DATE_REGEX.match(this1)) {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"" + this1 + " is not a valid date",{ fileName : "tink/Stringly.hx", lineNumber : 101, className : "tink._Stringly.Stringly_Impl_", methodName : "parseDate"}));
+			}
+			let date = new Date(this1);
+			let f1 = date.getTime();
+			if(isNaN(f1)) {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"" + this1 + " is not a valid date",{ fileName : "tink/Stringly.hx", lineNumber : 104, className : "tink._Stringly.Stringly_Impl_", methodName : "parseDate"}));
+			} else {
+				return tink_core_Outcome.Success(date);
+			}
+			break;
+		}
+	}
+	static toDate(this1) {
+		return tink_core_OutcomeTools.sure(tink_Stringly.parseDate(this1));
+	}
+	static parse(this1,f) {
+		let _g = f;
+		let a1 = this1;
+		return tink_core_TypedError.catchExceptions(function() {
+			return _g(a1);
+		},null,{ fileName : "tink/Stringly.hx", lineNumber : 171, className : "tink._Stringly.Stringly_Impl_", methodName : "parse"});
+	}
+	static ofBool(b) {
+		if(b) {
+			return "true";
+		} else {
+			return "false";
+		}
+	}
+	static ofInt(i) {
+		if(i == null) {
+			return "null";
+		} else {
+			return "" + i;
+		}
+	}
+	static ofFloat(f) {
+		if(f == null) {
+			return "null";
+		} else {
+			return "" + f;
+		}
+	}
+	static ofDate(d) {
+		let f = d.getTime();
+		if(f == null) {
+			return "null";
+		} else {
+			return "" + f;
+		}
+	}
+}
+class tink_Url {
+	static get_host(this1) {
+		return this1.hosts[0];
+	}
+	static get_hosts(this1) {
+		return this1.hosts;
+	}
+	static get_pathWithQuery(this1) {
+		if(this1.query == null) {
+			return this1.path;
+		} else {
+			return (this1.path == null ? "null" : this1.path) + "?" + (this1.query == null ? "null" : this1.query);
+		}
+	}
+	static _new(parts) {
+		return parts;
+	}
+	static resolve(this1,that) {
+		if(that.scheme != null) {
+			return that;
+		} else if(that.hosts[0] != null) {
+			if(that.scheme != null) {
+				return that;
+			} else {
+				let copy = Reflect.copy(that);
+				copy.scheme = this1.scheme;
+				return copy;
+			}
+		} else {
+			let parts = { path : tink_url_Path.join(this1.path,that.path), payload : "", scheme : this1.scheme, query : that.query, auth : this1.auth, hosts : this1.hosts, hash : that.hash};
+			tink_Url.makePayload(parts);
+			return parts;
+		}
+	}
+	static makePayload(parts) {
+		let payload = "";
+		let _g = parts.auth;
+		let _g1 = parts.hash;
+		let _g2 = parts.hosts;
+		let _g3 = parts.path;
+		let _g4 = parts.payload;
+		let _g5 = parts.query;
+		let _g6 = parts.scheme;
+		if(_g == null) {
+			if(_g2.length != 0) {
+				let v = _g2;
+				payload += "//" + v.join(",");
+			}
+		} else if(_g2.length == 0) {
+			let auth = _g;
+			payload += "//" + (auth == null ? "null" : auth == null ? "" : "" + auth + "@");
+		} else {
+			let auth = _g;
+			let v = _g2;
+			payload += "//" + (auth == null ? "null" : auth == null ? "" : "" + auth + "@") + v.join(",");
+		}
+		payload += parts.path == null ? "null" : parts.path;
+		let _g7 = parts.query;
+		if(_g7 != null) {
+			let v = _g7;
+			payload += "?" + (v == null ? "null" : v);
+		}
+		let _g8 = parts.hash;
+		if(_g8 != null) {
+			let v = _g8;
+			payload += "#" + v;
+		}
+		parts.payload = payload.toString();
+	}
+	static toString(this1) {
+		if(this1.scheme == null) {
+			return this1.payload;
+		} else {
+			return "" + this1.scheme + ":" + this1.payload;
+		}
+	}
+	static fromString(s) {
+		return tink_Url.parse(s);
+	}
+	static noop(_) {
+	}
+	static parse(s,onError) {
+		if(s == null) {
+			return tink_Url.parse("");
+		}
+		if(onError == null) {
+			onError = tink_Url.noop;
+		}
+		s = StringTools.trim(s);
+		if(s.startsWith("data:")) {
+			return { scheme : "data", payload : HxOverrides.substr(s,5,null), hosts : []};
+		}
+		let FORMAT = new EReg("^(([a-zA-Z][a-zA-Z0-9\\-+.]*):)?((//(([^@/]+)@)?([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?)$","");
+		let HOST = new EReg("^(\\[(.*)\\]|([^:]*))(:(.*))?$","");
+		FORMAT.match(s);
+		let hosts;
+		let _g = FORMAT.matched(7);
+		if(_g == null) {
+			hosts = [];
+		} else {
+			let v = _g;
+			let _g1 = [];
+			let _g2 = 0;
+			let _g3 = v.split(",");
+			while(_g2 < _g3.length) {
+				let host = _g3[_g2];
+				++_g2;
+				HOST.match(host);
+				let host1;
+				let _g = HOST.matched(3);
+				let _g4 = HOST.matched(2);
+				if(_g4 == null) {
+					let ipv4 = _g;
+					host1 = ipv4;
+				} else if(_g == null) {
+					let ipv6 = _g4;
+					host1 = "[" + ipv6 + "]";
+				} else {
+					onError("invalid host " + host);
+					host1 = null;
+				}
+				let port;
+				let _g5 = HOST.matched(5);
+				if(_g5 == null) {
+					port = null;
+				} else {
+					let v = _g5;
+					let _g = Std.parseInt(v);
+					if(_g == null) {
+						onError("invalid port " + v);
+						port = null;
+					} else {
+						let p = _g;
+						port = p;
+					}
+				}
+				_g1.push(tink_url_Host._new(host1,port));
+			}
+			hosts = _g1;
+		}
+		let path = FORMAT.matched(8);
+		if(hosts.length > 0 && path.charAt(0) != "/") {
+			path = "/" + path;
+		}
+		return { scheme : FORMAT.matched(2), payload : FORMAT.matched(3), hosts : hosts, auth : FORMAT.matched(6), path : tink_url_Path.ofString(path), query : FORMAT.matched(10), hash : FORMAT.matched(12)};
+	}
+	static make(parts) {
+		let parts1 = { payload : "", path : parts.path, query : parts.query, hosts : parts.hosts, auth : parts.auth, scheme : parts.scheme, hash : parts.hash};
+		tink_Url.makePayload(parts1);
+		return parts1;
+	}
+}
+class tink_SingleHostUrl {
+	static _new(v) {
+		return v;
+	}
+	static ofUrl(u) {
+		let v;
+		let _g = u.hosts;
+		switch(_g.length) {
+		case 0:
+			v = u;
+			break;
+		case 1:
+			let _g1 = _g[0];
+			v = u;
+			break;
+		default:
+			let v1 = _g;
+			v = tink_Url.make({ path : u.path, query : u.query, hosts : [u.hosts[0]], auth : u.auth, scheme : u.scheme, hash : u.hash});
+		}
+		return v;
+	}
+	static ofString(s) {
+		return tink_SingleHostUrl.ofUrl(tink_Url.fromString(s));
+	}
+}
+class tink_chunk_ByteChunk extends tink_chunk_ChunkBase {
+	constructor(data,from,to) {
+		super();
+		this.data = data;
+		this.from = from;
+		this.to = to;
+	}
+	get_wrapped() {
+		if(this.wrapped == null) {
+			this.wrapped = haxe_io_Bytes.ofData(this.data);
+		}
+		return this.wrapped;
+	}
+	getByte(index) {
+		return this.data.bytes[this.from + index];
+	}
+	flatten(into) {
+		into.push(this);
+	}
+	getLength() {
+		return this.to - this.from;
+	}
+	getSlice(from,to) {
+		if(to > this.to - this.from) {
+			to = this.to - this.from;
+		}
+		if(from < 0) {
+			from = 0;
+		}
+		if(to <= from) {
+			return null;
+		} else if(to == this.to - this.from && from == 0) {
+			return this;
+		} else {
+			return new tink_chunk_ByteChunk(this.data,this.from + from,to + this.from);
+		}
+	}
+	slice(from,to) {
+		let _g = this.getSlice(from,to);
+		if(_g == null) {
+			return tink_Chunk.EMPTY;
+		} else {
+			let v = _g;
+			return v;
+		}
+	}
+	blitTo(target,offset) {
+		if(this.wrapped == null) {
+			this.wrapped = haxe_io_Bytes.ofData(this.data);
+		}
+		target.blit(offset,this.wrapped,this.from,this.to - this.from);
+	}
+	toBytes() {
+		if(this.wrapped == null) {
+			this.wrapped = haxe_io_Bytes.ofData(this.data);
+		}
+		return this.wrapped.sub(this.from,this.to - this.from);
+	}
+	toString() {
+		if(this.wrapped == null) {
+			this.wrapped = haxe_io_Bytes.ofData(this.data);
+		}
+		return this.wrapped.getString(this.from,this.to - this.from);
+	}
+	static of(b) {
+		if(b.length == 0) {
+			return tink_Chunk.EMPTY;
+		}
+		let ret = new tink_chunk_ByteChunk(b.b.bufferValue,0,b.length);
+		ret.wrapped = b;
+		return ret;
+	}
+}
+tink_chunk_ByteChunk.__name__ = "tink.chunk.ByteChunk";
+tink_chunk_ByteChunk.__interfaces__ = [tink_chunk_ChunkObject];
+tink_chunk_ByteChunk.__super__ = tink_chunk_ChunkBase;
+Object.assign(tink_chunk_ByteChunk.prototype, {
+	__class__: tink_chunk_ByteChunk
+});
+class tink_chunk_ChunkCursor {
+	constructor() {
+		this.currentByte = -1;
+		this.currentPos = 0;
+		this.length = 0;
+		this.curLength = 0;
+		this.curOffset = 0;
+		this.curPartIndex = 0;
+	}
+	clone() {
+		let ret = new tink_chunk_ChunkCursor();
+		ret.parts = this.parts.slice();
+		ret.curPart = this.curPart;
+		ret.curPartIndex = this.curPartIndex;
+		ret.curOffset = this.curOffset;
+		ret.curLength = this.curLength;
+		ret.length = this.length;
+		ret.currentPos = this.currentPos;
+		ret.currentByte = this.currentByte;
+		return ret;
+	}
+	reset() {
+		this.length = 0;
+		this.currentPos = 0;
+		this.currentByte = -1;
+		this.curOffset = 0;
+		let _g = 0;
+		let _g1 = this.parts;
+		while(_g < _g1.length) {
+			let p = _g1[_g];
+			++_g;
+			this.length += p.to - p.from;
+		}
+		this.curPart = this.parts[this.curPartIndex = 0];
+		if(this.curPart != null) {
+			let _this = this.curPart;
+			this.curLength = _this.to - _this.from;
+			let _this1 = this.curPart;
+			this.currentByte = _this1.data.bytes[_this1.from];
+		}
+	}
+	flush() {
+		let ret = this.left();
+		this.shift();
+		return ret;
+	}
+	prune() {
+		this.shift();
+	}
+	add(chunk) {
+		chunk.flatten(this.parts);
+		this.reset();
+	}
+	shift(chunk) {
+		this.parts.splice(0,this.curPartIndex);
+		let _g = this.parts[0];
+		if(_g != null) {
+			let chunk = _g;
+			let _g1 = chunk.getSlice(this.curOffset,this.curLength);
+			if(_g1 == null) {
+				this.parts.shift();
+			} else {
+				let rest = _g1;
+				this.parts[0] = rest;
+			}
+		}
+		if(chunk != null) {
+			this.add(chunk);
+		} else {
+			this.reset();
+		}
+	}
+	clear() {
+		this.parts = [];
+		this.reset();
+	}
+	left() {
+		if(this.curPart == null) {
+			return tink_Chunk.EMPTY;
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.curPartIndex;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(this.parts[i]);
+		}
+		let left = _g;
+		left.push(this.curPart.slice(0,this.curOffset));
+		return tink_Chunk.join(left);
+	}
+	right() {
+		if(this.curPart == null) {
+			return tink_Chunk.EMPTY;
+		}
+		let _g = [];
+		let _g1 = this.curPartIndex;
+		let _g2 = this.parts.length;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(this.parts[i]);
+		}
+		let right = _g;
+		if(right.length > 0) {
+			right[0] = this.curPart.slice(this.curOffset,this.curLength);
+		}
+		return tink_Chunk.join(right);
+	}
+	seek(seekable,options) {
+		if(this.curPart == null || seekable == null || seekable.length == 0) {
+			return haxe_ds_Option.None;
+		}
+		let max = seekable.length - 1;
+		let first = seekable[0];
+		let candidates = [];
+		let count = 0;
+		let copy = this.clone();
+		copy.shift();
+		let _gthis = this;
+		let part = function(b,offset) {
+			let data = b.data;
+			let _g = b.from + offset;
+			let _g1 = b.to;
+			while(_g < _g1) {
+				let i = _g++;
+				let byte = data.bytes[i];
+				if(candidates.length > 0) {
+					let c = 0;
+					while(c < count) {
+						let pos = candidates[c];
+						if(seekable[pos] == byte) {
+							if(pos == max) {
+								copy.moveTo(copy.currentPos + (i - (b.from + offset) - seekable.length + 1));
+								let before = copy.left();
+								let delta = before.getLength() + seekable.length;
+								_gthis.moveTo(_gthis.currentPos + delta);
+								if(options == null) {
+									_gthis.shift();
+								} else {
+									let _g = options.withoutPruning;
+									if(_g == null) {
+										_gthis.shift();
+									} else if(_g == false) {
+										_gthis.shift();
+									}
+								}
+								return haxe_ds_Option.Some(before);
+							} else {
+								candidates[c++] = pos + 1;
+							}
+						} else {
+							count -= 1;
+							let last = candidates.pop();
+							if(count > c) {
+								candidates[c] = last;
+							}
+						}
+					}
+				}
+				if(byte == first) {
+					count = candidates.push(1);
+				}
+			}
+			copy.moveTo(copy.currentPos + (b.to - (b.from + offset)));
+			return haxe_ds_Option.None;
+		};
+		let _g = part(this.curPart,this.curOffset);
+		if(_g._hx_index == 1) {
+			let _g = this.curPartIndex + 1;
+			let _g1 = this.parts.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let _g1 = part(this.parts[i],0);
+				switch(_g1._hx_index) {
+				case 0:
+					let v = _g1.v;
+					return haxe_ds_Option.Some(v);
+				case 1:
+					break;
+				}
+			}
+			return haxe_ds_Option.None;
+		} else {
+			let v = _g;
+			return v;
+		}
+	}
+	sweep(len) {
+		let data = this.right().slice(0,len);
+		this.moveTo(this.currentPos + len);
+		return data;
+	}
+	sweepTo(pos) {
+		return this.sweep(pos - this.currentPos);
+	}
+	moveBy(delta) {
+		return this.moveTo(this.currentPos + delta);
+	}
+	moveTo(position) {
+		if(this.length == 0) {
+			return 0;
+		}
+		if(position > this.length) {
+			position = this.length - 1;
+		}
+		if(position < 0) {
+			position = 0;
+		}
+		this.currentPos = position;
+		if(position == this.length) {
+			this.ffwd();
+		} else {
+			let _g = 0;
+			let _g1 = this.parts.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let c = this.parts[i];
+				let _g1 = c.to - c.from;
+				let enough = _g1;
+				if(enough > position) {
+					this.curPart = c;
+					this.curPartIndex = i;
+					this.curOffset = position;
+					this.curLength = c.to - c.from;
+					this.currentByte = c.data.bytes[c.from + position];
+					break;
+				} else {
+					let v = _g1;
+					position -= v;
+				}
+			}
+		}
+		return this.currentPos;
+	}
+	ffwd() {
+		this.currentByte = -1;
+		this.curLength = 0;
+		this.curOffset = 0;
+		this.curPart = null;
+		this.curPartIndex = this.parts.length;
+	}
+	next() {
+		if(this.currentPos == this.length) {
+			return false;
+		}
+		this.currentPos++;
+		if(this.currentPos == this.length) {
+			this.ffwd();
+			return false;
+		}
+		if(this.curOffset == this.curLength - 1) {
+			this.curOffset = 0;
+			this.curPart = this.parts[++this.curPartIndex];
+			let _this = this.curPart;
+			this.curLength = _this.to - _this.from;
+			let _this1 = this.curPart;
+			this.currentByte = _this1.data.bytes[_this1.from];
+		} else {
+			let _this = this.curPart;
+			this.currentByte = _this.data.bytes[_this.from + ++this.curOffset];
+		}
+		return true;
+	}
+	static create(parts) {
+		let ret = new tink_chunk_ChunkCursor();
+		ret.parts = parts;
+		ret.reset();
+		return ret;
+	}
+}
+tink_chunk_ChunkCursor.__name__ = "tink.chunk.ChunkCursor";
+Object.assign(tink_chunk_ChunkCursor.prototype, {
+	__class__: tink_chunk_ChunkCursor
+});
+class tink_chunk_ChunkIterator {
+	constructor(target) {
+		this.target = target;
+		this._hasNext = target.length > target.currentPos;
+	}
+	hasNext() {
+		return this._hasNext;
+	}
+	next() {
+		let ret = this.target.currentByte;
+		this._hasNext = this.target.next();
+		return ret;
+	}
+}
+tink_chunk_ChunkIterator.__name__ = "tink.chunk.ChunkIterator";
+Object.assign(tink_chunk_ChunkIterator.prototype, {
+	__class__: tink_chunk_ChunkIterator
+});
+class tink_chunk_ChunkTools {
+	static readUInt8(chunk,offset) {
+		if(chunk.getLength() < offset + 1) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + 1 + ")");
+		}
+		let val = chunk.getByte(offset);
+		return val;
+	}
+	static readInt8(chunk,offset) {
+		let val = tink_chunk_ChunkTools.readUInt8(chunk,offset);
+		if(val > 127) {
+			return val - 256;
+		} else {
+			return val;
+		}
+	}
+	static readUInt16LE(chunk,offset) {
+		if(chunk.getLength() < offset + 2) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + 2 + ")");
+		}
+		let first = chunk.getByte(offset);
+		let last = chunk.getByte(offset + 1);
+		return first + (last << 8);
+	}
+	static readInt16LE(chunk,offset) {
+		let val = tink_chunk_ChunkTools.readUInt16LE(chunk,offset);
+		if(val > 32767) {
+			return val - 65536;
+		} else {
+			return val;
+		}
+	}
+	static readUInt24LE(chunk,offset) {
+		if(chunk.getLength() < offset + 3) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + 3 + ")");
+		}
+		let first = chunk.getByte(offset);
+		let mid = chunk.getByte(offset + 1);
+		let last = chunk.getByte(offset + 2);
+		return first + (mid << 8) + (last << 16);
+	}
+	static readInt24LE(chunk,offset) {
+		let val = tink_chunk_ChunkTools.readUInt24LE(chunk,offset);
+		if(val > 8388607) {
+			return val - 16777216;
+		} else {
+			return val;
+		}
+	}
+	static readInt32LE(chunk,offset) {
+		if(chunk.getLength() < offset + 4) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + 4 + ")");
+		}
+		let val = chunk.getByte(offset) + (chunk.getByte(offset + 1) << 8) + (chunk.getByte(offset + 2) << 16) + (chunk.getByte(offset + 3) << 24);
+		return val;
+	}
+	static readDoubleLE(chunk,offset) {
+		let l = tink_chunk_ChunkTools.readInt32LE(chunk,0);
+		let h = tink_chunk_ChunkTools.readInt32LE(chunk,4);
+		return haxe_io_FPHelper.i64ToDouble(l,h);
+	}
+	static readNullTerminatedString(chunk,offset) {
+		try {
+			return new haxe_io_BytesInput(chunk.toBytes(),offset).readUntil(0);
+		} catch( _g ) {
+			return chunk.toString();
+		}
+	}
+	static writeUInt8(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(1));
+		bytes.b[0] = v & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeInt8(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(1));
+		v &= 255;
+		if(v < 0) {
+			v += 256;
+		}
+		bytes.b[0] = v;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeUInt16LE(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(2));
+		bytes.b[0] = v & 255;
+		bytes.b[1] = v >>> 8 & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeInt16LE(v) {
+		return tink_chunk_ChunkTools.writeUInt16LE(v);
+	}
+	static writeUInt24LE(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(3));
+		bytes.b[0] = v & 255;
+		bytes.b[1] = v >>> 8 & 255;
+		bytes.b[2] = v >>> 16 & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeInt24LE(v) {
+		return tink_chunk_ChunkTools.writeUInt24LE(v);
+	}
+	static writeInt32LE(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(4));
+		bytes.b[0] = v & 255;
+		bytes.b[1] = v >>> 8 & 255;
+		bytes.b[2] = v >>> 16 & 255;
+		bytes.b[3] = v >>> 24 & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeDoubleLE(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(8));
+		let i64 = haxe_io_FPHelper.doubleToI64(v);
+		let l = i64.low;
+		let h = i64.high;
+		bytes.b[0] = l & 255;
+		bytes.b[1] = l >>> 8 & 255;
+		bytes.b[2] = l >>> 16 & 255;
+		bytes.b[3] = l >>> 24 & 255;
+		bytes.b[4] = h & 255;
+		bytes.b[5] = h >>> 8 & 255;
+		bytes.b[6] = h >>> 16 & 255;
+		bytes.b[7] = h >>> 24 & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static lpad(chunk,pad,length) {
+		if(pad.getLength() != 0) {
+			while(chunk.getLength() < length) chunk = tink_Chunk.concat(pad,chunk);
+		}
+		return chunk;
+	}
+	static rpad(chunk,pad,length) {
+		if(pad.getLength() != 0) {
+			while(chunk.getLength() < length) chunk = tink_Chunk.concat(chunk,pad);
+		}
+		return chunk;
+	}
+	static check(chunk,offset,length) {
+		if(chunk.getLength() < offset + length) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + length + ")");
+		}
+	}
+}
+tink_chunk_ChunkTools.__name__ = "tink.chunk.ChunkTools";
+class tink_chunk_CompoundChunk extends tink_chunk_ChunkBase {
+	constructor() {
+		super();
+	}
+	getByte(i) {
+		let index = this.findChunk(i);
+		return this.chunks[index].getByte(i - this.offsets[index]);
+	}
+	getLength() {
+		return this.length;
+	}
+	findChunk(target) {
+		let min = 0;
+		let max = this.offsets.length - 1;
+		while(min + 1 < max) {
+			let guess = min + max >> 1;
+			if(this.offsets[guess] > target) {
+				max = guess;
+			} else {
+				min = guess;
+			}
+		}
+		return min;
+	}
+	flatten(into) {
+		let _g = 0;
+		let _g1 = this.chunks;
+		while(_g < _g1.length) {
+			let c = _g1[_g];
+			++_g;
+			c.flatten(into);
+		}
+	}
+	slice(from,to) {
+		let idxFrom = this.findChunk(from);
+		let idxTo = this.findChunk(to);
+		if(idxFrom == idxTo) {
+			let offset = this.offsets[idxFrom];
+			return this.chunks[idxFrom].slice(from - offset,to - offset);
+		}
+		let ret = this.chunks.slice(idxFrom,idxTo + 1);
+		let c = ret[0];
+		ret[0] = c.slice(from - this.offsets[idxFrom],this.offsets[idxFrom + 1]);
+		let c1 = ret[ret.length - 1];
+		ret[ret.length - 1] = c1.slice(0,to - this.offsets[idxTo]);
+		return tink_chunk_CompoundChunk.create(ret,this.depth);
+	}
+	blitTo(target,offset) {
+		let _g = 0;
+		let _g1 = this.chunks.length;
+		while(_g < _g1) {
+			let i = _g++;
+			this.chunks[i].blitTo(target,offset + this.offsets[i]);
+		}
+	}
+	toString() {
+		return this.toBytes().toString();
+	}
+	toBytes() {
+		let ret = new haxe_io_Bytes(new ArrayBuffer(this.length));
+		this.blitTo(ret,0);
+		return ret;
+	}
+	static asCompound(c) {
+		if(((c) instanceof tink_chunk_CompoundChunk)) {
+			return c;
+		} else {
+			return null;
+		}
+	}
+	static cons(a,b) {
+		let _g = a.getLength();
+		let _g1 = b.getLength();
+		if(_g == 0) {
+			if(_g1 == 0) {
+				return tink_Chunk.EMPTY;
+			} else {
+				return b;
+			}
+		} else if(_g1 == 0) {
+			return a;
+		} else {
+			let la = _g;
+			let lb = _g1;
+			let _g2 = tink_chunk_CompoundChunk.asCompound(a);
+			let _g3 = tink_chunk_CompoundChunk.asCompound(b);
+			if(_g2 == null) {
+				if(_g3 == null) {
+					return tink_chunk_CompoundChunk.create([a,b],2);
+				} else {
+					let v = _g3;
+					if(v.depth < 100) {
+						return tink_chunk_CompoundChunk.create([a,b],v.depth + 1);
+					} else {
+						let flat = [];
+						v.flatten(flat);
+						b.flatten(flat);
+						return tink_chunk_CompoundChunk.create(flat,2);
+					}
+				}
+			} else if(_g3 == null) {
+				let v = _g2;
+				if(v.depth < 100) {
+					return tink_chunk_CompoundChunk.create([a,b],v.depth + 1);
+				} else {
+					let flat = [];
+					v.flatten(flat);
+					b.flatten(flat);
+					return tink_chunk_CompoundChunk.create(flat,2);
+				}
+			} else {
+				let a = _g2;
+				let b = _g3;
+				let depth = a.depth > b.depth ? a.depth : b.depth;
+				return tink_chunk_CompoundChunk.create(a.chunks.concat(b.chunks),depth);
+			}
+		}
+	}
+	static create(chunks,depth) {
+		let ret = new tink_chunk_CompoundChunk();
+		let offsets = [0];
+		let length = 0;
+		let _g = 0;
+		while(_g < chunks.length) {
+			let c = chunks[_g];
+			++_g;
+			offsets.push(length += c.getLength());
+		}
+		ret.chunks = chunks;
+		ret.offsets = offsets;
+		ret.length = length;
+		ret.depth = depth;
+		return ret;
+	}
+}
+tink_chunk_CompoundChunk.__name__ = "tink.chunk.CompoundChunk";
+tink_chunk_CompoundChunk.__interfaces__ = [tink_chunk_ChunkObject];
+tink_chunk_CompoundChunk.__super__ = tink_chunk_ChunkBase;
+Object.assign(tink_chunk_CompoundChunk.prototype, {
+	__class__: tink_chunk_CompoundChunk
+});
+class tink_chunk_Seekable {
+	static _new(a) {
+		return a;
+	}
+	static get_length(this1) {
+		return this1.length;
+	}
+	static get(this1,index) {
+		return this1[index];
+	}
+	static ofChunk(c) {
+		return tink_chunk_Seekable.ofBytes(c.toBytes());
+	}
+	static ofBytes(b) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = b.length;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(b.b[i]);
+		}
+		return _g;
+	}
+	static ofString(s) {
+		return tink_chunk_Seekable.ofBytes(haxe_io_Bytes.ofString(s));
+	}
+}
+class tink_core_Annex {
+	constructor(target) {
+		this.target = target;
+		this.registry = new haxe_ds_ObjectMap();
+	}
+}
+tink_core_Annex.__name__ = "tink.core.Annex";
+Object.assign(tink_core_Annex.prototype, {
+	__class__: tink_core_Annex
+});
+class tink_core_Callback {
+	static _new(f) {
+		return f;
+	}
+	static toFunction(this1) {
+		return this1;
+	}
+	static invoke(this1,data) {
+		if(tink_core_Callback.depth < 500) {
+			tink_core_Callback.depth++;
+			this1(data);
+			tink_core_Callback.depth--;
+		} else {
+			tink_core_Callback.defer(function() {
+				this1(data);
+			});
+		}
+	}
+	static fromNiladic(f) {
+		return f;
+	}
+	static fromMany(callbacks) {
+		return function(v) {
+			let _g = 0;
+			while(_g < callbacks.length) {
+				let callback = callbacks[_g];
+				++_g;
+				tink_core_Callback.invoke(callback,v);
+			}
+		};
+	}
+	static defer(f) {
+		haxe_Timer.delay(f,0);
+	}
+}
+class tink_core_LinkObject {
+}
+tink_core_LinkObject.__name__ = "tink.core.LinkObject";
+tink_core_LinkObject.__isInterface__ = true;
+Object.assign(tink_core_LinkObject.prototype, {
+	__class__: tink_core_LinkObject
+});
+class tink_core_CallbackLinkRef {
+	constructor() {
+	}
+	set_link(param) {
+		let this1 = this.link;
+		if(this1 != null) {
+			this1.cancel();
+		}
+		return this.link = param;
+	}
+	cancel() {
+		let this1 = this.link;
+		if(this1 != null) {
+			this1.cancel();
+		}
+	}
+}
+tink_core_CallbackLinkRef.__name__ = "tink.core.CallbackLinkRef";
+tink_core_CallbackLinkRef.__interfaces__ = [tink_core_LinkObject];
+Object.assign(tink_core_CallbackLinkRef.prototype, {
+	__class__: tink_core_CallbackLinkRef
+});
+class tink_core_CallbackLink {
+	static _new(link) {
+		return new tink_core_SimpleLink(link);
+	}
+	static cancel(this1) {
+		if(this1 != null) {
+			this1.cancel();
+		}
+	}
+	static dissolve(this1) {
+		if(this1 != null) {
+			this1.cancel();
+		}
+	}
+	static noop() {
+	}
+	static toFunction(this1) {
+		if(this1 == null) {
+			return tink_core_CallbackLink.noop;
+		} else {
+			return $bind(this1,this1.cancel);
+		}
+	}
+	static toCallback(this1) {
+		if(this1 == null) {
+			return tink_core_CallbackLink.noop;
+		} else {
+			return $bind(this1,this1.cancel);
+		}
+	}
+	static fromFunction(f) {
+		return new tink_core_SimpleLink(f);
+	}
+	static join(this1,b) {
+		return new tink_core__$Callback_LinkPair(this1,b);
+	}
+	static fromMany(callbacks) {
+		return new tink_core_SimpleLink(function() {
+			if(callbacks != null) {
+				let _g = 0;
+				while(_g < callbacks.length) {
+					let cb = callbacks[_g];
+					++_g;
+					if(cb != null) {
+						cb.cancel();
+					}
+				}
+			} else {
+				callbacks = null;
+			}
+		});
+	}
+}
+class tink_core_SimpleLink {
+	constructor(f) {
+		this.f = f;
+	}
+	cancel() {
+		if(this.f != null) {
+			this.f();
+			this.f = null;
+		}
+	}
+}
+tink_core_SimpleLink.__name__ = "tink.core.SimpleLink";
+tink_core_SimpleLink.__interfaces__ = [tink_core_LinkObject];
+Object.assign(tink_core_SimpleLink.prototype, {
+	__class__: tink_core_SimpleLink
+});
+class tink_core__$Callback_LinkPair {
+	constructor(a,b) {
+		this.dissolved = false;
+		this.a = a;
+		this.b = b;
+	}
+	cancel() {
+		if(!this.dissolved) {
+			this.dissolved = true;
+			let this1 = this.a;
+			if(this1 != null) {
+				this1.cancel();
+			}
+			let this2 = this.b;
+			if(this2 != null) {
+				this2.cancel();
+			}
+			this.a = null;
+			this.b = null;
+		}
+	}
+}
+tink_core__$Callback_LinkPair.__name__ = "tink.core._Callback.LinkPair";
+tink_core__$Callback_LinkPair.__interfaces__ = [tink_core_LinkObject];
+Object.assign(tink_core__$Callback_LinkPair.prototype, {
+	__class__: tink_core__$Callback_LinkPair
+});
+class tink_core__$Callback_ListCell {
+	constructor(cb,list) {
+		if(cb == null) {
+			throw haxe_Exception.thrown("callback expected but null received");
+		}
+		this.cb = cb;
+		this.list = list;
+	}
+	invoke(data) {
+		if(this.list != null) {
+			this.cb(data);
+		}
+	}
+	clear() {
+		this.cb = null;
+		this.list = null;
+	}
+	cancel() {
+		if(this.list != null) {
+			let list = this.list;
+			this.cb = null;
+			this.list = null;
+			if(--list.used <= list.cells.length >> 1) {
+				list.compact();
+			}
+		}
+	}
+}
+tink_core__$Callback_ListCell.__name__ = "tink.core._Callback.ListCell";
+tink_core__$Callback_ListCell.__interfaces__ = [tink_core_LinkObject];
+Object.assign(tink_core__$Callback_ListCell.prototype, {
+	__class__: tink_core__$Callback_ListCell
+});
+class tink_core_Disposable {
+}
+tink_core_Disposable.__name__ = "tink.core.Disposable";
+tink_core_Disposable.__isInterface__ = true;
+Object.assign(tink_core_Disposable.prototype, {
+	__class__: tink_core_Disposable
+});
+class tink_core_OwnedDisposable {
+}
+tink_core_OwnedDisposable.__name__ = "tink.core.OwnedDisposable";
+tink_core_OwnedDisposable.__isInterface__ = true;
+tink_core_OwnedDisposable.__interfaces__ = [tink_core_Disposable];
+Object.assign(tink_core_OwnedDisposable.prototype, {
+	__class__: tink_core_OwnedDisposable
+});
+class tink_core_SimpleDisposable {
+	constructor(dispose) {
+		if(tink_core_SimpleDisposable._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(dispose);
+	}
+	_hx_constructor(dispose) {
+		this.disposeHandlers = [];
+		this.f = dispose;
+	}
+	get_disposed() {
+		return this.disposeHandlers == null;
+	}
+	ondispose(d) {
+		let _g = this.disposeHandlers;
+		if(_g == null) {
+			d();
+		} else {
+			let v = _g;
+			v.push(d);
+		}
+	}
+	dispose() {
+		let _g = this.disposeHandlers;
+		if(_g != null) {
+			let v = _g;
+			this.disposeHandlers = null;
+			let f = this.f;
+			this.f = tink_core_SimpleDisposable.noop;
+			f();
+			let _g1 = 0;
+			while(_g1 < v.length) {
+				let h = v[_g1];
+				++_g1;
+				h();
+			}
+		}
+	}
+	static noop() {
+	}
+}
+tink_core_SimpleDisposable.__name__ = "tink.core.SimpleDisposable";
+tink_core_SimpleDisposable.__interfaces__ = [tink_core_OwnedDisposable];
+Object.assign(tink_core_SimpleDisposable.prototype, {
+	__class__: tink_core_SimpleDisposable
+});
+class tink_core_CallbackList extends tink_core_SimpleDisposable {
+	constructor(destructive) {
+		tink_core_SimpleDisposable._hx_skip_constructor = true;
+		super();
+		tink_core_SimpleDisposable._hx_skip_constructor = false;
+		this._hx_constructor(destructive);
+	}
+	_hx_constructor(destructive) {
+		if(destructive == null) {
+			destructive = false;
+		}
+		this.onfill = function() {
+		};
+		this.ondrain = function() {
+		};
+		this.busy = false;
+		this.queue = [];
+		this.used = 0;
+		let _gthis = this;
+		super._hx_constructor(function() {
+			if(!_gthis.busy) {
+				_gthis.destroy();
+			}
+		});
+		this.destructive = destructive;
+		this.cells = [];
+	}
+	get_length() {
+		return this.used;
+	}
+	release() {
+		if(--this.used <= this.cells.length >> 1) {
+			this.compact();
+		}
+	}
+	destroy() {
+		let _g = 0;
+		let _g1 = this.cells;
+		while(_g < _g1.length) {
+			let c = _g1[_g];
+			++_g;
+			c.cb = null;
+			c.list = null;
+		}
+		this.queue = null;
+		this.cells = null;
+		if(this.used > 0) {
+			this.used = 0;
+			let fn = this.ondrain;
+			if(tink_core_Callback.depth < 500) {
+				tink_core_Callback.depth++;
+				fn();
+				tink_core_Callback.depth--;
+			} else {
+				tink_core_Callback.defer(fn);
+			}
+		}
+	}
+	drain() {
+		let fn = this.ondrain;
+		if(tink_core_Callback.depth < 500) {
+			tink_core_Callback.depth++;
+			fn();
+			tink_core_Callback.depth--;
+		} else {
+			tink_core_Callback.defer(fn);
+		}
+	}
+	add(cb) {
+		if(this.disposeHandlers == null) {
+			return null;
+		}
+		let node = new tink_core__$Callback_ListCell(cb,this);
+		this.cells.push(node);
+		if(this.used++ == 0) {
+			let fn = this.onfill;
+			if(tink_core_Callback.depth < 500) {
+				tink_core_Callback.depth++;
+				fn();
+				tink_core_Callback.depth--;
+			} else {
+				tink_core_Callback.defer(fn);
+			}
+		}
+		return node;
+	}
+	invoke(data) {
+		let _gthis = this;
+		if(tink_core_Callback.depth < 500) {
+			tink_core_Callback.depth++;
+			if(_gthis.disposeHandlers != null) {
+				if(_gthis.busy) {
+					if(_gthis.destructive != true) {
+						let _g = _gthis;
+						let data1 = data;
+						let tmp = function() {
+							_g.invoke(data1);
+						};
+						_gthis.queue.push(tmp);
+					}
+				} else {
+					_gthis.busy = true;
+					if(_gthis.destructive) {
+						_gthis.dispose();
+					}
+					let length = _gthis.cells.length;
+					let _g = 0;
+					let _g1 = length;
+					while(_g < _g1) {
+						let i = _g++;
+						let _this = _gthis.cells[i];
+						if(_this.list != null) {
+							_this.cb(data);
+						}
+					}
+					_gthis.busy = false;
+					if(_gthis.disposeHandlers == null) {
+						_gthis.destroy();
+					} else {
+						if(_gthis.used < _gthis.cells.length) {
+							_gthis.compact();
+						}
+						if(_gthis.queue.length > 0) {
+							(_gthis.queue.shift())();
+						}
+					}
+				}
+			}
+			tink_core_Callback.depth--;
+		} else {
+			tink_core_Callback.defer(function() {
+				if(_gthis.disposeHandlers != null) {
+					if(_gthis.busy) {
+						if(_gthis.destructive != true) {
+							let _g = _gthis;
+							let data1 = data;
+							let tmp = function() {
+								_g.invoke(data1);
+							};
+							_gthis.queue.push(tmp);
+						}
+					} else {
+						_gthis.busy = true;
+						if(_gthis.destructive) {
+							_gthis.dispose();
+						}
+						let length = _gthis.cells.length;
+						let _g = 0;
+						let _g1 = length;
+						while(_g < _g1) {
+							let i = _g++;
+							let _this = _gthis.cells[i];
+							if(_this.list != null) {
+								_this.cb(data);
+							}
+						}
+						_gthis.busy = false;
+						if(_gthis.disposeHandlers == null) {
+							_gthis.destroy();
+						} else {
+							if(_gthis.used < _gthis.cells.length) {
+								_gthis.compact();
+							}
+							if(_gthis.queue.length > 0) {
+								(_gthis.queue.shift())();
+							}
+						}
+					}
+				}
+			});
+		}
+	}
+	compact() {
+		if(this.busy) {
+			return;
+		} else if(this.used == 0) {
+			this.resize(0);
+			let fn = this.ondrain;
+			if(tink_core_Callback.depth < 500) {
+				tink_core_Callback.depth++;
+				fn();
+				tink_core_Callback.depth--;
+			} else {
+				tink_core_Callback.defer(fn);
+			}
+		} else {
+			let compacted = 0;
+			let _g = 0;
+			let _g1 = this.cells.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let _g1 = this.cells[i];
+				let _g2 = _g1.list;
+				if(_g1.cb != null) {
+					let v = _g1;
+					if(compacted != i) {
+						this.cells[compacted] = v;
+					}
+					if(++compacted == this.used) {
+						break;
+					}
+				}
+			}
+			this.resize(this.used);
+		}
+	}
+	resize(length) {
+		this.cells.length = length;
+	}
+	clear() {
+		if(this.busy) {
+			this.queue.push($bind(this,this.clear));
+		}
+		let _g = 0;
+		let _g1 = this.cells;
+		while(_g < _g1.length) {
+			let cell = _g1[_g];
+			++_g;
+			cell.cb = null;
+			cell.list = null;
+		}
+		this.resize(0);
+	}
+}
+tink_core_CallbackList.__name__ = "tink.core.CallbackList";
+tink_core_CallbackList.__super__ = tink_core_SimpleDisposable;
+Object.assign(tink_core_CallbackList.prototype, {
+	__class__: tink_core_CallbackList
+});
+class tink_core_AlreadyDisposed {
+	constructor() {
+	}
+	get_disposed() {
+		return true;
+	}
+	ondispose(d) {
+		d();
+	}
+	dispose() {
+	}
+}
+tink_core_AlreadyDisposed.__name__ = "tink.core.AlreadyDisposed";
+tink_core_AlreadyDisposed.__interfaces__ = [tink_core_OwnedDisposable];
+Object.assign(tink_core_AlreadyDisposed.prototype, {
+	__class__: tink_core_AlreadyDisposed
+});
+class tink_core_TypedError {
+	constructor(code,message,pos) {
+		if(code == null) {
+			code = 500;
+		}
+		this.isTinkError = true;
+		this.code = code;
+		this.message = message;
+		this.pos = pos;
+		this.exceptionStack = [];
+		this.callStack = [];
+	}
+	printPos() {
+		return this.pos.className + "." + this.pos.methodName + ":" + this.pos.lineNumber;
+	}
+	toString() {
+		let ret = "Error#" + this.code + ": " + this.message;
+		if(this.pos != null) {
+			ret += " @ " + this.printPos();
+		}
+		return ret;
+	}
+	toPromise() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(this)));
+	}
+	throwSelf() {
+		let any = this;
+		throw haxe_Exception.thrown(any);
+	}
+	toJsError() {
+		if(((this.data) instanceof Error)) {
+			return this.data;
+		} else {
+			return new tink_core__$Error_TinkError(this);
+		}
+	}
+	static withData(code,message,data,pos) {
+		return tink_core_TypedError.typed(code,message,data,pos);
+	}
+	static typed(code,message,data,pos) {
+		let ret = new tink_core_TypedError(code,message,pos);
+		ret.data = data;
+		return ret;
+	}
+	static ofJsError(e,pos) {
+		return tink_core_TypedError.withData(500,e.message,e,pos);
+	}
+	static asError(v) {
+		if(v != null && v.isTinkError) {
+			return v;
+		} else {
+			return null;
+		}
+	}
+	static catchExceptions(f,report,pos) {
+		try {
+			return tink_core_Outcome.Success(f());
+		} catch( _g ) {
+			let ex = haxe_Exception.caught(_g).unwrap();
+			let e = tink_core_TypedError.asError(ex);
+			let tmp;
+			if(e == null) {
+				tmp = report == null ? tink_core_TypedError.withData(null,"Unexpected Error",ex,pos) : report(ex);
+			} else {
+				let e1 = e;
+				tmp = e1;
+			}
+			return tink_core_Outcome.Failure(tmp);
+		}
+	}
+	static reporter(code,message,pos) {
+		return function(e) {
+			return tink_core_TypedError.withData(code,message,e,pos);
+		};
+	}
+	static rethrow(any) {
+		throw haxe_Exception.thrown(any);
+	}
+	static tryFinally(f,cleanup) {
+		try { return f(); } finally { cleanup(); }
+		return null;
+	}
+}
+tink_core_TypedError.__name__ = "tink.core.TypedError";
+Object.assign(tink_core_TypedError.prototype, {
+	__class__: tink_core_TypedError
+});
+class tink_core_Stack {
+	static toString(this1) {
+		return "Error stack not available. Compile with -D error_stack.";
+	}
+}
+class tink_core__$Error_TinkError extends Error {
+	constructor(e) {
+		super();
+		this.message = e.message;
+		this.data = e;
+	}
+}
+tink_core__$Error_TinkError.__name__ = "tink.core._Error.TinkError";
+tink_core__$Error_TinkError.__super__ = Error;
+Object.assign(tink_core__$Error_TinkError.prototype, {
+	__class__: tink_core__$Error_TinkError
+});
+class tink_core__$Future_FutureObject {
+	constructor() {
+		if(tink_core__$Future_FutureObject._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+	}
+	getStatus() {
+		return tink_core_FutureStatus.NeverEver;
+	}
+	handle(callback) {
+		return null;
+	}
+	eager() {
+	}
+}
+tink_core__$Future_FutureObject.__name__ = "tink.core._Future.FutureObject";
+Object.assign(tink_core__$Future_FutureObject.prototype, {
+	__class__: tink_core__$Future_FutureObject
+});
+class tink_core__$Lazy_Computable {
+}
+tink_core__$Lazy_Computable.__name__ = "tink.core._Lazy.Computable";
+tink_core__$Lazy_Computable.__isInterface__ = true;
+Object.assign(tink_core__$Lazy_Computable.prototype, {
+	__class__: tink_core__$Lazy_Computable
+});
+class tink_core__$Lazy_LazyObject {
+}
+tink_core__$Lazy_LazyObject.__name__ = "tink.core._Lazy.LazyObject";
+tink_core__$Lazy_LazyObject.__isInterface__ = true;
+tink_core__$Lazy_LazyObject.__interfaces__ = [tink_core__$Lazy_Computable];
+Object.assign(tink_core__$Lazy_LazyObject.prototype, {
+	__class__: tink_core__$Lazy_LazyObject
+});
+class tink_core__$Lazy_LazyConst {
+	constructor(value) {
+		this.value = value;
+	}
+	isComputed() {
+		return true;
+	}
+	get() {
+		return this.value;
+	}
+	compute() {
+	}
+	underlying() {
+		return null;
+	}
+}
+tink_core__$Lazy_LazyConst.__name__ = "tink.core._Lazy.LazyConst";
+tink_core__$Lazy_LazyConst.__interfaces__ = [tink_core__$Lazy_LazyObject];
+Object.assign(tink_core__$Lazy_LazyConst.prototype, {
+	__class__: tink_core__$Lazy_LazyConst
+});
+class tink_core__$Future_SyncFuture extends tink_core__$Future_FutureObject {
+	constructor(value) {
+		super();
+		this.value = value;
+	}
+	getStatus() {
+		return tink_core_FutureStatus.Ready(this.value);
+	}
+	handle(cb) {
+		tink_core_Callback.invoke(cb,tink_core_Lazy.get(this.value));
+		return null;
+	}
+	eager() {
+		if(!this.value.isComputed()) {
+			tink_core_Lazy.get(this.value);
+		}
+	}
+}
+tink_core__$Future_SyncFuture.__name__ = "tink.core._Future.SyncFuture";
+tink_core__$Future_SyncFuture.__super__ = tink_core__$Future_FutureObject;
+Object.assign(tink_core__$Future_SyncFuture.prototype, {
+	__class__: tink_core__$Future_SyncFuture
+});
+class tink_core_Future {
+	static never() {
+		return tink_core_Future.NEVER_INST;
+	}
+	static get_status(this1) {
+		return this1.getStatus();
+	}
+	static _new(wakeup) {
+		return new tink_core__$Future_SuspendableFuture(wakeup);
+	}
+	static handle(this1,callback) {
+		return this1.handle(callback);
+	}
+	static eager(this1) {
+		this1.eager();
+		return this1;
+	}
+	static noise(this1) {
+		if(this1.getStatus()._hx_index == 4) {
+			return tink_core_Future.never();
+		} else {
+			return tink_core_Future.map(this1,function(_) {
+				return null;
+			});
+		}
+	}
+	static first(this1,that) {
+		let _g = this1;
+		let _g1 = _g.getStatus();
+		switch(_g1._hx_index) {
+		case 3:
+			let _g2 = _g1.result;
+			let _g3 = that.getStatus();
+			switch(_g3._hx_index) {
+			case 3:
+				let _g4 = _g3.result;
+				let v = _g;
+				return v;
+			case 4:
+				let v1 = _g;
+				return v1;
+			default:
+				let v2 = _g;
+				return v2;
+			}
+			break;
+		case 4:
+			let v3 = that;
+			return v3;
+		default:
+			let _g5 = that.getStatus();
+			switch(_g5._hx_index) {
+			case 3:
+				let _g6 = _g5.result;
+				let v4 = that;
+				return v4;
+			case 4:
+				let v5 = _g;
+				return v5;
+			default:
+				return new tink_core__$Future_SuspendableFuture(function(fire) {
+					return new tink_core__$Callback_LinkPair(this1.handle(fire),that.handle(fire));
+				});
+			}
+		}
+	}
+	static map(this1,f,gather) {
+		let _g = this1.getStatus();
+		switch(_g._hx_index) {
+		case 3:
+			let l = _g.result;
+			let this2 = l;
+			let f1 = f;
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyFunc(function() {
+				return f1(this2.get());
+			},this2));
+		case 4:
+			return tink_core_Future.never();
+		default:
+			return new tink_core__$Future_SuspendableFuture(function(fire) {
+				return this1.handle(function(v) {
+					fire(f(v));
+				});
+			});
+		}
+	}
+	static flatMap(this1,next,gather) {
+		let _g = this1.getStatus();
+		switch(_g._hx_index) {
+		case 3:
+			let l = _g.result;
+			return new tink_core__$Future_SuspendableFuture(function(fire) {
+				return next(tink_core_Lazy.get(l)).handle(function(v) {
+					fire(v);
+				});
+			});
+		case 4:
+			return tink_core_Future.never();
+		default:
+			return new tink_core__$Future_SuspendableFuture(function($yield) {
+				let inner = new tink_core_CallbackLinkRef();
+				let outer = this1.handle(function(v) {
+					let param = next(v).handle($yield);
+					let this1 = inner.link;
+					if(this1 != null) {
+						this1.cancel();
+					}
+					inner.link = param;
+				});
+				return new tink_core__$Callback_LinkPair(outer,inner);
+			});
+		}
+	}
+	static swap(this1,v) {
+		return tink_core_Future.map(this1,function(_) {
+			return v;
+		});
+	}
+	static next(this1,n) {
+		return tink_core_Future.flatMap(this1,n);
+	}
+	static withSideEffect(this1,c) {
+		return tink_core_Future.map(this1,function(v) {
+			tink_core_Callback.invoke(c,v);
+			return v;
+		});
+	}
+	static gather(this1) {
+		return this1;
+	}
+	static merge(this1,that,combine) {
+		let _g = this1.getStatus();
+		let _g1 = that.getStatus();
+		if(_g._hx_index == 4) {
+			return tink_core_Future.never();
+		} else if(_g1._hx_index == 4) {
+			return tink_core_Future.never();
+		} else {
+			return new tink_core__$Future_SuspendableFuture(function($yield) {
+				let check = function(v) {
+					let _g = this1.getStatus();
+					let _g1 = that.getStatus();
+					if(_g._hx_index == 3) {
+						if(_g1._hx_index == 3) {
+							let b = _g1.result;
+							let a = _g.result;
+							$yield(combine(tink_core_Lazy.get(a),tink_core_Lazy.get(b)));
+						}
+					}
+				};
+				return new tink_core__$Callback_LinkPair(this1.handle(check),that.handle(check));
+			});
+		}
+	}
+	static flatten(f) {
+		return tink_core_Future.flatMap(f,function(v) {
+			return v;
+		});
+	}
+	static ofJsPromise(promise,transformError) {
+		return tink_core_Future.irreversible(function(cb) {
+			promise.then(function(a) {
+				let _g = cb;
+				let a1 = tink_core_Outcome.Success(a);
+				tink_core_Callback.defer(function() {
+					_g(a1);
+				});
+			},function(e) {
+				let cb1 = cb;
+				let tmp;
+				if(transformError == null) {
+					let e1 = e;
+					tmp = tink_core_TypedError.withData(500,e1.message,e1,{ fileName : "tink/core/Future.hx", lineNumber : 176, className : "tink.core._Future.Future_Impl_", methodName : "ofJsPromise"});
+				} else {
+					let f = transformError;
+					tmp = f(e);
+				}
+				cb1(tink_core_Outcome.Failure(tmp));
+			});
+		});
+	}
+	static fromJsPromise(promise) {
+		return tink_core_Future.ofJsPromise(promise);
+	}
+	static neverToAny(l) {
+		return l;
+	}
+	static ofAny(v) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+	}
+	static asPromise(s) {
+		return s;
+	}
+	static ofMany(futures,gather) {
+		return tink_core_Future.inSequence(futures);
+	}
+	static inParallel(futures,concurrency) {
+		return tink_core_Future.many(futures,concurrency);
+	}
+	static inSequence(futures) {
+		return tink_core_Future.many(futures,1);
+	}
+	static many(a,concurrency) {
+		return tink_core_Future.processMany(a,concurrency,tink_core_Outcome.Success,function(o) {
+			return tink_core_OutcomeTools.orNull(o);
+		});
+	}
+	static processMany(a,concurrency,fn,lift) {
+		if(a.length == 0) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(lift(tink_core_Outcome.Success([]))));
+		} else {
+			return new tink_core__$Future_SuspendableFuture(function($yield) {
+				let links = [];
+				let _g = [];
+				let _g1 = 0;
+				while(_g1 < a.length) {
+					let x = a[_g1];
+					++_g1;
+					_g.push(null);
+				}
+				let ret = _g;
+				let index = 0;
+				let pending = 0;
+				let done = false;
+				let concurrency1;
+				if(concurrency == null) {
+					concurrency1 = a.length;
+				} else {
+					let v = concurrency;
+					concurrency1 = v < 1 ? 1 : v > a.length ? a.length : v;
+				}
+				let fireWhenReady = function() {
+					if(index == ret.length) {
+						if(pending == 0) {
+							let v = lift(tink_core_Outcome.Success(ret));
+							done = true;
+							$yield(v);
+							return true;
+						} else {
+							return false;
+						}
+					} else {
+						return false;
+					}
+				};
+				let step = null;
+				step = function() {
+					if(!done && !fireWhenReady()) {
+						while(index < ret.length) {
+							index += 1;
+							let index1 = index - 1;
+							let p = a[index1];
+							let check = function(o) {
+								let _g = fn(o);
+								switch(_g._hx_index) {
+								case 0:
+									let v = _g.data;
+									ret[index1] = v;
+									fireWhenReady();
+									break;
+								case 1:
+									let e = _g.failure;
+									let _g1 = 0;
+									while(_g1 < links.length) {
+										let l = links[_g1];
+										++_g1;
+										if(l != null) {
+											l.cancel();
+										}
+									}
+									let v1 = lift(tink_core_Outcome.Failure(e));
+									done = true;
+									$yield(v1);
+									break;
+								}
+							};
+							let _g = p.getStatus();
+							if(_g._hx_index == 3) {
+								let _hx_tmp;
+								_hx_tmp = tink_core_Lazy.get(_g.result);
+								let v = _hx_tmp;
+								check(v);
+								if(!done) {
+									continue;
+								}
+							} else {
+								pending += 1;
+								links.push(p.handle(function(o) {
+									pending -= 1;
+									check(o);
+									if(!done) {
+										step();
+									}
+								}));
+							}
+							break;
+						}
+					}
+				};
+				let _g2 = 0;
+				let _g3 = concurrency1;
+				while(_g2 < _g3) {
+					let i = _g2++;
+					step();
+				}
+				return tink_core_CallbackLink.fromMany(links);
+			});
+		}
+	}
+	static lazy(l) {
+		return new tink_core__$Future_SyncFuture(l);
+	}
+	static sync(v) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+	}
+	static isFuture(maybeFuture) {
+		return ((maybeFuture) instanceof tink_core__$Future_FutureObject);
+	}
+	static async(init,lazy) {
+		if(lazy == null) {
+			lazy = false;
+		}
+		let ret = tink_core_Future.irreversible(init);
+		if(lazy) {
+			return ret;
+		} else {
+			ret.eager();
+			return ret;
+		}
+	}
+	static irreversible(init) {
+		return new tink_core__$Future_SuspendableFuture(function($yield) {
+			init($yield);
+			return null;
+		});
+	}
+	static or(a,b) {
+		return tink_core_Future.first(a,b);
+	}
+	static either(a,b) {
+		return tink_core_Future.first(tink_core_Future.map(a,haxe_ds_Either.Left),tink_core_Future.map(b,haxe_ds_Either.Right));
+	}
+	static and(a,b) {
+		return tink_core_Future.merge(a,b,function(a,b) {
+			return new tink_core_MPair(a,b);
+		});
+	}
+	static _tryFailingFlatMap(f,map) {
+		return tink_core_Future.flatMap(f,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return map(d);
+			case 1:
+				let f = o.failure;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(f)));
+			}
+		});
+	}
+	static _tryFlatMap(f,map) {
+		return tink_core_Future.flatMap(f,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return tink_core_Future.map(map(d),tink_core_Outcome.Success);
+			case 1:
+				let f = o.failure;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(f)));
+			}
+		});
+	}
+	static _tryFailingMap(f,map) {
+		return tink_core_Future.map(f,function(o) {
+			return tink_core_OutcomeTools.flatMap(o,tink_core__$Outcome_OutcomeMapper.withSameError(map));
+		});
+	}
+	static _tryMap(f,map) {
+		return tink_core_Future.map(f,function(o) {
+			return tink_core_OutcomeTools.map(o,map);
+		});
+	}
+	static _flatMap(f,map) {
+		return tink_core_Future.flatMap(f,map);
+	}
+	static _map(f,map) {
+		return tink_core_Future.map(f,map);
+	}
+	static trigger() {
+		return new tink_core_FutureTrigger();
+	}
+	static delay(ms,value) {
+		let this1 = tink_core_Future.irreversible(function(cb) {
+			haxe_Timer.delay(function() {
+				cb(tink_core_Lazy.get(value));
+			},ms);
+		});
+		this1.eager();
+		return this1;
+	}
+}
+var tink_core_FutureStatus = $hxEnums["tink.core.FutureStatus"] = { __ename__:true,__constructs__:null
+	,Suspended: {_hx_name:"Suspended",_hx_index:0,__enum__:"tink.core.FutureStatus",toString:$estr}
+	,Awaited: {_hx_name:"Awaited",_hx_index:1,__enum__:"tink.core.FutureStatus",toString:$estr}
+	,EagerlyAwaited: {_hx_name:"EagerlyAwaited",_hx_index:2,__enum__:"tink.core.FutureStatus",toString:$estr}
+	,Ready: ($_=function(result) { return {_hx_index:3,result:result,__enum__:"tink.core.FutureStatus",toString:$estr}; },$_._hx_name="Ready",$_.__params__ = ["result"],$_)
+	,NeverEver: {_hx_name:"NeverEver",_hx_index:4,__enum__:"tink.core.FutureStatus",toString:$estr}
+};
+tink_core_FutureStatus.__constructs__ = [tink_core_FutureStatus.Suspended,tink_core_FutureStatus.Awaited,tink_core_FutureStatus.EagerlyAwaited,tink_core_FutureStatus.Ready,tink_core_FutureStatus.NeverEver];
+class tink_core_FutureTrigger extends tink_core__$Future_FutureObject {
+	constructor() {
+		tink_core__$Future_FutureObject._hx_skip_constructor = true;
+		super();
+		tink_core__$Future_FutureObject._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.status = tink_core_FutureStatus.Awaited;
+		super._hx_constructor();
+		this.list = new tink_core_CallbackList(true);
+	}
+	getStatus() {
+		return this.status;
+	}
+	handle(callback) {
+		let _g = this.status;
+		if(_g._hx_index == 3) {
+			let result = _g.result;
+			tink_core_Callback.invoke(callback,tink_core_Lazy.get(result));
+			return null;
+		} else {
+			let v = _g;
+			let _this = this.list;
+			if(_this.disposeHandlers == null) {
+				return null;
+			} else {
+				let node = new tink_core__$Callback_ListCell(callback,_this);
+				_this.cells.push(node);
+				if(_this.used++ == 0) {
+					let fn = _this.onfill;
+					if(tink_core_Callback.depth < 500) {
+						tink_core_Callback.depth++;
+						fn();
+						tink_core_Callback.depth--;
+					} else {
+						tink_core_Callback.defer(fn);
+					}
+				}
+				return node;
+			}
+		}
+	}
+	asFuture() {
+		return this;
+	}
+	trigger(result) {
+		let _g = this.status;
+		if(_g._hx_index == 3) {
+			let _g1 = _g.result;
+			return false;
+		} else {
+			this.status = tink_core_FutureStatus.Ready(new tink_core__$Lazy_LazyConst(result));
+			this.list.invoke(result);
+			return true;
+		}
+	}
+}
+tink_core_FutureTrigger.__name__ = "tink.core.FutureTrigger";
+tink_core_FutureTrigger.__super__ = tink_core__$Future_FutureObject;
+Object.assign(tink_core_FutureTrigger.prototype, {
+	__class__: tink_core_FutureTrigger
+});
+class tink_core_JsPromiseTools {
+	static toSurprise(promise) {
+		return tink_core_Future.ofJsPromise(promise);
+	}
+	static toPromise(promise) {
+		return tink_core_Future.ofJsPromise(promise);
+	}
+}
+tink_core_JsPromiseTools.__name__ = "tink.core.JsPromiseTools";
+class tink_core__$Future_SuspendableFuture extends tink_core__$Future_FutureObject {
+	constructor(wakeup) {
+		tink_core__$Future_FutureObject._hx_skip_constructor = true;
+		super();
+		tink_core__$Future_FutureObject._hx_skip_constructor = false;
+		this._hx_constructor(wakeup);
+	}
+	_hx_constructor(wakeup) {
+		this.status = tink_core_FutureStatus.Suspended;
+		super._hx_constructor();
+		this.wakeup = wakeup;
+		this.callbacks = new tink_core_CallbackList(true);
+		let _gthis = this;
+		this.callbacks.ondrain = function() {
+			if(_gthis.status == tink_core_FutureStatus.Awaited) {
+				_gthis.status = tink_core_FutureStatus.Suspended;
+				let this1 = _gthis.link;
+				if(this1 != null) {
+					this1.cancel();
+				}
+				_gthis.link = null;
+			}
+		};
+		this.callbacks.onfill = function() {
+			if(_gthis.status == tink_core_FutureStatus.Suspended) {
+				_gthis.status = tink_core_FutureStatus.Awaited;
+				_gthis.arm();
+			}
+		};
+	}
+	getStatus() {
+		return this.status;
+	}
+	trigger(value) {
+		let _g = this.status;
+		if(_g._hx_index == 3) {
+			let _g1 = _g.result;
+		} else {
+			this.status = tink_core_FutureStatus.Ready(new tink_core__$Lazy_LazyConst(value));
+			let link = this.link;
+			this.link = null;
+			this.wakeup = null;
+			this.callbacks.invoke(value);
+			if(link != null) {
+				link.cancel();
+			}
+		}
+	}
+	handle(callback) {
+		let _g = this.status;
+		if(_g._hx_index == 3) {
+			let result = _g.result;
+			tink_core_Callback.invoke(callback,tink_core_Lazy.get(result));
+			return null;
+		} else {
+			let _this = this.callbacks;
+			if(_this.disposeHandlers == null) {
+				return null;
+			} else {
+				let node = new tink_core__$Callback_ListCell(callback,_this);
+				_this.cells.push(node);
+				if(_this.used++ == 0) {
+					let fn = _this.onfill;
+					if(tink_core_Callback.depth < 500) {
+						tink_core_Callback.depth++;
+						fn();
+						tink_core_Callback.depth--;
+					} else {
+						tink_core_Callback.defer(fn);
+					}
+				}
+				return node;
+			}
+		}
+	}
+	arm() {
+		let _gthis = this;
+		this.link = this.wakeup(function(x) {
+			_gthis.trigger(x);
+		});
+	}
+	eager() {
+		switch(this.status._hx_index) {
+		case 0:
+			this.status = tink_core_FutureStatus.EagerlyAwaited;
+			this.arm();
+			break;
+		case 1:
+			this.status = tink_core_FutureStatus.EagerlyAwaited;
+			break;
+		default:
+		}
+	}
+}
+tink_core__$Future_SuspendableFuture.__name__ = "tink.core._Future.SuspendableFuture";
+tink_core__$Future_SuspendableFuture.__super__ = tink_core__$Future_FutureObject;
+Object.assign(tink_core__$Future_SuspendableFuture.prototype, {
+	__class__: tink_core__$Future_SuspendableFuture
+});
+class tink_core_Lazy {
+	static get_computed(this1) {
+		return this1.isComputed();
+	}
+	static get(this1) {
+		this1.compute();
+		return this1.get();
+	}
+	static fromNoise(l) {
+		return l;
+	}
+	static ofFunc(f) {
+		return new tink_core__$Lazy_LazyFunc(f);
+	}
+	static map(this1,f) {
+		return new tink_core__$Lazy_LazyFunc(function() {
+			return f(this1.get());
+		},this1);
+	}
+	static flatMap(this1,f) {
+		return new tink_core__$Lazy_LazyFunc(function() {
+			return tink_core_Lazy.get(f(this1.get()));
+		},this1);
+	}
+	static ofConst(c) {
+		return new tink_core__$Lazy_LazyConst(c);
+	}
+}
+class tink_core__$Lazy_LazyFunc {
+	constructor(f,from) {
+		this.f = f;
+		this.from = from;
+	}
+	underlying() {
+		return this.from;
+	}
+	isComputed() {
+		return this.f == null;
+	}
+	get() {
+		return this.result;
+	}
+	compute() {
+		let _g = this.f;
+		if(_g != null) {
+			let v = _g;
+			this.f = null;
+			let _g1 = this.from;
+			if(_g1 != null) {
+				let cur = _g1;
+				this.from = null;
+				let stack = [];
+				while(cur != null && !cur.isComputed()) {
+					stack.push(cur);
+					cur = cur.underlying();
+				}
+				stack.reverse();
+				let _g = 0;
+				while(_g < stack.length) {
+					let c = stack[_g];
+					++_g;
+					c.compute();
+				}
+			}
+			this.result = v();
+		}
+	}
+}
+tink_core__$Lazy_LazyFunc.__name__ = "tink.core._Lazy.LazyFunc";
+tink_core__$Lazy_LazyFunc.__interfaces__ = [tink_core__$Lazy_LazyObject];
+Object.assign(tink_core__$Lazy_LazyFunc.prototype, {
+	__class__: tink_core__$Lazy_LazyFunc
+});
+class tink_core_NamedWith {
+	constructor(name,value) {
+		this.name = name;
+		this.value = value;
+	}
+}
+tink_core_NamedWith.__name__ = "tink.core.NamedWith";
+Object.assign(tink_core_NamedWith.prototype, {
+	__class__: tink_core_NamedWith
+});
+class tink_core_Noise {
+	static ofAny(t) {
+		return null;
+	}
+}
+class tink_core_OptionTools {
+	static force(o,pos) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return v;
+		} else {
+			throw haxe_Exception.thrown(new tink_core_TypedError(404,"Some value expected but none found",pos));
+		}
+	}
+	static sure(o,pos) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return v;
+		} else {
+			throw haxe_Exception.thrown(new tink_core_TypedError(404,"Some value expected but none found",pos));
+		}
+	}
+	static toOutcome(o,pos) {
+		switch(o._hx_index) {
+		case 0:
+			let value = o.v;
+			return tink_core_Outcome.Success(value);
+		case 1:
+			return tink_core_Outcome.Failure(new tink_core_TypedError(404,"Some value expected but none found in " + pos.fileName + "@line " + pos.lineNumber,{ fileName : "tink/core/Option.hx", lineNumber : 31, className : "tink.core.OptionTools", methodName : "toOutcome"}));
+		}
+	}
+	static or(o,l) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return v;
+		} else {
+			return tink_core_Lazy.get(l);
+		}
+	}
+	static orTry(o,fallback) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return o;
+		} else {
+			return tink_core_Lazy.get(fallback);
+		}
+	}
+	static orNull(o) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return v;
+		} else {
+			return null;
+		}
+	}
+	static filter(o,f) {
+		if(o._hx_index == 0) {
+			if(f(o.v) == false) {
+				return haxe_ds_Option.None;
+			} else {
+				return o;
+			}
+		} else {
+			return o;
+		}
+	}
+	static satisfies(o,f) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return f(v);
+		} else {
+			return false;
+		}
+	}
+	static equals(o,v) {
+		if(o._hx_index == 0) {
+			let v1 = o.v;
+			return v1 == v;
+		} else {
+			return false;
+		}
+	}
+	static map(o,f) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return haxe_ds_Option.Some(f(v));
+		} else {
+			return haxe_ds_Option.None;
+		}
+	}
+	static flatMap(o,f) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return f(v);
+		} else {
+			return haxe_ds_Option.None;
+		}
+	}
+	static iterator(o) {
+		return new tink_core_OptionIter(o);
+	}
+	static toArray(o) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return [v];
+		} else {
+			return [];
+		}
+	}
+}
+tink_core_OptionTools.__name__ = "tink.core.OptionTools";
+class tink_core_OptionIter {
+	constructor(o) {
+		this.alive = true;
+		if(o._hx_index == 0) {
+			let v = o.v;
+			this.value = v;
+		} else {
+			this.alive = false;
+		}
+	}
+	hasNext() {
+		return this.alive;
+	}
+	next() {
+		this.alive = false;
+		return this.value;
+	}
+}
+tink_core_OptionIter.__name__ = "tink.core.OptionIter";
+Object.assign(tink_core_OptionIter.prototype, {
+	__class__: tink_core_OptionIter
+});
+var tink_core_Outcome = $hxEnums["tink.core.Outcome"] = { __ename__:true,__constructs__:null
+	,Success: ($_=function(data) { return {_hx_index:0,data:data,__enum__:"tink.core.Outcome",toString:$estr}; },$_._hx_name="Success",$_.__params__ = ["data"],$_)
+	,Failure: ($_=function(failure) { return {_hx_index:1,failure:failure,__enum__:"tink.core.Outcome",toString:$estr}; },$_._hx_name="Failure",$_.__params__ = ["failure"],$_)
+};
+tink_core_Outcome.__constructs__ = [tink_core_Outcome.Success,tink_core_Outcome.Failure];
+class tink_core_OutcomeTools {
+	static sure(outcome) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return data;
+		case 1:
+			let failure = outcome.failure;
+			let _g = tink_core_TypedError.asError(failure);
+			if(_g == null) {
+				throw haxe_Exception.thrown(failure);
+			} else {
+				let e = _g;
+				return e.throwSelf();
+			}
+			break;
+		}
+	}
+	static toOption(outcome) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return haxe_ds_Option.Some(data);
+		case 1:
+			let _g = outcome.failure;
+			return haxe_ds_Option.None;
+		}
+	}
+	static orNull(outcome) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return data;
+		case 1:
+			let _g = outcome.failure;
+			return null;
+		}
+	}
+	static orUse(outcome,fallback) {
+		return tink_core_OutcomeTools.or(outcome,fallback);
+	}
+	static or(outcome,fallback) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return data;
+		case 1:
+			let _g = outcome.failure;
+			return tink_core_Lazy.get(fallback);
+		}
+	}
+	static orTry(outcome,fallback) {
+		switch(outcome._hx_index) {
+		case 0:
+			let _g = outcome.data;
+			return outcome;
+		case 1:
+			let _g1 = outcome.failure;
+			return tink_core_Lazy.get(fallback);
+		}
+	}
+	static equals(outcome,to) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return data == to;
+		case 1:
+			let _g = outcome.failure;
+			return false;
+		}
+	}
+	static map(outcome,transform) {
+		switch(outcome._hx_index) {
+		case 0:
+			let a = outcome.data;
+			return tink_core_Outcome.Success(transform(a));
+		case 1:
+			let f = outcome.failure;
+			return tink_core_Outcome.Failure(f);
+		}
+	}
+	static isSuccess(outcome) {
+		if(outcome._hx_index == 0) {
+			let _g = outcome.data;
+			return true;
+		} else {
+			return false;
+		}
+	}
+	static flatMap(o,mapper) {
+		return tink_core__$Outcome_OutcomeMapper.apply(mapper,o);
+	}
+	static swap(outcome,v) {
+		switch(outcome._hx_index) {
+		case 0:
+			let a = outcome.data;
+			return tink_core_Outcome.Success(v);
+		case 1:
+			let f = outcome.failure;
+			return tink_core_Outcome.Failure(f);
+		}
+	}
+	static next(outcome,f) {
+		switch(outcome._hx_index) {
+		case 0:
+			let v = outcome.data;
+			return f(v);
+		case 1:
+			let e = outcome.failure;
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+		}
+	}
+	static attempt(f,report) {
+		try {
+			return tink_core_Outcome.Success(f());
+		} catch( _g ) {
+			let e = haxe_Exception.caught(_g).unwrap();
+			return tink_core_Outcome.Failure(report(e));
+		}
+	}
+	static satisfies(o,f) {
+		if(o._hx_index == 0) {
+			let d = o.data;
+			return f(d);
+		} else {
+			return false;
+		}
+	}
+	static flatten(o) {
+		switch(o._hx_index) {
+		case 0:
+			let _g = o.data;
+			switch(_g._hx_index) {
+			case 0:
+				let d = _g.data;
+				return tink_core_Outcome.Success(d);
+			case 1:
+				let f = _g.failure;
+				return tink_core_Outcome.Failure(f);
+			}
+			break;
+		case 1:
+			let f1 = o.failure;
+			return tink_core_Outcome.Failure(f1);
+		}
+	}
+}
+tink_core_OutcomeTools.__name__ = "tink.core.OutcomeTools";
+class tink_core__$Outcome_OutcomeMapper {
+	static _new(f) {
+		return { f : f};
+	}
+	static apply(this1,o) {
+		return this1.f(o);
+	}
+	static withSameError(f) {
+		return tink_core__$Outcome_OutcomeMapper._new(function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return f(d);
+			case 1:
+				let f1 = o.failure;
+				return tink_core_Outcome.Failure(f1);
+			}
+		});
+	}
+	static withEitherError(f) {
+		return tink_core__$Outcome_OutcomeMapper._new(function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				let _g = f(d);
+				switch(_g._hx_index) {
+				case 0:
+					let d1 = _g.data;
+					return tink_core_Outcome.Success(d1);
+				case 1:
+					let f1 = _g.failure;
+					return tink_core_Outcome.Failure(haxe_ds_Either.Right(f1));
+				}
+				break;
+			case 1:
+				let f2 = o.failure;
+				return tink_core_Outcome.Failure(haxe_ds_Either.Left(f2));
+			}
+		});
+	}
+}
+class tink_core_Pair {
+	static _new(a,b) {
+		return new tink_core_MPair(a,b);
+	}
+	static get_a(this1) {
+		return this1.a;
+	}
+	static get_b(this1) {
+		return this1.b;
+	}
+	static toBool(this1) {
+		return this1 != null;
+	}
+	static isNil(this1) {
+		return this1 == null;
+	}
+	static nil() {
+		return null;
+	}
+}
+class tink_core_MPair {
+	constructor(a,b) {
+		this.a = a;
+		this.b = b;
+	}
+}
+tink_core_MPair.__name__ = "tink.core.MPair";
+Object.assign(tink_core_MPair.prototype, {
+	__class__: tink_core_MPair
+});
+class tink_core_ProgressValue {
+	static _new(value,total) {
+		return new tink_core_MPair(value,total);
+	}
+	static normalize(this1) {
+		let o = this1.b;
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return haxe_ds_Option.Some(this1.a / v);
+		} else {
+			return haxe_ds_Option.None;
+		}
+	}
+	static get_value(this1) {
+		return this1.a;
+	}
+	static get_total(this1) {
+		return this1.b;
+	}
+}
+class tink_core_Progress {
+	static listen(this1,cb) {
+		return this1.progressed.listen(cb);
+	}
+	static handle(this1,cb) {
+		return this1.result.handle(cb);
+	}
+	static trigger() {
+		return new tink_core_ProgressTrigger();
+	}
+	static make(f) {
+		return new tink_core__$Progress_SuspendableProgress(function(fire) {
+			return f(function(value,total) {
+				fire(tink_core_ProgressStatus.InProgress(new tink_core_MPair(value,total)));
+			},function(result) {
+				fire(tink_core_ProgressStatus.Finished(result));
+			});
+		});
+	}
+	static map(this1,f) {
+		return new tink_core__$Progress_ProgressObject(tink_core_Signal.map(this1.changed,function(s) {
+			return tink_core_ProgressStatusTools.map(s,f);
+		}),function() {
+			return tink_core_ProgressStatusTools.map(this1.getStatus(),f);
+		});
+	}
+	static asFuture(this1) {
+		return this1.result;
+	}
+	static promise(v) {
+		return new tink_core__$Progress_SuspendableProgress(function(fire) {
+			let inner = new tink_core_CallbackLinkRef();
+			return new tink_core__$Callback_LinkPair(v.handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let p = o.data;
+					let param = p.changed.listen(function(s) {
+						fire(tink_core_ProgressStatusTools.map(s,tink_core_Outcome.Success));
+					});
+					let this1 = inner.link;
+					if(this1 != null) {
+						this1.cancel();
+					}
+					inner.link = param;
+					break;
+				case 1:
+					let e = o.failure;
+					fire(tink_core_ProgressStatus.Finished(tink_core_Outcome.Failure(e)));
+					break;
+				}
+			}),inner);
+		});
+	}
+	static flatten(v) {
+		return tink_core_Progress.map(tink_core_Progress.promise(v),function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let _g = o.data;
+				switch(_g._hx_index) {
+				case 0:
+					let v = _g.data;
+					return tink_core_Outcome.Success(v);
+				case 1:
+					let e = _g.failure;
+					return tink_core_Outcome.Failure(e);
+				}
+				break;
+			case 1:
+				let e1 = o.failure;
+				return tink_core_Outcome.Failure(e1);
+			}
+		});
+	}
+	static future(v) {
+		return new tink_core__$Progress_SuspendableProgress(function(fire) {
+			let inner = new tink_core_CallbackLinkRef();
+			return new tink_core__$Callback_LinkPair(v.handle(function(p) {
+				let param = p.changed.listen(fire);
+				let this1 = inner.link;
+				if(this1 != null) {
+					this1.cancel();
+				}
+				inner.link = param;
+			}),inner);
+		});
+	}
+	static next(this1,f) {
+		return tink_core_Future.flatMap(this1.result,f);
+	}
+}
+class tink_core__$Progress_ProgressObject {
+	constructor(changed,getStatus) {
+		if(tink_core__$Progress_ProgressObject._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(changed,getStatus);
+	}
+	_hx_constructor(changed,getStatus) {
+		this.changed = changed;
+		this.progressed = new tink_core__$Signal_Suspendable(function(fire) {
+			return changed.listen(function(s) {
+				if(s._hx_index == 0) {
+					let v = s.v;
+					fire(v);
+				}
+			});
+		},null);
+		this.getStatus = getStatus;
+		this.result = new tink_core__$Future_SuspendableFuture(function(fire) {
+			let _g = getStatus();
+			if(_g._hx_index == 1) {
+				let v = _g.v;
+				fire(v);
+				return null;
+			} else {
+				return changed.listen(function(s) {
+					if(s._hx_index == 1) {
+						let v = s.v;
+						fire(v);
+					}
+				});
+			}
+		});
+	}
+	get_status() {
+		return this.getStatus();
+	}
+}
+tink_core__$Progress_ProgressObject.__name__ = "tink.core._Progress.ProgressObject";
+Object.assign(tink_core__$Progress_ProgressObject.prototype, {
+	__class__: tink_core__$Progress_ProgressObject
+});
+class tink_core__$Progress_SuspendableProgress extends tink_core__$Progress_ProgressObject {
+	constructor(wakeup,status) {
+		if(status == null) {
+			status = tink_core_ProgressStatus.InProgress(tink_core_ProgressValue.ZERO);
+		}
+		let disposable = tink_core_AlreadyDisposed.INST;
+		let changed;
+		switch(status._hx_index) {
+		case 0:
+			let _g = status.v;
+			changed = new tink_core__$Signal_Suspendable(function(fire) {
+				return wakeup(function(s) {
+					status = s;
+					fire(status);
+				});
+			},function(d) {
+				disposable = d;
+			});
+			break;
+		case 1:
+			let _g1 = status.v;
+			changed = tink_core_Signal.dead();
+			break;
+		}
+		super(changed,function() {
+			return status;
+		});
+	}
+	noop(_,_1) {
+		return null;
+	}
+}
+tink_core__$Progress_SuspendableProgress.__name__ = "tink.core._Progress.SuspendableProgress";
+tink_core__$Progress_SuspendableProgress.__super__ = tink_core__$Progress_ProgressObject;
+Object.assign(tink_core__$Progress_SuspendableProgress.prototype, {
+	__class__: tink_core__$Progress_SuspendableProgress
+});
+class tink_core_ProgressTrigger extends tink_core__$Progress_ProgressObject {
+	constructor(status) {
+		tink_core__$Progress_ProgressObject._hx_skip_constructor = true;
+		super();
+		tink_core__$Progress_ProgressObject._hx_skip_constructor = false;
+		this._hx_constructor(status);
+	}
+	_hx_constructor(status) {
+		this._changed = null;
+		if(status == null) {
+			status = tink_core_ProgressStatus.InProgress(tink_core_ProgressValue.ZERO);
+			this._status = status;
+		}
+		let _gthis = this;
+		let tmp;
+		if(status == null) {
+			tmp = false;
+		} else if(status._hx_index == 1) {
+			let _g = status.v;
+			tmp = true;
+		} else {
+			tmp = false;
+		}
+		super._hx_constructor(tmp ? tink_core_Signal.dead() : this._changed = tink_core_Signal.trigger(),function() {
+			return _gthis._status;
+		});
+	}
+	asProgress() {
+		return this;
+	}
+	progress(v,total) {
+		let _g = this._status;
+		let tmp;
+		if(_g._hx_index == 1) {
+			let _g1 = _g.v;
+			tmp = true;
+		} else {
+			tmp = false;
+		}
+		if(!tmp) {
+			let _this = this._changed;
+			let this1 = new tink_core_MPair(v,total);
+			_this.handlers.invoke(this._status = tink_core_ProgressStatus.InProgress(this1));
+		}
+	}
+	finish(v) {
+		let _g = this._status;
+		let tmp;
+		if(_g._hx_index == 1) {
+			let _g1 = _g.v;
+			tmp = true;
+		} else {
+			tmp = false;
+		}
+		if(!tmp) {
+			this._changed.handlers.invoke(this._status = tink_core_ProgressStatus.Finished(v));
+		}
+	}
+}
+tink_core_ProgressTrigger.__name__ = "tink.core.ProgressTrigger";
+tink_core_ProgressTrigger.__super__ = tink_core__$Progress_ProgressObject;
+Object.assign(tink_core_ProgressTrigger.prototype, {
+	__class__: tink_core_ProgressTrigger
+});
+class tink_core_UnitInterval {
+	static toPercentageString(this1,dp) {
+		let m = Math.pow(10,dp);
+		let v = Math.round(this1 * m * 100) / m;
+		let s = v == null ? "null" : "" + v;
+		let _g = s.indexOf(".");
+		if(_g == -1) {
+			return s + "." + StringTools.lpad("","0",dp) + "%";
+		} else {
+			let i = _g;
+			if(s.length - i > dp) {
+				return HxOverrides.substr(s,0,dp + i + 1) + "%";
+			} else {
+				let i = _g;
+				return StringTools.rpad(s,"0",i + dp + 1) + "%";
+			}
+		}
+	}
+}
+var tink_core_ProgressStatus = $hxEnums["tink.core.ProgressStatus"] = { __ename__:true,__constructs__:null
+	,InProgress: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"tink.core.ProgressStatus",toString:$estr}; },$_._hx_name="InProgress",$_.__params__ = ["v"],$_)
+	,Finished: ($_=function(v) { return {_hx_index:1,v:v,__enum__:"tink.core.ProgressStatus",toString:$estr}; },$_._hx_name="Finished",$_.__params__ = ["v"],$_)
+};
+tink_core_ProgressStatus.__constructs__ = [tink_core_ProgressStatus.InProgress,tink_core_ProgressStatus.Finished];
+class tink_core_ProgressStatusTools {
+	static map(p,f) {
+		switch(p._hx_index) {
+		case 0:
+			let v = p.v;
+			return tink_core_ProgressStatus.InProgress(v);
+		case 1:
+			let v1 = p.v;
+			return tink_core_ProgressStatus.Finished(f(v1));
+		}
+	}
+}
+tink_core_ProgressStatusTools.__name__ = "tink.core.ProgressStatusTools";
+class tink_core_TotalTools {
+	static eq(a,b) {
+		switch(a._hx_index) {
+		case 0:
+			if(b._hx_index == 0) {
+				let t2 = b.v;
+				let t1 = a.v;
+				return t1 == t2;
+			} else {
+				return false;
+			}
+			break;
+		case 1:
+			if(b._hx_index == 1) {
+				return true;
+			} else {
+				return false;
+			}
+			break;
+		}
+	}
+}
+tink_core_TotalTools.__name__ = "tink.core.TotalTools";
+class tink_core_ProgressTools {
+	static asPromise(p) {
+		return p.result;
+	}
+}
+tink_core_ProgressTools.__name__ = "tink.core.ProgressTools";
+class tink_core_Promise {
+	static never() {
+		return tink_core_Future.never();
+	}
+	static _new(f) {
+		return new tink_core__$Future_SuspendableFuture(function(cb) {
+			return f(function(v) {
+				cb(tink_core_Outcome.Success(v));
+			},function(e) {
+				cb(tink_core_Outcome.Failure(e));
+			});
+		});
+	}
+	static eager(this1) {
+		this1.eager();
+		return this1;
+	}
+	static map(this1,f) {
+		return tink_core_Future.map(this1,f);
+	}
+	static flatMap(this1,f) {
+		return tink_core_Future.flatMap(this1,f);
+	}
+	static tryRecover(this1,f) {
+		return tink_core_Future.flatMap(this1,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(o));
+			case 1:
+				let e = o.failure;
+				return f(e);
+			}
+		});
+	}
+	static recover(this1,f) {
+		return tink_core_Future.flatMap(this1,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(d));
+			case 1:
+				let e = o.failure;
+				return f(e);
+			}
+		});
+	}
+	static mapError(this1,f) {
+		return tink_core_Future.map(this1,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let _g = o.data;
+				return o;
+			case 1:
+				let e = o.failure;
+				return tink_core_Outcome.Failure(f(e));
+			}
+		});
+	}
+	static withSideEffect(this1,c) {
+		let c1 = function(o) {
+			if(o._hx_index == 0) {
+				let data = o.data;
+				tink_core_Callback.invoke(c,data);
+			}
+		};
+		return tink_core_Future.map(this1,function(v) {
+			tink_core_Callback.invoke(c1,v);
+			return v;
+		});
+	}
+	static handle(this1,cb) {
+		return this1.handle(cb);
+	}
+	static noise(this1) {
+		if(this1.getStatus()._hx_index == 4) {
+			return tink_core_Promise.never();
+		} else {
+			return tink_core_Promise.next(this1,function(v) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(null)));
+			});
+		}
+	}
+	static isSuccess(this1) {
+		return tink_core_Future.map(this1,function(o) {
+			return tink_core_OutcomeTools.isSuccess(o);
+		});
+	}
+	static next(this1,f,gather) {
+		return tink_core_Future.flatMap(this1,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return f(d);
+			case 1:
+				let f1 = o.failure;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(f1)));
+			}
+		});
+	}
+	static swap(this1,v) {
+		return tink_core_Promise.next(this1,function(_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(v)));
+		});
+	}
+	static swapError(this1,e) {
+		return tink_core_Promise.mapError(this1,function(_) {
+			return e;
+		});
+	}
+	static merge(this1,other,merger,gather) {
+		return tink_core_Future.flatMap(tink_core_Future.merge(this1,other,function(a,b) {
+			switch(a._hx_index) {
+			case 0:
+				let _g = a.data;
+				switch(b._hx_index) {
+				case 0:
+					let b1 = b.data;
+					let a1 = _g;
+					return merger(a1,b1);
+				case 1:
+					let e = b.failure;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+				}
+				break;
+			case 1:
+				let e1 = a.failure;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e1)));
+			}
+		}),function(o) {
+			return o;
+		});
+	}
+	static irreversible(f) {
+		let f1 = function(res,rej) {
+			f(res,rej);
+			return null;
+		};
+		return new tink_core__$Future_SuspendableFuture(function(cb) {
+			return f1(function(v) {
+				cb(tink_core_Outcome.Success(v));
+			},function(e) {
+				cb(tink_core_Outcome.Failure(e));
+			});
+		});
+	}
+	static and(a,b) {
+		return tink_core_Promise.merge(a,b,function(a,b) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_core_MPair(a,b))));
+		});
+	}
+	static iterate(promises,$yield,fallback,fallThroughOnError) {
+		if(fallThroughOnError == null) {
+			fallThroughOnError = false;
+		}
+		return tink_core_Future.irreversible(function(cb) {
+			let iter = $getIterator(promises);
+			let next = null;
+			next = function() {
+				if(iter.hasNext()) {
+					iter.next().handle(function(o) {
+						switch(o._hx_index) {
+						case 0:
+							let v = o.data;
+							$yield(v).handle(function(o) {
+								switch(o._hx_index) {
+								case 0:
+									let _g = o.data;
+									switch(_g._hx_index) {
+									case 0:
+										let ret = _g.v;
+										cb(tink_core_Outcome.Success(ret));
+										break;
+									case 1:
+										next();
+										break;
+									}
+									break;
+								case 1:
+									let e = o.failure;
+									cb(tink_core_Outcome.Failure(e));
+									break;
+								}
+							});
+							break;
+						case 1:
+							let e = o.failure;
+							if(fallThroughOnError) {
+								next();
+							} else {
+								cb(tink_core_Outcome.Failure(e));
+							}
+							break;
+						}
+					});
+				} else {
+					fallback.handle(cb);
+				}
+			};
+			next();
+		});
+	}
+	static retry(gen,next) {
+		let stamp = function() {
+			return HxOverrides.now() / 1000 * 1000;
+		};
+		let start = stamp();
+		let attempt = null;
+		attempt = function(count) {
+			let f = function(error) {
+				return tink_core_Promise.next(next({ attempt : count, error : error, elapsed : stamp() - start}),function(_) {
+					return attempt(count + 1);
+				});
+			};
+			return tink_core_Future.flatMap(gen(),function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let d = o.data;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(o));
+				case 1:
+					let e = o.failure;
+					return f(e);
+				}
+			});
+		};
+		return attempt(1);
+	}
+	static ofJsPromise(promise,transformError) {
+		return tink_core_Future.ofJsPromise(promise,transformError);
+	}
+	static fromJsPromise(promise) {
+		return tink_core_Future.ofJsPromise(promise);
+	}
+	static toJsPromise(this1) {
+		return new Promise(function(resolve,reject) {
+			this1.handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let v = o.data;
+					resolve(v);
+					break;
+				case 1:
+					let e = o.failure;
+					reject(e.toJsError());
+					break;
+				}
+			});
+		});
+	}
+	static ofSpecific(s) {
+		return s;
+	}
+	static fromNever(l) {
+		return l;
+	}
+	static ofTrigger(f) {
+		return f;
+	}
+	static ofHappyTrigger(f) {
+		return tink_core_Future.map(f,tink_core_Outcome.Success);
+	}
+	static ofFuture(f) {
+		return tink_core_Future.map(f,tink_core_Outcome.Success);
+	}
+	static ofOutcome(o) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(o));
+	}
+	static ofError(e) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+	}
+	static ofData(d) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(d)));
+	}
+	static asFuture(this1) {
+		return this1;
+	}
+	static lazy(p) {
+		return new tink_core__$Future_SuspendableFuture(function(cb) {
+			return tink_core_Lazy.get(p).handle(cb);
+		});
+	}
+	static inParallel(a,concurrency) {
+		return tink_core_Promise.many(a,concurrency);
+	}
+	static many(a,concurrency) {
+		return tink_core_Future.processMany(a,concurrency,function(o) {
+			return o;
+		},function(o) {
+			return o;
+		});
+	}
+	static inSequence(a) {
+		return tink_core_Promise.many(a,1);
+	}
+	static cache(gen) {
+		let p = null;
+		return function() {
+			let ret = p;
+			if(ret == null) {
+				let sync = false;
+				ret = tink_core_Promise.next(gen(),function(o) {
+					o.b.handle(function(_) {
+						sync = true;
+						p = null;
+					});
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(o.a)));
+				});
+				if(!sync) {
+					p = ret;
+				}
+			}
+			return tink_core_Future.map(ret,function(o) {
+				if(!tink_core_OutcomeTools.isSuccess(o)) {
+					p = null;
+				}
+				return o;
+			});
+		};
+	}
+	static lift(p) {
+		return p;
+	}
+	static trigger() {
+		return new tink_core_FutureTrigger();
+	}
+	static resolve(v) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(v)));
+	}
+	static reject(e) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+	}
+}
+class tink_core_Next {
+	static ofSafe(f) {
+		return function(x) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(x)));
+		};
+	}
+	static ofSync(f) {
+		return function(x) {
+			return tink_core_Future.map(f(x),tink_core_Outcome.Success);
+		};
+	}
+	static ofSafeSync(f) {
+		return function(x) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(f(x))));
+		};
+	}
+	static _chain(a,b) {
+		return function(v) {
+			return tink_core_Promise.next(a(v),b);
+		};
+	}
+}
+class tink_core_Recover {
+	static ofSync(f) {
+		return function(e) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(e)));
+		};
+	}
+}
+class tink_core_Combiner {
+	static ofSync(f) {
+		return function(x1,x2) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(x1,x2)));
+		};
+	}
+	static ofSafe(f) {
+		return function(x1,x2) {
+			return tink_core_Future.map(f(x1,x2),tink_core_Outcome.Success);
+		};
+	}
+	static ofSafeSync(f) {
+		return function(x1,x2) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(f(x1,x2))));
+		};
+	}
+}
+class tink_core_PromiseTrigger {
+	static _new() {
+		return new tink_core_FutureTrigger();
+	}
+	static resolve(this1,v) {
+		return this1.trigger(tink_core_Outcome.Success(v));
+	}
+	static reject(this1,e) {
+		return this1.trigger(tink_core_Outcome.Failure(e));
+	}
+	static asPromise(this1) {
+		return this1;
+	}
+}
+class tink_core_Ref {
+	static _new() {
+		return new Array(1);
+	}
+	static get_value(this1) {
+		return this1[0];
+	}
+	static set_value(this1,param) {
+		return this1[0] = param;
+	}
+	static toString(this1) {
+		return "@[" + Std.string(this1[0]) + "]";
+	}
+	static to(v) {
+		let ret = new Array(1);
+		ret[0] = v;
+		return ret;
+	}
+}
+class tink_core_Gather {
+	static _new(v) {
+		return v;
+	}
+	static ofBool(b) {
+		return b;
+	}
+}
+class tink_core_Signal {
+	static _new(f,init) {
+		return new tink_core__$Signal_Suspendable(f,init);
+	}
+	static handle(this1,handler) {
+		return this1.listen(handler);
+	}
+	static map(this1,f,gather) {
+		return tink_core__$Signal_Suspendable.over(this1,function(fire) {
+			return this1.listen(function(v) {
+				fire(f(v));
+			});
+		});
+	}
+	static flatMap(this1,f,gather) {
+		return tink_core__$Signal_Suspendable.over(this1,function(fire) {
+			return this1.listen(function(v) {
+				f(v).handle(fire);
+			});
+		});
+	}
+	static filter(this1,f,gather) {
+		return tink_core__$Signal_Suspendable.over(this1,function(fire) {
+			return this1.listen(function(v) {
+				if(f(v)) {
+					fire(v);
+				}
+			});
+		});
+	}
+	static select(this1,selector,gather) {
+		return tink_core__$Signal_Suspendable.over(this1,function(fire) {
+			return this1.listen(function(v) {
+				let _g = selector(v);
+				if(_g._hx_index == 0) {
+					let v = _g.v;
+					fire(v);
+				}
+			});
+		});
+	}
+	static join(this1,that,gather) {
+		if(this1.get_disposed()) {
+			return that;
+		} else if(that.get_disposed()) {
+			return this1;
+		} else {
+			return new tink_core__$Signal_Suspendable(function(fire) {
+				let cb = fire;
+				return new tink_core__$Callback_LinkPair(this1.listen(cb),that.listen(cb));
+			},function(self) {
+				let release = function() {
+					if(this1.get_disposed() && that.get_disposed()) {
+						self.dispose();
+					}
+				};
+				this1.ondispose(release);
+				that.ondispose(release);
+			});
+		}
+	}
+	static nextTime(this1,condition) {
+		return tink_core_Signal.pickNext(this1,function(v) {
+			if(condition == null || condition(v)) {
+				return haxe_ds_Option.Some(v);
+			} else {
+				return haxe_ds_Option.None;
+			}
+		});
+	}
+	static pickNext(this1,selector) {
+		let ret = new tink_core_FutureTrigger();
+		let link = null;
+		link = this1.listen(function(v) {
+			let _g = selector(v);
+			switch(_g._hx_index) {
+			case 0:
+				let v1 = _g.v;
+				ret.trigger(v1);
+				break;
+			case 1:
+				break;
+			}
+		});
+		ret.handle(link == null ? tink_core_CallbackLink.noop : ($_=link,$bind($_,$_.cancel)));
+		return ret;
+	}
+	static until(this1,end) {
+		return new tink_core__$Signal_Suspendable(function($yield) {
+			return this1.listen($yield);
+		},function(self) {
+			end.handle($bind(self,self.dispose));
+		});
+	}
+	static next(this1,condition) {
+		return tink_core_Signal.nextTime(this1,condition);
+	}
+	static noise(this1) {
+		return tink_core_Signal.map(this1,function(_) {
+			return null;
+		});
+	}
+	static gather(this1) {
+		return this1;
+	}
+	static create(f) {
+		return new tink_core__$Signal_Suspendable(f,null);
+	}
+	static generate(generator,init) {
+		return new tink_core__$Signal_Suspendable(function(fire) {
+			generator(fire);
+			return null;
+		},init);
+	}
+	static trigger() {
+		return new tink_core_SignalTrigger();
+	}
+	static ofClassical(add,remove,gather) {
+		return new tink_core__$Signal_Suspendable(function(fire) {
+			add(fire);
+			let _g = remove;
+			let a1 = fire;
+			return new tink_core_SimpleLink(function() {
+				_g(a1);
+			});
+		});
+	}
+	static dead() {
+		return tink_core__$Signal_Disposed.INST;
+	}
+}
+class tink_core__$Signal_SignalObject {
+}
+tink_core__$Signal_SignalObject.__name__ = "tink.core._Signal.SignalObject";
+tink_core__$Signal_SignalObject.__isInterface__ = true;
+tink_core__$Signal_SignalObject.__interfaces__ = [tink_core_Disposable];
+Object.assign(tink_core__$Signal_SignalObject.prototype, {
+	__class__: tink_core__$Signal_SignalObject
+});
+class tink_core__$Signal_Disposed extends tink_core_AlreadyDisposed {
+	constructor() {
+		super();
+	}
+	listen(cb) {
+		return null;
+	}
+}
+tink_core__$Signal_Disposed.__name__ = "tink.core._Signal.Disposed";
+tink_core__$Signal_Disposed.__interfaces__ = [tink_core__$Signal_SignalObject];
+tink_core__$Signal_Disposed.__super__ = tink_core_AlreadyDisposed;
+Object.assign(tink_core__$Signal_Disposed.prototype, {
+	__class__: tink_core__$Signal_Disposed
+});
+class tink_core__$Signal_Suspendable {
+	constructor(activate,init) {
+		this.handlers = new tink_core_CallbackList();
+		this.activate = activate;
+		this.init = init;
+		let _gthis = this;
+		this.handlers.ondrain = function() {
+			let this1 = _gthis.subscription;
+			if(this1 != null) {
+				this1.cancel();
+			}
+		};
+		this.handlers.onfill = function() {
+			if(init != null) {
+				let f = init;
+				init = null;
+				f(_gthis);
+			}
+			_gthis.subscription = activate(($_=_gthis.handlers,$bind($_,$_.invoke)));
+		};
+	}
+	get_disposed() {
+		return this.handlers.disposeHandlers == null;
+	}
+	dispose() {
+		this.handlers.dispose();
+	}
+	ondispose(handler) {
+		this.handlers.ondispose(handler);
+	}
+	listen(cb) {
+		let _this = this.handlers;
+		if(_this.disposeHandlers == null) {
+			return null;
+		} else {
+			let node = new tink_core__$Callback_ListCell(cb,_this);
+			_this.cells.push(node);
+			if(_this.used++ == 0) {
+				let fn = _this.onfill;
+				if(tink_core_Callback.depth < 500) {
+					tink_core_Callback.depth++;
+					fn();
+					tink_core_Callback.depth--;
+				} else {
+					tink_core_Callback.defer(fn);
+				}
+			}
+			return node;
+		}
+	}
+	static over(s,activate) {
+		if(s.get_disposed()) {
+			return tink_core_Signal.dead();
+		} else {
+			let ret = new tink_core__$Signal_Suspendable(activate);
+			s.ondispose($bind(ret,ret.dispose));
+			return ret;
+		}
+	}
+}
+tink_core__$Signal_Suspendable.__name__ = "tink.core._Signal.Suspendable";
+tink_core__$Signal_Suspendable.__interfaces__ = [tink_core_OwnedDisposable,tink_core__$Signal_SignalObject];
+Object.assign(tink_core__$Signal_Suspendable.prototype, {
+	__class__: tink_core__$Signal_Suspendable
+});
+class tink_core_SignalTrigger {
+	constructor() {
+		this.handlers = new tink_core_CallbackList();
+	}
+	get_disposed() {
+		return this.handlers.disposeHandlers == null;
+	}
+	dispose() {
+		this.handlers.dispose();
+	}
+	ondispose(d) {
+		this.handlers.ondispose(d);
+	}
+	trigger(event) {
+		this.handlers.invoke(event);
+	}
+	getLength() {
+		return this.handlers.used;
+	}
+	listen(cb) {
+		let _this = this.handlers;
+		if(_this.disposeHandlers == null) {
+			return null;
+		} else {
+			let node = new tink_core__$Callback_ListCell(cb,_this);
+			_this.cells.push(node);
+			if(_this.used++ == 0) {
+				let fn = _this.onfill;
+				if(tink_core_Callback.depth < 500) {
+					tink_core_Callback.depth++;
+					fn();
+					tink_core_Callback.depth--;
+				} else {
+					tink_core_Callback.defer(fn);
+				}
+			}
+			return node;
+		}
+	}
+	clear() {
+		this.handlers.clear();
+	}
+	asSignal() {
+		return this;
+	}
+}
+tink_core_SignalTrigger.__name__ = "tink.core.SignalTrigger";
+tink_core_SignalTrigger.__interfaces__ = [tink_core_OwnedDisposable,tink_core__$Signal_SignalObject];
+Object.assign(tink_core_SignalTrigger.prototype, {
+	__class__: tink_core_SignalTrigger
+});
+class tink_http_Chunked {
+	static encoder() {
+		if(tink_http_Chunked._encoder == null) {
+			tink_http_Chunked._encoder = new tink_http_ChunkedEncoder();
+		}
+		return tink_http_Chunked._encoder;
+	}
+	static decoder() {
+		if(tink_http_Chunked._decoder == null) {
+			tink_http_Chunked._decoder = new tink_http_ChunkedDecoder();
+		}
+		return tink_http_Chunked._decoder;
+	}
+	static encode(source) {
+		return tink_http_Chunked.encoder().transform(source);
+	}
+	static decode(source) {
+		return tink_http_Chunked.decoder().transform(source);
+	}
+}
+tink_http_Chunked.__name__ = "tink.http.Chunked";
+class tink_io_Transformer {
+}
+tink_io_Transformer.__name__ = "tink.io.Transformer";
+tink_io_Transformer.__isInterface__ = true;
+Object.assign(tink_io_Transformer.prototype, {
+	__class__: tink_io_Transformer
+});
+class tink_http_ChunkedEncoder {
+	constructor() {
+	}
+	transform(source) {
+		return tink_io_Source.chunked(source).map(tink_streams_Mapping.ofPlain(function(chunk) {
+			return tink_Chunk.concat(tink_Chunk.concat(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString("" + StringTools.hex(chunk.getLength()) + "\r\n")),chunk),tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString("\r\n")));
+		})).append(tink_streams_Stream.ofIterator(new haxe_iterators_ArrayIterator([tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString("0\r\n"))])));
+	}
+}
+tink_http_ChunkedEncoder.__name__ = "tink.http.ChunkedEncoder";
+tink_http_ChunkedEncoder.__interfaces__ = [tink_io_Transformer];
+Object.assign(tink_http_ChunkedEncoder.prototype, {
+	__class__: tink_http_ChunkedEncoder
+});
+class tink_http_ChunkedDecoder {
+	constructor() {
+	}
+	transform(source) {
+		return tink_io_RealSourceTools.parseStream(source,new tink_http_ChunkedParser()).map(tink_streams_Mapping.ofPlain(function(v) {
+			if(tink_Chunk.reqString(v,null.toString())) {
+				return tink_Chunk.EMPTY;
+			} else {
+				return v;
+			}
+		}));
+	}
+}
+tink_http_ChunkedDecoder.__name__ = "tink.http.ChunkedDecoder";
+tink_http_ChunkedDecoder.__interfaces__ = [tink_io_Transformer];
+Object.assign(tink_http_ChunkedDecoder.prototype, {
+	__class__: tink_http_ChunkedDecoder
+});
+class tink_io_StreamParserObject {
+}
+tink_io_StreamParserObject.__name__ = "tink.io.StreamParserObject";
+tink_io_StreamParserObject.__isInterface__ = true;
+Object.assign(tink_io_StreamParserObject.prototype, {
+	__class__: tink_io_StreamParserObject
+});
+class tink_http_ChunkedParser {
+	constructor() {
+		this.reset();
+	}
+	reset() {
+		this.chunkSize = -1;
+	}
+	progress(cursor) {
+		if(this.chunkSize < 0) {
+			let _g = cursor.seek(tink_http_ChunkedParser.LINEBREAK);
+			switch(_g._hx_index) {
+			case 0:
+				let v = _g.v;
+				this.chunkSize = Std.parseInt("0x" + (v == null ? "null" : v.toString()));
+				break;
+			case 1:
+				break;
+			}
+			return tink_io_ParseStep.Progressed;
+		} else if(this.chunkSize == 0) {
+			return tink_io_ParseStep.Progressed;
+		} else if(cursor.length >= this.chunkSize + 2) {
+			let _g = cursor.seek(tink_http_ChunkedParser.LINEBREAK);
+			switch(_g._hx_index) {
+			case 0:
+				let v = _g.v;
+				this.reset();
+				return tink_io_ParseStep.Done(v);
+			case 1:
+				return tink_io_ParseStep.Failed(new tink_core_TypedError(null,"Invalid encoding",{ fileName : "tink/http/Chunked.hx", lineNumber : 82, className : "tink.http.ChunkedParser", methodName : "progress"}));
+			}
+		} else {
+			return tink_io_ParseStep.Progressed;
+		}
+	}
+	eof(rest) {
+		if(this.chunkSize == 0) {
+			return tink_core_Outcome.Success(tink_Chunk.EMPTY);
+		} else {
+			return tink_core_Outcome.Failure(new tink_core_TypedError(null,"Unexpected end of input",{ fileName : "tink/http/Chunked.hx", lineNumber : 89, className : "tink.http.ChunkedParser", methodName : "eof"}));
+		}
+	}
+}
+tink_http_ChunkedParser.__name__ = "tink.http.ChunkedParser";
+tink_http_ChunkedParser.__interfaces__ = [tink_io_StreamParserObject];
+Object.assign(tink_http_ChunkedParser.prototype, {
+	__class__: tink_http_ChunkedParser
+});
+class tink_http_Client {
+	static fetch(url,options) {
+		return tink_http_Fetch.fetch(url,options);
+	}
+	static augment(this1,pipeline) {
+		return tink_http__$Client_CustomClient.create(this1,pipeline.before,pipeline.after);
+	}
+}
+class tink_http_ClientObject {
+}
+tink_http_ClientObject.__name__ = "tink.http.ClientObject";
+tink_http_ClientObject.__isInterface__ = true;
+Object.assign(tink_http_ClientObject.prototype, {
+	__class__: tink_http_ClientObject
+});
+class tink_http__$Client_CustomClient {
+	constructor(preprocessors,postprocessors,real) {
+		this.preprocessors = preprocessors;
+		this.postprocessors = postprocessors;
+		this.real = real;
+	}
+	pipe(value,transforms,index) {
+		if(index == null) {
+			index = 0;
+		}
+		if(transforms != null && index < transforms.length) {
+			let _g = this;
+			let transforms1 = transforms;
+			let index1 = index + 1;
+			let tmp = function(value) {
+				return _g.pipe(value,transforms1,index1);
+			};
+			return tink_core_Promise.next(transforms[index](value),tmp);
+		} else {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(value)));
+		}
+	}
+	request(req) {
+		let _gthis = this;
+		return tink_core_Promise.next(this.pipe(req,this.preprocessors),function(req) {
+			let tmp = _gthis.real.request(req);
+			let _g = _gthis;
+			let transforms;
+			if(_gthis.postprocessors == null) {
+				transforms = null;
+			} else {
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = _gthis.postprocessors;
+				while(_g1 < _g2.length) {
+					let p = _g2[_g1];
+					++_g1;
+					_g.push(p(req));
+				}
+				transforms = _g;
+			}
+			return tink_core_Promise.next(tmp,function(value) {
+				return _g.pipe(value,transforms);
+			});
+		});
+	}
+	static concat(a,b) {
+		if(a == null) {
+			let v = b;
+			return v;
+		} else if(b == null) {
+			let v = a;
+			return v;
+		} else {
+			return a.concat(b);
+		}
+	}
+	static create(c,preprocessors,postprocessors) {
+		let _g = ((c) instanceof tink_http__$Client_CustomClient) ? c : null;
+		if(_g == null) {
+			return new tink_http__$Client_CustomClient(preprocessors,postprocessors,c);
+		} else {
+			let v = _g;
+			return new tink_http__$Client_CustomClient(tink_http__$Client_CustomClient.concat(preprocessors,v.preprocessors),tink_http__$Client_CustomClient.concat(v.postprocessors,postprocessors),v.real);
+		}
+	}
+}
+tink_http__$Client_CustomClient.__name__ = "tink.http._Client.CustomClient";
+tink_http__$Client_CustomClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http__$Client_CustomClient.prototype, {
+	__class__: tink_http__$Client_CustomClient
+});
+class tink_http_Container {
+}
+tink_http_Container.__name__ = "tink.http.Container";
+tink_http_Container.__isInterface__ = true;
+Object.assign(tink_http_Container.prototype, {
+	__class__: tink_http_Container
+});
+var tink_http_ContainerResult = $hxEnums["tink.http.ContainerResult"] = { __ename__:true,__constructs__:null
+	,Running: ($_=function(running) { return {_hx_index:0,running:running,__enum__:"tink.http.ContainerResult",toString:$estr}; },$_._hx_name="Running",$_.__params__ = ["running"],$_)
+	,Failed: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.http.ContainerResult",toString:$estr}; },$_._hx_name="Failed",$_.__params__ = ["e"],$_)
+	,Shutdown: {_hx_name:"Shutdown",_hx_index:2,__enum__:"tink.http.ContainerResult",toString:$estr}
+};
+tink_http_ContainerResult.__constructs__ = [tink_http_ContainerResult.Running,tink_http_ContainerResult.Failed,tink_http_ContainerResult.Shutdown];
+class tink_http_Fetch {
+	static fetch(url,options) {
+		return tink_core_Future.async(function(cb) {
+			let uri = url.path;
+			if(url.query != null) {
+				uri += "?" + (url.query == null ? "null" : url.query);
+			}
+			let method = "GET";
+			let headers = null;
+			let body = tink_io_Source.EMPTY;
+			let type = tink_http_ClientType.Default;
+			let followRedirect = true;
+			if(options != null) {
+				if(options.method != null) {
+					method = options.method;
+				}
+				if(options.headers != null) {
+					headers = options.headers;
+				}
+				if(options.body != null) {
+					body = options.body;
+				}
+				if(options.client != null) {
+					type = options.client;
+				}
+				if(options.followRedirect == false) {
+					followRedirect = false;
+				}
+			}
+			let client = tink_http_Fetch.getClient(type);
+			if(options != null && options.augment != null) {
+				let pipeline = options.augment;
+				client = tink_http__$Client_CustomClient.create(client,pipeline.before,pipeline.after);
+			}
+			client.request(new tink_http_OutgoingRequest(new tink_http_OutgoingRequestHeader(method,url,null,headers),body)).handle(function(res) {
+				switch(res._hx_index) {
+				case 0:
+					let res1 = res.data;
+					let _g = res1.header.statusCode;
+					switch(_g) {
+					case 301:case 302:case 303:case 307:case 308:
+						let code = _g;
+						if(followRedirect) {
+							tink_core_Promise.next(new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(res1.header.byName("location".toLowerCase()))),function(location) {
+								let this1 = tink_Url.resolve(url,tink_Url.fromString(location));
+								let this2;
+								if(code == 303) {
+									let __o0 = options;
+									let __tink_tmp0 = { method : "GET"};
+									let _g = __o0.headers;
+									if(_g != null) {
+										let v = _g;
+										__tink_tmp0.headers = v;
+									}
+									let _g1 = __o0.followRedirect;
+									if(_g1 != null) {
+										let v = _g1;
+										__tink_tmp0.followRedirect = v;
+									}
+									let _g2 = __o0.client;
+									if(_g2 != null) {
+										let v = _g2;
+										__tink_tmp0.client = v;
+									}
+									let _g3 = __o0.body;
+									if(_g3 != null) {
+										let v = _g3;
+										__tink_tmp0.body = v;
+									}
+									let _g4 = __o0.augment;
+									if(_g4 != null) {
+										let v = _g4;
+										__tink_tmp0.augment = v;
+									}
+									this2 = __tink_tmp0;
+								} else {
+									this2 = options;
+								}
+								return tink_http_Fetch.fetch(this1,this2);
+							}).handle(cb);
+						} else {
+							cb(tink_core_Outcome.Success(res1));
+						}
+						break;
+					default:
+						cb(tink_core_Outcome.Success(res1));
+					}
+					break;
+				case 1:
+					let e = res.failure;
+					cb(tink_core_Outcome.Failure(e));
+					break;
+				}
+			});
+		});
+	}
+	static getClient(type) {
+		if(!tink_http_Fetch.cache.exists(type)) {
+			let c;
+			switch(type._hx_index) {
+			case 0:
+				c = new tink_http_clients_JsClient();
+				break;
+			case 1:
+				let c1 = type.container;
+				c = new tink_http_clients_LocalContainerClient(c1);
+				break;
+			case 2:
+				c = new tink_http_clients_StdClient();
+				break;
+			case 3:
+				let c2 = type.v;
+				c = c2;
+				break;
+			}
+			tink_http_Fetch.cache.set(type,c);
+		}
+		return tink_http_Fetch.cache.get(type);
+	}
+}
+tink_http_Fetch.__name__ = "tink.http.Fetch";
+var tink_http_ClientType = $hxEnums["tink.http.ClientType"] = { __ename__:true,__constructs__:null
+	,Default: {_hx_name:"Default",_hx_index:0,__enum__:"tink.http.ClientType",toString:$estr}
+	,Local: ($_=function(container) { return {_hx_index:1,container:container,__enum__:"tink.http.ClientType",toString:$estr}; },$_._hx_name="Local",$_.__params__ = ["container"],$_)
+	,StdLib: {_hx_name:"StdLib",_hx_index:2,__enum__:"tink.http.ClientType",toString:$estr}
+	,Custom: ($_=function(v) { return {_hx_index:3,v:v,__enum__:"tink.http.ClientType",toString:$estr}; },$_._hx_name="Custom",$_.__params__ = ["v"],$_)
+};
+tink_http_ClientType.__constructs__ = [tink_http_ClientType.Default,tink_http_ClientType.Local,tink_http_ClientType.StdLib,tink_http_ClientType.Custom];
+class tink_http_FetchResponse {
+	static all(this1) {
+		return tink_core_Promise.next(this1,function(r) {
+			return tink_core_Promise.next(tink_io_RealSourceTools.all(r.body),function(chunk) {
+				if(r.header.statusCode >= 400) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(tink_core_TypedError.withData(r.header.statusCode,r.header.reason,chunk.toString(),{ fileName : "tink/http/Fetch.hx", lineNumber : 125, className : "tink.http._Fetch.FetchResponse_Impl_", methodName : "all"}))));
+				} else {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_Message(r.header,chunk))));
+				}
+			});
+		});
+	}
+	static progress(this1) {
+		return tink_core_Promise.next(this1,function(r) {
+			if(r.header.statusCode >= 400) {
+				return tink_core_Promise.next(tink_io_RealSourceTools.all(r.body),function(chunk) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(tink_core_TypedError.withData(r.header.statusCode,r.header.reason,chunk.toString(),{ fileName : "tink/http/Fetch.hx", lineNumber : 137, className : "tink.http._Fetch.FetchResponse_Impl_", methodName : "progress"}))));
+				});
+			} else {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_Message(r.header,tink_core_Progress.make(function(progress,finish) {
+					let total;
+					let _g = r.header.getContentLength();
+					switch(_g._hx_index) {
+					case 0:
+						let len = _g.data;
+						total = haxe_ds_Option.Some(len);
+						break;
+					case 1:
+						let _g1 = _g.failure;
+						total = haxe_ds_Option.None;
+						break;
+					}
+					let chunk = tink_Chunk.EMPTY;
+					progress(chunk.getLength(),total);
+					return tink_io_Source.chunked(r.body).forEach(tink_streams_Handler.ofSafeSync(function(part) {
+						chunk = tink_Chunk.concat(chunk,part);
+						progress(chunk.getLength(),total);
+						return tink_streams_Handled.Resume;
+					})).handle(function(o) {
+						switch(o._hx_index) {
+						case 0:
+							let _g = o.rest;
+							finish(tink_core_Outcome.Failure(new tink_core_TypedError(null,"unreachable",{ fileName : "tink/http/Fetch.hx", lineNumber : 157, className : "tink.http._Fetch.FetchResponse_Impl_", methodName : "progress"})));
+							break;
+						case 2:
+							let e = o.error;
+							finish(tink_core_Outcome.Failure(e));
+							break;
+						case 3:
+							finish(tink_core_Outcome.Success(chunk));
+							break;
+						}
+					});
+				})))));
+			}
+		});
+	}
+}
+class tink_http_Handler {
+	static ofFunc(f) {
+		return new tink_http_SimpleHandler(f);
+	}
+}
+class tink_http_HandlerObject {
+}
+tink_http_HandlerObject.__name__ = "tink.http.HandlerObject";
+tink_http_HandlerObject.__isInterface__ = true;
+Object.assign(tink_http_HandlerObject.prototype, {
+	__class__: tink_http_HandlerObject
+});
+class tink_http_SimpleHandler {
+	constructor(f) {
+		this.f = f;
+	}
+	process(req) {
+		return this.f(req);
+	}
+}
+tink_http_SimpleHandler.__name__ = "tink.http.SimpleHandler";
+tink_http_SimpleHandler.__interfaces__ = [tink_http_HandlerObject];
+Object.assign(tink_http_SimpleHandler.prototype, {
+	__class__: tink_http_SimpleHandler
+});
+class tink_http_ReadonlyMap {
+	static get(this1,key) {
+		return this1.get(key);
+	}
+	static exists(this1,key) {
+		return this1.exists(key);
+	}
+	static iterator(this1) {
+		return this1.iterator();
+	}
+	static keys(this1) {
+		return this1.keys();
+	}
+}
+class tink_http_ContentType {
+	constructor() {
+		this.subtype = "*";
+		this.type = "*";
+		this.extensions = new haxe_ds_StringMap();
+	}
+	get_fullType() {
+		return "" + this.type + "/" + this.subtype;
+	}
+	toString() {
+		return this.raw;
+	}
+	static ofString(s) {
+		let ret = new tink_http_ContentType();
+		ret.raw = s;
+		let parsed = tink_http_HeaderValue.parse(s);
+		let value = parsed[0].value;
+		let _g = value.indexOf("/");
+		if(_g == -1) {
+			ret.type = value;
+		} else {
+			let pos = _g;
+			ret.type = value.substring(0,pos);
+			ret.subtype = value.substring(pos + 1);
+		}
+		ret.extensions = parsed[0].extensions;
+		return ret;
+	}
+}
+tink_http_ContentType.__name__ = "tink.http.ContentType";
+Object.assign(tink_http_ContentType.prototype, {
+	__class__: tink_http_ContentType
+});
+class tink_http_Header {
+	constructor(fields) {
+		if(tink_http_Header._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(fields);
+	}
+	_hx_constructor(fields) {
+		let tmp;
+		if(fields == null) {
+			tmp = [];
+		} else {
+			let v = fields;
+			tmp = v;
+		}
+		this.fields = tmp;
+	}
+	get(name) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.fields;
+		while(_g1 < _g2.length) {
+			let f = _g2[_g1];
+			++_g1;
+			if(f.name == name) {
+				_g.push(f.value);
+			}
+		}
+		return _g;
+	}
+	byName(name) {
+		let _g = this.get(name);
+		switch(_g.length) {
+		case 0:
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"No " + name + " header found",{ fileName : "tink/http/Header.hx", lineNumber : 91, className : "tink.http.Header", methodName : "byName"}));
+		case 1:
+			let v = _g[0];
+			return tink_core_Outcome.Success(v);
+		default:
+			let v1 = _g;
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Multiple entries for " + name + " header",{ fileName : "tink/http/Header.hx", lineNumber : 95, className : "tink.http.Header", methodName : "byName"}));
+		}
+	}
+	contentType() {
+		return tink_core_OutcomeTools.map(this.byName("content-type"),tink_http_ContentType.ofString);
+	}
+	iterator() {
+		return new haxe_iterators_ArrayIterator(this.fields);
+	}
+	concat(fields) {
+		return new tink_http_Header(this.fields.concat(fields));
+	}
+	getContentLength() {
+		let _g = this.byName("content-length");
+		switch(_g._hx_index) {
+		case 0:
+			let _hx_tmp = Std.parseInt(_g.data);
+			if(_hx_tmp == null) {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Invalid Content-Length Header",{ fileName : "tink/http/Header.hx", lineNumber : 120, className : "tink.http.Header", methodName : "getContentLength"}));
+			} else {
+				let v = _hx_tmp;
+				return tink_core_Outcome.Success(v);
+			}
+			break;
+		case 1:
+			let e = _g.failure;
+			return tink_core_Outcome.Failure(e);
+		}
+	}
+	accepts(type) {
+		let prefix = type.split("/")[0];
+		return tink_core_OutcomeTools.map(this.byName("accept"),function(v) {
+			let _g = 0;
+			let _g1 = tink_http_HeaderValue.parse(v);
+			while(_g < _g1.length) {
+				let entry = _g1[_g];
+				++_g;
+				if(entry.value == "*/*" || entry.value == type) {
+					return true;
+				}
+				let _g2 = entry.value.split("/");
+				if(_g2.length == 2) {
+					if(_g2[1] == "*") {
+						let p = _g2[0];
+						if(prefix == p) {
+							return true;
+						}
+					}
+				}
+			}
+			return false;
+		});
+	}
+	get_LINEBREAK() {
+		return "\r\n";
+	}
+	toString() {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.fields;
+		while(_g1 < _g2.length) {
+			let f = _g2[_g1];
+			++_g1;
+			_g.push(f.toString());
+		}
+		return _g.join("\r\n") + "\r\n" + "\r\n";
+	}
+	headerNotFound(name) {
+		return "No " + name + " header found";
+	}
+}
+tink_http_Header.__name__ = "tink.http.Header";
+Object.assign(tink_http_Header.prototype, {
+	__class__: tink_http_Header
+});
+class tink_http_HeaderValue {
+	static getExtension(this1) {
+		return tink_http_HeaderValue.parse(this1)[0].extensions;
+	}
+	static parse(this1) {
+		return tink_http_HeaderValue.parseWith(this1,function(_,params) {
+			let _g = new haxe_ds_StringMap();
+			let p = params;
+			while(p.hasNext()) {
+				let p1 = p.next();
+				let key = p1.name;
+				let value;
+				let _g1 = tink_url_Portion.toString(p1.value);
+				let quoted = _g1;
+				if(HxOverrides.cca(quoted,0) == 34) {
+					value = HxOverrides.substr(quoted,1,quoted.length - 2);
+				} else {
+					let v = _g1;
+					value = v;
+				}
+				_g.h[key] = value;
+			}
+			return _g;
+		});
+	}
+	static parseWith(this1,parseExtension) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this1.split(",");
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			v = StringTools.trim(v);
+			let i;
+			let _g3 = v.indexOf(";");
+			if(_g3 == -1) {
+				i = v.length;
+			} else {
+				let i1 = _g3;
+				i = i1;
+			}
+			let value = HxOverrides.substr(v,0,i);
+			let sep = ";";
+			let pos = i + 1;
+			if(pos == null) {
+				pos = 0;
+			}
+			if(sep == null) {
+				sep = "&";
+			}
+			_g.push({ value : value, extensions : parseExtension(value,new tink_url__$Query_QueryStringParser(v,sep,"=",pos))});
+		}
+		return _g;
+	}
+	static basicAuth(username,password) {
+		return "Basic " + haxe_crypto_Base64.encode(haxe_io_Bytes.ofString("" + username + ":" + password)).toString();
+	}
+	static ofDate(d) {
+		return DateTools.format(d,tink_http_HeaderValue.DAYS[d.getDay()] + ", %d " + tink_http_HeaderValue.MONTHS[d.getMonth()] + " %Y %H:%M:%S GMT");
+	}
+	static ofInt(i) {
+		if(i == null) {
+			return "null";
+		} else {
+			return "" + i;
+		}
+	}
+}
+class tink_http_HeaderName {
+	static _new(s) {
+		return s;
+	}
+	static ofString(s) {
+		return s.toLowerCase();
+	}
+}
+class tink_http_HeaderField extends tink_core_NamedWith {
+	constructor(name,value) {
+		super(name,value);
+	}
+	toString() {
+		if(this.value == null) {
+			return this.name;
+		} else {
+			return "" + this.name + ": " + this.value;
+		}
+	}
+	static ofString(s) {
+		let _g = s.indexOf(":");
+		if(_g == -1) {
+			return new tink_http_HeaderField(s.toLowerCase(),null);
+		} else {
+			let v = _g;
+			return new tink_http_HeaderField(HxOverrides.substr(s,0,v).toLowerCase(),StringTools.trim(HxOverrides.substr(s,v + 1,null)));
+		}
+	}
+	static setCookie(key,value,options) {
+		if(options == null) {
+			options = { };
+		}
+		let buf_b = "";
+		buf_b += Std.string(encodeURIComponent(key) + "=" + encodeURIComponent(value));
+		if(options.expires != null) {
+			let value = tink_http_HeaderValue.ofDate(options.expires);
+			if(value != null) {
+				buf_b += "; ";
+				buf_b += "expires=";
+				buf_b += Std.string(value);
+			}
+		}
+		let value1 = options.domain;
+		if(value1 != null) {
+			buf_b += "; ";
+			buf_b += "domain=";
+			buf_b += Std.string(value1);
+		}
+		let value2 = options.path;
+		if(value2 != null) {
+			buf_b += "; ";
+			buf_b += "path=";
+			buf_b += Std.string(value2);
+		}
+		if(options.secure) {
+			buf_b += "; ";
+			buf_b += "secure";
+			buf_b += "";
+		}
+		if(options.scriptable != true) {
+			buf_b += "; ";
+			buf_b += "HttpOnly";
+			buf_b += "";
+		}
+		return new tink_http_HeaderField("set-cookie",buf_b);
+	}
+}
+tink_http_HeaderField.__name__ = "tink.http.HeaderField";
+tink_http_HeaderField.__super__ = tink_core_NamedWith;
+Object.assign(tink_http_HeaderField.prototype, {
+	__class__: tink_http_HeaderField
+});
+class tink_io_BytewiseParser {
+	read(char) {
+		throw haxe_Exception.thrown("abstract");
+	}
+	progress(cursor) {
+		do {
+			let _g = this.read(cursor.currentByte);
+			switch(_g._hx_index) {
+			case 0:
+				break;
+			case 1:
+				let r = _g.r;
+				cursor.next();
+				return tink_io_ParseStep.Done(r);
+			case 2:
+				let e = _g.e;
+				return tink_io_ParseStep.Failed(e);
+			}
+		} while(cursor.next());
+		return tink_io_ParseStep.Progressed;
+	}
+	eof(rest) {
+		let _g = this.read(-1);
+		switch(_g._hx_index) {
+		case 0:
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Unexpected end of input",{ fileName : "tink/io/StreamParser.hx", lineNumber : 180, className : "tink.io.BytewiseParser", methodName : "eof"}));
+		case 1:
+			let r = _g.r;
+			return tink_core_Outcome.Success(r);
+		case 2:
+			let e = _g.e;
+			return tink_core_Outcome.Failure(e);
+		}
+	}
+}
+tink_io_BytewiseParser.__name__ = "tink.io.BytewiseParser";
+tink_io_BytewiseParser.__interfaces__ = [tink_io_StreamParserObject];
+Object.assign(tink_io_BytewiseParser.prototype, {
+	__class__: tink_io_BytewiseParser
+});
+var tink_io_ParseStep = $hxEnums["tink.io.ParseStep"] = { __ename__:true,__constructs__:null
+	,Progressed: {_hx_name:"Progressed",_hx_index:0,__enum__:"tink.io.ParseStep",toString:$estr}
+	,Done: ($_=function(r) { return {_hx_index:1,r:r,__enum__:"tink.io.ParseStep",toString:$estr}; },$_._hx_name="Done",$_.__params__ = ["r"],$_)
+	,Failed: ($_=function(e) { return {_hx_index:2,e:e,__enum__:"tink.io.ParseStep",toString:$estr}; },$_._hx_name="Failed",$_.__params__ = ["e"],$_)
+};
+tink_io_ParseStep.__constructs__ = [tink_io_ParseStep.Progressed,tink_io_ParseStep.Done,tink_io_ParseStep.Failed];
+class tink_http_HeaderParser extends tink_io_BytewiseParser {
+	constructor(makeHeader) {
+		super();
+		this.last = -1;
+		this.buf = new StringBuf();
+		this.makeHeader = makeHeader;
+	}
+	read(c) {
+		let _g = this.last;
+		switch(c) {
+		case -1:
+			return this.nextLine();
+		case 10:
+			if(_g == 13) {
+				return this.nextLine();
+			} else {
+				let other = c;
+				this.last = other;
+				this.buf.b += String.fromCodePoint(other);
+				return tink_io_ParseStep.Progressed;
+			}
+			break;
+		case 13:
+			if(_g == 13) {
+				let c = this.last;
+				this.buf.b += String.fromCodePoint(c);
+				return tink_io_ParseStep.Progressed;
+			} else {
+				this.last = 13;
+				return tink_io_ParseStep.Progressed;
+			}
+			break;
+		default:
+			if(_g == 13) {
+				let other = c;
+				let c1 = this.last;
+				this.buf.b += String.fromCodePoint(c1);
+				this.buf.b += String.fromCodePoint(other);
+				this.last = -1;
+				return tink_io_ParseStep.Progressed;
+			} else {
+				let other = c;
+				this.last = other;
+				this.buf.b += String.fromCodePoint(other);
+				return tink_io_ParseStep.Progressed;
+			}
+		}
+	}
+	nextLine() {
+		let line = this.buf.b;
+		this.buf = new StringBuf();
+		this.last = -1;
+		if(line == "") {
+			if(this.header == null) {
+				return tink_io_ParseStep.Progressed;
+			} else {
+				return tink_io_ParseStep.Done(this.header);
+			}
+		} else if(this.header == null) {
+			let _g = this.makeHeader(line,this.fields = []);
+			switch(_g._hx_index) {
+			case 0:
+				let _g1 = _g.data;
+				if(_g1 == null) {
+					return tink_io_ParseStep.Done(this.header = null);
+				} else {
+					let v = _g1;
+					this.header = v;
+					return tink_io_ParseStep.Progressed;
+				}
+				break;
+			case 1:
+				let e = _g.failure;
+				return tink_io_ParseStep.Failed(e);
+			}
+		} else {
+			this.fields.push(tink_http_HeaderField.ofString(line));
+			return tink_io_ParseStep.Progressed;
+		}
+	}
+}
+tink_http_HeaderParser.__name__ = "tink.http.HeaderParser";
+tink_http_HeaderParser.__super__ = tink_io_BytewiseParser;
+Object.assign(tink_http_HeaderParser.prototype, {
+	__class__: tink_http_HeaderParser
+});
+class tink_http_Message {
+	constructor(header,body) {
+		if(tink_http_Message._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(header,body);
+	}
+	_hx_constructor(header,body) {
+		this.header = header;
+		this.body = body;
+	}
+}
+tink_http_Message.__name__ = "tink.http.Message";
+Object.assign(tink_http_Message.prototype, {
+	__class__: tink_http_Message
+});
+class tink_http_Method {
+	static ofString(s,fallback) {
+		let _g = s.toUpperCase();
+		switch(_g) {
+		case "DELETE":
+			return "DELETE";
+		case "GET":
+			return "GET";
+		case "HEAD":
+			return "HEAD";
+		case "OPTIONS":
+			return "OPTIONS";
+		case "PATCH":
+			return "PATCH";
+		case "POST":
+			return "POST";
+		case "PUT":
+			return "PUT";
+		default:
+			let v = _g;
+			return fallback(v);
+		}
+	}
+}
+class tink_http_RequestHeader extends tink_http_Header {
+	constructor(method,url,protocol,fields) {
+		tink_http_Header._hx_skip_constructor = true;
+		super();
+		tink_http_Header._hx_skip_constructor = false;
+		this._hx_constructor(method,url,protocol,fields);
+	}
+	_hx_constructor(method,url,protocol,fields) {
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		this.method = method;
+		this.url = url;
+		this.protocol = protocol;
+		super._hx_constructor(fields);
+	}
+	concat(fields) {
+		return new tink_http_RequestHeader(this.method,this.url,this.protocol,this.fields.concat(fields));
+	}
+	toString() {
+		let this1 = this.url;
+		return "" + this.method + " " + (this1.query == null ? this1.path : (this1.path == null ? "null" : this1.path) + "?" + (this1.query == null ? "null" : this1.query)) + " " + this.protocol + "\r\n" + super.toString();
+	}
+}
+tink_http_RequestHeader.__name__ = "tink.http.RequestHeader";
+tink_http_RequestHeader.__super__ = tink_http_Header;
+Object.assign(tink_http_RequestHeader.prototype, {
+	__class__: tink_http_RequestHeader
+});
+class tink_http_IncomingRequestHeader extends tink_http_RequestHeader {
+	constructor(method,url,protocol,fields) {
+		super(method,url,protocol,fields);
+	}
+	getCookies() {
+		if(this.cookies == null) {
+			let _g = new haxe_ds_StringMap();
+			let _g1 = 0;
+			let _g2 = this.get("cookie".toLowerCase());
+			while(_g1 < _g2.length) {
+				let header = _g2[_g1];
+				++_g1;
+				let sep = ";";
+				if(sep == null) {
+					sep = "&";
+				}
+				let entry = new tink_url__$Query_QueryStringParser(header,sep,"=",0);
+				while(entry.hasNext()) {
+					let entry1 = entry.next();
+					let key = entry1.name;
+					let value = tink_url_Portion.toString(entry1.value);
+					_g.h[key] = value;
+				}
+			}
+			this.cookies = _g;
+		}
+		return this.cookies;
+	}
+	concat(fields) {
+		return new tink_http_IncomingRequestHeader(this.method,this.url,this.protocol,this.fields.concat(fields));
+	}
+	cookieNames() {
+		return new haxe_ds__$StringMap_StringMapKeyIterator(this.cookies.h);
+	}
+	getCookie(name) {
+		return this.getCookies().h[name];
+	}
+	getAuth() {
+		return this.getAuthWith(function(s,p) {
+			switch(s) {
+			case "Basic":
+				let decoded;
+				try {
+					decoded = haxe_crypto_Base64.decode(p).toString();
+				} catch( _g ) {
+					let e = haxe_Exception.caught(_g).unwrap();
+					return tink_core_Outcome.Failure(tink_core_TypedError.withData(null,"Error in decoding basic auth",e,{ fileName : "tink/http/Request.hx", lineNumber : 67, className : "tink.http.IncomingRequestHeader", methodName : "getAuth"}));
+				}
+				let _g = decoded.indexOf(":");
+				if(_g == -1) {
+					return tink_core_Outcome.Failure(new tink_core_TypedError(null,"Cannot parse username and password because \":\" is missing",{ fileName : "tink/http/Request.hx", lineNumber : 69, className : "tink.http.IncomingRequestHeader", methodName : "getAuth"}));
+				} else {
+					let i = _g;
+					return tink_core_Outcome.Success(tink_http_Authorization.Basic(HxOverrides.substr(decoded,0,i),HxOverrides.substr(decoded,i + 1,null)));
+				}
+				break;
+			case "Bearer":
+				return tink_core_Outcome.Success(tink_http_Authorization.Bearer(p));
+			default:
+				let s1 = s;
+				return tink_core_Outcome.Success(tink_http_Authorization.Others(s1,p));
+			}
+		});
+	}
+	getAuthWith(parser) {
+		return tink_core_OutcomeTools.flatMap(this.byName("authorization"),tink_core__$Outcome_OutcomeMapper.withSameError(function(v) {
+			let _g = v.indexOf(" ");
+			if(_g == -1) {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Invalid Authorization Header",{ fileName : "tink/http/Request.hx", lineNumber : 81, className : "tink.http.IncomingRequestHeader", methodName : "getAuthWith"}));
+			} else {
+				let i = _g;
+				return parser(HxOverrides.substr(v,0,i),HxOverrides.substr(v,i + 1,null));
+			}
+		}));
+	}
+	static parser() {
+		return new tink_http_HeaderParser(function(line,headers) {
+			let _g = line.split(" ");
+			if(_g.length == 3) {
+				let method = _g[0];
+				let url = _g[1];
+				let protocol = _g[2];
+				return tink_core_Outcome.Success(new tink_http_IncomingRequestHeader(method,tink_Url.fromString(url),protocol,headers));
+			} else {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Invalid HTTP header",{ fileName : "tink/http/Request.hx", lineNumber : 95, className : "tink.http.IncomingRequestHeader", methodName : "parser"}));
+			}
+		});
+	}
+}
+tink_http_IncomingRequestHeader.__name__ = "tink.http.IncomingRequestHeader";
+tink_http_IncomingRequestHeader.__super__ = tink_http_RequestHeader;
+Object.assign(tink_http_IncomingRequestHeader.prototype, {
+	__class__: tink_http_IncomingRequestHeader
+});
+class tink_http_OutgoingRequestHeader extends tink_http_RequestHeader {
+	constructor(method,url,protocol,fields) {
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		let _g = tink_http_OutgoingRequestHeader.extractAuth(url);
+		if(_g._hx_index == 0) {
+			let v = _g.v;
+			url = v.url;
+			fields = fields.concat(v.headers);
+		}
+		super(method,url,protocol,fields);
+	}
+	concat(fields) {
+		return new tink_http_OutgoingRequestHeader(this.method,this.url,this.protocol,this.fields.concat(fields));
+	}
+	static extractAuth(url) {
+		let _g = url.auth;
+		if(_g == null) {
+			return haxe_ds_Option.None;
+		} else {
+			let v = _g;
+			let tmp = [new tink_http_HeaderField("authorization",tink_http_HeaderValue.basicAuth(v == null ? null : v.split(":")[0],v == null ? null : v.split(":")[1]))];
+			let url1 = url.scheme;
+			let _g1 = [];
+			let _g2 = 0;
+			let _g3 = url.hosts;
+			while(_g2 < _g3.length) {
+				let host = _g3[_g2];
+				++_g2;
+				_g1.push(host);
+			}
+			return haxe_ds_Option.Some({ headers : tmp, url : tink_Url.make({ scheme : url1, hosts : _g1, path : url.path, query : url.query})});
+		}
+	}
+}
+tink_http_OutgoingRequestHeader.__name__ = "tink.http.OutgoingRequestHeader";
+tink_http_OutgoingRequestHeader.__super__ = tink_http_RequestHeader;
+Object.assign(tink_http_OutgoingRequestHeader.prototype, {
+	__class__: tink_http_OutgoingRequestHeader
+});
+class tink_http_OutgoingRequest extends tink_http_Message {
+	constructor(header,body) {
+		super(header,body);
+	}
+}
+tink_http_OutgoingRequest.__name__ = "tink.http.OutgoingRequest";
+tink_http_OutgoingRequest.__super__ = tink_http_Message;
+Object.assign(tink_http_OutgoingRequest.prototype, {
+	__class__: tink_http_OutgoingRequest
+});
+class tink_http_IncomingRequest extends tink_http_Message {
+	constructor(clientIp,header,body) {
+		tink_http_Message._hx_skip_constructor = true;
+		super();
+		tink_http_Message._hx_skip_constructor = false;
+		this._hx_constructor(clientIp,header,body);
+	}
+	_hx_constructor(clientIp,header,body) {
+		this.clientIp = clientIp;
+		super._hx_constructor(header,body);
+	}
+	static parse(clientIp,source) {
+		return tink_core_Promise.next(tink_io_RealSourceTools.parse(source,tink_http_IncomingRequestHeader.parser()),function(parts) {
+			let clientIp1 = clientIp;
+			let parts1 = parts.a;
+			let _g = parts.a.getContentLength();
+			let d;
+			switch(_g._hx_index) {
+			case 0:
+				let len = _g.data;
+				d = tink_io_Source.limit(parts.b,len);
+				break;
+			case 1:
+				let _g1 = _g.failure;
+				let _g2 = parts.a.method;
+				let _g3 = parts.a.byName("transfer-encoding");
+				switch(_g2) {
+				case "GET":case "OPTIONS":
+					d = tink_io_Source.EMPTY;
+					break;
+				default:
+					if(_g3._hx_index == 0) {
+						let _this = _g3.data.split(",");
+						let f = StringTools.trim;
+						let result = new Array(_this.length);
+						let _g = 0;
+						let _g1 = _this.length;
+						while(_g < _g1) {
+							let i = _g++;
+							result[i] = f(_this[i]);
+						}
+						let encodings = result;
+						if(encodings.indexOf("chunked") != -1) {
+							let source = parts.b;
+							d = tink_http_Chunked.decoder().transform(source);
+						} else {
+							return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(new tink_core_TypedError(411,"Content-Length header missing",{ fileName : "tink/http/Request.hx", lineNumber : 171, className : "tink.http.IncomingRequest", methodName : "parse"}))));
+						}
+					} else {
+						return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(new tink_core_TypedError(411,"Content-Length header missing",{ fileName : "tink/http/Request.hx", lineNumber : 171, className : "tink.http.IncomingRequest", methodName : "parse"}))));
+					}
+				}
+				break;
+			}
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_IncomingRequest(clientIp1,parts1,tink_http_IncomingRequestBody.Plain(d)))));
+		});
+	}
+}
+tink_http_IncomingRequest.__name__ = "tink.http.IncomingRequest";
+tink_http_IncomingRequest.__super__ = tink_http_Message;
+Object.assign(tink_http_IncomingRequest.prototype, {
+	__class__: tink_http_IncomingRequest
+});
+var tink_http_IncomingRequestBody = $hxEnums["tink.http.IncomingRequestBody"] = { __ename__:true,__constructs__:null
+	,Plain: ($_=function(source) { return {_hx_index:0,source:source,__enum__:"tink.http.IncomingRequestBody",toString:$estr}; },$_._hx_name="Plain",$_.__params__ = ["source"],$_)
+	,Parsed: ($_=function(parts) { return {_hx_index:1,parts:parts,__enum__:"tink.http.IncomingRequestBody",toString:$estr}; },$_._hx_name="Parsed",$_.__params__ = ["parts"],$_)
+};
+tink_http_IncomingRequestBody.__constructs__ = [tink_http_IncomingRequestBody.Plain,tink_http_IncomingRequestBody.Parsed];
+var tink_http_Authorization = $hxEnums["tink.http.Authorization"] = { __ename__:true,__constructs__:null
+	,Basic: ($_=function(user,pass) { return {_hx_index:0,user:user,pass:pass,__enum__:"tink.http.Authorization",toString:$estr}; },$_._hx_name="Basic",$_.__params__ = ["user","pass"],$_)
+	,Bearer: ($_=function(token) { return {_hx_index:1,token:token,__enum__:"tink.http.Authorization",toString:$estr}; },$_._hx_name="Bearer",$_.__params__ = ["token"],$_)
+	,Others: ($_=function(scheme,param) { return {_hx_index:2,scheme:scheme,param:param,__enum__:"tink.http.Authorization",toString:$estr}; },$_._hx_name="Others",$_.__params__ = ["scheme","param"],$_)
+};
+tink_http_Authorization.__constructs__ = [tink_http_Authorization.Basic,tink_http_Authorization.Bearer,tink_http_Authorization.Others];
+class tink_http_ResponseHeader {
+	static _new(statusCode,reason,fields,protocol) {
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		return new tink_http_ResponseHeaderBase(statusCode,reason,fields,protocol);
+	}
+	static fromStatusCode(code) {
+		return new tink_http_ResponseHeaderBase(code,null,null,"HTTP/1.1");
+	}
+	static fromHeaderFields(fields) {
+		return new tink_http_ResponseHeaderBase(200,null,fields,"HTTP/1.1");
+	}
+	static parser() {
+		return tink_http_ResponseHeaderBase.parser();
+	}
+}
+class tink_http_ResponseHeaderBase extends tink_http_Header {
+	constructor(statusCode,reason,fields,protocol) {
+		tink_http_Header._hx_skip_constructor = true;
+		super();
+		tink_http_Header._hx_skip_constructor = false;
+		this._hx_constructor(statusCode,reason,fields,protocol);
+	}
+	_hx_constructor(statusCode,reason,fields,protocol) {
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		this.statusCode = statusCode;
+		this.reason = reason == null ? httpstatus_HttpStatusMessage.fromCode(statusCode) : reason;
+		this.protocol = protocol;
+		super._hx_constructor(fields);
+	}
+	concat(fields) {
+		let statusCode = this.statusCode;
+		let reason = this.reason;
+		let fields1 = this.fields.concat(fields);
+		let protocol = this.protocol;
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		return new tink_http_ResponseHeaderBase(statusCode,reason,fields1,protocol);
+	}
+	toString() {
+		return "" + this.protocol + " " + this.statusCode + " " + this.reason + "\r\n" + super.toString();
+	}
+	static parser() {
+		return new tink_http_HeaderParser(function(line,headers) {
+			let v = line.split(" ");
+			if(v.length >= 3) {
+				let statusCode = Std.parseInt(v[1]);
+				let reason = v.slice(2).join(" ");
+				let protocol = v[0];
+				if(protocol == null) {
+					protocol = "HTTP/1.1";
+				}
+				return tink_core_Outcome.Success(new tink_http_ResponseHeaderBase(statusCode,reason,headers,protocol));
+			} else {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Invalid HTTP response header",{ fileName : "tink/http/Response.hx", lineNumber : 56, className : "tink.http.ResponseHeaderBase", methodName : "parser"}));
+			}
+		});
+	}
+}
+tink_http_ResponseHeaderBase.__name__ = "tink.http.ResponseHeaderBase";
+tink_http_ResponseHeaderBase.__super__ = tink_http_Header;
+Object.assign(tink_http_ResponseHeaderBase.prototype, {
+	__class__: tink_http_ResponseHeaderBase
+});
+class tink_http__$Response_OutgoingResponseData extends tink_http_Message {
+	constructor(header,body) {
+		super(header,body);
+	}
+}
+tink_http__$Response_OutgoingResponseData.__name__ = "tink.http._Response.OutgoingResponseData";
+tink_http__$Response_OutgoingResponseData.__super__ = tink_http_Message;
+Object.assign(tink_http__$Response_OutgoingResponseData.prototype, {
+	__class__: tink_http__$Response_OutgoingResponseData
+});
+class tink_http_OutgoingResponse {
+	static _new(header,body) {
+		return new tink_http__$Response_OutgoingResponseData(header,body);
+	}
+	static blob(code,chunk,contentType,headers) {
+		if(code == null) {
+			code = 200;
+		}
+		let this1 = httpstatus_HttpStatusMessage.fromCode(code);
+		let fields = new tink_http_HeaderField("Content-Type".toLowerCase(),contentType);
+		let this2 = "Content-Length".toLowerCase();
+		let fields1 = Std.string(chunk.getLength());
+		let fields2;
+		if(headers == null) {
+			fields2 = [];
+		} else {
+			let v = headers;
+			fields2 = v;
+		}
+		return new tink_http__$Response_OutgoingResponseData(new tink_http_ResponseHeaderBase(code,this1,[fields,new tink_http_HeaderField(this2,fields1)].concat(fields2),"HTTP/1.1"),new tink_streams_Single(new tink_core__$Lazy_LazyConst(chunk)));
+	}
+	static chunked(contentType,headers,source) {
+	}
+	static ofString(s) {
+		return tink_http_OutgoingResponse.blob(null,tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(s)),"text/plain");
+	}
+	static ofChunk(c) {
+		return tink_http_OutgoingResponse.blob(null,c,"application/octet-stream");
+	}
+	static reportError(e) {
+		let code = e.code;
+		if(code < 100 || code > 999) {
+			code = 500;
+		}
+		return new tink_http__$Response_OutgoingResponseData(new tink_http_ResponseHeaderBase(code,httpstatus_HttpStatusMessage.fromCode(code),[new tink_http_HeaderField("Content-Type".toLowerCase(),"application/json")],"HTTP/1.1"),new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(JSON.stringify({ error : e.message, details : e.data}))))));
+	}
+}
+class tink_http_IncomingResponse extends tink_http_Message {
+	constructor(header,body) {
+		super(header,body);
+	}
+	static readAll(res) {
+		return tink_core_Promise.next(tink_io_RealSourceTools.all(res.body),function(b) {
+			if(res.header.statusCode >= 400) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(tink_core_TypedError.withData(res.header.statusCode,res.header.reason,b.toString(),{ fileName : "tink/http/Response.hx", lineNumber : 115, className : "tink.http.IncomingResponse", methodName : "readAll"}))));
+			} else {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(b)));
+			}
+		});
+	}
+	static reportError(e) {
+		return new tink_http_IncomingResponse(new tink_http_ResponseHeaderBase(e.code,httpstatus_HttpStatusMessage.fromCode(e.code),[new tink_http_HeaderField("Content-Type".toLowerCase(),"application/json")],"HTTP/1.1"),new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(JSON.stringify({ error : e.message, details : e.data}))))));
+	}
+}
+tink_http_IncomingResponse.__name__ = "tink.http.IncomingResponse";
+tink_http_IncomingResponse.__super__ = tink_http_Message;
+Object.assign(tink_http_IncomingResponse.prototype, {
+	__class__: tink_http_IncomingResponse
+});
+var tink_http_BodyPart = $hxEnums["tink.http.BodyPart"] = { __ename__:true,__constructs__:null
+	,Value: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"tink.http.BodyPart",toString:$estr}; },$_._hx_name="Value",$_.__params__ = ["v"],$_)
+	,File: ($_=function(handle) { return {_hx_index:1,handle:handle,__enum__:"tink.http.BodyPart",toString:$estr}; },$_._hx_name="File",$_.__params__ = ["handle"],$_)
+};
+tink_http_BodyPart.__constructs__ = [tink_http_BodyPart.Value,tink_http_BodyPart.File];
+class tink_http_UploadedFile {
+	static ofBlob(name,type,data) {
+		return { fileName : name, mimeType : type, size : data.length, read : function() {
+			return new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(data)));
+		}, saveTo : function(path) {
+			let name = "File sink " + path;
+			throw haxe_Exception.thrown("not implemented");
+		}};
+	}
+}
+class tink_http_clients_JsClient {
+	constructor(credentials) {
+		this.credentials = false;
+		if(credentials) {
+			this.credentials = true;
+		}
+	}
+	request(req) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			let http = new XMLHttpRequest();
+			http.open(req.header.method,tink_Url.toString(req.header.url));
+			http.withCredentials = _gthis.credentials;
+			http.responseType = "arraybuffer";
+			let _g_current = 0;
+			let _g_array = req.header.fields;
+			while(_g_current < _g_array.length) {
+				let header = _g_array[_g_current++];
+				switch(header.name) {
+				case "content-length":case "host":
+					break;
+				default:
+					http.setRequestHeader(header.name,header.value);
+				}
+			}
+			http.onreadystatechange = function() {
+				if(http.readyState == 4) {
+					if(http.status != 0) {
+						let headers;
+						let _g = http.getAllResponseHeaders();
+						if(_g == null) {
+							headers = [];
+						} else {
+							let v = _g;
+							let _g1 = [];
+							let _g2 = 0;
+							let _g3 = v.split("\r\n");
+							while(_g2 < _g3.length) {
+								let line = _g3[_g2];
+								++_g2;
+								if(line != "") {
+									_g1.push(tink_http_HeaderField.ofString(line));
+								}
+							}
+							headers = _g1;
+						}
+						let header = new tink_http_ResponseHeaderBase(http.status,http.statusText,headers,"HTTP/1.1");
+						let cb1 = cb;
+						let this1 = new tink_http_ResponseHeaderBase(http.status,http.statusText,headers,"HTTP/1.1");
+						let _g1 = http.response;
+						let tmp;
+						if(_g1 == null) {
+							tmp = tink_io_Source.EMPTY;
+						} else {
+							let v = _g1;
+							tmp = new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofData(v))));
+						}
+						cb1(tink_core_Outcome.Success(new tink_http_IncomingResponse(this1,tmp)));
+					} else {
+						let _g = cb;
+						let a1 = tink_core_Outcome.Failure(tink_core_TypedError.withData(502,"XMLHttpRequest Error",{ request : req, error : "Status code is zero"},{ fileName : "tink/http/clients/JsClient.hx", lineNumber : 54, className : "tink.http.clients.JsClient", methodName : "request"}));
+						haxe_Timer.delay(function() {
+							_g(a1);
+						},1);
+					}
+				}
+			};
+			http.onerror = function(e) {
+				cb(tink_core_Outcome.Failure(tink_core_TypedError.withData(502,"XMLHttpRequest Error",{ request : req, error : e},{ fileName : "tink/http/clients/JsClient.hx", lineNumber : 60, className : "tink.http.clients.JsClient", methodName : "request"})));
+			};
+			if(req.header.method == "GET") {
+				http.send();
+			} else {
+				tink_io_IdealSourceTools.all(req.body).handle(function(chunk) {
+					http.send(new Int8Array(chunk.toBytes().b.bufferValue));
+				});
+			}
+		});
+	}
+	getHttp() {
+		return new XMLHttpRequest();
+	}
+}
+tink_http_clients_JsClient.__name__ = "tink.http.clients.JsClient";
+tink_http_clients_JsClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http_clients_JsClient.prototype, {
+	__class__: tink_http_clients_JsClient
+});
+class tink_http_clients_LocalContainerClient {
+	constructor(container) {
+		this.container = container;
+	}
+	request(req) {
+		let this1 = req.header.url;
+		return tink_core_Future.flatMap(this.container.serve(new tink_http_IncomingRequest("127.0.0.1",new tink_http_IncomingRequestHeader(req.header.method,tink_Url.fromString(this1.query == null ? this1.path : (this1.path == null ? "null" : this1.path) + "?" + (this1.query == null ? "null" : this1.query)),"HTTP/1.1",req.header.fields),tink_http_IncomingRequestBody.Plain(req.body))),function(res) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_IncomingResponse(res.header,res.body))));
+		});
+	}
+}
+tink_http_clients_LocalContainerClient.__name__ = "tink.http.clients.LocalContainerClient";
+tink_http_clients_LocalContainerClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http_clients_LocalContainerClient.prototype, {
+	__class__: tink_http_clients_LocalContainerClient
+});
+class tink_http_clients_StdClient {
+	constructor(worker) {
+		this.worker = tink_io_Worker.ensure(worker);
+	}
+	request(req) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			let r = new haxe_http_HttpJs(tink_Url.toString(req.header.url));
+			let send = function(post) {
+				let code = 200;
+				r.onStatus = function(c) {
+					code = c;
+				};
+				let headers = function() {
+					return [];
+				};
+				r.onError = function(msg) {
+					if(code == 200) {
+						code = 500;
+					}
+					tink_io_Worker.work(_gthis.worker,new tink_core__$Lazy_LazyConst(true)).handle(function() {
+						cb(tink_core_Outcome.Failure(new tink_core_TypedError(code,msg,{ fileName : "tink/http/clients/StdClient.hx", lineNumber : 44, className : "tink.http.clients.StdClient", methodName : "request"})));
+					});
+				};
+				r.onData = function(data) {
+					tink_io_Worker.work(_gthis.worker,new tink_core__$Lazy_LazyConst(true)).handle(function() {
+						let cb1 = cb;
+						let fields = headers();
+						cb1(tink_core_Outcome.Success(new tink_http_IncomingResponse(new tink_http_ResponseHeaderBase(code,"OK",fields,"HTTP/1.1"),new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(data)))))));
+					});
+				};
+				tink_io_Worker.work(_gthis.worker,new tink_core__$Lazy_LazyFunc(function() {
+					r.request(post);
+				}));
+			};
+			let _g_current = 0;
+			let _g_array = req.header.fields;
+			while(_g_current < _g_array.length) {
+				let h = _g_array[_g_current++];
+				r.setHeader(h.name,h.value);
+			}
+			switch(req.header.method) {
+			case "GET":case "HEAD":case "OPTIONS":
+				send(false);
+				break;
+			default:
+				tink_io_IdealSourceTools.all(req.body).handle(function(bytes) {
+					r.setPostData(bytes.toString());
+					send(true);
+				});
+			}
+		});
+	}
+}
+tink_http_clients_StdClient.__name__ = "tink.http.clients.StdClient";
+tink_http_clients_StdClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http_clients_StdClient.prototype, {
+	__class__: tink_http_clients_StdClient
+});
+class tink_http_containers_LocalContainer {
+	constructor() {
+	}
+	run(handler) {
+		this.handler = handler;
+		this.running = true;
+		let _gthis = this;
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_http_ContainerResult.Running({ failures : new tink_core_SignalTrigger(), shutdown : function(hard) {
+			_gthis.running = false;
+			return tink_core_Future.map(new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(true)),tink_core_Outcome.Success);
+		}})));
+	}
+	serve(req) {
+		if(!this.running) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(new tink_http__$Response_OutgoingResponseData(new tink_http_ResponseHeaderBase(503,"Server stopped",[],"HTTP/1.1"),tink_io_Source.EMPTY)));
+		}
+		return this.handler.process(req);
+	}
+}
+tink_http_containers_LocalContainer.__name__ = "tink.http.containers.LocalContainer";
+tink_http_containers_LocalContainer.__interfaces__ = [tink_http_Container];
+Object.assign(tink_http_containers_LocalContainer.prototype, {
+	__class__: tink_http_containers_LocalContainer
+});
+class tink_io_PipeOptions {
+	static get_end(this1) {
+		if(this1 != null) {
+			return this1.end;
+		} else {
+			return false;
+		}
+	}
+	static get_destructive(this1) {
+		if(this1 != null) {
+			return this1.destructive;
+		} else {
+			return false;
+		}
+	}
+}
+var tink_io_PipeResult = $hxEnums["tink.io.PipeResult"] = { __ename__:true,__constructs__:null
+	,AllWritten: {_hx_name:"AllWritten",_hx_index:0,__enum__:"tink.io.PipeResult",toString:$estr}
+	,SinkEnded: ($_=function(result,rest) { return {_hx_index:1,result:result,rest:rest,__enum__:"tink.io.PipeResult",toString:$estr}; },$_._hx_name="SinkEnded",$_.__params__ = ["result","rest"],$_)
+	,SinkFailed: ($_=function(e,rest) { return {_hx_index:2,e:e,rest:rest,__enum__:"tink.io.PipeResult",toString:$estr}; },$_._hx_name="SinkFailed",$_.__params__ = ["e","rest"],$_)
+	,SourceFailed: ($_=function(e) { return {_hx_index:3,e:e,__enum__:"tink.io.PipeResult",toString:$estr}; },$_._hx_name="SourceFailed",$_.__params__ = ["e"],$_)
+};
+tink_io_PipeResult.__constructs__ = [tink_io_PipeResult.AllWritten,tink_io_PipeResult.SinkEnded,tink_io_PipeResult.SinkFailed,tink_io_PipeResult.SourceFailed];
+class tink_io_PipeResultTools {
+	static toOutcome(result) {
+		switch(result._hx_index) {
+		case 0:
+			return tink_core_Outcome.Success(haxe_ds_Option.None);
+		case 1:
+			let _g = result.rest;
+			let result1 = result.result;
+			return tink_core_Outcome.Success(haxe_ds_Option.Some(result1));
+		case 2:
+			let _g1 = result.rest;
+			let e = result.e;
+			return tink_core_Outcome.Failure(e);
+		case 3:
+			let e1 = result.e;
+			return tink_core_Outcome.Failure(e1);
+		}
+	}
+	static toResult(c,result,buffered) {
+		let mk = function(s) {
+			if(buffered == null) {
+				return s;
+			} else {
+				let v = buffered;
+				return s.prepend(new tink_streams_Single(new tink_core__$Lazy_LazyConst(v)));
+			}
+		};
+		switch(c._hx_index) {
+		case 0:
+			let rest = c.rest;
+			return tink_io_PipeResult.SinkEnded(result,mk(rest));
+		case 1:
+			let e = c.error;
+			let rest1 = c.at;
+			return tink_io_PipeResult.SinkFailed(e,mk(rest1));
+		case 2:
+			let e1 = c.error;
+			return tink_io_PipeResult.SourceFailed(e1);
+		case 3:
+			return tink_io_PipeResult.AllWritten;
+		}
+	}
+}
+tink_io_PipeResultTools.__name__ = "tink.io.PipeResultTools";
+class tink_io_SinkObject {
+}
+tink_io_SinkObject.__name__ = "tink.io.SinkObject";
+tink_io_SinkObject.__isInterface__ = true;
+Object.assign(tink_io_SinkObject.prototype, {
+	__class__: tink_io_SinkObject
+});
+class tink_io_SinkBase {
+	get_sealed() {
+		return true;
+	}
+	consume(source,options) {
+		throw haxe_Exception.thrown("not implemented");
+	}
+}
+tink_io_SinkBase.__name__ = "tink.io.SinkBase";
+tink_io_SinkBase.__interfaces__ = [tink_io_SinkObject];
+Object.assign(tink_io_SinkBase.prototype, {
+	__class__: tink_io_SinkBase
+});
+class tink_io__$Sink_Blackhole extends tink_io_SinkBase {
+	constructor() {
+		super();
+	}
+	consume(source,options) {
+		return tink_core_Future.map(source.forEach(tink_streams_Handler.ofSafeSync(function(_) {
+			return tink_streams_Handled.Resume;
+		})),function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let _g = o.rest;
+				throw haxe_Exception.thrown("unreachable");
+			case 2:
+				let e = o.error;
+				return tink_io_PipeResult.SourceFailed(e);
+			case 3:
+				return tink_io_PipeResult.AllWritten;
+			}
+		});
+	}
+}
+tink_io__$Sink_Blackhole.__name__ = "tink.io._Sink.Blackhole";
+tink_io__$Sink_Blackhole.__super__ = tink_io_SinkBase;
+Object.assign(tink_io__$Sink_Blackhole.prototype, {
+	__class__: tink_io__$Sink_Blackhole
+});
+class tink_io_SinkYielding {
+	static end(this1) {
+		if(this1.get_sealed()) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(false)));
+		} else {
+			return tink_core_Future.map(this1.consume(tink_io_Source.EMPTY,{ end : true}),function(r) {
+				switch(r._hx_index) {
+				case 0:
+					return tink_core_Outcome.Success(true);
+				case 1:
+					let _g = r.result;
+					let _g1 = r.rest;
+					return tink_core_Outcome.Success(true);
+				case 2:
+					let _g2 = r.rest;
+					let e = r.e;
+					return tink_core_Outcome.Failure(e);
+				}
+			});
+		}
+	}
+	static dirty(this1) {
+		return this1;
+	}
+	static ofError(e) {
+		return new tink_io__$Sink_ErrorSink(e);
+	}
+	static ofPromised(p) {
+		return new tink_io__$Sink_FutureSink(tink_core_Future.map(p,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let v = o.data;
+				return v;
+			case 1:
+				let e = o.failure;
+				return tink_io_SinkYielding.ofError(e);
+			}
+		}));
+	}
+	static ofOutput(name,target,options) {
+		let tmp;
+		if(options == null) {
+			tmp = tink_io_Worker.get();
+		} else {
+			let _g = options.worker;
+			if(_g == null) {
+				tmp = tink_io_Worker.get();
+			} else {
+				let w = _g;
+				tmp = w;
+			}
+		}
+		return new tink_io_std_OutputSink(name,target,tmp);
+	}
+}
+class tink_io__$Sink_FutureSink extends tink_io_SinkBase {
+	constructor(f) {
+		super();
+		this.f = f;
+	}
+	consume(source,options) {
+		return tink_core_Future.flatMap(this.f,function(sink) {
+			return sink.consume(source,options);
+		});
+	}
+}
+tink_io__$Sink_FutureSink.__name__ = "tink.io._Sink.FutureSink";
+tink_io__$Sink_FutureSink.__super__ = tink_io_SinkBase;
+Object.assign(tink_io__$Sink_FutureSink.prototype, {
+	__class__: tink_io__$Sink_FutureSink
+});
+class tink_io__$Sink_ErrorSink extends tink_io_SinkBase {
+	constructor(error) {
+		super();
+		this.error = error;
+	}
+	get_sealed() {
+		return false;
+	}
+	consume(source,options) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_PipeResult.SinkFailed(this.error,source)));
+	}
+}
+tink_io__$Sink_ErrorSink.__name__ = "tink.io._Sink.ErrorSink";
+tink_io__$Sink_ErrorSink.__super__ = tink_io_SinkBase;
+Object.assign(tink_io__$Sink_ErrorSink.prototype, {
+	__class__: tink_io__$Sink_ErrorSink
+});
+class tink_streams_StreamObject {
+}
+tink_streams_StreamObject.__name__ = "tink.streams.StreamObject";
+tink_streams_StreamObject.__isInterface__ = true;
+Object.assign(tink_streams_StreamObject.prototype, {
+	__class__: tink_streams_StreamObject
+});
+class tink_streams_StreamBase {
+	constructor() {
+		if(tink_streams_StreamBase._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.retainCount = 0;
+	}
+	get_depleted() {
+		return false;
+	}
+	retain() {
+		this.retainCount++;
+		let retained = true;
+		let _gthis = this;
+		return function() {
+			if(retained) {
+				retained = false;
+				if(--_gthis.retainCount == 0) {
+					_gthis.destroy();
+				}
+			}
+		};
+	}
+	next() {
+		throw haxe_Exception.thrown("not implemented");
+	}
+	regroup(f) {
+		return new tink_streams__$Stream_RegroupStream(this,f);
+	}
+	map(f) {
+		return this.regroup(f);
+	}
+	filter(f) {
+		return this.regroup(f);
+	}
+	destroy() {
+	}
+	append(other) {
+		if(this.get_depleted()) {
+			return other;
+		} else {
+			return tink_streams__$Stream_CompoundStream.of([this,other]);
+		}
+	}
+	prepend(other) {
+		if(this.get_depleted()) {
+			return other;
+		} else {
+			return tink_streams__$Stream_CompoundStream.of([other,this]);
+		}
+	}
+	blend(other) {
+		if(this.get_depleted()) {
+			return other;
+		} else {
+			return new tink_streams_BlendStream(this,other);
+		}
+	}
+	decompose(into) {
+		if(!this.get_depleted()) {
+			into.push(this);
+		}
+	}
+	idealize(rescue) {
+		if(this.get_depleted()) {
+			return tink_streams_Empty.inst;
+		} else {
+			return new tink_streams_IdealizeStream(this,rescue);
+		}
+	}
+	reduce(initial,reducer) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			_gthis.forEach(tink_streams_Handler.ofUnknown(function(item) {
+				return tink_core_Future.map(reducer(initial,item),function(o) {
+					switch(o._hx_index) {
+					case 0:
+						let v = o.result;
+						initial = v;
+						return tink_streams_Handled.Resume;
+					case 1:
+						let e = o.e;
+						return tink_streams_Handled.Clog(e);
+					}
+				});
+			})).handle(function(c) {
+				switch(c._hx_index) {
+				case 0:
+					let _g = c.rest;
+					throw haxe_Exception.thrown("assert");
+				case 1:
+					let e = c.error;
+					let rest = c.at;
+					cb(tink_streams_Reduction.Crashed(e,rest));
+					break;
+				case 2:
+					let e1 = c.error;
+					cb(tink_streams_Reduction.Failed(e1));
+					break;
+				case 3:
+					cb(tink_streams_Reduction.Reduced(initial));
+					break;
+				}
+			});
+		});
+	}
+	forEach(handler) {
+		throw haxe_Exception.thrown("not implemented");
+	}
+}
+tink_streams_StreamBase.__name__ = "tink.streams.StreamBase";
+tink_streams_StreamBase.__interfaces__ = [tink_streams_StreamObject];
+Object.assign(tink_streams_StreamBase.prototype, {
+	__class__: tink_streams_StreamBase
+});
+class tink_streams_Empty extends tink_streams_StreamBase {
+	constructor() {
+		super();
+	}
+	get_depleted() {
+		return true;
+	}
+	next() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.End));
+	}
+	forEach(handler) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Conclusion.Depleted));
+	}
+	static make() {
+		return tink_streams_Empty.inst;
+	}
+}
+tink_streams_Empty.__name__ = "tink.streams.Empty";
+tink_streams_Empty.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_Empty.prototype, {
+	__class__: tink_streams_Empty
+});
+class tink_io_Source {
+	static dirty(this1) {
+		return this1;
+	}
+	static get_depleted(this1) {
+		return this1.get_depleted();
+	}
+	static ofJsFile(name,file,options) {
+		let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+		return new tink_io_js_BlobSource(name,file,0,chunkSize);
+	}
+	static ofJsBlob(name,blob,options) {
+		let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+		return new tink_io_js_BlobSource(name,blob,0,chunkSize);
+	}
+	static ofInput(name,input,options) {
+		if(options == null) {
+			options = { };
+		}
+		let tmp = tink_io_Worker.ensure(options.worker);
+		let length;
+		let _g = options.chunkSize;
+		if(_g == null) {
+			length = 65536;
+		} else {
+			let v = _g;
+			length = v;
+		}
+		return new tink_io_std_InputSource(name,input,tmp,new haxe_io_Bytes(new ArrayBuffer(length)),0);
+	}
+	static chunked(this1) {
+		return this1;
+	}
+	static concatAll(s) {
+		return s.reduce(tink_Chunk.EMPTY,tink_streams_Reducer.ofSafeSync(function(res,cur) {
+			return tink_streams_ReductionStep.Progress(tink_Chunk.concat(res,cur));
+		}));
+	}
+	static pipeTo(this1,target,options) {
+		return target.consume(this1,options);
+	}
+	static append(this1,that) {
+		return this1.append(that);
+	}
+	static prepend(this1,that) {
+		return this1.prepend(that);
+	}
+	static transform(this1,transformer) {
+		return transformer.transform(this1);
+	}
+	static skip(this1,len) {
+		return this1.regroup(tink_streams_Regrouper.ofIgnoranceSync(function(chunks) {
+			let chunk = chunks[0];
+			if(len <= 0) {
+				return tink_streams_RegroupResult.Converted(tink_streams_Stream.single(chunk));
+			}
+			let length = chunk.getLength();
+			let out = tink_streams_RegroupResult.Converted(len < length ? tink_streams_Stream.single(chunk.slice(len,length)) : tink_streams_Empty.inst);
+			len -= length;
+			return out;
+		}));
+	}
+	static limit(this1,len) {
+		if(len == 0) {
+			return tink_io_Source.EMPTY;
+		}
+		return this1.regroup(tink_streams_Regrouper.ofIgnoranceSync(function(chunks) {
+			if(len <= 0) {
+				return tink_streams_RegroupResult.Terminated(haxe_ds_Option.None);
+			}
+			let chunk = chunks[0];
+			let length = chunk.getLength();
+			let out = len == length ? tink_streams_RegroupResult.Terminated(haxe_ds_Option.Some(tink_streams_Stream.single(chunk))) : tink_streams_RegroupResult.Converted(tink_streams_Stream.single(len < length ? chunk.slice(0,len) : chunk));
+			len -= length;
+			return out;
+		}));
+	}
+	static ofError(e) {
+		return tink_streams_Stream.ofError(e);
+	}
+	static ofFuture(f) {
+		return tink_streams_Stream.future(f);
+	}
+	static ofPromised(p) {
+		return tink_streams_Stream.future(tink_core_Future.map(p,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let s = o.data;
+				return s;
+			case 1:
+				let e = o.failure;
+				return tink_io_Source.ofError(e);
+			}
+		}));
+	}
+	static ofChunk(chunk) {
+		return new tink_streams_Single(new tink_core__$Lazy_LazyConst(chunk));
+	}
+	static ofString(s) {
+		return new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(s))));
+	}
+	static ofBytes(b) {
+		return new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(b)));
+	}
+	static ofFutureChunk(chunk) {
+		return tink_io_Source.ofFuture(tink_core_Future.map(chunk,tink_io_Source.ofChunk));
+	}
+	static ofFutureString(s) {
+		return tink_io_Source.ofFuture(tink_core_Future.map(s,tink_io_Source.ofString));
+	}
+	static ofFutureBytes(b) {
+		return tink_io_Source.ofFuture(tink_core_Future.map(b,tink_io_Source.ofBytes));
+	}
+	static ofPromiseChunk(chunk) {
+		return tink_io_Source.ofPromised(tink_core_Promise.next(chunk,tink_core_Next.ofSafeSync(tink_io_Source.ofChunk)));
+	}
+	static ofPromiseString(s) {
+		return tink_io_Source.ofPromised(tink_core_Promise.next(s,tink_core_Next.ofSafeSync(tink_io_Source.ofString)));
+	}
+	static ofPromiseBytes(b) {
+		return tink_io_Source.ofPromised(tink_core_Promise.next(b,tink_core_Next.ofSafeSync(tink_io_Source.ofBytes)));
+	}
+}
+class tink_io_RealSourceTools {
+	static all(s) {
+		return tink_core_Future.map(tink_io_Source.concatAll(s),function(o) {
+			switch(o._hx_index) {
+			case 1:
+				let e = o.error;
+				return tink_core_Outcome.Failure(e);
+			case 2:
+				let c = o.result;
+				return tink_core_Outcome.Success(c);
+			}
+		});
+	}
+	static parse(s,p) {
+		return tink_core_Future.map(tink_io_StreamParser.parse(s,p),function(r) {
+			switch(r._hx_index) {
+			case 0:
+				let data = r.data;
+				let rest = r.rest;
+				return tink_core_Outcome.Success(new tink_core_MPair(data,rest));
+			case 1:
+				let _g = r.rest;
+				let e = r.e;
+				return tink_core_Outcome.Failure(e);
+			case 2:
+				let e1 = r.e;
+				return tink_core_Outcome.Failure(e1);
+			}
+		});
+	}
+	static split(src,delim) {
+		let s = tink_io_RealSourceTools.parse(src,new tink_io_Splitter(delim));
+		return { before : tink_streams_Stream.promise(tink_core_Promise.next(s,tink_core_Next.ofSafeSync(function(p) {
+			let _g = p.a;
+			switch(_g._hx_index) {
+			case 0:
+				let chunk = _g.v;
+				return new tink_streams_Single(new tink_core__$Lazy_LazyConst(chunk));
+			case 1:
+				return src;
+			}
+		}))), delimiter : tink_core_Promise.next(s,function(p) {
+			let _g = p.a;
+			switch(_g._hx_index) {
+			case 0:
+				let _g1 = _g.v;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(delim)));
+			case 1:
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(new tink_core_TypedError(404,"Delimiter not found",{ fileName : "tink/io/Source.hx", lineNumber : 213, className : "tink.io.RealSourceTools", methodName : "split"}))));
+			}
+		}), after : tink_streams_Stream.promise(tink_core_Promise.next(s,tink_core_Next.ofSafeSync(function(p) {
+			return p.b;
+		})))};
+	}
+	static parseStream(s,p) {
+		return tink_io_StreamParser.parseStream(s,p);
+	}
+	static idealize(s,rescue) {
+		return tink_io_Source.chunked(s).idealize(rescue);
+	}
+}
+tink_io_RealSourceTools.__name__ = "tink.io.RealSourceTools";
+class tink_io_IdealSourceTools {
+	static all(s) {
+		return tink_core_Future.map(tink_io_Source.concatAll(s),function(o) {
+			let c = o.result;
+			return c;
+		});
+	}
+	static parse(s,p) {
+		return tink_core_Future.map(tink_io_StreamParser.parse(s,p),function(r) {
+			switch(r._hx_index) {
+			case 0:
+				let data = r.data;
+				let rest = r.rest;
+				return tink_core_Outcome.Success(new tink_core_MPair(data,rest));
+			case 1:
+				let _g = r.rest;
+				let e = r.e;
+				return tink_core_Outcome.Failure(e);
+			}
+		});
+	}
+	static parseStream(s,p) {
+		return tink_io_StreamParser.parseStream(s,p);
+	}
+	static split(s,delim) {
+		let s1 = tink_io_RealSourceTools.split(s,delim);
+		return { before : tink_io_RealSourceTools.idealize(s1.before,function(e) {
+			return tink_io_Source.EMPTY;
+		}), delimiter : s1.delimiter, after : tink_io_RealSourceTools.idealize(s1.after,function(e) {
+			return tink_io_Source.EMPTY;
+		})};
+	}
+}
+tink_io_IdealSourceTools.__name__ = "tink.io.IdealSourceTools";
+var tink_io_ParseResult = $hxEnums["tink.io.ParseResult"] = { __ename__:true,__constructs__:null
+	,Parsed: ($_=function(data,rest) { return {_hx_index:0,data:data,rest:rest,__enum__:"tink.io.ParseResult",toString:$estr}; },$_._hx_name="Parsed",$_.__params__ = ["data","rest"],$_)
+	,Invalid: ($_=function(e,rest) { return {_hx_index:1,e:e,rest:rest,__enum__:"tink.io.ParseResult",toString:$estr}; },$_._hx_name="Invalid",$_.__params__ = ["e","rest"],$_)
+	,Broke: ($_=function(e) { return {_hx_index:2,e:e,__enum__:"tink.io.ParseResult",toString:$estr}; },$_._hx_name="Broke",$_.__params__ = ["e"],$_)
+};
+tink_io_ParseResult.__constructs__ = [tink_io_ParseResult.Parsed,tink_io_ParseResult.Invalid,tink_io_ParseResult.Broke];
+class tink_io_StreamParser {
+	static doParse(source,p,consume,finish) {
+		let cursor = tink_Chunk.EMPTY.getCursor();
+		let resume = true;
+		let mk = function(source) {
+			if(cursor.currentPos < cursor.length) {
+				return source.prepend(new tink_streams_Single(new tink_core__$Lazy_LazyConst(cursor.right())));
+			} else {
+				return source;
+			}
+		};
+		let flush = function() {
+			let _g = cursor.flush();
+			let c = _g;
+			if(c.getLength() == 0) {
+				return tink_io_Source.EMPTY;
+			} else {
+				let c = _g;
+				return new tink_streams_Single(new tink_core__$Lazy_LazyConst(c));
+			}
+		};
+		return tink_core_Future.flatMap(source.forEach(tink_streams_Handler.ofUnknown(function(chunk) {
+			if(chunk.getLength() == 0) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Handled.Resume));
+			}
+			cursor.shift(chunk);
+			return tink_core_Future.async(function(cb) {
+				let next = null;
+				next = function() {
+					cursor.shift();
+					let lastPos = cursor.currentPos;
+					let _g = p.progress(cursor);
+					switch(_g._hx_index) {
+					case 0:
+						if(lastPos != cursor.currentPos && cursor.currentPos < cursor.length) {
+							next();
+						} else {
+							cb(tink_streams_Handled.Resume);
+						}
+						break;
+					case 1:
+						let v = _g.r;
+						consume(v).handle(function(o) {
+							resume = o.resume;
+							if(resume) {
+								if(lastPos != cursor.currentPos && cursor.currentPos < cursor.length) {
+									next();
+								} else {
+									cb(tink_streams_Handled.Resume);
+								}
+							} else {
+								cb(tink_streams_Handled.Finish);
+							}
+						});
+						break;
+					case 2:
+						let e = _g.e;
+						cb(tink_streams_Handled.Clog(e));
+						break;
+					}
+				};
+				next();
+			});
+		})),function(c) {
+			switch(c._hx_index) {
+			case 0:
+				let rest = c.rest;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Parsed(finish(),mk(rest))));
+			case 1:
+				let e = c.error;
+				let rest1 = c.at;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Invalid(e,mk(rest1))));
+			case 2:
+				let e1 = c.error;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Broke(e1)));
+			case 3:
+				if(cursor.currentPos < cursor.length) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Parsed(finish(),mk(new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_Chunk.EMPTY))))));
+				} else if(!resume) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Parsed(finish(),flush())));
+				} else {
+					let _g = p.eof(cursor);
+					switch(_g._hx_index) {
+					case 0:
+						let result = _g.data;
+						return tink_core_Future.map(consume(result),function(_) {
+							return tink_io_ParseResult.Parsed(finish(),flush());
+						});
+					case 1:
+						let e = _g.failure;
+						return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Invalid(e,flush())));
+					}
+				}
+				break;
+			}
+		});
+	}
+	static parse(s,p) {
+		let res = null;
+		let onResult = function(r) {
+			res = r;
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst({ resume : false}));
+		};
+		return tink_io_StreamParser.doParse(s,p,onResult,function() {
+			return res;
+		});
+	}
+	static parseStream(s,p) {
+		let next = null;
+		next = function(step) {
+			if(s.get_depleted()) {
+				step(tink_streams_Step.End);
+			} else {
+				tink_io_StreamParser.parse(s,p).handle(function(o) {
+					switch(o._hx_index) {
+					case 0:
+						let result = o.data;
+						let rest = o.rest;
+						s = rest;
+						step(tink_streams_Step.Link(result,tink_streams_Generator.stream(next)));
+						break;
+					case 1:
+						let _g = o.rest;
+						let e = o.e;
+						step(tink_streams_Step.Fail(e));
+						break;
+					case 2:
+						let e1 = o.e;
+						step(tink_streams_Step.Fail(e1));
+						break;
+					}
+				});
+			}
+		};
+		return tink_streams_Generator.stream(next);
+	}
+}
+class tink_io_Splitter extends tink_io_BytewiseParser {
+	constructor(delim) {
+		super();
+		this.buf = tink_Chunk.EMPTY;
+		this.delim = delim;
+	}
+	read(char) {
+		if(char == -1) {
+			return tink_io_ParseStep.Done(haxe_ds_Option.None);
+		}
+		this.buf = tink_Chunk.concat(this.buf,tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(String.fromCodePoint(char))));
+		if(this.buf.getLength() >= this.delim.getLength()) {
+			let bcursor = this.buf.getCursor();
+			let delta = this.buf.getLength() - this.delim.getLength();
+			bcursor.moveTo(bcursor.currentPos + delta);
+			let dcursor = this.delim.getCursor();
+			let _g = 0;
+			let _g1 = this.delim.getLength();
+			while(_g < _g1) {
+				let i = _g++;
+				if(bcursor.currentByte != dcursor.currentByte) {
+					return tink_io_ParseStep.Progressed;
+				} else {
+					bcursor.next();
+					dcursor.next();
+				}
+			}
+			let out = tink_io_ParseStep.Done(haxe_ds_Option.Some(this.buf.slice(0,bcursor.currentPos - this.delim.getLength())));
+			this.buf = tink_Chunk.EMPTY;
+			return out;
+		} else {
+			return tink_io_ParseStep.Progressed;
+		}
+	}
+}
+tink_io_Splitter.__name__ = "tink.io.Splitter";
+tink_io_Splitter.__super__ = tink_io_BytewiseParser;
+Object.assign(tink_io_Splitter.prototype, {
+	__class__: tink_io_Splitter
+});
+class tink_io_SimpleBytewiseParser extends tink_io_BytewiseParser {
+	constructor(f) {
+		super();
+		this._read = f;
+	}
+	read(char) {
+		return this._read(char);
+	}
+}
+tink_io_SimpleBytewiseParser.__name__ = "tink.io.SimpleBytewiseParser";
+tink_io_SimpleBytewiseParser.__super__ = tink_io_BytewiseParser;
+Object.assign(tink_io_SimpleBytewiseParser.prototype, {
+	__class__: tink_io_SimpleBytewiseParser
+});
+class tink_io_WorkerObject {
+}
+tink_io_WorkerObject.__name__ = "tink.io.WorkerObject";
+tink_io_WorkerObject.__isInterface__ = true;
+Object.assign(tink_io_WorkerObject.prototype, {
+	__class__: tink_io_WorkerObject
+});
+class tink_io__$Worker_EagerWorker {
+	constructor() {
+	}
+	work(task) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Lazy.get(task)));
+	}
+}
+tink_io__$Worker_EagerWorker.__name__ = "tink.io._Worker.EagerWorker";
+tink_io__$Worker_EagerWorker.__interfaces__ = [tink_io_WorkerObject];
+Object.assign(tink_io__$Worker_EagerWorker.prototype, {
+	__class__: tink_io__$Worker_EagerWorker
+});
+class tink_io_Worker {
+	static ensure(this1) {
+		if(this1 == null) {
+			return tink_io_Worker.get();
+		} else {
+			return this1;
+		}
+	}
+	static get() {
+		return tink_io_Worker.pool[Std.random(tink_io_Worker.pool.length)];
+	}
+	static work(this1,task) {
+		return this1.work(task);
+	}
+}
+class tink_streams_Generator extends tink_streams_StreamBase {
+	constructor(upcoming) {
+		if(tink_streams_StreamBase._hx_skip_constructor) {
+			super();
+			return;
+		}
+		tink_streams_StreamBase._hx_skip_constructor = true;
+		super();
+		tink_streams_StreamBase._hx_skip_constructor = false;
+		this._hx_constructor(upcoming);
+	}
+	_hx_constructor(upcoming) {
+		super._hx_constructor();
+		this.upcoming = upcoming;
+	}
+	next() {
+		return this.upcoming;
+	}
+	forEach(handler) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			_gthis.upcoming.handle(function(e) {
+				switch(e._hx_index) {
+				case 0:
+					let v = e.value;
+					let then = e.next;
+					handler(v).handle(function(s) {
+						switch(s._hx_index) {
+						case 0:
+							cb(tink_streams_Conclusion.Halted(_gthis));
+							break;
+						case 1:
+							cb(tink_streams_Conclusion.Halted(then));
+							break;
+						case 2:
+							then.forEach(handler).handle(cb);
+							break;
+						case 3:
+							let e = s.e;
+							cb(tink_streams_Conclusion.Clogged(e,_gthis));
+							break;
+						}
+					});
+					break;
+				case 1:
+					let e1 = e.e;
+					cb(tink_streams_Conclusion.Failed(e1));
+					break;
+				case 2:
+					cb(tink_streams_Conclusion.Depleted);
+					break;
+				}
+			});
+		});
+	}
+	static stream(step) {
+		return new tink_streams_Generator(tink_core_Future.async(step));
+	}
+}
+tink_streams_Generator.__name__ = "tink.streams.Generator";
+tink_streams_Generator.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_Generator.prototype, {
+	__class__: tink_streams_Generator
+});
+class tink_io_js_BlobSource extends tink_streams_Generator {
+	constructor(name,blob,pos,chunkSize) {
+		tink_streams_StreamBase._hx_skip_constructor = true;
+		super();
+		tink_streams_StreamBase._hx_skip_constructor = false;
+		this._hx_constructor(name,blob,pos,chunkSize);
+	}
+	_hx_constructor(name,blob,pos,chunkSize) {
+		this.name = name;
+		super._hx_constructor(tink_core_Future.async(function(cb) {
+			if(pos >= blob.size) {
+				cb(tink_streams_Step.End);
+			} else {
+				let end = pos + chunkSize;
+				if(end > blob.size) {
+					end = blob.size;
+				}
+				let reader = new FileReader();
+				reader.onload = function() {
+					let chunk = tink_chunk_ByteChunk.of(haxe_io_Bytes.ofData(reader.result));
+					cb(tink_streams_Step.Link(chunk,new tink_io_js_BlobSource(name,blob,end,chunkSize)));
+				};
+				reader.onerror = function(e) {
+					cb(tink_streams_Step.Fail(tink_core_TypedError.withData(500,e.message,e,{ fileName : "tink/io/js/BlobSource.hx", lineNumber : 29, className : "tink.io.js.BlobSource", methodName : "new"})));
+				};
+				reader.readAsArrayBuffer(blob.slice(pos,end));
+			}
+		},true));
+	}
+	static wrap(name,blob,chunkSize) {
+		return new tink_io_js_BlobSource(name,blob,0,chunkSize);
+	}
+}
+tink_io_js_BlobSource.__name__ = "tink.io.js.BlobSource";
+tink_io_js_BlobSource.__super__ = tink_streams_Generator;
+Object.assign(tink_io_js_BlobSource.prototype, {
+	__class__: tink_io_js_BlobSource
+});
+class tink_io_std_InputSource extends tink_streams_Generator {
+	constructor(name,target,worker,buf,offset) {
+		let next = function(buf,offset) {
+			return new tink_io_std_InputSource(name,target,worker,buf,offset);
+		};
+		let free = buf.length - offset;
+		super(tink_core_Future.async(function(cb) {
+			tink_io_Worker.work(worker,new tink_core__$Lazy_LazyFunc(function() {
+				try {
+					let read = target.readBytes(buf,offset,free);
+					if(read == 0) {
+						return tink_streams_Step.Link(tink_Chunk.EMPTY,next(buf,offset));
+					} else {
+						let nextOffset = free - read < 1024 ? 0 : offset + read;
+						let nextBuf = nextOffset == 0 ? new haxe_io_Bytes(new ArrayBuffer(buf.length)) : buf;
+						return tink_streams_Step.Link(tink_chunk_ByteChunk.of(buf).slice(offset,offset + read),next(nextBuf,nextOffset));
+					}
+				} catch( _g ) {
+					let _g1 = haxe_Exception.caught(_g).unwrap();
+					if(((_g1) instanceof haxe_io_Eof)) {
+						return tink_streams_Step.End;
+					} else if(js_Boot.__instanceof(_g1,haxe_io_Error)) {
+						let e = _g1;
+						if(e._hx_index == 0) {
+							return tink_streams_Step.Link(tink_Chunk.EMPTY,next(buf,offset));
+						} else {
+							return tink_streams_Step.Fail(tink_core_TypedError.withData(null,"Failed to read from " + name,e,{ fileName : "tink/io/std/InputSource.hx", lineNumber : 50, className : "tink.io.std.InputSource", methodName : "new"}));
+						}
+					} else {
+						throw _g;
+					}
+				}
+			})).handle(function(step) {
+				switch(step._hx_index) {
+				case 1:
+					let _g = step.e;
+					try {
+						target.close();
+					} catch( _g ) {
+					}
+					break;
+				case 2:
+					try {
+						target.close();
+					} catch( _g ) {
+					}
+					break;
+				default:
+				}
+				cb(step);
+			});
+		},true));
+	}
+}
+tink_io_std_InputSource.__name__ = "tink.io.std.InputSource";
+tink_io_std_InputSource.__super__ = tink_streams_Generator;
+Object.assign(tink_io_std_InputSource.prototype, {
+	__class__: tink_io_std_InputSource
+});
+class tink_io_std_OutputSink extends tink_io_SinkBase {
+	constructor(name,target,worker) {
+		super();
+		this.name = name;
+		this.target = target;
+		this.worker = worker;
+	}
+	consume(source,options) {
+		let rest = tink_Chunk.EMPTY;
+		let _gthis = this;
+		let ret = source.forEach(tink_streams_Handler.ofUnknown(function(c) {
+			return tink_core_Future.async(function(cb) {
+				let pos = 0;
+				let bytes = c.toBytes();
+				let write = null;
+				write = function() {
+					if(pos == bytes.length) {
+						cb(tink_streams_Handled.Resume);
+					} else {
+						tink_io_Worker.work(_gthis.worker,new tink_core__$Lazy_LazyFunc(function() {
+							try {
+								return tink_core_Outcome.Success(_gthis.target.writeBytes(bytes,pos,bytes.length - pos));
+							} catch( _g ) {
+								let _g1 = haxe_Exception.caught(_g).unwrap();
+								if(((_g1) instanceof haxe_io_Eof)) {
+									return tink_core_Outcome.Success(-1);
+								} else if(js_Boot.__instanceof(_g1,haxe_io_Error)) {
+									let e = _g1;
+									if(e._hx_index == 0) {
+										return tink_core_Outcome.Success(0);
+									} else {
+										return tink_core_Outcome.Failure(tink_core_TypedError.withData(null,"Error writing to " + _gthis.name,e,{ fileName : "tink/io/std/OutputSink.hx", lineNumber : 40, className : "tink.io.std.OutputSink", methodName : "consume"}));
+									}
+								} else if(((_g1) instanceof tink_core_TypedError)) {
+									let e = _g1;
+									return tink_core_Outcome.Failure(e);
+								} else {
+									let e = _g1;
+									return tink_core_Outcome.Failure(tink_core_TypedError.withData(null,"Error writing to " + _gthis.name,e,{ fileName : "tink/io/std/OutputSink.hx", lineNumber : 46, className : "tink.io.std.OutputSink", methodName : "consume"}));
+								}
+							}
+						})).handle(function(o) {
+							switch(o._hx_index) {
+							case 0:
+								let _g = o.data;
+								if(_g == -1) {
+									rest = tink_chunk_ByteChunk.of(bytes).slice(pos,bytes.length);
+									cb(tink_streams_Handled.Finish);
+								} else {
+									let v = _g;
+									pos += v;
+									if(pos == bytes.length) {
+										cb(tink_streams_Handled.Resume);
+									} else {
+										write();
+									}
+								}
+								break;
+							case 1:
+								let e = o.failure;
+								cb(tink_streams_Handled.Clog(e));
+								break;
+							}
+						});
+					}
+				};
+				write();
+			});
+		}));
+		if(options != null && options.end) {
+			ret.handle(function(end) {
+				try {
+					_gthis.target.close();
+				} catch( _g ) {
+				}
+			});
+		}
+		return tink_core_Future.map(ret,function(c) {
+			return tink_io_PipeResultTools.toResult(c,null,rest);
+		});
+	}
+}
+tink_io_std_OutputSink.__name__ = "tink.io.std.OutputSink";
+tink_io_std_OutputSink.__super__ = tink_io_SinkBase;
+Object.assign(tink_io_std_OutputSink.prototype, {
+	__class__: tink_io_std_OutputSink
+});
+class tink_streams_IdealStream {
+	static promiseOfIdealStream(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static promiseOfStreamNoise(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static collect(this1) {
+		let buf = [];
+		return tink_core_Future.map(this1.forEach(tink_streams_Handler.ofSafeSync(function(x) {
+			buf.push(x);
+			return tink_streams_Handled.Resume;
+		})),function(c) {
+			return buf;
+		});
+	}
+}
+class tink_streams_IdealStreamBase extends tink_streams_StreamBase {
+	constructor() {
+		super();
+	}
+	idealize(rescue) {
+		return this;
+	}
+}
+tink_streams_IdealStreamBase.__name__ = "tink.streams.IdealStreamBase";
+tink_streams_IdealStreamBase.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_IdealStreamBase.prototype, {
+	__class__: tink_streams_IdealStreamBase
+});
+class tink_streams_RealStream {
+	static promiseOfIdealStream(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static promiseOfStreamNoise(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static promiseOfRealStream(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static promiseOfStreamError(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static collect(this1) {
+		let buf = [];
+		return tink_core_Future.map(this1.forEach(tink_streams_Handler.ofSafeSync(function(x) {
+			buf.push(x);
+			return tink_streams_Handled.Resume;
+		})),function(c) {
+			switch(c._hx_index) {
+			case 0:
+				let _g = c.rest;
+				throw haxe_Exception.thrown("unreachable");
+			case 2:
+				let e = c.error;
+				return tink_core_Outcome.Failure(e);
+			case 3:
+				return tink_core_Outcome.Success(buf);
+			}
+		});
+	}
+}
+class tink_streams_Stream {
+	static get_depleted(this1) {
+		return this1.get_depleted();
+	}
+	static dirty(this1) {
+		return this1;
+	}
+	static single(i) {
+		return new tink_streams_Single(new tink_core__$Lazy_LazyConst(i));
+	}
+	static ofIterator(i) {
+		let next = null;
+		next = function(step) {
+			step(i.hasNext() ? tink_streams_Step.Link(i.next(),tink_streams_Generator.stream(next)) : tink_streams_Step.End);
+		};
+		return tink_streams_Generator.stream(next);
+	}
+	static flatten(stream) {
+		return stream.regroup(tink_streams_Regrouper.ofIgnoranceSync(function(arr) {
+			return tink_streams_RegroupResult.Converted(arr[0]);
+		}));
+	}
+	static future(f) {
+		return new tink_streams_FutureStream(f);
+	}
+	static promiseIdeal(f) {
+		return tink_streams_Stream.promise(f);
+	}
+	static promiseReal(f) {
+		return tink_streams_Stream.promise(f);
+	}
+	static promise(f) {
+		return tink_streams_Stream.future(tink_core_Future.map(f,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let s = o.data;
+				return tink_streams_Stream.dirty(s);
+			case 1:
+				let e = o.failure;
+				return tink_streams_Stream.ofError(e);
+			}
+		}));
+	}
+	static ofError(e) {
+		return new tink_streams__$Stream_ErrorStream(e);
+	}
+}
+var tink_streams_RegroupStatus = $hxEnums["tink.streams.RegroupStatus"] = { __ename__:true,__constructs__:null
+	,Flowing: {_hx_name:"Flowing",_hx_index:0,__enum__:"tink.streams.RegroupStatus",toString:$estr}
+	,Errored: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.streams.RegroupStatus",toString:$estr}; },$_._hx_name="Errored",$_.__params__ = ["e"],$_)
+	,Ended: {_hx_name:"Ended",_hx_index:2,__enum__:"tink.streams.RegroupStatus",toString:$estr}
+};
+tink_streams_RegroupStatus.__constructs__ = [tink_streams_RegroupStatus.Flowing,tink_streams_RegroupStatus.Errored,tink_streams_RegroupStatus.Ended];
+var tink_streams_RegroupResult = $hxEnums["tink.streams.RegroupResult"] = { __ename__:true,__constructs__:null
+	,Converted: ($_=function(data,untouched) { return {_hx_index:0,data:data,untouched:untouched,__enum__:"tink.streams.RegroupResult",toString:$estr}; },$_._hx_name="Converted",$_.__params__ = ["data","untouched"],$_)
+	,Terminated: ($_=function(data) { return {_hx_index:1,data:data,__enum__:"tink.streams.RegroupResult",toString:$estr}; },$_._hx_name="Terminated",$_.__params__ = ["data"],$_)
+	,Untouched: {_hx_name:"Untouched",_hx_index:2,__enum__:"tink.streams.RegroupResult",toString:$estr}
+	,Errored: ($_=function(e) { return {_hx_index:3,e:e,__enum__:"tink.streams.RegroupResult",toString:$estr}; },$_._hx_name="Errored",$_.__params__ = ["e"],$_)
+};
+tink_streams_RegroupResult.__constructs__ = [tink_streams_RegroupResult.Converted,tink_streams_RegroupResult.Terminated,tink_streams_RegroupResult.Untouched,tink_streams_RegroupResult.Errored];
+class tink_streams_Regrouper {
+	static ofIgnorance(f) {
+		return { apply : function(i,_) {
+			return f(i);
+		}};
+	}
+	static ofIgnoranceSync(f) {
+		return { apply : function(i,_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(i)));
+		}};
+	}
+	static ofFunc(f) {
+		return { apply : f};
+	}
+	static ofFuncSync(f) {
+		return { apply : function(i,s) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(i,s)));
+		}};
+	}
+}
+class tink_streams__$Stream_CompoundStream extends tink_streams_StreamBase {
+	constructor(parts) {
+		super();
+		this.parts = parts;
+	}
+	get_depleted() {
+		switch(this.parts.length) {
+		case 0:
+			return true;
+		case 1:
+			return this.parts[0].get_depleted();
+		default:
+			return false;
+		}
+	}
+	next() {
+		let _gthis = this;
+		if(this.parts.length == 0) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.End));
+		} else {
+			return tink_core_Future.flatMap(this.parts[0].next(),function(v) {
+				switch(v._hx_index) {
+				case 0:
+					let v1 = v.value;
+					let rest = v.next;
+					let copy = _gthis.parts.slice();
+					copy[0] = rest;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.Link(v1,new tink_streams__$Stream_CompoundStream(copy))));
+				case 2:
+					if(_gthis.parts.length > 1) {
+						return _gthis.parts[1].next();
+					} else {
+						return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+					}
+					break;
+				default:
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+				}
+			});
+		}
+	}
+	decompose(into) {
+		let _g = 0;
+		let _g1 = this.parts;
+		while(_g < _g1.length) {
+			let p = _g1[_g];
+			++_g;
+			p.decompose(into);
+		}
+	}
+	forEach(handler) {
+		let parts = this.parts;
+		let handler1 = handler;
+		return tink_core_Future.async(function(cb) {
+			tink_streams__$Stream_CompoundStream.consumeParts(parts,handler1,cb);
+		});
+	}
+	static consumeParts(parts,handler,cb) {
+		if(parts.length == 0) {
+			cb(tink_streams_Conclusion.Depleted);
+		} else {
+			parts[0].forEach(handler).handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let rest = o.rest;
+					parts = parts.slice();
+					parts[0] = rest;
+					cb(tink_streams_Conclusion.Halted(new tink_streams__$Stream_CompoundStream(parts)));
+					break;
+				case 1:
+					let e = o.error;
+					let at = o.at;
+					if(at.get_depleted()) {
+						parts = parts.slice(1);
+					} else {
+						parts = parts.slice();
+						parts[0] = at;
+					}
+					cb(tink_streams_Conclusion.Clogged(e,new tink_streams__$Stream_CompoundStream(parts)));
+					break;
+				case 2:
+					let e1 = o.error;
+					cb(tink_streams_Conclusion.Failed(e1));
+					break;
+				case 3:
+					tink_streams__$Stream_CompoundStream.consumeParts(parts.slice(1),handler,cb);
+					break;
+				}
+			});
+		}
+	}
+	static of(streams) {
+		let ret = [];
+		let _g = 0;
+		while(_g < streams.length) {
+			let s = streams[_g];
+			++_g;
+			s.decompose(ret);
+		}
+		if(ret.length == 0) {
+			return tink_streams_Empty.inst;
+		} else {
+			return new tink_streams__$Stream_CompoundStream(ret);
+		}
+	}
+}
+tink_streams__$Stream_CompoundStream.__name__ = "tink.streams._Stream.CompoundStream";
+tink_streams__$Stream_CompoundStream.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams__$Stream_CompoundStream.prototype, {
+	__class__: tink_streams__$Stream_CompoundStream
+});
+class tink_streams__$Stream_RegroupStream extends tink_streams__$Stream_CompoundStream {
+	constructor(source,f,prev,buf) {
+		if(prev == null) {
+			prev = tink_streams_Empty.inst;
+		}
+		if(buf == null) {
+			buf = [];
+		}
+		let ret = null;
+		let terminated = false;
+		let next = tink_streams_Stream.future(tink_core_Future.map(source.forEach(tink_streams_Handler.ofUnknown(function(item) {
+			buf.push(item);
+			return tink_core_Future.map(f.apply(buf,tink_streams_RegroupStatus.Flowing),function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let v = o.data;
+					let untouched = o.untouched;
+					ret = v;
+					buf = untouched;
+					return tink_streams_Handled.Finish;
+				case 1:
+					let v1 = o.data;
+					let l = new tink_core__$Lazy_LazyFunc(tink_streams_Empty.make);
+					if(v1._hx_index == 0) {
+						let v = v1.v;
+						ret = v;
+					} else {
+						ret = tink_core_Lazy.get(l);
+					}
+					terminated = true;
+					return tink_streams_Handled.Finish;
+				case 2:
+					return tink_streams_Handled.Resume;
+				case 3:
+					let e = o.e;
+					return tink_streams_Handled.Clog(e);
+				}
+			});
+		})),function(o) {
+			switch(o._hx_index) {
+			case 0:
+				if(terminated) {
+					return ret;
+				} else {
+					let rest = o.rest;
+					return new tink_streams__$Stream_RegroupStream(rest,f,ret,buf);
+				}
+				break;
+			case 1:
+				let _g = o.at;
+				let e = o.error;
+				return new tink_streams__$Stream_ErrorStream(e);
+			case 2:
+				let e1 = o.error;
+				return tink_streams_Stream.ofError(e1);
+			case 3:
+				if(buf.length == 0) {
+					return tink_streams_Empty.inst;
+				} else {
+					return tink_streams_Stream.future(tink_core_Future.map(f.apply(buf,tink_streams_RegroupStatus.Ended),function(o) {
+						switch(o._hx_index) {
+						case 0:
+							let _g = o.untouched;
+							let v = o.data;
+							return v;
+						case 1:
+							let v1 = o.data;
+							let l = new tink_core__$Lazy_LazyFunc(tink_streams_Empty.make);
+							if(v1._hx_index == 0) {
+								let v = v1.v;
+								return v;
+							} else {
+								return tink_core_Lazy.get(l);
+							}
+							break;
+						case 2:
+							return tink_streams_Empty.inst;
+						case 3:
+							let e = o.e;
+							return tink_streams_Stream.ofError(e);
+						}
+					}));
+				}
+				break;
+			}
+		}));
+		super([prev,next]);
+	}
+}
+tink_streams__$Stream_RegroupStream.__name__ = "tink.streams._Stream.RegroupStream";
+tink_streams__$Stream_RegroupStream.__super__ = tink_streams__$Stream_CompoundStream;
+Object.assign(tink_streams__$Stream_RegroupStream.prototype, {
+	__class__: tink_streams__$Stream_RegroupStream
+});
+var tink_streams_Handled = $hxEnums["tink.streams.Handled"] = { __ename__:true,__constructs__:null
+	,BackOff: {_hx_name:"BackOff",_hx_index:0,__enum__:"tink.streams.Handled",toString:$estr}
+	,Finish: {_hx_name:"Finish",_hx_index:1,__enum__:"tink.streams.Handled",toString:$estr}
+	,Resume: {_hx_name:"Resume",_hx_index:2,__enum__:"tink.streams.Handled",toString:$estr}
+	,Clog: ($_=function(e) { return {_hx_index:3,e:e,__enum__:"tink.streams.Handled",toString:$estr}; },$_._hx_name="Clog",$_.__params__ = ["e"],$_)
+};
+tink_streams_Handled.__constructs__ = [tink_streams_Handled.BackOff,tink_streams_Handled.Finish,tink_streams_Handled.Resume,tink_streams_Handled.Clog];
+var tink_streams_Conclusion = $hxEnums["tink.streams.Conclusion"] = { __ename__:true,__constructs__:null
+	,Halted: ($_=function(rest) { return {_hx_index:0,rest:rest,__enum__:"tink.streams.Conclusion",toString:$estr}; },$_._hx_name="Halted",$_.__params__ = ["rest"],$_)
+	,Clogged: ($_=function(error,at) { return {_hx_index:1,error:error,at:at,__enum__:"tink.streams.Conclusion",toString:$estr}; },$_._hx_name="Clogged",$_.__params__ = ["error","at"],$_)
+	,Failed: ($_=function(error) { return {_hx_index:2,error:error,__enum__:"tink.streams.Conclusion",toString:$estr}; },$_._hx_name="Failed",$_.__params__ = ["error"],$_)
+	,Depleted: {_hx_name:"Depleted",_hx_index:3,__enum__:"tink.streams.Conclusion",toString:$estr}
+};
+tink_streams_Conclusion.__constructs__ = [tink_streams_Conclusion.Halted,tink_streams_Conclusion.Clogged,tink_streams_Conclusion.Failed,tink_streams_Conclusion.Depleted];
+var tink_streams_ReductionStep = $hxEnums["tink.streams.ReductionStep"] = { __ename__:true,__constructs__:null
+	,Progress: ($_=function(result) { return {_hx_index:0,result:result,__enum__:"tink.streams.ReductionStep",toString:$estr}; },$_._hx_name="Progress",$_.__params__ = ["result"],$_)
+	,Crash: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.streams.ReductionStep",toString:$estr}; },$_._hx_name="Crash",$_.__params__ = ["e"],$_)
+};
+tink_streams_ReductionStep.__constructs__ = [tink_streams_ReductionStep.Progress,tink_streams_ReductionStep.Crash];
+var tink_streams_Reduction = $hxEnums["tink.streams.Reduction"] = { __ename__:true,__constructs__:null
+	,Crashed: ($_=function(error,at) { return {_hx_index:0,error:error,at:at,__enum__:"tink.streams.Reduction",toString:$estr}; },$_._hx_name="Crashed",$_.__params__ = ["error","at"],$_)
+	,Failed: ($_=function(error) { return {_hx_index:1,error:error,__enum__:"tink.streams.Reduction",toString:$estr}; },$_._hx_name="Failed",$_.__params__ = ["error"],$_)
+	,Reduced: ($_=function(result) { return {_hx_index:2,result:result,__enum__:"tink.streams.Reduction",toString:$estr}; },$_._hx_name="Reduced",$_.__params__ = ["result"],$_)
+};
+tink_streams_Reduction.__constructs__ = [tink_streams_Reduction.Crashed,tink_streams_Reduction.Failed,tink_streams_Reduction.Reduced];
+class tink_streams__$Stream_CloggedStream extends tink_streams_StreamBase {
+	constructor(rest,error) {
+		super();
+		this.rest = rest;
+		this.error = error;
+	}
+	next() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.Fail(this.error)));
+	}
+	forEach(handler) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Conclusion.Clogged(this.error,this.rest)));
+	}
+}
+tink_streams__$Stream_CloggedStream.__name__ = "tink.streams._Stream.CloggedStream";
+tink_streams__$Stream_CloggedStream.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams__$Stream_CloggedStream.prototype, {
+	__class__: tink_streams__$Stream_CloggedStream
+});
+class tink_streams__$Stream_ErrorStream extends tink_streams_StreamBase {
+	constructor(error) {
+		super();
+		this.error = error;
+	}
+	next() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.Fail(this.error)));
+	}
+	forEach(handler) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Conclusion.Failed(this.error)));
+	}
+}
+tink_streams__$Stream_ErrorStream.__name__ = "tink.streams._Stream.ErrorStream";
+tink_streams__$Stream_ErrorStream.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams__$Stream_ErrorStream.prototype, {
+	__class__: tink_streams__$Stream_ErrorStream
+});
+class tink_streams_Mapping {
+	static _new(o) {
+		return o;
+	}
+	static ofNext(n) {
+		return { apply : function(i,_) {
+			let this1 = tink_core_Promise.next(n(i[0]),function(o) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(tink_streams_RegroupResult.Converted(tink_streams_Stream.single(o)))));
+			});
+			let f = tink_core_Recover.ofSync(tink_streams_RegroupResult.Errored);
+			return tink_core_Future.flatMap(this1,function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let d = o.data;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(d));
+				case 1:
+					let e = o.failure;
+					return f(e);
+				}
+			});
+		}};
+	}
+	static ofAsync(f) {
+		return { apply : function(i,_) {
+			return tink_core_Future.map(f(i[0]),function(o) {
+				return tink_streams_RegroupResult.Converted(tink_streams_Stream.single(o));
+			});
+		}};
+	}
+	static ofSync(f) {
+		return { apply : function(i,_) {
+			let v;
+			let _g = f(i[0]);
+			switch(_g._hx_index) {
+			case 0:
+				let v1 = _g.data;
+				v = tink_streams_RegroupResult.Converted(tink_streams_Stream.single(v1));
+				break;
+			case 1:
+				let e = _g.failure;
+				v = tink_streams_RegroupResult.Errored(e);
+				break;
+			}
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+		}};
+	}
+	static ofPlain(f) {
+		return { apply : function(i,_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_RegroupResult.Converted(tink_streams_Stream.single(f(i[0])))));
+		}};
+	}
+}
+class tink_streams_Filter {
+	static _new(o) {
+		return o;
+	}
+	static ofNext(n) {
+		return { apply : function(i,_) {
+			let this1 = tink_core_Promise.next(n(i[0]),function(matched) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(tink_streams_RegroupResult.Converted(matched ? tink_streams_Stream.single(i[0]) : tink_streams_Empty.inst))));
+			});
+			let f = tink_core_Recover.ofSync(tink_streams_RegroupResult.Errored);
+			return tink_core_Future.flatMap(this1,function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let d = o.data;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(d));
+				case 1:
+					let e = o.failure;
+					return f(e);
+				}
+			});
+		}};
+	}
+	static ofAsync(f) {
+		return { apply : function(i,_) {
+			return tink_core_Future.map(f(i[0]),function(matched) {
+				return tink_streams_RegroupResult.Converted(matched ? tink_streams_Stream.single(i[0]) : tink_streams_Empty.inst);
+			});
+		}};
+	}
+	static ofSync(f) {
+		return { apply : function(i,_) {
+			let v;
+			let _g = f(i[0]);
+			switch(_g._hx_index) {
+			case 0:
+				let v1 = _g.data;
+				v = tink_streams_RegroupResult.Converted(v1 ? tink_streams_Stream.single(i[0]) : tink_streams_Empty.inst);
+				break;
+			case 1:
+				let e = _g.failure;
+				v = tink_streams_RegroupResult.Errored(e);
+				break;
+			}
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+		}};
+	}
+	static ofPlain(f) {
+		return { apply : function(i,_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_RegroupResult.Converted(f(i[0]) ? tink_streams_Stream.single(i[0]) : tink_streams_Empty.inst)));
+		}};
+	}
+}
+class tink_streams_IdealizeStream extends tink_streams_IdealStreamBase {
+	constructor(target,rescue) {
+		super();
+		this.target = target;
+		this.rescue = rescue;
+	}
+	get_depleted() {
+		return this.target.get_depleted();
+	}
+	next() {
+		let _gthis = this;
+		return tink_core_Future.flatMap(this.target.next(),function(v) {
+			if(v._hx_index == 1) {
+				let e = v.e;
+				return _gthis.rescue(e).idealize(_gthis.rescue).next();
+			} else {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+			}
+		});
+	}
+	forEach(handler) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			_gthis.target.forEach(handler).handle(function(end) {
+				switch(end._hx_index) {
+				case 0:
+					let rest = end.rest;
+					cb(tink_streams_Conclusion.Halted(rest.idealize(_gthis.rescue)));
+					break;
+				case 1:
+					let e = end.error;
+					let at = end.at;
+					cb(tink_streams_Conclusion.Clogged(e,at.idealize(_gthis.rescue)));
+					break;
+				case 2:
+					let e1 = end.error;
+					_gthis.rescue(e1).idealize(_gthis.rescue).forEach(handler).handle(cb);
+					break;
+				case 3:
+					cb(tink_streams_Conclusion.Depleted);
+					break;
+				}
+			});
+		});
+	}
+}
+tink_streams_IdealizeStream.__name__ = "tink.streams.IdealizeStream";
+tink_streams_IdealizeStream.__super__ = tink_streams_IdealStreamBase;
+Object.assign(tink_streams_IdealizeStream.prototype, {
+	__class__: tink_streams_IdealizeStream
+});
+class tink_streams_Single extends tink_streams_StreamBase {
+	constructor(value) {
+		super();
+		this.value = value;
+	}
+	next() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.Link(tink_core_Lazy.get(this.value),tink_streams_Empty.inst)));
+	}
+	forEach(handle) {
+		let _gthis = this;
+		return tink_core_Future.map(handle(tink_core_Lazy.get(this.value)),function(step) {
+			switch(step._hx_index) {
+			case 0:
+				return tink_streams_Conclusion.Halted(_gthis);
+			case 1:
+				return tink_streams_Conclusion.Halted(tink_streams_Empty.inst);
+			case 2:
+				return tink_streams_Conclusion.Depleted;
+			case 3:
+				let e = step.e;
+				return tink_streams_Conclusion.Clogged(e,_gthis);
+			}
+		});
+	}
+}
+tink_streams_Single.__name__ = "tink.streams.Single";
+tink_streams_Single.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_Single.prototype, {
+	__class__: tink_streams_Single
+});
+class tink_streams_Handler {
+	static _new(f) {
+		return f;
+	}
+	static apply(this1,item) {
+		return this1(item);
+	}
+	static ofSafeSync(f) {
+		return function(i) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(i)));
+		};
+	}
+	static ofUnknownSync(f) {
+		return function(i) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(i)));
+		};
+	}
+	static ofSafe(f) {
+		return f;
+	}
+	static ofUnknown(f) {
+		return f;
+	}
+}
+class tink_streams_Reducer {
+	static _new(f) {
+		return f;
+	}
+	static apply(this1,res,item) {
+		return this1(res,item);
+	}
+	static ofSafeSync(f) {
+		return function(res,cur) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(res,cur)));
+		};
+	}
+	static ofUnknownSync(f) {
+		return function(res,cur) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(res,cur)));
+		};
+	}
+	static ofSafe(f) {
+		return f;
+	}
+	static ofPlainSync(f) {
+		return function(res,cur) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_ReductionStep.Progress(f(res,cur))));
+		};
+	}
+	static ofUnknown(f) {
+		return f;
+	}
+	static ofPromiseBased(f) {
+		return function(res,cur) {
+			return tink_core_Future.map(f(res,cur),function(s) {
+				switch(s._hx_index) {
+				case 0:
+					let r = s.data;
+					return tink_streams_ReductionStep.Progress(r);
+				case 1:
+					let e = s.failure;
+					return tink_streams_ReductionStep.Crash(e);
+				}
+			});
+		};
+	}
+}
+class tink_streams_FutureStream extends tink_streams_StreamBase {
+	constructor(f) {
+		super();
+		this.f = f;
+	}
+	next() {
+		return tink_core_Future.flatMap(this.f,function(s) {
+			return s.next();
+		});
+	}
+	forEach(handler) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			_gthis.f.handle(function(s) {
+				s.forEach(handler).handle(cb);
+			});
+		});
+	}
+}
+tink_streams_FutureStream.__name__ = "tink.streams.FutureStream";
+tink_streams_FutureStream.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_FutureStream.prototype, {
+	__class__: tink_streams_FutureStream
+});
+class tink_streams_BlendStream extends tink_streams_Generator {
+	constructor(a,b) {
+		let first = null;
+		let wait = function(s) {
+			return tink_core_Future.map(s.next(),function(o) {
+				if(first == null) {
+					first = s;
+				}
+				return o;
+			});
+		};
+		let n1 = wait(a);
+		let n2 = wait(b);
+		super(tink_core_Future.async(function(cb) {
+			tink_core_Future.first(n1,n2).handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let item = o.value;
+					let rest = o.next;
+					cb(tink_streams_Step.Link(item,new tink_streams_BlendStream(rest,first == a ? b : a)));
+					break;
+				case 1:
+					let e = o.e;
+					cb(tink_streams_Step.Fail(e));
+					break;
+				case 2:
+					(first == a ? n2 : n1).handle(cb);
+					break;
+				}
+			});
+		}));
+	}
+}
+tink_streams_BlendStream.__name__ = "tink.streams.BlendStream";
+tink_streams_BlendStream.__super__ = tink_streams_Generator;
+Object.assign(tink_streams_BlendStream.prototype, {
+	__class__: tink_streams_BlendStream
+});
+var tink_streams_Step = $hxEnums["tink.streams.Step"] = { __ename__:true,__constructs__:null
+	,Link: ($_=function(value,next) { return {_hx_index:0,value:value,next:next,__enum__:"tink.streams.Step",toString:$estr}; },$_._hx_name="Link",$_.__params__ = ["value","next"],$_)
+	,Fail: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.streams.Step",toString:$estr}; },$_._hx_name="Fail",$_.__params__ = ["e"],$_)
+	,End: {_hx_name:"End",_hx_index:2,__enum__:"tink.streams.Step",toString:$estr}
+};
+tink_streams_Step.__constructs__ = [tink_streams_Step.Link,tink_streams_Step.Fail,tink_streams_Step.End];
+class tink_streams_SignalStream extends tink_streams_Generator {
+	constructor(signal) {
+		let this1 = tink_core_Future.map(tink_core_Signal.nextTime(signal),function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let data = o.data;
+				return tink_streams_Step.Link(data,new tink_streams_SignalStream(signal));
+			case 1:
+				let e = o.e;
+				return tink_streams_Step.Fail(e);
+			case 2:
+				return tink_streams_Step.End;
+			}
+		});
+		this1.eager();
+		super(this1);
+	}
+}
+tink_streams_SignalStream.__name__ = "tink.streams.SignalStream";
+tink_streams_SignalStream.__super__ = tink_streams_Generator;
+Object.assign(tink_streams_SignalStream.prototype, {
+	__class__: tink_streams_SignalStream
+});
+var tink_streams_Yield = $hxEnums["tink.streams.Yield"] = { __ename__:true,__constructs__:null
+	,Data: ($_=function(data) { return {_hx_index:0,data:data,__enum__:"tink.streams.Yield",toString:$estr}; },$_._hx_name="Data",$_.__params__ = ["data"],$_)
+	,Fail: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.streams.Yield",toString:$estr}; },$_._hx_name="Fail",$_.__params__ = ["e"],$_)
+	,End: {_hx_name:"End",_hx_index:2,__enum__:"tink.streams.Yield",toString:$estr}
+};
+tink_streams_Yield.__constructs__ = [tink_streams_Yield.Data,tink_streams_Yield.Fail,tink_streams_Yield.End];
+class tink_url_Auth {
+	static _new(user,password) {
+		return "" + user + ":" + password;
+	}
+	static get_user(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			return this1.split(":")[0];
+		}
+	}
+	static get_password(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			return this1.split(":")[1];
+		}
+	}
+	static toString(this1) {
+		if(this1 == null) {
+			return "";
+		} else {
+			return "" + this1 + "@";
+		}
+	}
+}
+class tink_url_Host {
+	static _new(name,port) {
+		let this1;
+		if(port == null) {
+			this1 = name;
+		} else if(port > 65535 || port <= 0) {
+			throw haxe_Exception.thrown("Invalid port");
+		} else {
+			this1 = "" + name + ":" + port;
+		}
+		return this1;
+	}
+	static get_name(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			let _g = this1.split("]");
+			switch(_g.length) {
+			case 1:
+				let v = _g[0];
+				return v.split(":")[0];
+			case 2:
+				let _g1 = _g[1];
+				let v1 = _g[0];
+				return v1 + "]";
+			default:
+				throw haxe_Exception.thrown("assert");
+			}
+		}
+	}
+	static get_port(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			let _g = this1.split("]");
+			switch(_g.length) {
+			case 1:
+				let v = _g[0];
+				let _g1 = v.split(":")[1];
+				if(_g1 == null) {
+					return null;
+				} else {
+					let p = _g1;
+					return Std.parseInt(p);
+				}
+				break;
+			case 2:
+				let _g2 = _g[0];
+				let v1 = _g[1];
+				let _g3 = v1.split(":")[1];
+				if(_g3 == null) {
+					return null;
+				} else {
+					let p = _g3;
+					return Std.parseInt(p);
+				}
+				break;
+			default:
+				throw haxe_Exception.thrown("assert");
+			}
+		}
+	}
+	static toString(this1) {
+		return this1;
+	}
+}
+class tink_url_Path {
+	static parts(this1) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this1.split("/");
+		while(_g1 < _g2.length) {
+			let p = _g2[_g1];
+			++_g1;
+			if(p != "") {
+				_g.push(p);
+			}
+		}
+		return _g;
+	}
+	static get_absolute(this1) {
+		return this1.charAt(0) == "/";
+	}
+	static get_isDir(this1) {
+		return this1.charAt(this1.length - 1) == "/";
+	}
+	static _new(s) {
+		return s;
+	}
+	static join(this1,that) {
+		if(that == "") {
+			return this1;
+		} else if(that.charAt(0) == "/") {
+			return that;
+		} else if(this1.charAt(this1.length - 1) == "/") {
+			return tink_url_Path.ofString(this1 + that);
+		} else {
+			let _g = this1.lastIndexOf("/");
+			if(_g == -1) {
+				return that;
+			} else {
+				let v = _g;
+				return tink_url_Path.ofString(HxOverrides.substr(this1,0,v + 1) + (that == null ? "null" : that));
+			}
+		}
+	}
+	static ofString(s) {
+		return tink_url_Path.normalize(s);
+	}
+	static normalize(s) {
+		s = StringTools.trim(StringTools.replace(s,"\\","/"));
+		if(s == ".") {
+			return "./";
+		}
+		let isDir = s.endsWith("/..") || s.endsWith("/") || s.endsWith("/.");
+		let parts = [];
+		let isAbsolute = s.startsWith("/");
+		let up = 0;
+		let _g = 0;
+		let _g1 = s.split("/");
+		while(_g < _g1.length) {
+			let part = _g1[_g];
+			++_g;
+			let _g2 = StringTools.trim(part);
+			switch(_g2) {
+			case "":
+				break;
+			case ".":
+				break;
+			case "..":
+				if(parts.pop() == null) {
+					++up;
+				}
+				break;
+			default:
+				let v = _g2;
+				parts.push(v);
+			}
+		}
+		if(isAbsolute) {
+			parts.unshift("");
+		} else {
+			let _g = 0;
+			let _g1 = up;
+			while(_g < _g1) {
+				let i = _g++;
+				parts.unshift("..");
+			}
+		}
+		if(isDir) {
+			parts.push("");
+		}
+		return parts.join("/");
+	}
+	static toString(this1) {
+		return this1;
+	}
+}
+class tink_url_Portion {
+	static get_raw(this1) {
+		return this1;
+	}
+	static isValid(this1) {
+		if(this1 != null) {
+			try {
+				decodeURIComponent(this1.split("+").join(" "));
+				return true;
+			} catch( _g ) {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+	static _new(v) {
+		return v;
+	}
+	static stringly(this1) {
+		return tink_url_Portion.toString(this1);
+	}
+	static toString(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			try {
+				return decodeURIComponent(this1.split("+").join(" "));
+			} catch( _g ) {
+				return "";
+			}
+		}
+	}
+	static ofString(s) {
+		return s == null ? "" : encodeURIComponent(s);
+	}
+}
+class tink_url_PortionArray {
+	static toStringArray(this1) {
+		let _g = [];
+		let _g1 = 0;
+		while(_g1 < this1.length) {
+			let p = this1[_g1];
+			++_g1;
+			_g.push(tink_url_Portion.toString(p));
+		}
+		return _g;
+	}
+}
+class tink_url_Query {
+	static parse(this1) {
+		return new tink_url__$Query_QueryStringParser(this1,"&","=",0);
+	}
+	static with(this1,values) {
+		let ret = [];
+		let _g = [];
+		let key = new haxe_ds__$StringMap_StringMapKeyIterator(values.h);
+		while(key.hasNext()) {
+			let key1 = key.next();
+			_g.push(key1);
+		}
+		let insert = _g;
+		let p = new tink_url__$Query_QueryStringParser(this1,"&","=",0);
+		while(p.hasNext()) {
+			let p1 = p.next();
+			let key = tink_url_Portion.ofString(p1.name);
+			if(Object.prototype.hasOwnProperty.call(values.h,key)) {
+				let name = tink_url_Portion.ofString(p1.name);
+				let key = tink_url_Portion.ofString(p1.name);
+				ret.push(name + "=" + values.h[key]);
+				HxOverrides.remove(insert,tink_url_Portion.ofString(p1.name));
+			} else {
+				ret.push(tink_url_Portion.ofString(p1.name) + "=" + p1.value);
+			}
+		}
+		let _g1 = 0;
+		while(_g1 < insert.length) {
+			let name = insert[_g1];
+			++_g1;
+			ret.push(name + "=" + values.h[name]);
+		}
+		return ret.join("&");
+	}
+	static iterator(this1) {
+		return new tink_url__$Query_QueryStringParser(this1,"&","=",0);
+	}
+	static toMap(this1) {
+		let _g = new haxe_ds_StringMap();
+		let p = new tink_url__$Query_QueryStringParser(this1,"&","=",0);
+		while(p.hasNext()) {
+			let p1 = p.next();
+			_g.h[p1.name.toString()] = p1.value;
+		}
+		return _g;
+	}
+	static ofObj(v) {
+		let ret = [];
+		let v1 = v;
+		let _g = 0;
+		let _g1 = Reflect.fields(v1);
+		while(_g < _g1.length) {
+			let k = _g1[_g];
+			++_g;
+			ret.push(tink_url_Portion.ofString(k) + "=" + tink_url_Portion.ofString(v1[k]));
+		}
+		return ret.join("&");
+	}
+	static toString(this1) {
+		return this1;
+	}
+	static build() {
+		return [];
+	}
+	static parseString(s,sep,set,pos) {
+		if(pos == null) {
+			pos = 0;
+		}
+		if(set == null) {
+			set = "=";
+		}
+		if(sep == null) {
+			sep = "&";
+		}
+		return new tink_url__$Query_QueryStringParser(s,sep,set,pos);
+	}
+}
+class tink_url_QueryStringBuilder {
+	static _new() {
+		return [];
+	}
+	static add(this1,name,value) {
+		this1.push(name + "=" + value);
+		return this1;
+	}
+	static toString(this1,sep) {
+		if(sep == null) {
+			sep = "&";
+		}
+		return this1.join(sep);
+	}
+	static copy(this1) {
+		return this1.slice();
+	}
+}
+class tink_url__$Query_QueryStringParser {
+	constructor(s,sep,set,pos) {
+		this.s = s == null ? "" : s;
+		this.sep = sep;
+		this.set = set;
+		this.pos = pos;
+	}
+	hasNext() {
+		return this.pos < this.s.length;
+	}
+	next() {
+		let next = this.s.indexOf(this.sep,this.pos);
+		if(next == -1) {
+			next = this.s.length;
+		}
+		let split = this.s.indexOf(this.set,this.pos);
+		let start = this.pos;
+		this.pos = next + this.sep.length;
+		if(split == -1 || split > next) {
+			return new tink_core_NamedWith(tink_url_Portion.toString(tink_url__$Query_QueryStringParser.trimmedSub(this.s,start,next)),tink_url_Portion.ofString(""));
+		} else {
+			return new tink_core_NamedWith(tink_url_Portion.toString(tink_url__$Query_QueryStringParser.trimmedSub(this.s,start,split)),tink_url__$Query_QueryStringParser.trimmedSub(this.s,split + this.set.length,next));
+		}
+	}
+	static trimmedSub(s,start,end) {
+		if(start >= s.length) {
+			return "";
+		}
+		while(s.charCodeAt(start) < 33) ++start;
+		if(end < s.length - 1) {
+			while(s.charCodeAt(end - 1) < 33) --end;
+		}
+		return s.substring(start,end);
+	}
+}
+tink_url__$Query_QueryStringParser.__name__ = "tink.url._Query.QueryStringParser";
+Object.assign(tink_url__$Query_QueryStringParser.prototype, {
+	__class__: tink_url__$Query_QueryStringParser
+});
+function $getIterator(o) { if( o instanceof Array ) return new haxe_iterators_ArrayIterator(o); else return o.iterator(); }
+function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $global.$haxeUID++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = m.bind(o); o.hx__closures__[m.__id__] = f; } return f; }
+$global.$haxeUID |= 0;
+if(typeof(performance) != "undefined" ? typeof(performance.now) == "function" : false) {
+	HxOverrides.now = performance.now.bind(performance);
+}
+if( String.fromCodePoint == null ) String.fromCodePoint = function(c) { return c < 0x10000 ? String.fromCharCode(c) : String.fromCharCode((c>>10)+0xD7C0)+String.fromCharCode((c&0x3FF)+0xDC00); }
+{
+	Object.defineProperty(String.prototype,"__class__",{ value : String, enumerable : false, writable : true});
+	String.__name__ = "String";
+	Array.__name__ = "Array";
+	Date.prototype.__class__ = Date;
+	Date.__name__ = "Date";
+	var Int = { };
+	var Dynamic = { };
+	var Float = Number;
+	var Bool = Boolean;
+	var Class = { };
+	var Enum = { };
+}
+js_Boot.__toStr = ({ }).toString;
+DateTools.DAY_SHORT_NAMES = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
+DateTools.DAY_NAMES = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
+DateTools.MONTH_SHORT_NAMES = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
+DateTools.MONTH_NAMES = ["January","February","March","April","May","June","July","August","September","October","November","December"];
+Xml.Element = 0;
+Xml.PCData = 1;
+Xml.CData = 2;
+Xml.Comment = 3;
+Xml.DocType = 4;
+Xml.ProcessingInstruction = 5;
+Xml.Document = 6;
+datetime_DateTime.UNIX_EPOCH_DIFF = 62135596800.0;
+datetime_DateTime.SECONDS_IN_MINUTE = 60;
+datetime_DateTime.SECONDS_IN_HOUR = 3600;
+datetime_DateTime.SECONDS_IN_DAY = 86400;
+datetime_DateTime.SECONDS_IN_WEEK = 604800;
+datetime_DateTime.SECONDS_IN_YEAR = 31536000;
+datetime_DateTime.SECONDS_IN_LEAP_YEAR = 31622400;
+datetime_DateTime.SECONDS_IN_3_YEARS = 94608000;
+datetime_DateTime.SECONDS_IN_QUAD = 126230400.0;
+datetime_DateTime.SECONDS_IN_HALF_QUAD = 63072000.0;
+datetime_DateTime.SECONDS_IN_HALF_QUAD_LEAP = 63158400.0;
+datetime_DateTime.SECONDS_IN_3_PART_QUAD = 94694400.0;
+datetime_DateTime.SECONDS_IN_CQUAD = 12622780800.0;
+datetime_DateTime.SECONDS_IN_CENTURY = 3155673600.0;
+datetime_DateTime.SECONDS_IN_LEAP_CENTURY = 3155760000.0;
+haxe_crypto_Base64.CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+haxe_crypto_Base64.BYTES = haxe_io_Bytes.ofString(haxe_crypto_Base64.CHARS);
+haxe_crypto_Base64.URL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+haxe_crypto_Base64.URL_BYTES = haxe_io_Bytes.ofString(haxe_crypto_Base64.URL_CHARS);
+haxe_http_HttpBase._hx_skip_constructor = false;
+haxe_io_FPHelper.i64tmp = new haxe__$Int64__$_$_$Int64(0,0);
+haxe_io_FPHelper.helper = new DataView(new ArrayBuffer(8));
+haxe_xml_Parser.escapes = (function($this) {
+	var $r;
+	let h = new haxe_ds_StringMap();
+	h.h["lt"] = "<";
+	h.h["gt"] = ">";
+	h.h["amp"] = "&";
+	h.h["quot"] = "\"";
+	h.h["apos"] = "'";
+	$r = h;
+	return $r;
+}(this));
+hsluv_Hsluv.hexChars = "0123456789abcdef";
+hsluv_Hsluv.refY = 1.0;
+hsluv_Hsluv.refU = 0.19783000664283;
+hsluv_Hsluv.refV = 0.46831999493879;
+hsluv_Hsluv.kappa = 903.2962962;
+hsluv_Hsluv.epsilon = 0.0088564516;
+hsluv_Hsluv.m_r0 = 3.240969941904521;
+hsluv_Hsluv.m_r1 = -1.537383177570093;
+hsluv_Hsluv.m_r2 = -0.498610760293;
+hsluv_Hsluv.m_g0 = -0.96924363628087;
+hsluv_Hsluv.m_g1 = 1.87596750150772;
+hsluv_Hsluv.m_g2 = 0.041555057407175;
+hsluv_Hsluv.m_b0 = 0.055630079696993;
+hsluv_Hsluv.m_b1 = -0.20397695888897;
+hsluv_Hsluv.m_b2 = 1.056971514242878;
+htmlparser_CssSelector.reID = "[a-z](?:-?[_a-z0-9])*";
+htmlparser_CssSelector.reNamespacedID = htmlparser_CssSelector.reID + "(?::" + htmlparser_CssSelector.reID + ")?";
+htmlparser_CssSelector.reSelector = "(\\s*)((?:[>]\\s*)?)([.#]?)(" + htmlparser_CssSelector.reNamespacedID + "|[*])((?:\\[\\d+\\])?)";
+htmlparser_HtmlParser.SELF_CLOSING_TAGS_HTML = { img : 1, br : 1, input : 1, meta : 1, link : 1, hr : 1, base : 1, embed : 1, spacer : 1, source : 1, param : 1};
+htmlparser_HtmlParser.reID = "[a-z](?:-?[_a-z0-9])*";
+htmlparser_HtmlParser.reNamespacedID = htmlparser_HtmlParser.reID + "(?::" + htmlparser_HtmlParser.reID + ")?";
+htmlparser_HtmlParser.reCDATA = "[<]!\\[CDATA\\[[\\s\\S]*?\\]\\][>]";
+htmlparser_HtmlParser.reScript = "[<]\\s*script\\s*([^>]*)>([\\s\\S]*?)<\\s*/\\s*script\\s*>";
+htmlparser_HtmlParser.reStyle = "<\\s*style\\s*([^>]*)>([\\s\\S]*?)<\\s*/\\s*style\\s*>";
+htmlparser_HtmlParser.reElementOpen = "<\\s*(" + htmlparser_HtmlParser.reNamespacedID + ")";
+htmlparser_HtmlParser.reAttr = htmlparser_HtmlParser.reNamespacedID + "(?:\\s*=\\s*(?:'[^']*?'|\"[^\"]*?\"|[-_a-z0-9]+))?";
+htmlparser_HtmlParser.reElementEnd = "(/)?\\s*>";
+htmlparser_HtmlParser.reElementClose = "<\\s*/\\s*(" + htmlparser_HtmlParser.reNamespacedID + ")\\s*>";
+htmlparser_HtmlParser.reComment = "<!--[\\s\\S]*?-->";
+htmlparser_HtmlParser.reMain = new EReg("(" + htmlparser_HtmlParser.reCDATA + ")|(" + htmlparser_HtmlParser.reScript + ")|(" + htmlparser_HtmlParser.reStyle + ")|(" + htmlparser_HtmlParser.reElementOpen + "((?:\\s+" + htmlparser_HtmlParser.reAttr + ")*)\\s*" + htmlparser_HtmlParser.reElementEnd + ")|(" + htmlparser_HtmlParser.reElementClose + ")|(" + htmlparser_HtmlParser.reComment + ")","ig");
+htmlparser_HtmlParser.reParseAttrs = new EReg("(" + htmlparser_HtmlParser.reNamespacedID + ")(?:\\s*=\\s*('[^']*'|\"[^\"]*\"|[-_a-z0-9]+))?","ig");
+httpstatus_HttpStatusCode.Continue = 100;
+httpstatus_HttpStatusCode.SwitchingProtocols = 101;
+httpstatus_HttpStatusCode.Processing = 102;
+httpstatus_HttpStatusCode.OK = 200;
+httpstatus_HttpStatusCode.Created = 201;
+httpstatus_HttpStatusCode.Accepted = 202;
+httpstatus_HttpStatusCode.NonAuthoritativeInformation = 203;
+httpstatus_HttpStatusCode.NoContent = 204;
+httpstatus_HttpStatusCode.ResetContent = 205;
+httpstatus_HttpStatusCode.PartialContent = 206;
+httpstatus_HttpStatusCode.MultiStatus = 207;
+httpstatus_HttpStatusCode.AlreadyReported = 208;
+httpstatus_HttpStatusCode.IMUsed = 226;
+httpstatus_HttpStatusCode.MultipleChoices = 300;
+httpstatus_HttpStatusCode.MovedPermanently = 301;
+httpstatus_HttpStatusCode.Found = 302;
+httpstatus_HttpStatusCode.SeeOther = 303;
+httpstatus_HttpStatusCode.NotModified = 304;
+httpstatus_HttpStatusCode.UseProxy = 305;
+httpstatus_HttpStatusCode.SwitchProxy = 306;
+httpstatus_HttpStatusCode.TemporaryRedirect = 307;
+httpstatus_HttpStatusCode.PermanentRedirect = 308;
+httpstatus_HttpStatusCode.BadRequest = 400;
+httpstatus_HttpStatusCode.Unauthorized = 401;
+httpstatus_HttpStatusCode.PaymentRequired = 402;
+httpstatus_HttpStatusCode.Forbidden = 403;
+httpstatus_HttpStatusCode.NotFound = 404;
+httpstatus_HttpStatusCode.MethodNotAllowed = 405;
+httpstatus_HttpStatusCode.NotAcceptable = 406;
+httpstatus_HttpStatusCode.ProxyAuthenticationRequired = 407;
+httpstatus_HttpStatusCode.RequestTimeout = 408;
+httpstatus_HttpStatusCode.Conflict = 409;
+httpstatus_HttpStatusCode.Gone = 410;
+httpstatus_HttpStatusCode.LengthRequired = 411;
+httpstatus_HttpStatusCode.PreconditionFailed = 412;
+httpstatus_HttpStatusCode.PayloadTooLarge = 413;
+httpstatus_HttpStatusCode.URITooLong = 414;
+httpstatus_HttpStatusCode.UnsupportedMediaType = 415;
+httpstatus_HttpStatusCode.RangeNotSatisfiable = 416;
+httpstatus_HttpStatusCode.ExpectationFailed = 417;
+httpstatus_HttpStatusCode.ImATeapot = 418;
+httpstatus_HttpStatusCode.MisdirectedRequest = 421;
+httpstatus_HttpStatusCode.UnprocessableEntity = 422;
+httpstatus_HttpStatusCode.Locked = 423;
+httpstatus_HttpStatusCode.FailedDependency = 424;
+httpstatus_HttpStatusCode.UpgradeRequired = 426;
+httpstatus_HttpStatusCode.PreconditionRequired = 428;
+httpstatus_HttpStatusCode.TooManyRequests = 429;
+httpstatus_HttpStatusCode.RequestHeaderFieldsTooLarge = 431;
+httpstatus_HttpStatusCode.UnavailableForLegalReasons = 451;
+httpstatus_HttpStatusCode.InternalServerError = 500;
+httpstatus_HttpStatusCode.NotImplemented = 501;
+httpstatus_HttpStatusCode.BadGateway = 502;
+httpstatus_HttpStatusCode.ServiceUnavailable = 503;
+httpstatus_HttpStatusCode.GatewayTimeout = 504;
+httpstatus_HttpStatusCode.HTTPVersionNotSupported = 505;
+httpstatus_HttpStatusCode.VariantAlsoNegotiates = 506;
+httpstatus_HttpStatusCode.InsufficientStorage = 507;
+httpstatus_HttpStatusCode.LoopDetected = 508;
+httpstatus_HttpStatusCode.NotExtended = 510;
+httpstatus_HttpStatusCode.NetworkAuthenticationRequired = 511;
+hx_strings_Char.CHAR_CASE_MAPPER = new hx_strings__$Char_CharCaseMapper();
+hx_strings_Char.BACKSPACE = 8;
+hx_strings_Char.TAB = 9;
+hx_strings_Char.LF = 10;
+hx_strings_Char.CR = 13;
+hx_strings_Char.ESC = 27;
+hx_strings_Char.SPACE = 32;
+hx_strings_Char.EXCLAMATION_MARK = 33;
+hx_strings_Char.DOUBLE_QUOTE = 34;
+hx_strings_Char.HASH = 35;
+hx_strings_Char.DOLLAR = 36;
+hx_strings_Char.AMPERSAND = 38;
+hx_strings_Char.SINGLE_QUOTE = 39;
+hx_strings_Char.BRACKET_ROUND_LEFT = 40;
+hx_strings_Char.BRACKET_ROUND_RIGHT = 41;
+hx_strings_Char.ASTERISK = 42;
+hx_strings_Char.PLUS = 43;
+hx_strings_Char.COMMA = 44;
+hx_strings_Char.MINUS = 45;
+hx_strings_Char.DOT = 46;
+hx_strings_Char.SLASH = 47;
+hx_strings_Char.ZERO = 48;
+hx_strings_Char.ONE = 49;
+hx_strings_Char.TWO = 50;
+hx_strings_Char.TRHEE = 51;
+hx_strings_Char.FOUR = 52;
+hx_strings_Char.FIVE = 53;
+hx_strings_Char.SIX = 54;
+hx_strings_Char.SEVEN = 55;
+hx_strings_Char.EIGHT = 56;
+hx_strings_Char.NINE = 57;
+hx_strings_Char.COLON = 58;
+hx_strings_Char.SEMICOLON = 59;
+hx_strings_Char.LOWER_THAN = 60;
+hx_strings_Char.EQUALS = 61;
+hx_strings_Char.GREATER_THAN = 62;
+hx_strings_Char.QUESTION_MARK = 63;
+hx_strings_Char.BRACKET_SQUARE_LEFT = 91;
+hx_strings_Char.BACKSLASH = 92;
+hx_strings_Char.BRACKET_SQUARE_RIGHT = 93;
+hx_strings_Char.CARET = 94;
+hx_strings_Char.UNDERSCORE = 95;
+hx_strings_Char.BRACKET_CURLY_LEFT = 123;
+hx_strings_Char.PIPE = 124;
+hx_strings_Char.BRACKET_CURLY_RIGHT = 125;
+hx_strings_CharIterator._hx_skip_constructor = false;
+hx_strings__$CharIterator_NullCharIterator.INSTANCE = new hx_strings__$CharIterator_NullCharIterator();
+hx_strings_Pattern.__meta__ = { obj : { immutable : null, threadSafe : null}};
+hx_strings_Matcher.__meta__ = { obj : { notThreadSafe : null}};
+hx_strings_internal_OS.isNodeJS = (typeof process !== 'undefined') && (typeof process.release !== 'undefined') && (process.release.name === 'node');
+hx_strings_internal_OS.isWindows = (function($this) {
+	var $r;
+	let os = hx_strings_internal_OS.isNodeJS ? process.platform : $global.navigator.platform;
+	$r = new EReg("win","i").match(os);
+	return $r;
+}(this));
+hx_strings_Strings.REGEX_ANSI_ESC = hx_strings_Pattern.compile(String.fromCodePoint(27) + "\\[[;\\d]*m",hx_strings_internal__$Either3__$Either3.b("g"));
+hx_strings_Strings.REGEX_HTML_UNESCAPE = hx_strings_Pattern.compile("&(#\\d+|amp|nbsp|apos|lt|gt|quot);",hx_strings_internal__$Either3__$Either3.b("g"));
+hx_strings_Strings.REGEX_SPLIT_LINES = hx_strings_Pattern.compile("\\r?\\n",hx_strings_internal__$Either3__$Either3.b("g"));
+hx_strings_Strings.REGEX_REMOVE_XML_TAGS = hx_strings_Pattern.compile("<[!a-zA-Z\\/][^>]*>",hx_strings_internal__$Either3__$Either3.b("g"));
+hx_strings_Strings.POS_NOT_FOUND = -1;
+hx_strings_Strings.NEW_LINE_NIX = "\n";
+hx_strings_Strings.NEW_LINE_WIN = "\r\n";
+hx_strings_Strings.NEW_LINE = hx_strings_internal_OS.isWindows ? "\r\n" : "\n";
+hx_strings_RandomStrings.DIGITS = hx_strings_Strings.toChars("0123456789");
+hx_strings_RandomStrings.ASCII_ALPHA = hx_strings_RandomStrings._genAsciiAlpha();
+hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC = hx_strings_RandomStrings.DIGITS.concat(hx_strings_RandomStrings.ASCII_ALPHA);
+hx_strings_RandomStrings.MAX_INT = 2147483647;
+hx_strings_StringBuilder.__meta__ = { obj : { notThreadSafe : null}};
+sha_Hash._hx_skip_constructor = false;
+var sha_SHA256_K = [1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998];
+snikket_Autolink.__meta__ = { statics : { GOOD_IRI_CHAR : { Deprecated : null}}};
+snikket_Autolink.IANA_TOP_LEVEL_DOMAINS = "(?:" + "(?:aaa|aarp|abb|abbott|abogado|academy|accenture|accountant|accountants|aco|active" + "|actor|ads|adult|aeg|aero|afl|agency|aig|airforce|airtel|allfinanz|alsace|amica|amsterdam" + "|android|apartments|app|apple|aquarelle|aramco|archi|army|arpa|arte|asia|associates" + "|attorney|auction|audio|auto|autos|axa|azure|a[cdefgilmoqrstuwxz])" + "|(?:band|bank|bar|barcelona|barclaycard|barclays|bargains|bauhaus|bayern|bbc|bbva" + "|bcn|beats|beer|bentley|berlin|best|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black" + "|blackfriday|bloomberg|blue|bms|bmw|bnl|bnpparibas|boats|bom|bond|boo|boots|boutique" + "|bradesco|bridgestone|broadway|broker|brother|brussels|budapest|build|builders|business" + "|buzz|bzh|b[abdefghijmnorstvwyz])" + "|(?:cab|cafe|cal|camera|camp|cancerresearch|canon|capetown|capital|car|caravan|cards" + "|care|career|careers|cars|cartier|casa|cash|casino|cat|catering|cba|cbn|ceb|center|ceo" + "|cern|cfa|cfd|chanel|channel|chat|cheap|chloe|christmas|chrome|church|cipriani|cisco" + "|citic|city|cityeats|claims|cleaning|click|clinic|clothing|cloud|club|clubmed|coach" + "|codes|coffee|college|cologne|com|commbank|community|company|computer|comsec|condos" + "|construction|consulting|contractors|cooking|cool|coop|corsica|country|coupons|courses" + "|credit|creditcard|creditunion|cricket|crown|crs|cruises|csc|cuisinella|cymru|cyou|c[acdfghiklmnoruvwxyz])" + "|(?:dabur|dad|dance|date|dating|datsun|day|dclk|deals|degree|delivery|dell|delta" + "|democrat|dental|dentist|desi|design|dev|diamonds|diet|digital|direct|directory|discount" + "|dnp|docs|dog|doha|domains|doosan|download|drive|durban|dvag|d[ejkmoz])" + "|(?:earth|eat|edu|education|email|emerck|energy|engineer|engineering|enterprises" + "|epson|equipment|erni|esq|estate|eurovision|eus|events|everbank|exchange|expert|exposed" + "|express|e[cegrstu])" + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|fashion|feedback|ferrero|film" + "|final|finance|financial|firmdale|fish|fishing|fit|fitness|flights|florist|flowers|flsmidth" + "|fly|foo|football|forex|forsale|forum|foundation|frl|frogans|fund|furniture|futbol|fyi" + "|f[ijkmor])" + "|(?:gal|gallery|game|garden|gbiz|gdn|gea|gent|genting|ggee|gift|gifts|gives|giving" + "|glass|gle|global|globo|gmail|gmo|gmx|gold|goldpoint|golf|goo|goog|google|gop|gov|grainger" + "|graphics|gratis|green|gripe|group|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])" + "|(?:hamburg|hangout|haus|healthcare|help|here|hermes|hiphop|hitachi|hiv|hockey|holdings" + "|holiday|homedepot|homes|honda|horse|host|hosting|hoteles|hotmail|house|how|hsbc|hyundai" + "|h[kmnrtu])" + "|(?:ibm|icbc|ice|icu|ifm|iinet|immo|immobilien|industries|infiniti|info|ing|ink|institute" + "|insure|int|international|investments|ipiranga|irish|ist|istanbul|itau|iwc|i[delmnoqrst])" + "|(?:jaguar|java|jcb|jetzt|jewelry|jlc|jll|jobs|joburg|jprs|juegos|j[emop])" + "|(?:kaufen|kddi|kia|kim|kinder|kitchen|kiwi|koeln|komatsu|krd|kred|kyoto|k[eghimnprwyz])" + "|(?:lacaixa|lancaster|land|landrover|lasalle|lat|latrobe|law|lawyer|lds|lease|leclerc" + "|legal|lexus|lgbt|liaison|lidl|life|lifestyle|lighting|limited|limo|linde|link|live" + "|lixil|loan|loans|lol|london|lotte|lotto|love|ltd|ltda|lupin|luxe|luxury|l[abcikrstuvy])" + "|(?:madrid|maif|maison|man|management|mango|market|marketing|markets|marriott|mba" + "|media|meet|melbourne|meme|memorial|men|menu|meo|miami|microsoft|mil|mini|mma|mobi|moda" + "|moe|moi|mom|monash|money|montblanc|mormon|mortgage|moscow|motorcycles|mov|movie|movistar" + "|mtn|mtpc|mtr|museum|mutuelle|m[acdeghklmnopqrstuvwxyz])" + "|(?:nadex|nagoya|name|navy|nec|net|netbank|network|neustar|new|news|nexus|ngo|nhk" + "|nico|ninja|nissan|nokia|nra|nrw|ntt|nyc|n[acefgilopruz])" + "|(?:obi|office|okinawa|omega|one|ong|onl|online|ooo|oracle|orange|org|organic|osaka" + "|otsuka|ovh|om)" + "|(?:page|panerai|paris|partners|parts|party|pet|pharmacy|philips|photo|photography" + "|photos|physio|piaget|pics|pictet|pictures|ping|pink|pizza|place|play|playstation|plumbing" + "|plus|pohl|poker|porn|post|praxi|press|pro|prod|productions|prof|properties|property" + "|protection|pub|p[aefghklmnrstwy])" + "|(?:qpon|quebec|qa)" + "|(?:racing|realtor|realty|recipes|red|redstone|rehab|reise|reisen|reit|ren|rent|rentals" + "|repair|report|republican|rest|restaurant|review|reviews|rich|ricoh|rio|rip|rocher|rocks" + "|rodeo|rsvp|ruhr|run|rwe|ryukyu|r[eosuw])" + "|(?:saarland|sakura|sale|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|saxo" + "|sbs|sca|scb|schmidt|scholarships|school|schule|schwarz|science|scor|scot|seat|security" + "|seek|sener|services|seven|sew|sex|sexy|shiksha|shoes|show|shriram|singles|site|ski" + "|sky|skype|sncf|soccer|social|software|sohu|solar|solutions|sony|soy|space|spiegel|spreadbetting" + "|srl|stada|starhub|statoil|stc|stcgroup|stockholm|studio|study|style|sucks|supplies" + "|supply|support|surf|surgery|suzuki|swatch|swiss|sydney|systems|s[abcdeghijklmnortuvxyz])" + "|(?:tab|taipei|tatamotors|tatar|tattoo|tax|taxi|team|tech|technology|tel|telefonica" + "|temasek|tennis|thd|theater|theatre|tickets|tienda|tips|tires|tirol|today|tokyo|tools" + "|top|toray|toshiba|tours|town|toyota|toys|trade|trading|training|travel|trust|tui|t[cdfghjklmnortvwz])" + "|(?:ubs|university|uno|uol|u[agksyz])" + "|(?:vacations|vana|vegas|ventures|versicherung|vet|viajes|video|villas|vin|virgin" + "|vision|vista|vistaprint|viva|vlaanderen|vodka|vote|voting|voto|voyage|v[aceginu])" + "|(?:wales|walter|wang|watch|webcam|website|wed|wedding|weir|whoswho|wien|wiki|williamhill" + "|win|windows|wine|wme|work|works|world|wtc|wtf|w[fs])" + "|(?:ελ|бел|дети|ком|мкд" + "|мон|москва|онлайн" + "|орг|рус|рф|сайт|срб" + "|укр|қаз|հայ|קום|ارامكو" + "|الاردن|الجزائر|السعودية" + "|المغرب|امارات|ایران" + "|بازار|بھارت|تونس" + "|سودان|سورية|شبكة" + "|عراق|عمان|فلسطين" + "|قطر|كوم|مصر|مليسيا" + "|موقع|कॉम|नेट|भारत" + "|संगठन|ভারত|ਭਾਰਤ|ભારત" + "|இந்தியா|இலங்கை|சிங்கப்பூர்" + "|భారత్|ලංකා|คอม|ไทย" + "|გე|みんな|グーグル|コム|世界" + "|中信|中国|中國|中文网|企业|佛山" + "|信息|健康|八卦|公司|公益|台湾|台灣" + "|商城|商店|商标|在线|大拿|娱乐|工行" + "|广东|慈善|我爱你|手机|政务|政府" + "|新加坡|新闻|时尚|机构|淡马锡|游戏" + "|点看|移动|组织机构|网址|网店|网络" + "|谷歌|集团|飞利浦|餐厅|香港|닷넷" + "|닷컴|삼성|한국|xbox" + "|xerox|xin|xn\\-\\-11b4c3d|xn\\-\\-1qqw23a|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g" + "|xn\\-\\-3e0b707e|xn\\-\\-3pxu8k|xn\\-\\-42c2d9a|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4gbrim" + "|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks" + "|xn\\-\\-80ao21a|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-90a3ac|xn\\-\\-90ais|xn\\-\\-9dbq2a" + "|xn\\-\\-9et52u|xn\\-\\-b4w605ferd|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd" + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-efvy88h" + "|xn\\-\\-estv75g|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s" + "|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-gecrj9c" + "|xn\\-\\-h2brj9c|xn\\-\\-hxt814e|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i" + "|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d" + "|xn\\-\\-kput3i|xn\\-\\-l1acc|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgb9awbf|xn\\-\\-mgba3a3ejt" + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e" + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbpl2fh|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab" + "|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema" + "|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh" + "|xn\\-\\-pssy2u|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-s9brj9c" + "|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb" + "|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv|xn\\-\\-vuq861b|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a" + "|xn\\-\\-xhq521b|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-y9a3aq|xn\\-\\-yfro4i67o" + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xperia|xxx|xyz)" + "|(?:yachts|yamaxun|yandex|yodobashi|yoga|yokohama|youtube|y[et])" + "|(?:zara|zip|zone|zuerich|z[amw]))";
+snikket_Autolink.GOOD_IRI_CHAR = "a-zA-Z0-9 -퟿豈-﷏ﷰ-￯";
+snikket_Autolink.IP_ADDRESS = "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + "|[1-9][0-9]|[0-9]))";
+snikket_Autolink.IP6_ADDRESS = "\\[" + "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" + "([0-9a-fA-F]{1,4}:){1,7}:|" + "([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" + "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" + "([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" + "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" + "([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" + "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" + ":((:[0-9a-fA-F]{1,4}){1,7}|:)|" + "fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" + "::(ffff(:0{1,4}){0,1}:){0,1}" + "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}" + "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|" + "([0-9a-fA-F]{1,4}:){1,4}:" + "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}" + "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))" + "\\]";
+snikket_Autolink.UCS_CHAR = "[" + "\\u00A0-\\uD7FF" + "\\uF900-\\uFDCF" + "\\uFDF0-\\uFFEF";
+snikket_Autolink.LABEL_CHAR = "a-zA-Z0-9" + snikket_Autolink.UCS_CHAR;
+snikket_Autolink.TLD_CHAR = "a-zA-Z" + snikket_Autolink.UCS_CHAR;
+snikket_Autolink.IRI_LABEL = "[" + snikket_Autolink.LABEL_CHAR + "](?:[" + snikket_Autolink.LABEL_CHAR + "\\-]{0,61}[" + snikket_Autolink.LABEL_CHAR + "]){0,1}";
+snikket_Autolink.PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w";
+snikket_Autolink.TLD = "(" + snikket_Autolink.PUNYCODE_TLD + "|" + "[" + snikket_Autolink.TLD_CHAR + "]{2,63}" + ")";
+snikket_Autolink.HOST_NAME = "(" + snikket_Autolink.IRI_LABEL + "\\.)+" + snikket_Autolink.TLD;
+snikket_Autolink.PROTOCOL = "(?:http|https|rtsp):\\/\\/";
+snikket_Autolink.WORD_BOUNDARY = "(?:\\b|$|^)";
+snikket_Autolink.USER_INFO = "(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@";
+snikket_Autolink.PORT_NUMBER = "\\:\\d{1,5}";
+snikket_Autolink.PATH_CHAR = "(?:(?:[" + snikket_Autolink.LABEL_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_\\$])|(?:\\%[a-fA-F0-9]{2}))";
+snikket_Autolink.PATH_AND_QUERY = "\\/" + snikket_Autolink.PATH_CHAR + "*";
+snikket_Autolink.STRICT_TLD = "(?:" + snikket_Autolink.IANA_TOP_LEVEL_DOMAINS + "|" + snikket_Autolink.PUNYCODE_TLD + ")";
+snikket_Autolink.STRICT_HOST_NAME = "(?:(?:" + snikket_Autolink.IRI_LABEL + "\\.)+" + snikket_Autolink.STRICT_TLD + ")";
+snikket_Autolink.STRICT_DOMAIN_NAME = "(?:" + snikket_Autolink.STRICT_HOST_NAME + "|" + snikket_Autolink.IP_ADDRESS + "|" + snikket_Autolink.IP6_ADDRESS + ")";
+snikket_Autolink.RELAXED_DOMAIN_NAME = "(?:" + "(?:" + snikket_Autolink.IRI_LABEL + "(?:\\.(?=\\S))" + "?)+" + "|" + snikket_Autolink.IP_ADDRESS + "|" + snikket_Autolink.IP6_ADDRESS + ")";
+snikket_Autolink.WEB_URL_WITHOUT_PROTOCOL = "(" + snikket_Autolink.WORD_BOUNDARY + "(?<!:\\/\\/)" + "(" + "(?:" + snikket_Autolink.STRICT_DOMAIN_NAME + ")" + "(?:" + snikket_Autolink.PORT_NUMBER + ")?" + ")" + "(?:" + snikket_Autolink.PATH_AND_QUERY + ")?" + ")";
+snikket_Autolink.WEB_URL_WITH_PROTOCOL = "(" + snikket_Autolink.WORD_BOUNDARY + "(?:" + "(?:" + snikket_Autolink.PROTOCOL + "(?:" + snikket_Autolink.USER_INFO + ")?" + ")" + "(?:" + snikket_Autolink.RELAXED_DOMAIN_NAME + ")?" + "(?:" + snikket_Autolink.PORT_NUMBER + ")?" + ")" + "(?:" + snikket_Autolink.PATH_AND_QUERY + ")?" + ")";
+snikket_Autolink.AUTOLINK_WEB_URL = "(" + snikket_Autolink.WEB_URL_WITH_PROTOCOL + "|" + snikket_Autolink.WEB_URL_WITHOUT_PROTOCOL + ")" + snikket_Autolink.WORD_BOUNDARY;
+snikket_Autolink.TEL_URI = "tel:(?:(?:\\+\\d+)|(?:\\d+;phone-context=" + snikket_Autolink.PATH_CHAR + "+))";
+snikket_Autolink.SMS_URI = "sms:(?:(?:\\+\\d+)|(?:\\d+;phone-context=" + snikket_Autolink.PATH_CHAR + "+))";
+snikket_Autolink.XMPP_URI = "xmpp\\:(?:(?:[" + snikket_Autolink.GOOD_IRI_CHAR + "\\;\\/\\?\\@\\&\\=\\#\\~\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])" + "|(?:\\%[a-fA-F0-9]{2}))+";
+snikket_Chat._hx_skip_constructor = false;
+snikket_Chat.__meta__ = { fields : { addMedia : { 'HaxeCBridge.noemit' : null}}};
+snikket_DirectChat.__meta__ = { fields : { getParticipants : { 'HaxeCBridge.noemit' : null}, getParticipantDetails : { 'HaxeCBridge.noemit' : null}, getMessagesBefore : { 'HaxeCBridge.noemit' : null}, getMessagesAfter : { 'HaxeCBridge.noemit' : null}, getMessagesAround : { 'HaxeCBridge.noemit' : null}, correctMessage : { 'HaxeCBridge.noemit' : null}, sendMessage : { 'HaxeCBridge.noemit' : null}, removeReaction : { 'HaxeCBridge.noemit' : null}, lastMessageId : { 'HaxeCBridge.noemit' : null}, markReadUpTo : { 'HaxeCBridge.noemit' : null}, bookmark : { 'HaxeCBridge.noemit' : null}, close : { 'HaxeCBridge.noemit' : null}}};
+snikket_Channel.__meta__ = { fields : { getParticipants : { 'HaxeCBridge.noemit' : null}, getParticipantDetails : { 'HaxeCBridge.noemit' : null}, getMessagesBefore : { 'HaxeCBridge.noemit' : null}, getMessagesAfter : { 'HaxeCBridge.noemit' : null}, getMessagesAround : { 'HaxeCBridge.noemit' : null}, correctMessage : { 'HaxeCBridge.noemit' : null}, sendMessage : { 'HaxeCBridge.noemit' : null}, removeReaction : { 'HaxeCBridge.noemit' : null}, lastMessageId : { 'HaxeCBridge.noemit' : null}, markReadUpTo : { 'HaxeCBridge.noemit' : null}, bookmark : { 'HaxeCBridge.noemit' : null}, close : { 'HaxeCBridge.noemit' : null}}};
+snikket_ChatMessage.__meta__ = { fields : { reactions : { 'HaxeCBridge.noemit' : null}}};
+snikket_ChatMessageBuilder.__meta__ = { fields : { reactions : { 'HaxeCBridge.noemit' : null}}};
+snikket_EventEmitter._hx_skip_constructor = false;
+snikket_Config.relativeHashUri = false;
+snikket_EmojiUtil.MISC_SYMBOLS_AND_PICTOGRAPHS = new snikket_UnicodeRange(127744,128511);
+snikket_EmojiUtil.SUPPLEMENTAL_SYMBOLS = new snikket_UnicodeRange(129280,129535);
+snikket_EmojiUtil.EMOTICONS = new snikket_UnicodeRange(128512,129782);
+snikket_EmojiUtil.MISC_SYMBOLS = new snikket_UnicodeRange(9728,9983);
+snikket_EmojiUtil.DINGBATS = new snikket_UnicodeRange(9984,10175);
+snikket_EmojiUtil.ENCLOSED_ALPHANUMERIC_SUPPLEMENT = new snikket_UnicodeRange(127232,127487);
+snikket_EmojiUtil.ENCLOSED_IDEOGRAPHIC_SUPPLEMENT = new snikket_UnicodeRange(127488,127743);
+snikket_EmojiUtil.REGIONAL_INDICATORS = new snikket_UnicodeRange(127462,127487);
+snikket_EmojiUtil.GEOMETRIC_SHAPES = new snikket_UnicodeRange(9632,9727);
+snikket_EmojiUtil.LATIN_SUPPLEMENT = new snikket_UnicodeRange(128,255);
+snikket_EmojiUtil.MISC_TECHNICAL = new snikket_UnicodeRange(8960,9215);
+snikket_EmojiUtil.TAGS = new snikket_UnicodeRange(917536,917631);
+snikket_EmojiUtil.CYK_SYMBOLS_AND_PUNCTUATION = new snikket_UnicodeList(12336,12349);
+snikket_EmojiUtil.LETTERLIKE_SYMBOLS = new snikket_UnicodeList(8482,8505);
+snikket_EmojiUtil.KEYCAP_COMBINEABLE = new snikket_UnicodeBlocks(new snikket_UnicodeList(35),new snikket_UnicodeList(42),new snikket_UnicodeRange(48,57));
+snikket_EmojiUtil.SYMBOLIZE = new snikket_UnicodeBlocks(snikket_EmojiUtil.GEOMETRIC_SHAPES,snikket_EmojiUtil.LATIN_SUPPLEMENT,snikket_EmojiUtil.CYK_SYMBOLS_AND_PUNCTUATION,snikket_EmojiUtil.LETTERLIKE_SYMBOLS,snikket_EmojiUtil.KEYCAP_COMBINEABLE);
+snikket_EmojiUtil.EMOJIS = new snikket_UnicodeBlocks(snikket_EmojiUtil.MISC_SYMBOLS_AND_PICTOGRAPHS,snikket_EmojiUtil.SUPPLEMENTAL_SYMBOLS,snikket_EmojiUtil.EMOTICONS,snikket_EmojiUtil.MISC_SYMBOLS,snikket_EmojiUtil.DINGBATS,snikket_EmojiUtil.ENCLOSED_ALPHANUMERIC_SUPPLEMENT,snikket_EmojiUtil.ENCLOSED_IDEOGRAPHIC_SUPPLEMENT,snikket_EmojiUtil.MISC_TECHNICAL);
+snikket_EmojiUtil.MAX_EMOIJS = 42;
+snikket_EmojiUtil.ZWJ = 8205;
+snikket_EmojiUtil.VARIATION_16 = 65039;
+snikket_EmojiUtil.COMBINING_ENCLOSING_KEYCAP = 8419;
+snikket_EmojiUtil.BLACK_FLAG = 127988;
+snikket_EmojiUtil.FITZPATRICK = new snikket_UnicodeRange(127995,127999);
+snikket_Persistence.__meta__ = { fields : { getChatsUnreadDetails : { 'HaxeCBridge.noemit' : null}, findServicesWithFeature : { 'HaxeCBridge.noemit' : null}}};
+snikket_Version.HUMAN = "cf378ac";
+snikket_persistence_Dummy.__meta__ = { fields : { lastId : { 'HaxeCBridge.noemit' : null}, storeChats : { 'HaxeCBridge.noemit' : null}, getChats : { 'HaxeCBridge.noemit' : null}, storeMessages : { 'HaxeCBridge.noemit' : null}, updateMessage : { 'HaxeCBridge.noemit' : null}, getMessage : { 'HaxeCBridge.noemit' : null}, getMessagesBefore : { 'HaxeCBridge.noemit' : null}, getMessagesAfter : { 'HaxeCBridge.noemit' : null}, getMessagesAround : { 'HaxeCBridge.noemit' : null}, getChatsUnreadDetails : { 'HaxeCBridge.noemit' : null}, storeReaction : { 'HaxeCBridge.noemit' : null}, updateMessageStatus : { 'HaxeCBridge.noemit' : null}, getMediaUri : { 'HaxeCBridge.noemit' : null}, hasMedia : { 'HaxeCBridge.noemit' : null}, storeMedia : { 'HaxeCBridge.noemit' : null}, removeMedia : { 'HaxeCBridge.noemit' : null}, storeCaps : { 'HaxeCBridge.noemit' : null}, getCaps : { 'HaxeCBridge.noemit' : null}, storeLogin : { 'HaxeCBridge.noemit' : null}, getLogin : { 'HaxeCBridge.noemit' : null}, removeAccount : { 'HaxeCBridge.noemit' : null}, storeStreamManagement : { 'HaxeCBridge.noemit' : null}, getStreamManagement : { 'HaxeCBridge.noemit' : null}, storeService : { 'HaxeCBridge.noemit' : null}, findServicesWithFeature : { 'HaxeCBridge.noemit' : null}}};
+snikket_persistence_Sqlite.__meta__ = { fields : { get : { 'HaxeCBridge.noemit' : null}, set : { 'HaxeCBridge.noemit' : null}, lastId : { 'HaxeCBridge.noemit' : null}, storeChats : { 'HaxeCBridge.noemit' : null}, getChats : { 'HaxeCBridge.noemit' : null}, storeMessages : { 'HaxeCBridge.noemit' : null}, updateMessage : { 'HaxeCBridge.noemit' : null}, getMessagesBefore : { 'HaxeCBridge.noemit' : null}, getMessagesAfter : { 'HaxeCBridge.noemit' : null}, getMessagesAround : { 'HaxeCBridge.noemit' : null}, getChatsUnreadDetails : { 'HaxeCBridge.noemit' : null}, storeReaction : { 'HaxeCBridge.noemit' : null}, updateMessageStatus : { 'HaxeCBridge.noemit' : null}, hasMedia : { 'HaxeCBridge.noemit' : null}, removeMedia : { 'HaxeCBridge.noemit' : null}, storeMedia : { 'HaxeCBridge.noemit' : null}, storeCaps : { 'HaxeCBridge.noemit' : null}, getCaps : { 'HaxeCBridge.noemit' : null}, storeLogin : { 'HaxeCBridge.noemit' : null}, getLogin : { 'HaxeCBridge.noemit' : null}, removeAccount : { 'HaxeCBridge.noemit' : null}, storeStreamManagement : { 'HaxeCBridge.noemit' : null}, getStreamManagement : { 'HaxeCBridge.noemit' : null}, storeService : { 'HaxeCBridge.noemit' : null}, findServicesWithFeature : { 'HaxeCBridge.noemit' : null}}};
+snikket_queries_GenericQuery._hx_skip_constructor = false;
+thenshim_Promise.factory = new thenshim_js_JSPromiseFactory();
+tink__$Chunk_EmptyChunk.EMPTY = new haxe_io_Bytes(new ArrayBuffer(0));
+tink_Chunk.EMPTY = new tink__$Chunk_EmptyChunk();
+tink_Stringly.SUPPORTED_DATE_REGEX = new EReg("^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})(\\.\\d{3})?(Z|[\\+-]\\d{2}:\\d{2})$","");
+tink_Url.SCHEME = 2;
+tink_Url.PAYLOAD = 3;
+tink_Url.AUTH = 6;
+tink_Url.HOSTNAMES = 7;
+tink_Url.PATH = 8;
+tink_Url.QUERY = 10;
+tink_Url.HASH = 12;
+tink_core_Callback.depth = 0;
+tink_core_Callback.MAX_DEPTH = 500;
+tink_core_SimpleDisposable._hx_skip_constructor = false;
+tink_core_AlreadyDisposed.INST = new tink_core_AlreadyDisposed();
+tink_core__$Future_FutureObject._hx_skip_constructor = false;
+tink_core_Future.NOISE = new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(null));
+tink_core_Future.NEVER_INST = new tink_core__$Future_FutureObject();
+tink_core_Future.NEVER = tink_core_Future.NEVER_INST;
+tink_core_Lazy.NOISE = new tink_core__$Lazy_LazyConst(null);
+tink_core_Lazy.NULL = tink_core_Lazy.NOISE;
+tink_core_Noise.Noise = null;
+tink_core_ProgressValue.ZERO = new tink_core_MPair(0,haxe_ds_Option.None);
+tink_core_Progress.INIT = tink_core_ProgressValue.ZERO;
+tink_core__$Progress_ProgressObject._hx_skip_constructor = false;
+tink_core_Promise.NOISE = new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(null)));
+tink_core_Promise.NEVER = tink_core_Promise.never();
+tink_core__$Signal_Disposed.INST = new tink_core__$Signal_Disposed();
+tink_http_ChunkedParser.LINEBREAK = tink_chunk_Seekable.ofBytes(haxe_io_Bytes.ofString("\r\n"));
+tink_http_Fetch.cache = new haxe_ds_EnumValueMap();
+tink_http_Header._hx_skip_constructor = false;
+tink_http_HeaderValue.DAYS = "Sun,Mon,Tue,Wen,Thu,Fri,Sat".split(",");
+tink_http_HeaderValue.MONTHS = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(",");
+tink_http_HeaderName.REFERER = "referer";
+tink_http_HeaderName.HOST = "host";
+tink_http_HeaderName.SET_COOKIE = "set-cookie";
+tink_http_HeaderName.COOKIE = "cookie";
+tink_http_HeaderName.CONTENT_TYPE = "content-type";
+tink_http_HeaderName.CONTENT_LENGTH = "content-length";
+tink_http_HeaderName.CONTENT_DISPOSITION = "content-disposition";
+tink_http_HeaderName.CONTENT_RANGE = "content-range";
+tink_http_HeaderName.ACCEPT = "accept";
+tink_http_HeaderName.ACCEPT_ENCODING = "accept-encoding";
+tink_http_HeaderName.TRANSFER_ENCODING = "transfer-encoding";
+tink_http_HeaderName.RANGE = "range";
+tink_http_HeaderName.LOCATION = "location";
+tink_http_HeaderName.AUTHORIZATION = "authorization";
+tink_http_HeaderName.ORIGIN = "origin";
+tink_http_HeaderName.VARY = "vary";
+tink_http_HeaderName.CACHE_CONTROL = "cache-control";
+tink_http_HeaderName.EXPIRES = "expires";
+tink_http_HeaderName.ACCESS_CONTROL_REQUEST_METHOD = "access-control-request-method";
+tink_http_HeaderName.ACCESS_CONTROL_REQUEST_HEADERS = "access-control-request-headers";
+tink_http_HeaderName.ACCESS_CONTROL_ALLOW_ORIGIN = "access-control-allow-origin";
+tink_http_HeaderName.ACCESS_CONTROL_ALLOW_CREDENTIALS = "access-control-allow-credentials";
+tink_http_HeaderName.ACCESS_CONTROL_EXPOSE_HEADERS = "access-control-expose-headers";
+tink_http_HeaderName.ACCESS_CONTROL_MAX_AGE = "access-control-max-age";
+tink_http_HeaderName.ACCESS_CONTROL_ALLOW_METHODS = "access-control-allow-methods";
+tink_http_HeaderName.ACCESS_CONTROL_ALLOW_HEADERS = "access-control-allow-headers";
+tink_http_HeaderParser.INVALID = tink_io_ParseStep.Failed(new tink_core_TypedError(422,"Invalid HTTP header",{ fileName : "tink/http/Header.hx", lineNumber : 310, className : "tink.http.HeaderParser", methodName : "INVALID"}));
+tink_http_Message._hx_skip_constructor = false;
+tink_http_Method.GET = "GET";
+tink_http_Method.HEAD = "HEAD";
+tink_http_Method.OPTIONS = "OPTIONS";
+tink_http_Method.POST = "POST";
+tink_http_Method.PUT = "PUT";
+tink_http_Method.PATCH = "PATCH";
+tink_http_Method.DELETE = "DELETE";
+tink_io__$Sink_Blackhole.inst = new tink_io__$Sink_Blackhole();
+tink_io_SinkYielding.BLACKHOLE = tink_io__$Sink_Blackhole.inst;
+tink_streams_StreamBase._hx_skip_constructor = false;
+tink_streams_Empty.inst = new tink_streams_Empty();
+tink_io_Source.EMPTY = tink_streams_Empty.inst;
+tink_io_Worker.EAGER = new tink_io__$Worker_EagerWorker();
+tink_io_Worker.pool = [tink_io_Worker.EAGER];
+tink_url_Path.root = "/";
+})(typeof exports != "undefined" ? exports : typeof window != "undefined" ? window : typeof self != "undefined" ? self : this, typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this);
+export const snikket = exports.snikket;
diff --git a/npm/snikket-enums.d.ts b/npm/snikket-enums.d.ts
new file mode 100644
index 0000000..c0d9160
--- /dev/null
+++ b/npm/snikket-enums.d.ts
@@ -0,0 +1,54 @@
+ 
+export declare namespace snikket {
+    const enum UiState {
+        Pinned = 0,
+        Open = 1,
+        Closed = 2
+    }
+}
+export declare namespace snikket {
+    const enum MessageDirection {
+        MessageReceived = 0,
+        MessageSent = 1
+    }
+}
+export declare namespace snikket {
+    const enum MessageStatus {
+        MessagePending = 0,
+        MessageDeliveredToServer = 1,
+        MessageDeliveredToDevice = 2,
+        MessageFailedToSend = 3
+    }
+}
+export declare namespace snikket {
+    const enum MessageType {
+        MessageChat = 0,
+        MessageCall = 1,
+        MessageChannel = 2,
+        MessageChannelPrivate = 3
+    }
+}
+export declare namespace snikket {
+    const enum UserState {
+        Gone = 0,
+        Inactive = 1,
+        Active = 2,
+        Composing = 3,
+        Paused = 4
+    }
+}
+export declare namespace snikket {
+    const enum ChatMessageEvent {
+        DeliveryEvent = 0,
+        CorrectionEvent = 1,
+        ReactionEvent = 2,
+        StatusEvent = 3
+    }
+}
+export declare namespace snikket {
+    const enum ReactionUpdateKind {
+        EmojiReactions = 0,
+        AppendReactions = 1,
+        CompleteReactions = 2
+    }
+}
diff --git a/npm/snikket-enums.js b/npm/snikket-enums.js
new file mode 100644
index 0000000..1940e30
--- /dev/null
+++ b/npm/snikket-enums.js
@@ -0,0 +1,62 @@
+/* tslint:disable */ // Generated by Haxe TypeScript Declaration Generator :)
+export var snikket;
+(function (snikket) {
+    let UiState;
+    (function (UiState) {
+        UiState[UiState["Pinned"] = 0] = "Pinned";
+        UiState[UiState["Open"] = 1] = "Open";
+        UiState[UiState["Closed"] = 2] = "Closed";
+    })(UiState = snikket.UiState || (snikket.UiState = {}));
+})(snikket || (snikket = {}));
+(function (snikket) {
+    let MessageDirection;
+    (function (MessageDirection) {
+        MessageDirection[MessageDirection["MessageReceived"] = 0] = "MessageReceived";
+        MessageDirection[MessageDirection["MessageSent"] = 1] = "MessageSent";
+    })(MessageDirection = snikket.MessageDirection || (snikket.MessageDirection = {}));
+})(snikket || (snikket = {}));
+(function (snikket) {
+    let MessageStatus;
+    (function (MessageStatus) {
+        MessageStatus[MessageStatus["MessagePending"] = 0] = "MessagePending";
+        MessageStatus[MessageStatus["MessageDeliveredToServer"] = 1] = "MessageDeliveredToServer";
+        MessageStatus[MessageStatus["MessageDeliveredToDevice"] = 2] = "MessageDeliveredToDevice";
+        MessageStatus[MessageStatus["MessageFailedToSend"] = 3] = "MessageFailedToSend";
+    })(MessageStatus = snikket.MessageStatus || (snikket.MessageStatus = {}));
+})(snikket || (snikket = {}));
+(function (snikket) {
+    let MessageType;
+    (function (MessageType) {
+        MessageType[MessageType["MessageChat"] = 0] = "MessageChat";
+        MessageType[MessageType["MessageCall"] = 1] = "MessageCall";
+        MessageType[MessageType["MessageChannel"] = 2] = "MessageChannel";
+        MessageType[MessageType["MessageChannelPrivate"] = 3] = "MessageChannelPrivate";
+    })(MessageType = snikket.MessageType || (snikket.MessageType = {}));
+})(snikket || (snikket = {}));
+(function (snikket) {
+    let UserState;
+    (function (UserState) {
+        UserState[UserState["Gone"] = 0] = "Gone";
+        UserState[UserState["Inactive"] = 1] = "Inactive";
+        UserState[UserState["Active"] = 2] = "Active";
+        UserState[UserState["Composing"] = 3] = "Composing";
+        UserState[UserState["Paused"] = 4] = "Paused";
+    })(UserState = snikket.UserState || (snikket.UserState = {}));
+})(snikket || (snikket = {}));
+(function (snikket) {
+    let ChatMessageEvent;
+    (function (ChatMessageEvent) {
+        ChatMessageEvent[ChatMessageEvent["DeliveryEvent"] = 0] = "DeliveryEvent";
+        ChatMessageEvent[ChatMessageEvent["CorrectionEvent"] = 1] = "CorrectionEvent";
+        ChatMessageEvent[ChatMessageEvent["ReactionEvent"] = 2] = "ReactionEvent";
+        ChatMessageEvent[ChatMessageEvent["StatusEvent"] = 3] = "StatusEvent";
+    })(ChatMessageEvent = snikket.ChatMessageEvent || (snikket.ChatMessageEvent = {}));
+})(snikket || (snikket = {}));
+(function (snikket) {
+    let ReactionUpdateKind;
+    (function (ReactionUpdateKind) {
+        ReactionUpdateKind[ReactionUpdateKind["EmojiReactions"] = 0] = "EmojiReactions";
+        ReactionUpdateKind[ReactionUpdateKind["AppendReactions"] = 1] = "AppendReactions";
+        ReactionUpdateKind[ReactionUpdateKind["CompleteReactions"] = 2] = "CompleteReactions";
+    })(ReactionUpdateKind = snikket.ReactionUpdateKind || (snikket.ReactionUpdateKind = {}));
+})(snikket || (snikket = {}));
diff --git a/npm/snikket-enums.ts b/npm/snikket-enums.ts
new file mode 100644
index 0000000..0f094be
--- /dev/null
+++ b/npm/snikket-enums.ts
@@ -0,0 +1,61 @@
+/* tslint:disable */// Generated by Haxe TypeScript Declaration Generator :)
+
+export namespace snikket {
+	export const enum UiState {
+		Pinned = 0,
+		Open = 1,
+		Closed = 2,
+	}
+}
+
+export namespace snikket {
+	export const enum MessageDirection {
+		MessageReceived = 0,
+		MessageSent = 1,
+	}
+}
+
+export namespace snikket {
+	export const enum MessageStatus {
+		MessagePending = 0,
+		MessageDeliveredToServer = 1,
+		MessageDeliveredToDevice = 2,
+		MessageFailedToSend = 3,
+	}
+}
+
+export namespace snikket {
+	export const enum MessageType {
+		MessageChat = 0,
+		MessageCall = 1,
+		MessageChannel = 2,
+		MessageChannelPrivate = 3,
+	}
+}
+
+export namespace snikket {
+	export const enum UserState {
+		Gone = 0,
+		Inactive = 1,
+		Active = 2,
+		Composing = 3,
+		Paused = 4,
+	}
+}
+
+export namespace snikket {
+	export const enum ChatMessageEvent {
+		DeliveryEvent = 0,
+		CorrectionEvent = 1,
+		ReactionEvent = 2,
+		StatusEvent = 3,
+	}
+}
+
+export namespace snikket {
+	export const enum ReactionUpdateKind {
+		EmojiReactions = 0,
+		AppendReactions = 1,
+		CompleteReactions = 2,
+	}
+}
\ No newline at end of file
diff --git a/npm/snikket.d.ts b/npm/snikket.d.ts
new file mode 100644
index 0000000..d99794e
--- /dev/null
+++ b/npm/snikket.d.ts
@@ -0,0 +1,1109 @@
+/* tslint:disable */// Generated by Haxe TypeScript Declaration Generator :)
+
+import { snikket as enums } from "./snikket-enums";
+
+export namespace snikket {
+	export class Caps {
+		constructor(node: string, identities: snikket.Identity[], features: string[]);
+		node: string;
+		identities: snikket.Identity[];
+		features: string[];
+		isChannel(chatId: string): boolean;
+		discoReply(): snikket.Stanza;
+		addC(stanza: snikket.Stanza): snikket.Stanza;
+		verRaw(): snikket.Hash;
+		ver(): string;
+	}
+}
+
+export namespace snikket {
+	export class Identity {
+		constructor(category: string, type: string, name: string);
+		category: string;
+		type: string;
+		name: string;
+		addToDisco(stanza: snikket.Stanza): void;
+		ver(): string;
+	}
+}
+
+export namespace snikket {
+	export class GenericStream extends snikket.EventEmitter {
+		constructor();
+		_hx_constructor(): void;
+		clientId: string;
+		readonly csi: boolean;
+		connect(jid: string, sm: ArrayBuffer): void;
+		disconnect(): void;
+		sendStanza(stanza: snikket.Stanza): void;
+		newId(): string;
+		onIq(type: any, tag: string, xmlns: string, handler: (arg0: snikket.Stanza) => any): void;
+		sendIq(stanza: snikket.Stanza, callback: (stanza: snikket.Stanza) => void): void;
+	}
+}
+
+export namespace snikket {
+	export class Chat {
+		protected constructor(client: snikket.Client, stream: snikket.GenericStream, persistence: snikket.Persistence, chatId: string, uiState?: enums.UiState, isBlocked?: boolean, extensions?: snikket.Stanza, readUpToId?: string, readUpToBy?: string);
+		/**
+		 * ID of this Chat
+		 */
+		readonly chatId: string;
+		/**
+		 * Current state of this chat
+		 */
+		readonly uiState: enums.UiState;
+		readonly isBlocked: boolean;
+		/**
+		 * Fetch a page of messages before some point
+		 * @param beforeId id of the message to look before
+		 * @param beforeTime timestamp of the message to look before,
+		 * String in format YYYY-MM-DDThh:mm:ss[.sss]+00:00
+		 * @param handler takes one argument, an array of ChatMessage that are found
+		 */
+		getMessagesBefore(beforeId: string, beforeTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		/**
+		 * Fetch a page of messages after some point
+		 * @param afterId id of the message to look after
+		 * @param afterTime timestamp of the message to look after,
+		 * String in format YYYY-MM-DDThh:mm:ss[.sss]+00:00
+		 * @param handler takes one argument, an array of ChatMessage that are found
+		 */
+		getMessagesAfter(afterId: string, afterTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		/**
+		 * Fetch a page of messages around (before, including, and after) some point
+		 * @param aroundId id of the message to look around
+		 * @param aroundTime timestamp of the message to look around,
+		 * String in format YYYY-MM-DDThh:mm:ss[.sss]+00:00
+		 * @param handler takes one argument, an array of ChatMessage that are found
+		 */
+		getMessagesAround(aroundId: string, aroundTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		/**
+		 * Send a ChatMessage to this Chat
+		 * @param message the ChatMessage to send
+		 */
+		sendMessage(message: snikket.ChatMessageBuilder): void;
+		/**
+		 * Signals that all messages up to and including this one have probably
+		 * been displayed to the user
+		 * @param message the ChatMessage most recently displayed
+		 */
+		markReadUpTo(message: snikket.ChatMessage): void;
+		/**
+		 * Save this Chat on the server
+		 */
+		bookmark(): void;
+		/**
+		 * Get the list of IDs of participants in this Chat
+		 * @returns array of IDs
+		 */
+		getParticipants(): string[];
+		/**
+		 * Get the details for one participant in this Chat
+		 * @param participantId the ID of the participant to look up
+		 */
+		getParticipantDetails(participantId: string): snikket.Participant;
+		/**
+		 * Correct an already-send message by replacing it with a new one
+		 * @param localId the localId of the message to correct
+		 * must be the localId of the first version ever sent, not a subsequent correction
+		 * @param message the new ChatMessage to replace it with
+		 */
+		correctMessage(localId: string, message: snikket.ChatMessageBuilder): void;
+		/**
+		 * Add new reaction to a message in this Chat
+		 * @param m ChatMessage to react to
+		 * @param reaction emoji of the reaction
+		 */
+		addReaction(m: snikket.ChatMessage, reaction: snikket.Reaction): void;
+		/**
+		 * Remove an already-sent reaction from a message
+		 * @param m ChatMessage to remove the reaction from
+		 * @param reaction the emoji to remove
+		 */
+		removeReaction(m: snikket.ChatMessage, reaction: snikket.Reaction): void;
+		/**
+		 * Call this whenever the user is typing, can call on every keystroke
+		 * @param threadId optional, what thread the user has selected if any
+		 * @param content optional, what the user has typed so far
+		 */
+		typing(threadId: string, content: string): void;
+		/**
+		 * Call this whenever the user makes a chat or thread "active" in your UX
+		 * If you call this with true you MUST later call it will false
+		 * @param active true if the chat is "active", false otherwise
+		 * @param threadId optional, what thread the user has selected if any
+		 */
+		setActive(active: boolean, threadId: string): void;
+		/**
+		 * Archive this chat
+		 */
+		close(): void;
+		/**
+		 * Pin or unpin this chat
+		 */
+		togglePinned(): void;
+		/**
+		 * Block this chat so it will not re-open
+		 */
+		block(reportSpam: snikket.ChatMessage, onServer: boolean): void;
+		/**
+		 * Unblock this chat so it will open again
+		 */
+		unblock(onServer: boolean): void;
+		/**
+		 * An ID of the most recent message in this chat
+		 */
+		lastMessageId(): string;
+		/**
+		 * The timestamp of the most recent message in this chat
+		 */
+		lastMessageTimestamp(): string;
+		/**
+		 * Get the URI image to represent this Chat, or null
+		 */
+		getPhoto(): string;
+		/**
+		 * Get the URI to a placeholder image to represent this Chat
+		 */
+		getPlaceholder(): string;
+		/**
+		 * An ID of the last message displayed to the user
+		 */
+		readUpTo(): string;
+		/**
+		 * The number of message that have not yet been displayed to the user
+		 */
+		unreadCount(): number;
+		/**
+		 * A preview of the chat, such as the most recent message body
+		 */
+		preview(): string;
+		setDisplayName(fn: string): void;
+		/**
+		 * The display name of this Chat
+		 */
+		getDisplayName(): string;
+		setTrusted(trusted: boolean): void;
+		/**
+		 * Is this a chat with an entity we trust to see our online status?
+		 */
+		isTrusted(): boolean;
+		syncing(): boolean;
+		/**
+		 * Can audio calls be started in this Chat?
+		 */
+		canAudioCall(): boolean;
+		/**
+		 * Can video calls be started in this Chat?
+		 */
+		canVideoCall(): boolean;
+		/**
+		 * Start a new call in this Chat
+		 * @param audio do we want audio in this call
+		 * @param video do we want video in this call
+		 */
+		startCall(audio: boolean, video: boolean): void;
+		addMedia(streams: MediaStream[]): void;
+		/**
+		 * Accept any incoming calls in this Chat
+		 */
+		acceptCall(): void;
+		/**
+		 * Hangup or reject any calls in this chat
+		 */
+		hangup(): void;
+		/**
+		 * The current status of a call in this chat
+		 */
+		callStatus(): string;
+		/**
+		 * A DTMFSender for a call in this chat, or NULL
+		 */
+		dtmf(): RTCDTMFSender;
+		/**
+		 * All video tracks in all active calls in this chat
+		 */
+		videoTracks(): MediaStreamTrack[];
+	}
+}
+
+export namespace snikket {
+	export class DirectChat extends snikket.Chat {
+		protected constructor(client: snikket.Client, stream: snikket.GenericStream, persistence: snikket.Persistence, chatId: string, uiState?: enums.UiState, isBlocked?: boolean, extensions?: snikket.Stanza, readUpToId?: string, readUpToBy?: string);
+		getParticipants(): string[];
+		getParticipantDetails(participantId: string): snikket.Participant;
+		getMessagesBefore(beforeId: string, beforeTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(afterId: string, afterTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(aroundId: string, aroundTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		correctMessage(localId: string, message: snikket.ChatMessageBuilder): void;
+		sendMessage(message: snikket.ChatMessageBuilder): void;
+		removeReaction(m: snikket.ChatMessage, reaction: snikket.Reaction): void;
+		lastMessageId(): string;
+		markReadUpTo(message: snikket.ChatMessage): void;
+		bookmark(): void;
+		close(): void;
+	}
+}
+
+export namespace snikket {
+	export class Channel extends snikket.Chat {
+		protected constructor(client: snikket.Client, stream: snikket.GenericStream, persistence: snikket.Persistence, chatId: string, uiState?: enums.UiState, isBlocked?: boolean, extensions?: snikket.Stanza, readUpToId?: string, readUpToBy?: string, disco?: snikket.Caps);
+		setPresence(resource: string, presence: snikket.Presence): void;
+		isTrusted(): boolean;
+		preview(): string;
+		syncing(): boolean;
+		canAudioCall(): boolean;
+		canVideoCall(): boolean;
+		getParticipants(): string[];
+		getParticipantDetails(participantId: string): snikket.Participant;
+		getMessagesBefore(beforeId: string, beforeTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(afterId: string, afterTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(aroundId: string, aroundTime: string, handler: (arg0: snikket.ChatMessage[]) => void): void;
+		correctMessage(localId: string, message: snikket.ChatMessageBuilder): void;
+		sendMessage(message: snikket.ChatMessageBuilder): void;
+		removeReaction(m: snikket.ChatMessage, reaction: snikket.Reaction): void;
+		lastMessageId(): string;
+		markReadUpTo(message: snikket.ChatMessage): void;
+		bookmark(): void;
+		close(): void;
+	}
+}
+
+export namespace snikket {
+	export class AvailableChat {
+		protected constructor(chatId: string, displayName: string, note: string, caps: snikket.Caps);
+		/**
+		 * The ID of the Chat this search result represents
+		 */
+		chatId: string;
+		/**
+		 * The display name of this search result
+		 */
+		displayName: string;
+		/**
+		 * A human-readable note associated with this search result
+		 */
+		note: string;
+		/**
+		 * Is this search result a channel?
+		 */
+		isChannel(): boolean;
+	}
+}
+
+export namespace snikket {
+	export class SerializedChat {
+		constructor(chatId: string, trusted: boolean, avatarSha1: ArrayBuffer, presence: Map<string,snikket.Presence>, displayName: string, uiState: enums.UiState, isBlocked: boolean, extensions: string, readUpToId: string, readUpToBy: string, disco: snikket.Caps, klass: string);
+		chatId: string;
+		trusted: boolean;
+		avatarSha1: ArrayBuffer;
+		presence: Map<string,snikket.Presence>;
+		displayName: string;
+		uiState: enums.UiState;
+		isBlocked: boolean;
+		extensions: string;
+		readUpToId: string;
+		readUpToBy: string;
+		disco: snikket.Caps;
+		klass: string;
+		toChat(client: snikket.Client, stream: snikket.GenericStream, persistence: snikket.Persistence): snikket.Chat;
+	}
+}
+
+export namespace snikket {
+	export class ChatAttachment {
+		constructor(name: string, mime: string, size: number, uris: string[], hashes: snikket.Hash[]);
+		name: string;
+		mime: string;
+		size: number;
+		uris: string[];
+		hashes: snikket.Hash[];
+	}
+}
+
+export namespace snikket {
+	export class ChatMessage {
+		protected constructor(params: {attachments?: snikket.ChatAttachment[], direction?: enums.MessageDirection, from: snikket.JID, lang?: string, localId?: string, payloads?: snikket.Stanza[], reactions?: Map<string,snikket.Reaction[]>, recipients?: snikket.JID[], replyId?: string, replyTo?: snikket.JID[], replyToMessage?: snikket.ChatMessage, senderId: string, serverId?: string, serverIdBy?: string, stanza?: snikket.Stanza, status?: enums.MessageStatus, syncPoint?: boolean, text?: string, threadId?: string, timestamp: string, to: snikket.JID, type?: enums.MessageType, versions?: snikket.ChatMessage[]});
+		/**
+		 * The ID as set by the creator of this message
+		 */
+		localId: string;
+		/**
+		 * The ID as set by the authoritative server
+		 */
+		serverId: string;
+		/**
+		 * The ID of the server which set the serverId
+		 */
+		serverIdBy: string;
+		/**
+		 * The type of this message (Chat, Call, etc)
+		 */
+		type: enums.MessageType;
+		/**
+		 * The timestamp of this message, in format YYYY-MM-DDThh:mm:ss[.sss]Z
+		 */
+		timestamp: string;
+		/**
+		 * The ID of the sender of this message
+		 */
+		senderId: string;
+		/**
+		 * Message this one is in reply to, or NULL
+		 */
+		readonly replyToMessage: snikket.ChatMessage;
+		/**
+		 * ID of the thread this message is in, or NULL
+		 */
+		threadId: string;
+		/**
+		 * Array of attachments to this message
+		 */
+		attachments: snikket.ChatAttachment[];
+		/**
+		 * Map of reactions to this message
+		 */
+		readonly reactions: Map<string,snikket.Reaction[]>;
+		/**
+		 * Body text of this message or NULL
+		 */
+		text: string;
+		/**
+		 * Language code for the body text
+		 */
+		lang: string;
+		/**
+		 * Direction of this message
+		 */
+		direction: enums.MessageDirection;
+		/**
+		 * Status of this message
+		 */
+		status: enums.MessageStatus;
+		/**
+		 * Array of past versions of this message, if it has been edited
+		 */
+		versions: snikket.ChatMessage[];
+		stanza: snikket.Stanza;
+		/**
+		 * Create a new ChatMessage in reply to this one
+		 */
+		reply(): snikket.ChatMessageBuilder;
+		getReplyId(): string;
+		/**
+		 * Get HTML version of the message body
+		 * WARNING: this is possibly untrusted HTML. You must parse or sanitize appropriately!
+		 */
+		html(): string;
+		/**
+		 * The ID of the Chat this message is associated with
+		 */
+		chatId(): string;
+		/**
+		 * The ID of the account associated with this message
+		 */
+		account(): string;
+		/**
+		 * Is this an incoming message?
+		 */
+		isIncoming(): boolean;
+		/**
+		 * The URI of an icon for the thread associated with this message, or NULL
+		 */
+		threadIcon(): string;
+		/**
+		 * The last status of the call if this message is related to a call
+		 */
+		callStatus(): string;
+		/**
+		 * The session id of the call if this message is related to a call
+		 */
+		callSid(): string;
+		/**
+		 * The duration of the call if this message is related to a call
+		 */
+		callDuration(): string;
+	}
+}
+
+export namespace snikket {
+	export class ChatMessageBuilder {
+		/**
+		 * @returns a new blank ChatMessageBuilder
+		 */
+		constructor(params?: {attachments?: snikket.ChatAttachment[], direction?: enums.MessageDirection, html?: string, lang?: string, localId?: string, payloads?: snikket.Stanza[], reactions?: Map<string,snikket.Reaction[]>, replyId?: string, replyToMessage?: snikket.ChatMessage, senderId?: string, serverId?: string, serverIdBy?: string, status?: enums.MessageStatus, syncPoint?: boolean, text?: string, threadId?: string, timestamp?: string, type?: enums.MessageType, versions?: snikket.ChatMessage[]});
+		/**
+		 * The ID as set by the creator of this message
+		 */
+		localId: string;
+		/**
+		 * The ID as set by the authoritative server
+		 */
+		serverId: string;
+		/**
+		 * The ID of the server which set the serverId
+		 */
+		serverIdBy: string;
+		/**
+		 * The type of this message (Chat, Call, etc)
+		 */
+		type: enums.MessageType;
+		/**
+		 * The timestamp of this message, in format YYYY-MM-DDThh:mm:ss[.sss]+00:00
+		 */
+		timestamp: string;
+		/**
+		 * Message this one is in reply to, or NULL
+		 */
+		replyToMessage: snikket.ChatMessage;
+		/**
+		 * ID of the thread this message is in, or NULL
+		 */
+		threadId: string;
+		/**
+		 * Array of attachments to this message
+		 */
+		readonly attachments: snikket.ChatAttachment[];
+		/**
+		 * Map of reactions to this message
+		 */
+		reactions: Map<string,snikket.Reaction[]>;
+		/**
+		 * Body text of this message or NULL
+		 */
+		text: string;
+		/**
+		 * Language code for the body text
+		 */
+		lang: string;
+		/**
+		 * Direction of this message
+		 */
+		direction: enums.MessageDirection;
+		/**
+		 * Status of this message
+		 */
+		status: enums.MessageStatus;
+		/**
+		 * Array of past versions of this message, if it has been edited
+		 */
+		readonly versions: snikket.ChatMessage[];
+		addAttachment(attachment: snikket.ChatAttachment): void;
+		/**
+		 * Set rich text using an HTML string
+		 * Also sets the plain text body appropriately
+		 */
+		setHtml(html: string): void;
+		/**
+		 * The ID of the Chat this message is associated with
+		 */
+		chatId(): string;
+		/**
+		 * The ID of the sender of this message
+		 */
+		get_senderId(): string;
+		isIncoming(): boolean;
+		build(): snikket.ChatMessage;
+	}
+}
+
+export namespace snikket {
+	export class EventHandler {
+		constructor(handlers: snikket.EventHandler[], callback: (arg0: any) => any, onlyOnce?: boolean);
+		call(data: any): any;
+		once(): snikket.EventHandler;
+		unsubscribe(): void;
+	}
+}
+
+export namespace snikket {
+	export class EventEmitter {
+		protected constructor();
+		once(eventName: string, callback: (arg0: any) => any): snikket.EventHandler;
+		trigger(eventName: string, eventData: any): any;
+	}
+}
+
+export namespace snikket.jingle {
+	export interface Session {
+		get_sid(): string;
+		accept(): void;
+		hangup(): void;
+		addMedia(streams: MediaStream[]): void;
+		callStatus(): string;
+		videoTracks(): MediaStreamTrack[];
+		dtmf(): RTCDTMFSender;
+	}
+}
+
+export namespace snikket.jingle {
+	export class Attribute {
+		constructor(key: string, value: string);
+		readonly key: string;
+		readonly value: string;
+		toSdp(): string;
+		toString(): string;
+		static parse(input: string): snikket.jingle.Attribute;
+	}
+}
+
+export namespace snikket.jingle {
+	export class Media {
+		constructor(mid: string, media: string, connectionData: string, port: string, protocol: string, attributes: snikket.jingle.Attribute[], formats: number[]);
+		readonly mid: string;
+		readonly media: string;
+		readonly connectionData: string;
+		readonly port: string;
+		readonly protocol: string;
+		readonly attributes: snikket.jingle.Attribute[];
+		readonly formats: number[];
+		toSdp(): string;
+		contentElement(initiator: boolean): snikket.Stanza;
+		toElement(sessionAttributes: snikket.jingle.Attribute[], initiator: boolean): snikket.Stanza;
+		getUfragPwd(sessionAttributes?: snikket.jingle.Attribute[]): {pwd: string, ufrag: string};
+		toTransportElement(sessionAttributes: snikket.jingle.Attribute[]): snikket.Stanza;
+		static fromElement(content: snikket.Stanza, initiator: boolean, hasGroup: boolean, existingDescription?: snikket.jingle.SessionDescription): snikket.jingle.Media;
+	}
+}
+
+export namespace snikket.jingle {
+	export class SessionDescription {
+		constructor(version: number, name: string, media: snikket.jingle.Media[], attributes: snikket.jingle.Attribute[], identificationTags: string[]);
+		readonly version: number;
+		readonly name: string;
+		readonly media: snikket.jingle.Media[];
+		readonly attributes: snikket.jingle.Attribute[];
+		readonly identificationTags: string[];
+		getUfragPwd(): {pwd: string, ufrag: string};
+		getFingerprint(): snikket.jingle.Attribute;
+		getDtlsSetup(): string;
+		addContent(newDescription: snikket.jingle.SessionDescription): snikket.jingle.SessionDescription;
+		toSdp(): string;
+		toStanza(action: string, sid: string, initiator: boolean): snikket.Stanza;
+		static parse(input: string): snikket.jingle.SessionDescription;
+		static fromStanza(iq: snikket.Stanza, initiator: boolean, existingDescription?: snikket.jingle.SessionDescription): snikket.jingle.SessionDescription;
+	}
+}
+
+export namespace snikket.jingle {
+	export class InitiatedSession implements snikket.jingle.Session {
+		protected constructor(client: snikket.Client, counterpart: snikket.JID, sid: string, remoteDescription: snikket.jingle.SessionDescription);
+		get_sid(): string;
+		accept(): void;
+		hangup(): void;
+		addMedia(streams: MediaStream[]): void;
+		callStatus(): string;
+		videoTracks(): MediaStreamTrack[];
+		dtmf(): RTCDTMFSender;
+		supplyMedia(streams: MediaStream[]): void;
+	}
+}
+
+export namespace snikket {
+	export class Client extends snikket.EventEmitter {
+		/**
+		 * Create a new Client to connect to a particular account
+		 * @param address the account to connect to
+		 * @param persistence the persistence layer to use for storage
+		 */
+		constructor(address: string, persistence: snikket.Persistence);
+		/**
+		 * Set to false to suppress sending available presence
+		 */
+		sendAvailable: boolean;
+		/**
+		 * Start this client running and trying to connect to the server
+		 */
+		start(): void;
+		/**
+		 * Destroy local data for this account
+		 * @param completely if true chats, messages, etc will be deleted as well
+		 */
+		logout(completely: boolean): void;
+		/**
+		 * Sets the password to be used in response to the password needed event
+		 * @param password
+		 */
+		usePassword(password: string): void;
+		/**
+		 * Get the account ID for this Client
+		 * @returns account id
+		 */
+		accountId(): string;
+		/**
+		 * Get the current display name for this account
+		 * @returns display name
+		 */
+		displayName(): string;
+		/**
+		 * Set the current display name for this account on the server
+		 * @param display name to set (ignored if empty or NULL)
+		 */
+		setDisplayName(displayName: string): void;
+		/**
+		 * Turn a file into a ChatAttachment for attaching to a ChatMessage
+		 */
+		prepareAttachment(source: File, callback: (arg0: snikket.ChatAttachment) => void): void;
+		/**
+		 * @returns array of open chats, sorted by last activity
+		 */
+		getChats(): snikket.Chat[];
+		/**
+		 * Search for chats the user can start or join
+		 * @param q the search query to use
+		 * @param callback takes two arguments, the query that was used and the array of results
+		 */
+		findAvailableChats(q: string, callback: (arg0: string, arg1: snikket.AvailableChat[]) => void): void;
+		/**
+		 * Start or join a chat from the search results
+		 * @returns the chat that was started
+		 */
+		startChat(availableChat: snikket.AvailableChat): snikket.Chat;
+		/**
+		 * Find a chat by id
+		 * @returns the chat if known, or NULL
+		 */
+		getChat(chatId: string): snikket.Chat;
+		subscribePush(reg: ServiceWorkerRegistration, push_service: string, vapid_key: {privateKey: CryptoKey, publicKey: CryptoKey}): void;
+		enablePush(push_service: string, vapid_private_key: CryptoKey, endpoint: string, p256dh: ArrayBuffer, auth: ArrayBuffer): void;
+		/**
+		 * Event fired when client needs a password for authentication
+		 * @param handler takes one argument, the Client that needs a password
+		 */
+		addPasswordNeededListener(handler: (arg0: snikket.Client) => void): void;
+		/**
+		 * Event fired when client is connected and fully synchronized
+		 * @param handler takes no arguments
+		 */
+		addStatusOnlineListener(handler: () => void): void;
+		/**
+		 * Event fired when client is disconnected
+		 * @param handler takes no arguments
+		 */
+		addStatusOfflineListener(handler: () => void): void;
+		/**
+		 * Event fired when connection fails with a fatal error and will not be retried
+		 * @param handler takes no arguments
+		 */
+		addConnectionFailedListener(handler: () => void): void;
+		addUserStateListener(handler: (arg0: string, arg1: string, arg2: string, arg3: enums.UserState) => void): void;
+		/**
+		 * Event fired when a new ChatMessage comes in on any Chat
+		 * Also fires when status of a ChatMessage changes,
+		 * when a ChatMessage is edited, or when a reaction is added
+		 * @param handler takes two arguments, the ChatMessage and ChatMessageEvent enum describing what happened
+		 */
+		addChatMessageListener(handler: (arg0: snikket.ChatMessage, arg1: enums.ChatMessageEvent) => void): void;
+		/**
+		 * Event fired when syncing a new ChatMessage that was send when offline.
+		 * Normally you don't want this, but it may be useful if you want to notify on app start.
+		 * @param handler takes one argument, the ChatMessage
+		 */
+		addSyncMessageListener(handler: (arg0: snikket.ChatMessage) => void): void;
+		/**
+		 * Event fired when a Chat's metadata is updated, or when a new Chat is added
+		 * @param handler takes one argument, an array of Chats that were updated
+		 */
+		addChatsUpdatedListener(handler: (arg0: snikket.Chat[]) => void): void;
+		/**
+		 * Event fired when a new call comes in
+		 * @param handler takes two arguments, the call Session and the associated Chat ID
+		 */
+		addCallRingListener(handler: (arg0: snikket.jingle.Session, arg1: string) => void): void;
+		/**
+		 * Event fired when a call is retracted or hung up
+		 * @param handler takes one argument, the associated Chat ID
+		 */
+		addCallRetractListener(handler: (arg0: string) => void): void;
+		/**
+		 * Event fired when an outgoing call starts ringing
+		 * @param handler takes one argument, the associated Chat ID
+		 */
+		addCallRingingListener(handler: (arg0: string) => void): void;
+		/**
+		 * Event fired when a call is asking for media to send
+		 * @param handler takes three arguments, the call Session,
+		 * a boolean indicating if audio is desired,
+		 * and a boolean indicating if video is desired
+		 */
+		addCallMediaListener(handler: (arg0: snikket.jingle.InitiatedSession, arg1: boolean, arg2: boolean) => void): void;
+		/**
+		 * Event fired when call has a new MediaStreamTrack to play
+		 * @param handler takes three arguments, the associated Chat ID,
+		 * the new MediaStreamTrack, and an array of any associated MediaStreams
+		 */
+		addCallTrackListener(handler: (arg0: string, arg1: MediaStreamTrack, arg2: MediaStream[]) => void): void;
+		/**
+		 * Let the SDK know the UI is in the foreground
+		 */
+		setInForeground(): void;
+		/**
+		 * Let the SDK know the UI is in the foreground
+		 */
+		setNotInForeground(): void;
+	}
+}
+
+export namespace snikket {
+	export class Config {
+		protected constructor();
+		/**
+		 * Produce /.well-known/ni/ paths instead of ni:/// URIs
+		 * for referencing media by hash.
+		 * This can be useful eg for intercepting with a Service Worker.
+		 */
+		static relativeHashUri: boolean;
+	}
+}
+
+export namespace haxe.io {
+	export class Bytes {
+		protected constructor(data: ArrayBuffer);
+		readonly length: number;
+		/**
+		 * Copies `len` bytes from `src` into this instance.
+		 * @param pos Zero-based location in `this` instance at which to start writing
+		 * bytes.
+		 * @param src Source `Bytes` instance from which to copy bytes.
+		 * @param srcpos Zero-based location at `src` from which bytes will be copied.
+		 * @param len Number of bytes to be copied.
+		 */
+		blit(pos: number, src: haxe.io.Bytes, srcpos: number, len: number): void;
+		/**
+		 * Sets `len` consecutive bytes starting from index `pos` of `this` instance
+		 * to `value`.
+		 */
+		fill(pos: number, len: number, value: number): void;
+		/**
+		 * Returns a new `Bytes` instance that contains a copy of `len` bytes of
+		 * `this` instance, starting at index `pos`.
+		 */
+		sub(pos: number, len: number): haxe.io.Bytes;
+		/**
+		 * Returns the 16-bit unsigned integer at the given position `pos` (in
+		 * little-endian encoding).
+		 */
+		getUInt16(pos: number): number;
+		/**
+		 * Returns the `len`-bytes long string stored at the given position `pos`,
+		 * interpreted with the given `encoding` (UTF-8 by default).
+		 */
+		getString(pos: number, len: number, encoding?: any): string;
+		/**
+		 * Returns a `String` representation of the bytes interpreted as UTF-8.
+		 */
+		toString(): string;
+		/**
+		 * Returns a hexadecimal `String` representation of the bytes of `this`
+		 * instance.
+		 */
+		toHex(): string;
+		/**
+		 * Returns the `Bytes` representation of the given `String`, using the
+		 * specified encoding (UTF-8 by default).
+		 */
+		static ofString(s: string, encoding?: any): haxe.io.Bytes;
+		/**
+		 * Returns the `Bytes` representation of the given `BytesData`.
+		 */
+		static ofData(b: ArrayBuffer): haxe.io.Bytes;
+		/**
+		 * Converts the given hexadecimal `String` to `Bytes`. `s` must be a string of
+		 * even length consisting only of hexadecimal digits. For example:
+		 * `"0FDA14058916052309"`.
+		 */
+		static ofHex(s: string): haxe.io.Bytes;
+	}
+}
+
+export namespace snikket {
+	export class Hash {
+		protected constructor(algorithm: string, hash: ArrayBuffer);
+		algorithm: string;
+		toUri(): string;
+		toHex(): string;
+		toBase64(): string;
+		toBase64Url(): string;
+		static fromHex(algorithm: string, hash: string): snikket.Hash;
+		static fromUri(uri: string): snikket.Hash;
+		static sha1(bytes: haxe.io.Bytes): snikket.Hash;
+		static sha256(bytes: haxe.io.Bytes): snikket.Hash;
+	}
+}
+
+export namespace snikket {
+	export class Identicon {
+		protected constructor();
+		static svg(source: string): string;
+	}
+}
+
+export namespace snikket {
+	export class JID {
+		constructor(node: string, domain: string, resource?: string);
+		node: string;
+		domain: string;
+		resource: string;
+		asBare(): snikket.JID;
+		withResource(resource: string): snikket.JID;
+		isValid(): boolean;
+		isDomain(): boolean;
+		isBare(): boolean;
+		equals(rhs: snikket.JID): boolean;
+		asString(): string;
+		static parse(jid: string): snikket.JID;
+	}
+}
+
+export namespace snikket {
+	export class Notification {
+		constructor(title: string, body: string, accountId: string, chatId: string, messageId: string, type: enums.MessageType, callStatus: string, callSid: string, imageUri: string, lang: string, timestamp: string);
+		readonly title: string;
+		readonly body: string;
+		readonly accountId: string;
+		readonly chatId: string;
+		readonly messageId: string;
+		readonly type: enums.MessageType;
+		readonly callStatus: string;
+		readonly callSid: string;
+		readonly imageUri: string;
+		readonly lang: string;
+		readonly timestamp: string;
+		static fromChatMessage(m: snikket.ChatMessage): snikket.Notification;
+		static fromThinStanza(stanza: snikket.Stanza): snikket.Notification;
+	}
+}
+
+export namespace snikket {
+	export class Participant {
+		protected constructor(displayName: string, photoUri: string, placeholderUri: string, isSelf: boolean);
+		displayName: string;
+		photoUri: string;
+		placeholderUri: string;
+		isSelf: boolean;
+	}
+}
+
+export namespace snikket {
+	export class Presence {
+		constructor(caps: snikket.Caps, mucUser: snikket.Stanza);
+		caps: snikket.Caps;
+		mucUser: snikket.Stanza;
+	}
+}
+
+export namespace snikket.Push {
+	export function receive(data: string, persistence: snikket.Persistence): snikket.Notification;
+}
+
+export namespace snikket {
+	export class Reaction {
+		constructor(senderId: string, timestamp: string, text: string, envelopeId?: string, key?: string);
+		senderId: string;
+		timestamp: string;
+		text: string;
+		key: string;
+		envelopeId: string;
+		render<T>(forText: (arg0: string) => T, forImage: (arg0: string, arg1: string) => T): T;
+	}
+}
+
+export namespace snikket {
+	export class CustomEmojiReaction extends snikket.Reaction {
+		constructor(senderId: string, timestamp: string, text: string, uri: string, envelopeId?: string);
+		uri: string;
+		render<T>(forText: (arg0: string) => T, forImage: (arg0: string, arg1: string) => T): T;
+	}
+}
+
+export namespace snikket {
+	export class ReactionUpdate {
+		constructor(updateId: string, serverId: string, serverIdBy: string, localId: string, chatId: string, senderId: string, timestamp: string, reactions: snikket.Reaction[], kind: enums.ReactionUpdateKind);
+		updateId: string;
+		serverId: string;
+		serverIdBy: string;
+		localId: string;
+		chatId: string;
+		senderId: string;
+		timestamp: string;
+		reactions: snikket.Reaction[];
+		kind: enums.ReactionUpdateKind;
+		getReactions(existingReactions: snikket.Reaction[]): snikket.Reaction[];
+	}
+}
+
+export namespace snikket._Stanza {
+	export interface NodeInterface {
+		serialize(): string;
+		clone(): snikket._Stanza.NodeInterface;
+		traverse(f: (arg0: snikket.Stanza) => boolean): snikket._Stanza.NodeInterface;
+	}
+}
+
+export namespace snikket {
+	export class StanzaError {
+		constructor(type_: string, condition_: string, text_?: string);
+		type: string;
+		condition: string;
+		text: string;
+	}
+}
+
+export namespace snikket {
+	export class Stanza implements snikket._Stanza.NodeInterface {
+		constructor(name: string, attr?: { [key: string]: string });
+		readonly name: string;
+		readonly attr: { [key: string]: string };
+		readonly children: any[];
+		serialize(): string;
+		toString(): string;
+		tag(name: string, attr?: { [key: string]: string }): snikket.Stanza;
+		text(content: string): snikket.Stanza;
+		textTag(tagName: string, textContent: string, attr?: { [key: string]: string }): snikket.Stanza;
+		up(): snikket.Stanza;
+		reset(): snikket.Stanza;
+		addChild(stanza: snikket.Stanza): snikket.Stanza;
+		addDirectChild(child: any): snikket.Stanza;
+		clone(): snikket.Stanza;
+		allTags(name?: string, xmlns?: string): snikket.Stanza[];
+		allText(): string[];
+		getFirstChild(): snikket.Stanza;
+		getChildren(): snikket._Stanza.NodeInterface[];
+		getChild(name?: string, xmlns?: string): snikket.Stanza;
+		getChildText(name?: string, xmlns?: string): string;
+		getText(): string;
+		find(path: string): any;
+		findChild(path: string): snikket.Stanza;
+		findText(path: string): string;
+		traverse(f: (arg0: snikket.Stanza) => boolean): snikket.Stanza;
+		getError(): snikket.StanzaError;
+		removeChildren(name?: string, xmlns_?: string): void;
+		static parse(s: string): snikket.Stanza;
+		static parseXmlBool(x: string): boolean;
+	}
+}
+
+export namespace snikket {
+	export class Version {
+		protected constructor();
+		static readonly HUMAN: string;
+	}
+}
+
+export namespace snikket {
+	export interface Persistence {
+		lastId(accountId: string, chatId: string, callback: (serverId: string) => void): void;
+		storeChats(accountId: string, chats: snikket.Chat[]): void;
+		getChats(accountId: string, callback: (chats: snikket.SerializedChat[]) => void): void;
+		getChatsUnreadDetails(accountId: string, chats: snikket.Chat[], callback: (details: {chatId: string, message: snikket.ChatMessage, unreadCount: number}[]) => void): void;
+		storeReaction(accountId: string, update: snikket.ReactionUpdate, callback: (arg0: snikket.ChatMessage) => void): void;
+		storeMessages(accountId: string, message: snikket.ChatMessage[], callback: (arg0: snikket.ChatMessage[]) => void): void;
+		updateMessage(accountId: string, message: snikket.ChatMessage): void;
+		updateMessageStatus(accountId: string, localId: string, status: enums.MessageStatus, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMessage(accountId: string, chatId: string, serverId: string, localId: string, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMessagesBefore(accountId: string, chatId: string, beforeId: string, beforeTime: string, callback: (messages: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(accountId: string, chatId: string, afterId: string, afterTime: string, callback: (messages: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(accountId: string, chatId: string, aroundId: string, aroundTime: string, callback: (messages: snikket.ChatMessage[]) => void): void;
+		hasMedia(hashAlgorithm: string, hash: ArrayBuffer, callback: (has: boolean) => void): void;
+		storeMedia(mime: string, bytes: ArrayBuffer, callback: () => void): void;
+		removeMedia(hashAlgorithm: string, hash: ArrayBuffer): void;
+		storeCaps(caps: snikket.Caps): void;
+		getCaps(ver: string, callback: (arg0: snikket.Caps) => void): void;
+		storeLogin(login: string, clientId: string, displayName: string, token: string): void;
+		getLogin(login: string, callback: (clientId: string, token: string, fastCount: number, displayName: string) => void): void;
+		removeAccount(accountId: string, completely: boolean): void;
+		storeStreamManagement(accountId: string, data: ArrayBuffer): void;
+		getStreamManagement(accountId: string, callback: (arg0: ArrayBuffer) => void): void;
+		storeService(accountId: string, serviceId: string, name: string, node: string, caps: snikket.Caps): void;
+		findServicesWithFeature(accountId: string, feature: string, callback: (arg0: {caps: snikket.Caps, name: string, node: string, serviceId: string}[]) => void): void;
+	}
+}
+
+export namespace snikket.persistence {
+	export class Dummy implements snikket.Persistence {
+		/**
+		 * Create a basic persistence layer that persists nothing
+		 * @returns new persistence layer
+		 */
+		constructor();
+		lastId(accountId: string, chatId: string, callback: (arg0: string) => void): void;
+		storeChats(accountId: string, chat: snikket.Chat[]): void;
+		getChats(accountId: string, callback: (arg0: snikket.SerializedChat[]) => void): void;
+		storeMessages(accountId: string, messages: snikket.ChatMessage[], callback: (arg0: snikket.ChatMessage[]) => void): void;
+		updateMessage(accountId: string, message: snikket.ChatMessage): void;
+		getMessage(accountId: string, chatId: string, serverId: string, localId: string, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMessagesBefore(accountId: string, chatId: string, beforeId: string, beforeTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(accountId: string, chatId: string, afterId: string, afterTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(accountId: string, chatId: string, aroundId: string, aroundTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getChatsUnreadDetails(accountId: string, chats: snikket.Chat[], callback: (arg0: {chatId: string, message: snikket.ChatMessage, unreadCount: number}[]) => void): void;
+		storeReaction(accountId: string, update: snikket.ReactionUpdate, callback: (arg0: snikket.ChatMessage) => void): void;
+		updateMessageStatus(accountId: string, localId: string, status: enums.MessageStatus, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMediaUri(hashAlgorithm: string, hash: ArrayBuffer, callback: (arg0: string) => void): void;
+		hasMedia(hashAlgorithm: string, hash: ArrayBuffer, callback: (arg0: boolean) => void): void;
+		storeMedia(mime: string, bd: ArrayBuffer, callback: () => void): void;
+		removeMedia(hashAlgorithm: string, hash: ArrayBuffer): void;
+		storeCaps(caps: snikket.Caps): void;
+		getCaps(ver: string, callback: (arg0: snikket.Caps) => void): void;
+		storeLogin(login: string, clientId: string, displayName: string, token: string): void;
+		getLogin(login: string, callback: (arg0: string, arg1: string, arg2: number, arg3: string) => void): void;
+		removeAccount(accountId: string, completely: boolean): void;
+		storeStreamManagement(accountId: string, sm: ArrayBuffer): void;
+		getStreamManagement(accountId: string, callback: (arg0: ArrayBuffer) => void): void;
+		storeService(accountId: string, serviceId: string, name: string, node: string, caps: snikket.Caps): void;
+		findServicesWithFeature(accountId: string, feature: string, callback: (arg0: {caps: snikket.Caps, name: string, node: string, serviceId: string}[]) => void): void;
+	}
+}
+
+export namespace snikket.persistence {
+	export interface KeyValueStore {
+		get(k: string, callback: (arg0: string) => void): void;
+		set(k: string, v: string, callback: () => void): void;
+	}
+}
+
+export namespace snikket.persistence {
+	export interface MediaStore {
+		hasMedia(hashAlgorithm: string, hash: ArrayBuffer, callback: (has: boolean) => void): void;
+		removeMedia(hashAlgorithm: string, hash: ArrayBuffer): void;
+		storeMedia(mime: string, bytes: ArrayBuffer, callback: () => void): void;
+	}
+}
+
+export namespace snikket.persistence {
+	export class Sqlite implements snikket.persistence.KeyValueStore, snikket.Persistence {
+		/**
+		 * Create a basic persistence layer based on sqlite
+		 * @param dbfile path to sqlite database
+		 * @params media a MediaStore to use for media
+		 * @returns new persistence layer
+		 */
+		constructor(dbfile: string, media: snikket.persistence.MediaStore);
+		get(k: string, callback: (arg0: string) => void): void;
+		set(k: string, v: string, callback: () => void): void;
+		lastId(accountId: string, chatId: string, callback: (arg0: string) => void): void;
+		storeChats(accountId: string, chats: snikket.Chat[]): void;
+		getChats(accountId: string, callback: (arg0: snikket.SerializedChat[]) => void): void;
+		storeMessages(accountId: string, messages: snikket.ChatMessage[], callback: (arg0: snikket.ChatMessage[]) => void): void;
+		updateMessage(accountId: string, message: snikket.ChatMessage): void;
+		getMessage(accountId: string, chatId: string, serverId: string, localId: string, callback: (arg0: snikket.ChatMessage) => void): void;
+		getMessagesBefore(accountId: string, chatId: string, beforeId: string, beforeTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAfter(accountId: string, chatId: string, afterId: string, afterTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getMessagesAround(accountId: string, chatId: string, aroundId: string, aroundTime: string, callback: (arg0: snikket.ChatMessage[]) => void): void;
+		getChatsUnreadDetails(accountId: string, chats: snikket.Chat[], callback: (arg0: {chatId: string, message: snikket.ChatMessage, unreadCount: number}[]) => void): void;
+		storeReaction(accountId: string, update: snikket.ReactionUpdate, callback: (arg0: snikket.ChatMessage) => void): void;
+		updateMessageStatus(accountId: string, localId: string, status: enums.MessageStatus, callback: (arg0: snikket.ChatMessage) => void): void;
+		hasMedia(hashAlgorithm: string, hash: ArrayBuffer, callback: (arg0: boolean) => void): void;
+		removeMedia(hashAlgorithm: string, hash: ArrayBuffer): void;
+		storeMedia(mime: string, bd: ArrayBuffer, callback: () => void): void;
+		storeCaps(caps: snikket.Caps): void;
+		getCaps(ver: string, callback: (arg0: snikket.Caps) => void): void;
+		storeLogin(accountId: string, clientId: string, displayName: string, token: string): void;
+		getLogin(accountId: string, callback: (arg0: string, arg1: string, arg2: number, arg3: string) => void): void;
+		removeAccount(accountId: string, completely: boolean): void;
+		storeStreamManagement(accountId: string, sm: ArrayBuffer): void;
+		getStreamManagement(accountId: string, callback: (arg0: ArrayBuffer) => void): void;
+		storeService(accountId: string, serviceId: string, name: string, node: string, caps: snikket.Caps): void;
+		findServicesWithFeature(accountId: string, feature: string, callback: (arg0: {caps: snikket.Caps, name: string, node: string, serviceId: string}[]) => void): void;
+	}
+}
\ No newline at end of file
diff --git a/npm/snikket.js b/npm/snikket.js
new file mode 100644
index 0000000..511e28f
--- /dev/null
+++ b/npm/snikket.js
@@ -0,0 +1,29522 @@
+var exports = {};
+global.require = createRequire(import.meta.url);
+import { createRequire } from "module";
+// Generated by Haxe 4.3.2
+import { sqlite3Worker1Promiser as snikket_persistence_Worker1 } from "@sqlite.org/sqlite-wasm";
+import snikket_streams_XmppJsScramSha1 from "@xmpp/sasl-scram-sha-1";
+import { client as snikket_streams_XmppJsClient } from "@xmpp/client";
+import { jid as snikket_streams_XmppJsJID } from "@xmpp/jid";
+import snikket_streams_XmppJsDebug from "@xmpp/debug";
+import snikket_streams_XmppJsXml from "@xmpp/xml";
+import * as snikket_streams_XmppJsLtx from "ltx";
+import snikket_streams_XmppJsId from "@xmpp/id";
+import snikket_streams_XmppJsError from "@xmpp/error";
+;(function ($hx_exports, $global) { "use strict";
+$hx_exports["snikket"] = $hx_exports["snikket"] || {};
+$hx_exports["snikket"]["Push"] = $hx_exports["snikket"]["Push"] || {};
+;$hx_exports["snikket"]["persistence"] = $hx_exports["snikket"]["persistence"] || {};
+var $estr = function() { return js_Boot.__string_rec(this,''); },$hxEnums = $hxEnums || {},$_;
+class DateTools {
+	static __format_get(d,e) {
+		switch(e) {
+		case "%":
+			return "%";
+		case "A":
+			return DateTools.DAY_NAMES[d.getDay()];
+		case "B":
+			return DateTools.MONTH_NAMES[d.getMonth()];
+		case "C":
+			return StringTools.lpad(Std.string(d.getFullYear() / 100 | 0),"0",2);
+		case "D":
+			return DateTools.__format(d,"%m/%d/%y");
+		case "F":
+			return DateTools.__format(d,"%Y-%m-%d");
+		case "M":
+			return StringTools.lpad(Std.string(d.getMinutes()),"0",2);
+		case "R":
+			return DateTools.__format(d,"%H:%M");
+		case "S":
+			return StringTools.lpad(Std.string(d.getSeconds()),"0",2);
+		case "T":
+			return DateTools.__format(d,"%H:%M:%S");
+		case "Y":
+			return Std.string(d.getFullYear());
+		case "a":
+			return DateTools.DAY_SHORT_NAMES[d.getDay()];
+		case "d":
+			return StringTools.lpad(Std.string(d.getDate()),"0",2);
+		case "e":
+			return Std.string(d.getDate());
+		case "b":case "h":
+			return DateTools.MONTH_SHORT_NAMES[d.getMonth()];
+		case "H":case "k":
+			return StringTools.lpad(Std.string(d.getHours()),e == "H" ? "0" : " ",2);
+		case "I":case "l":
+			let hour = d.getHours() % 12;
+			return StringTools.lpad(Std.string(hour == 0 ? 12 : hour),e == "I" ? "0" : " ",2);
+		case "m":
+			return StringTools.lpad(Std.string(d.getMonth() + 1),"0",2);
+		case "n":
+			return "\n";
+		case "p":
+			if(d.getHours() > 11) {
+				return "PM";
+			} else {
+				return "AM";
+			}
+			break;
+		case "r":
+			return DateTools.__format(d,"%I:%M:%S %p");
+		case "s":
+			return Std.string(d.getTime() / 1000 | 0);
+		case "t":
+			return "\t";
+		case "u":
+			let t = d.getDay();
+			if(t == 0) {
+				return "7";
+			} else if(t == null) {
+				return "null";
+			} else {
+				return "" + t;
+			}
+			break;
+		case "w":
+			return Std.string(d.getDay());
+		case "y":
+			return StringTools.lpad(Std.string(d.getFullYear() % 100),"0",2);
+		default:
+			throw new haxe_exceptions_NotImplementedException("Date.format %" + e + "- not implemented yet.",null,{ fileName : "DateTools.hx", lineNumber : 101, className : "DateTools", methodName : "__format_get"});
+		}
+	}
+	static __format(d,f) {
+		let r_b = "";
+		let p = 0;
+		while(true) {
+			let np = f.indexOf("%",p);
+			if(np < 0) {
+				break;
+			}
+			let len = np - p;
+			r_b += len == null ? HxOverrides.substr(f,p,null) : HxOverrides.substr(f,p,len);
+			r_b += Std.string(DateTools.__format_get(d,HxOverrides.substr(f,np + 1,1)));
+			p = np + 2;
+		}
+		let len = f.length - p;
+		r_b += len == null ? HxOverrides.substr(f,p,null) : HxOverrides.substr(f,p,len);
+		return r_b;
+	}
+	static format(d,f) {
+		return DateTools.__format(d,f);
+	}
+}
+DateTools.__name__ = "DateTools";
+class EReg {
+	constructor(r,opt) {
+		this.r = new RegExp(r,opt.split("u").join(""));
+	}
+	match(s) {
+		if(this.r.global) {
+			this.r.lastIndex = 0;
+		}
+		this.r.m = this.r.exec(s);
+		this.r.s = s;
+		return this.r.m != null;
+	}
+	matched(n) {
+		if(this.r.m != null && n >= 0 && n < this.r.m.length) {
+			return this.r.m[n];
+		} else {
+			throw haxe_Exception.thrown("EReg::matched");
+		}
+	}
+	matchedLeft() {
+		if(this.r.m == null) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		return HxOverrides.substr(this.r.s,0,this.r.m.index);
+	}
+	matchedRight() {
+		if(this.r.m == null) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		let sz = this.r.m.index + this.r.m[0].length;
+		return HxOverrides.substr(this.r.s,sz,this.r.s.length - sz);
+	}
+	matchedPos() {
+		if(this.r.m == null) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		return { pos : this.r.m.index, len : this.r.m[0].length};
+	}
+	matchSub(s,pos,len) {
+		if(len == null) {
+			len = -1;
+		}
+		if(this.r.global) {
+			this.r.lastIndex = pos;
+			this.r.m = this.r.exec(len < 0 ? s : HxOverrides.substr(s,0,pos + len));
+			let b = this.r.m != null;
+			if(b) {
+				this.r.s = s;
+			}
+			return b;
+		} else {
+			let b = this.match(len < 0 ? HxOverrides.substr(s,pos,null) : HxOverrides.substr(s,pos,len));
+			if(b) {
+				this.r.s = s;
+				this.r.m.index += pos;
+			}
+			return b;
+		}
+	}
+	split(s) {
+		let d = "#__delim__#";
+		return s.replace(this.r,d).split(d);
+	}
+	map(s,f) {
+		let offset = 0;
+		let buf_b = "";
+		do {
+			if(offset >= s.length) {
+				break;
+			} else if(!this.matchSub(s,offset)) {
+				buf_b += Std.string(HxOverrides.substr(s,offset,null));
+				break;
+			}
+			let p = this.matchedPos();
+			buf_b += Std.string(HxOverrides.substr(s,offset,p.pos - offset));
+			buf_b += Std.string(f(this));
+			if(p.len == 0) {
+				buf_b += Std.string(HxOverrides.substr(s,p.pos,1));
+				offset = p.pos + 1;
+			} else {
+				offset = p.pos + p.len;
+			}
+		} while(this.r.global);
+		if(!this.r.global && offset > 0 && offset < s.length) {
+			buf_b += Std.string(HxOverrides.substr(s,offset,null));
+		}
+		return buf_b;
+	}
+}
+EReg.__name__ = "EReg";
+Object.assign(EReg.prototype, {
+	__class__: EReg
+});
+class HxOverrides {
+	static cca(s,index) {
+		let x = s.charCodeAt(index);
+		if(x != x) {
+			return undefined;
+		}
+		return x;
+	}
+	static substr(s,pos,len) {
+		if(len == null) {
+			len = s.length;
+		} else if(len < 0) {
+			if(pos == 0) {
+				len = s.length + len;
+			} else {
+				return "";
+			}
+		}
+		return s.substr(pos,len);
+	}
+	static remove(a,obj) {
+		let i = a.indexOf(obj);
+		if(i == -1) {
+			return false;
+		}
+		a.splice(i,1);
+		return true;
+	}
+	static now() {
+		return Date.now();
+	}
+}
+HxOverrides.__name__ = "HxOverrides";
+class Lambda {
+	static array(it) {
+		let a = [];
+		let i = $getIterator(it);
+		while(i.hasNext()) {
+			let i1 = i.next();
+			a.push(i1);
+		}
+		return a;
+	}
+	static exists(it,f) {
+		let x = $getIterator(it);
+		while(x.hasNext()) {
+			let x1 = x.next();
+			if(f(x1)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static fold(it,f,first) {
+		let x = $getIterator(it);
+		while(x.hasNext()) {
+			let x1 = x.next();
+			first = f(x1,first);
+		}
+		return first;
+	}
+	static empty(it) {
+		return !$getIterator(it).hasNext();
+	}
+	static indexOf(it,v) {
+		let i = 0;
+		let v2 = $getIterator(it);
+		while(v2.hasNext()) {
+			let v21 = v2.next();
+			if(v == v21) {
+				return i;
+			}
+			++i;
+		}
+		return -1;
+	}
+	static find(it,f) {
+		let v = $getIterator(it);
+		while(v.hasNext()) {
+			let v1 = v.next();
+			if(f(v1)) {
+				return v1;
+			}
+		}
+		return null;
+	}
+	static findIndex(it,f) {
+		let i = 0;
+		let v = $getIterator(it);
+		while(v.hasNext()) {
+			let v1 = v.next();
+			if(f(v1)) {
+				return i;
+			}
+			++i;
+		}
+		return -1;
+	}
+}
+Lambda.__name__ = "Lambda";
+Math.__name__ = "Math";
+class Reflect {
+	static field(o,field) {
+		try {
+			return o[field];
+		} catch( _g ) {
+			return null;
+		}
+	}
+	static fields(o) {
+		let a = [];
+		if(o != null) {
+			let hasOwnProperty = Object.prototype.hasOwnProperty;
+			for( var f in o ) {
+			if(f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o,f)) {
+				a.push(f);
+			}
+			}
+		}
+		return a;
+	}
+	static compare(a,b) {
+		if(a == b) {
+			return 0;
+		} else if(a > b) {
+			return 1;
+		} else {
+			return -1;
+		}
+	}
+	static isEnumValue(v) {
+		if(v != null) {
+			return v.__enum__ != null;
+		} else {
+			return false;
+		}
+	}
+	static copy(o) {
+		if(o == null) {
+			return null;
+		}
+		let o2 = { };
+		let _g = 0;
+		let _g1 = Reflect.fields(o);
+		while(_g < _g1.length) {
+			let f = _g1[_g];
+			++_g;
+			o2[f] = Reflect.field(o,f);
+		}
+		return o2;
+	}
+}
+Reflect.__name__ = "Reflect";
+class Std {
+	static string(s) {
+		return js_Boot.__string_rec(s,"");
+	}
+	static parseInt(x) {
+		let v = parseInt(x);
+		if(isNaN(v)) {
+			return null;
+		}
+		return v;
+	}
+	static random(x) {
+		if(x <= 0) {
+			return 0;
+		} else {
+			return Math.floor(Math.random() * x);
+		}
+	}
+}
+Std.__name__ = "Std";
+class StringBuf {
+	constructor() {
+		this.b = "";
+	}
+}
+StringBuf.__name__ = "StringBuf";
+Object.assign(StringBuf.prototype, {
+	__class__: StringBuf
+});
+class StringTools {
+	static htmlEscape(s,quotes) {
+		let buf_b = "";
+		let _g_offset = 0;
+		let _g_s = s;
+		while(_g_offset < _g_s.length) {
+			let s = _g_s;
+			let index = _g_offset++;
+			let c = s.charCodeAt(index);
+			if(c >= 55296 && c <= 56319) {
+				c = c - 55232 << 10 | s.charCodeAt(index + 1) & 1023;
+			}
+			let c1 = c;
+			if(c1 >= 65536) {
+				++_g_offset;
+			}
+			let code = c1;
+			switch(code) {
+			case 34:
+				if(quotes) {
+					buf_b += "&quot;";
+				} else {
+					buf_b += String.fromCodePoint(code);
+				}
+				break;
+			case 38:
+				buf_b += "&amp;";
+				break;
+			case 39:
+				if(quotes) {
+					buf_b += "&#039;";
+				} else {
+					buf_b += String.fromCodePoint(code);
+				}
+				break;
+			case 60:
+				buf_b += "&lt;";
+				break;
+			case 62:
+				buf_b += "&gt;";
+				break;
+			default:
+				buf_b += String.fromCodePoint(code);
+			}
+		}
+		return buf_b;
+	}
+	static isSpace(s,pos) {
+		let c = HxOverrides.cca(s,pos);
+		if(!(c > 8 && c < 14)) {
+			return c == 32;
+		} else {
+			return true;
+		}
+	}
+	static ltrim(s) {
+		let l = s.length;
+		let r = 0;
+		while(r < l && StringTools.isSpace(s,r)) ++r;
+		if(r > 0) {
+			return HxOverrides.substr(s,r,l - r);
+		} else {
+			return s;
+		}
+	}
+	static rtrim(s) {
+		let l = s.length;
+		let r = 0;
+		while(r < l && StringTools.isSpace(s,l - r - 1)) ++r;
+		if(r > 0) {
+			return HxOverrides.substr(s,0,l - r);
+		} else {
+			return s;
+		}
+	}
+	static trim(s) {
+		return StringTools.ltrim(StringTools.rtrim(s));
+	}
+	static lpad(s,c,l) {
+		if(c.length <= 0) {
+			return s;
+		}
+		let buf_b = "";
+		l -= s.length;
+		while(buf_b.length < l) buf_b += c == null ? "null" : "" + c;
+		buf_b += s == null ? "null" : "" + s;
+		return buf_b;
+	}
+	static rpad(s,c,l) {
+		if(c.length <= 0) {
+			return s;
+		}
+		let buf_b = "";
+		buf_b += s == null ? "null" : "" + s;
+		while(buf_b.length < l) buf_b += c == null ? "null" : "" + c;
+		return buf_b;
+	}
+	static replace(s,sub,by) {
+		return s.split(sub).join(by);
+	}
+	static hex(n,digits) {
+		let s = "";
+		let hexChars = "0123456789ABCDEF";
+		do {
+			s = hexChars.charAt(n & 15) + s;
+			n >>>= 4;
+		} while(n > 0);
+		if(digits != null) {
+			while(s.length < digits) s = "0" + s;
+		}
+		return s;
+	}
+}
+StringTools.__name__ = "StringTools";
+class Type {
+	static enumParameters(e) {
+		let enm = $hxEnums[e.__enum__];
+		let params = enm.__constructs__[e._hx_index].__params__;
+		if(params != null) {
+			let _g = [];
+			let _g1 = 0;
+			while(_g1 < params.length) {
+				let p = params[_g1];
+				++_g1;
+				_g.push(e[p]);
+			}
+			return _g;
+		} else {
+			return [];
+		}
+	}
+}
+Type.__name__ = "Type";
+class XmlType {
+	static toString(this1) {
+		switch(this1) {
+		case 0:
+			return "Element";
+		case 1:
+			return "PCData";
+		case 2:
+			return "CData";
+		case 3:
+			return "Comment";
+		case 4:
+			return "DocType";
+		case 5:
+			return "ProcessingInstruction";
+		case 6:
+			return "Document";
+		}
+	}
+}
+class Xml {
+	constructor(nodeType) {
+		this.nodeType = nodeType;
+		this.children = [];
+		this.attributeMap = new haxe_ds_StringMap();
+	}
+	get(att) {
+		if(this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		return this.attributeMap.h[att];
+	}
+	set(att,value) {
+		if(this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		this.attributeMap.h[att] = value;
+	}
+	exists(att) {
+		if(this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		return Object.prototype.hasOwnProperty.call(this.attributeMap.h,att);
+	}
+	attributes() {
+		if(this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		return new haxe_ds__$StringMap_StringMapKeyIterator(this.attributeMap.h);
+	}
+	firstElement() {
+		if(this.nodeType != Xml.Document && this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		let _g = 0;
+		let _g1 = this.children;
+		while(_g < _g1.length) {
+			let child = _g1[_g];
+			++_g;
+			if(child.nodeType == Xml.Element) {
+				return child;
+			}
+		}
+		return null;
+	}
+	addChild(x) {
+		if(this.nodeType != Xml.Document && this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		if(x.parent != null) {
+			x.parent.removeChild(x);
+		}
+		this.children.push(x);
+		x.parent = this;
+	}
+	removeChild(x) {
+		if(this.nodeType != Xml.Document && this.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (this.nodeType == null ? "null" : XmlType.toString(this.nodeType)));
+		}
+		if(HxOverrides.remove(this.children,x)) {
+			x.parent = null;
+			return true;
+		}
+		return false;
+	}
+	toString() {
+		return haxe_xml_Printer.print(this);
+	}
+	static parse(str) {
+		return haxe_xml_Parser.parse(str);
+	}
+	static createElement(name) {
+		let xml = new Xml(Xml.Element);
+		if(xml.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeName = name;
+		return xml;
+	}
+	static createPCData(data) {
+		let xml = new Xml(Xml.PCData);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createCData(data) {
+		let xml = new Xml(Xml.CData);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createComment(data) {
+		let xml = new Xml(Xml.Comment);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createDocType(data) {
+		let xml = new Xml(Xml.DocType);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createProcessingInstruction(data) {
+		let xml = new Xml(Xml.ProcessingInstruction);
+		if(xml.nodeType == Xml.Document || xml.nodeType == Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, unexpected " + (xml.nodeType == null ? "null" : XmlType.toString(xml.nodeType)));
+		}
+		xml.nodeValue = data;
+		return xml;
+	}
+	static createDocument() {
+		return new Xml(Xml.Document);
+	}
+}
+Xml.__name__ = "Xml";
+Object.assign(Xml.prototype, {
+	__class__: Xml
+});
+var datetime_DTPeriod = $hxEnums["datetime.DTPeriod"] = { __ename__:true,__constructs__:null
+	,Year: ($_=function(n) { return {_hx_index:0,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Year",$_.__params__ = ["n"],$_)
+	,Month: ($_=function(n) { return {_hx_index:1,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Month",$_.__params__ = ["n"],$_)
+	,Day: ($_=function(n) { return {_hx_index:2,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Day",$_.__params__ = ["n"],$_)
+	,Hour: ($_=function(n) { return {_hx_index:3,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Hour",$_.__params__ = ["n"],$_)
+	,Minute: ($_=function(n) { return {_hx_index:4,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Minute",$_.__params__ = ["n"],$_)
+	,Second: ($_=function(n) { return {_hx_index:5,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Second",$_.__params__ = ["n"],$_)
+	,Week: ($_=function(n) { return {_hx_index:6,n:n,__enum__:"datetime.DTPeriod",toString:$estr}; },$_._hx_name="Week",$_.__params__ = ["n"],$_)
+};
+datetime_DTPeriod.__constructs__ = [datetime_DTPeriod.Year,datetime_DTPeriod.Month,datetime_DTPeriod.Day,datetime_DTPeriod.Hour,datetime_DTPeriod.Minute,datetime_DTPeriod.Second,datetime_DTPeriod.Week];
+var datetime_DTSnap = $hxEnums["datetime.DTSnap"] = { __ename__:true,__constructs__:null
+	,Year: ($_=function(direction) { return {_hx_index:0,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Year",$_.__params__ = ["direction"],$_)
+	,Month: ($_=function(direction) { return {_hx_index:1,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Month",$_.__params__ = ["direction"],$_)
+	,Day: ($_=function(direction) { return {_hx_index:2,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Day",$_.__params__ = ["direction"],$_)
+	,Hour: ($_=function(direction) { return {_hx_index:3,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Hour",$_.__params__ = ["direction"],$_)
+	,Minute: ($_=function(direction) { return {_hx_index:4,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Minute",$_.__params__ = ["direction"],$_)
+	,Second: ($_=function(direction) { return {_hx_index:5,direction:direction,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Second",$_.__params__ = ["direction"],$_)
+	,Week: ($_=function(direction,day) { return {_hx_index:6,direction:direction,day:day,__enum__:"datetime.DTSnap",toString:$estr}; },$_._hx_name="Week",$_.__params__ = ["direction","day"],$_)
+};
+datetime_DTSnap.__constructs__ = [datetime_DTSnap.Year,datetime_DTSnap.Month,datetime_DTSnap.Day,datetime_DTSnap.Hour,datetime_DTSnap.Minute,datetime_DTSnap.Second,datetime_DTSnap.Week];
+class datetime_DateTime {
+	static now() {
+		return Math.floor(new Date().getTime() / 1000) + 62135596800.0;
+	}
+	static local() {
+		let utc = Math.floor(new Date().getTime() / 1000) + 62135596800.0;
+		return utc - 62135596800.0 + datetime_DateTime.getLocalOffset() + 62135596800.0;
+	}
+	static make(year,month,day,hour,minute,second) {
+		if(second == null) {
+			second = 0;
+		}
+		if(minute == null) {
+			minute = 0;
+		}
+		if(hour == null) {
+			hour = 0;
+		}
+		if(day == null) {
+			day = 1;
+		}
+		if(month == null) {
+			month = 1;
+		}
+		if(year == null) {
+			year = 1970;
+		}
+		return datetime_utils_DateTimeUtils.yearToStamp(year) + datetime_utils_DateTimeMonthUtils.toSeconds(month,year % 4 == 0 && (year % 100 == 0 ? year % 400 == 0 : true)) + (day - 1) * 86400 + hour * 3600 + minute * 60 + second - 62135596800.0 + 62135596800.0;
+	}
+	static fromTime(time) {
+		return time + 62135596800.0;
+	}
+	static fromString(str) {
+		return datetime_utils_DateTimeUtils.fromString(str);
+	}
+	static fromDate(date) {
+		return Math.floor(date.getTime() / 1000) + 62135596800.0;
+	}
+	static daysInMonth(month,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		return datetime_utils_DateTimeMonthUtils.days(month,isLeapYear);
+	}
+	static weeksInYear(year) {
+		let start = datetime_utils_DateTimeUtils.yearToStamp(year) - 62135596800.0 + 62135596800.0;
+		let weekDay = datetime_DateTime.getWeekDay(start);
+		if(weekDay == 4 || weekDay == 3 && datetime_DateTime.isLeapYear(start)) {
+			return 53;
+		} else {
+			return 52;
+		}
+	}
+	static isLeap(year) {
+		if(year % 4 == 0) {
+			if(year % 100 == 0) {
+				return year % 400 == 0;
+			} else {
+				return true;
+			}
+		} else {
+			return false;
+		}
+	}
+	static getLocalOffset() {
+		let now = new Date();
+		let year = now.getFullYear();
+		let month = now.getMonth() + 1;
+		let day = now.getDate();
+		let hour = now.getHours();
+		let minute = now.getMinutes();
+		let second = now.getSeconds();
+		if(second == null) {
+			second = 0;
+		}
+		if(minute == null) {
+			minute = 0;
+		}
+		if(hour == null) {
+			hour = 0;
+		}
+		if(day == null) {
+			day = 1;
+		}
+		if(month == null) {
+			month = 1;
+		}
+		if(year == null) {
+			year = 1970;
+		}
+		let local = datetime_utils_DateTimeUtils.yearToStamp(year) + datetime_utils_DateTimeMonthUtils.toSeconds(month,year % 4 == 0 && (year % 100 == 0 ? year % 400 == 0 : true)) + (day - 1) * 86400 + hour * 3600 + minute * 60 + second - 62135596800.0 + 62135596800.0;
+		return local - 62135596800.0 - (now.getTime() / 1000 | 0) | 0;
+	}
+	static _new(time) {
+		return time + 62135596800.0;
+	}
+	static utc(this1) {
+		return this1 - 62135596800.0 - datetime_DateTime.getLocalOffset() + 62135596800.0;
+	}
+	static getYear(this1) {
+		let cquads = (this1 / 12622780800.0 | 0) * 12622780800.0;
+		let centuries = ((this1 - cquads) / 3155673600.0 | 0) * 3155673600.0;
+		if(centuries > 9467020800.) {
+			centuries -= 3155673600.0;
+		}
+		let quads = ((this1 - cquads - centuries) / 126230400.0 | 0) * 126230400.0;
+		let years = (this1 - cquads - centuries - quads) / 31536000 | 0;
+		return (cquads / 12622780800.0 | 0) * 400 + (centuries / 3155673600.0 | 0) * 100 + (quads / 126230400.0 | 0) * 4 + (years == 4 ? years : years + 1);
+	}
+	static yearStart(this1) {
+		let cquads = (this1 / 12622780800.0 | 0) * 12622780800.0;
+		let centuries = ((this1 - cquads) / 3155673600.0 | 0) * 3155673600.0;
+		if(centuries > 9467020800.) {
+			centuries -= 3155673600.0;
+		}
+		let quads = ((this1 - cquads - centuries) / 126230400.0 | 0) * 126230400.0;
+		let years = (this1 - cquads - centuries - quads) / 31536000 | 0;
+		if(years == 4) {
+			--years;
+		}
+		return cquads + centuries + quads + years * 31536000 - 62135596800.0;
+	}
+	static monthStart(this1,month) {
+		if(month == null) {
+			month = 0;
+		}
+		if(month == 0) {
+			let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+			month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+		}
+		return datetime_DateTime.yearStart(this1) + datetime_utils_DateTimeMonthUtils.toSeconds(month,datetime_DateTime.isLeapYear(this1));
+	}
+	static getMonthStart(this1,month) {
+		return datetime_DateTime.monthStart(this1,month) + 62135596800.0;
+	}
+	static isLeapYear(this1) {
+		let year = datetime_DateTime.getYear(this1);
+		if(year % 4 == 0) {
+			if(year % 100 == 0) {
+				return year % 400 == 0;
+			} else {
+				return true;
+			}
+		} else {
+			return false;
+		}
+	}
+	static getMonth(this1) {
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		return datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+	}
+	static getDay(this1) {
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		return datetime_utils_DateTimeMonthUtils.getMonthDay(days,datetime_DateTime.isLeapYear(this1));
+	}
+	static daysInThisMonth(this1) {
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+		return datetime_utils_DateTimeMonthUtils.days(month,month == 2 && datetime_DateTime.isLeapYear(this1));
+	}
+	static getYearDay(this1) {
+		return ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+	}
+	static weeksInThisYear(this1) {
+		return datetime_DateTime.weeksInYear(datetime_DateTime.getYear(this1));
+	}
+	static getWeekDay(this1,mondayBased) {
+		if(mondayBased == null) {
+			mondayBased = false;
+		}
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+		let a = (14 - month) / 12 | 0;
+		let y = datetime_DateTime.getYear(this1) - a;
+		let m = month + 12 * a - 2;
+		let days1 = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let weekDay = (7000 + (datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(this1)) + y + (y / 4 | 0) - (y / 100 | 0) + (y / 400 | 0) + (31 * m / 12 | 0))) % 7;
+		if(mondayBased && weekDay == 0) {
+			return 7;
+		} else {
+			return weekDay;
+		}
+	}
+	static getWeekDayNum(this1,weekDay,num) {
+		if(num == null) {
+			num = 1;
+		}
+		return datetime_utils_DateTimeUtils.getWeekDayNum(this1 - 62135596800.0 + 62135596800.0,weekDay,num) + 62135596800.0;
+	}
+	static getWeek(this1) {
+		let week = (((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1 - datetime_DateTime.getWeekDay(this1,true) + 10) / 7 | 0;
+		let year = datetime_DateTime.getYear(this1);
+		if(week < 1) {
+			return datetime_DateTime.weeksInYear(year - 1);
+		} else if(week > 52 && week > datetime_DateTime.weeksInYear(year)) {
+			return 1;
+		} else {
+			return week;
+		}
+	}
+	static getHour(this1) {
+		return (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+	}
+	static getHour12(this1) {
+		let hour = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+		if(hour == 0) {
+			return 12;
+		} else if(hour > 12) {
+			return hour - 12;
+		} else {
+			return hour;
+		}
+	}
+	static getMinute(this1) {
+		return (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+	}
+	static getSecond(this1) {
+		return this1 - Math.floor(this1 / 60) * 60 | 0;
+	}
+	static add(this1,period) {
+		let time;
+		switch(period._hx_index) {
+		case 0:
+			let n = period.n;
+			time = datetime_utils_DateTimeUtils.addYear(this1 - 62135596800.0 + 62135596800.0,n);
+			break;
+		case 1:
+			let n1 = period.n;
+			time = datetime_utils_DateTimeUtils.addMonth(this1 - 62135596800.0 + 62135596800.0,n1);
+			break;
+		case 2:
+			let n2 = period.n;
+			time = this1 - 62135596800.0 + n2 * 86400;
+			break;
+		case 3:
+			let n3 = period.n;
+			time = this1 - 62135596800.0 + n3 * 3600;
+			break;
+		case 4:
+			let n4 = period.n;
+			time = this1 - 62135596800.0 + n4 * 60;
+			break;
+		case 5:
+			let n5 = period.n;
+			time = this1 - 62135596800.0 + n5;
+			break;
+		case 6:
+			let n6 = period.n;
+			time = this1 - 62135596800.0 + n6 * 7 * 86400;
+			break;
+		}
+		return time + 62135596800.0;
+	}
+	static sub(this1,period) {
+		let time;
+		switch(period._hx_index) {
+		case 0:
+			let n = period.n;
+			time = datetime_utils_DateTimeUtils.addYear(this1 - 62135596800.0 + 62135596800.0,-n);
+			break;
+		case 1:
+			let n1 = period.n;
+			time = datetime_utils_DateTimeUtils.addMonth(this1 - 62135596800.0 + 62135596800.0,-n1);
+			break;
+		case 2:
+			let n2 = period.n;
+			time = this1 - 62135596800.0 - n2 * 86400;
+			break;
+		case 3:
+			let n3 = period.n;
+			time = this1 - 62135596800.0 - n3 * 3600;
+			break;
+		case 4:
+			let n4 = period.n;
+			time = this1 - 62135596800.0 - n4 * 60;
+			break;
+		case 5:
+			let n5 = period.n;
+			time = this1 - 62135596800.0 - n5;
+			break;
+		case 6:
+			let n6 = period.n;
+			time = this1 - 62135596800.0 - n6 * 7 * 86400;
+			break;
+		}
+		return time + 62135596800.0;
+	}
+	static snap(this1,period) {
+		let time;
+		switch(period._hx_index) {
+		case 0:
+			let d = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapYear(this1 - 62135596800.0 + 62135596800.0,d);
+			break;
+		case 1:
+			let d1 = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapMonth(this1 - 62135596800.0 + 62135596800.0,d1);
+			break;
+		case 2:
+			let d2 = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapDay(this1 - 62135596800.0 + 62135596800.0,d2);
+			break;
+		case 3:
+			let d3 = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapHour(this1 - 62135596800.0 + 62135596800.0,d3);
+			break;
+		case 4:
+			let d4 = period.direction;
+			time = datetime_utils_DateTimeSnapUtils.snapMinute(this1 - 62135596800.0 + 62135596800.0,d4);
+			break;
+		case 5:
+			let d5 = period.direction;
+			time = d5 == 1 ? this1 - 62135596800.0 + 1 : this1 - 62135596800.0;
+			break;
+		case 6:
+			let d6 = period.direction;
+			let day = period.day;
+			time = datetime_utils_DateTimeSnapUtils.snapWeek(this1 - 62135596800.0 + 62135596800.0,d6,day);
+			break;
+		}
+		return time + 62135596800.0;
+	}
+	static toString(this1) {
+		let Y = datetime_DateTime.getYear(this1);
+		let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let M = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+		let days1 = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+		let D = datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(this1));
+		let h = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+		let m = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+		let s = this1 - Math.floor(this1 / 60) * 60 | 0;
+		return "" + Y + "-" + (M < 10 ? "0" + M : "" + M) + "-" + (D < 10 ? "0" + D : "" + D) + " " + (h < 10 ? "0" + h : "" + h) + ":" + (m < 10 ? "0" + m : "" + m) + ":" + (s < 10 ? "0" + s : "" + s);
+	}
+	static format(this1,format) {
+		return datetime_utils_DateTimeUtils.strftime(this1 - 62135596800.0 + 62135596800.0,format);
+	}
+	static getTime(this1) {
+		return this1 - 62135596800.0;
+	}
+	static getDate(this1) {
+		return new Date((this1 - 62135596800.0) * 1000);
+	}
+	static gt(this1,dt) {
+		return this1 - 62135596800.0 > dt - 62135596800.0;
+	}
+	static gte(this1,dt) {
+		return this1 - 62135596800.0 >= dt - 62135596800.0;
+	}
+	static lt(this1,dt) {
+		return this1 - 62135596800.0 < dt - 62135596800.0;
+	}
+	static lte(this1,dt) {
+		return this1 - 62135596800.0 <= dt - 62135596800.0;
+	}
+	static eq(this1,dt) {
+		return this1 - 62135596800.0 == dt - 62135596800.0;
+	}
+	static neq(this1,dt) {
+		return this1 - 62135596800.0 != dt - 62135596800.0;
+	}
+	static mathPlus1(this1,period) {
+		return datetime_DateTime.add(this1,period);
+	}
+	static mathPlus2(this1,period) {
+		return datetime_DateTime.add(this1,period);
+	}
+	static mathPlus3(this1,period) {
+		this1 = datetime_DateTime.add(this1,period) - 62135596800.0 + 62135596800.0;
+		return this1 + 62135596800.0;
+	}
+	static mathMinus1(this1,period) {
+		return datetime_DateTime.sub(this1,period);
+	}
+	static mathMinus2(this1,period) {
+		this1 = datetime_DateTime.sub(this1,period) - 62135596800.0 + 62135596800.0;
+		return this1 + 62135596800.0;
+	}
+	static dtiCreate(this1,begin) {
+		return datetime_DateTimeInterval.create(begin,this1 - 62135596800.0 + 62135596800.0);
+	}
+	static dtiMinus(this1,dti) {
+		return datetime_DateTimeInterval.subFrom(dti,this1 - 62135596800.0 + 62135596800.0);
+	}
+	static dtiPlus1(this1,dti) {
+		return datetime_DateTimeInterval.addTo(dti,this1 - 62135596800.0 + 62135596800.0);
+	}
+	static dtiPlus2(this1,dti) {
+		return datetime_DateTimeInterval.addTo(dti,this1 - 62135596800.0 + 62135596800.0);
+	}
+	static dtiMinus2(this1,dti) {
+		this1 = datetime_DateTimeInterval.subFrom(dti,this1 - 62135596800.0 + 62135596800.0) - 62135596800.0 + 62135596800.0;
+		return this1 + 62135596800.0;
+	}
+	static dtiPlus3(this1,dti) {
+		this1 = datetime_DateTimeInterval.addTo(dti,this1 - 62135596800.0 + 62135596800.0) - 62135596800.0 + 62135596800.0;
+		return this1 + 62135596800.0;
+	}
+}
+class datetime_DateTimeInterval {
+	static create(begin,end) {
+		let dtic = new datetime_cores_DateTimeIntervalCore();
+		dtic.begin = end - 62135596800.0 < begin - 62135596800.0 ? end : begin;
+		dtic.end = end - 62135596800.0 < begin - 62135596800.0 ? begin : end;
+		dtic.negative = end - 62135596800.0 < begin - 62135596800.0;
+		return dtic;
+	}
+	static _new(dtic) {
+		return dtic;
+	}
+	static invert(this1) {
+		this1.negative = !this1.negative;
+		return this1;
+	}
+	static addTo(this1,dt) {
+		return dt - 62135596800.0 + (this1.negative ? -1 : 1) * (this1.end - 62135596800.0 - (this1.begin - 62135596800.0)) + 62135596800.0;
+	}
+	static subFrom(this1,dt) {
+		return dt - 62135596800.0 - (this1.negative ? -1 : 1) * (this1.end - 62135596800.0 - (this1.begin - 62135596800.0)) + 62135596800.0;
+	}
+	static toString(this1) {
+		let years = this1.getYears();
+		let months = this1.getMonths();
+		let days = this1.getDays();
+		let hours = this1.getHours();
+		let minutes = this1.getMinutes();
+		let seconds = this1.getSeconds();
+		let parts = [];
+		if(years != 0) {
+			parts.push("" + years + "y");
+		}
+		if(months != 0) {
+			parts.push("" + months + "m");
+		}
+		if(days != 0) {
+			parts.push("" + days + "d");
+		}
+		if(hours != 0) {
+			parts.push("" + hours + "hrs");
+		}
+		if(minutes != 0) {
+			parts.push("" + minutes + "min");
+		}
+		if(seconds != 0) {
+			parts.push("" + seconds + "sec");
+		}
+		return (this1.negative ? "-" : "") + "(" + (parts.length == 0 ? "0sec" : parts.join(", ")) + ")";
+	}
+	static sign(this1) {
+		if(this1.negative) {
+			return -1;
+		} else {
+			return 1;
+		}
+	}
+	static format(this1,format) {
+		return datetime_utils_DateTimeIntervalUtils.strftime(this1,format);
+	}
+	static formatPartial(this1,format) {
+		return datetime_utils_DateTimeIntervalUtils.formatPartial(this1,format);
+	}
+	static eq(this1,dtic) {
+		if(this1.negative == dtic.negative) {
+			return this1.getTotalSeconds() == dtic.getTotalSeconds();
+		} else {
+			return false;
+		}
+	}
+	static gt(this1,dtic) {
+		if(this1.negative != dtic.negative) {
+			return dtic.negative;
+		}
+		let delta = this1.getTotalSeconds() - dtic.getTotalSeconds();
+		if(this1.negative) {
+			return delta < 0;
+		} else {
+			return delta > 0;
+		}
+	}
+	static gte(this1,dtic) {
+		if(!(this1.negative == dtic.negative && this1.getTotalSeconds() == dtic.getTotalSeconds())) {
+			if(this1.negative != dtic.negative) {
+				return dtic.negative;
+			} else {
+				let delta = this1.getTotalSeconds() - dtic.getTotalSeconds();
+				if(this1.negative) {
+					return delta < 0;
+				} else {
+					return delta > 0;
+				}
+			}
+		} else {
+			return true;
+		}
+	}
+	static lt(this1,dtic) {
+		let tmp;
+		if(!(this1.negative == dtic.negative && this1.getTotalSeconds() == dtic.getTotalSeconds())) {
+			if(this1.negative != dtic.negative) {
+				tmp = dtic.negative;
+			} else {
+				let delta = this1.getTotalSeconds() - dtic.getTotalSeconds();
+				tmp = this1.negative ? delta < 0 : delta > 0;
+			}
+		} else {
+			tmp = true;
+		}
+		return !tmp;
+	}
+	static lte(this1,dtic) {
+		let tmp;
+		if(this1.negative != dtic.negative) {
+			tmp = dtic.negative;
+		} else {
+			let delta = this1.getTotalSeconds() - dtic.getTotalSeconds();
+			tmp = this1.negative ? delta < 0 : delta > 0;
+		}
+		return !tmp;
+	}
+	static neq(this1,dtic) {
+		return !(this1.negative == dtic.negative && this1.getTotalSeconds() == dtic.getTotalSeconds());
+	}
+}
+class datetime_cores_DateTimeIntervalCore {
+	constructor() {
+		this.seconds = -1;
+		this.minutes = -1;
+		this.hours = -1;
+		this.days = -1;
+		this.months = -1;
+		this.years = -1;
+		this.negative = false;
+	}
+	getYears() {
+		if(this.years < 0) {
+			this.years = datetime_DateTime.getYear(this.end) - datetime_DateTime.getYear(this.begin);
+			let this1 = this.begin;
+			let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+			let m1 = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+			let this2 = this.end;
+			let days1 = ((this2 - 62135596800.0 - datetime_DateTime.yearStart(this2)) / 86400 | 0) + 1;
+			let m2 = datetime_utils_DateTimeMonthUtils.getMonth(days1,datetime_DateTime.isLeapYear(this2));
+			if(m2 < m1) {
+				this.years--;
+			} else if(m1 == m2) {
+				let this1 = this.begin;
+				let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+				let d1 = datetime_utils_DateTimeMonthUtils.getMonthDay(days,datetime_DateTime.isLeapYear(this1));
+				let this2 = this.end;
+				let days1 = ((this2 - 62135596800.0 - datetime_DateTime.yearStart(this2)) / 86400 | 0) + 1;
+				let d2 = datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(this2));
+				if(d2 < d1) {
+					this.years--;
+				} else if(d1 == d2) {
+					let this1 = this.begin;
+					let h1 = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+					let this2 = this.end;
+					let h2 = (this2 - Math.floor(this2 / 86400) * 86400) / 3600 | 0;
+					if(h2 < h1) {
+						this.years--;
+					} else if(h2 == h1) {
+						let this1 = this.begin;
+						let m1 = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+						let this2 = this.end;
+						let m2 = (this2 - Math.floor(this2 / 3600) * 3600) / 60 | 0;
+						if(m2 < m1) {
+							this.years--;
+						} else {
+							let tmp;
+							if(m2 == m1) {
+								let this1 = this.end;
+								let this2 = this.begin;
+								tmp = (this1 - Math.floor(this1 / 60) * 60 | 0) < (this2 - Math.floor(this2 / 60) * 60 | 0);
+							} else {
+								tmp = false;
+							}
+							if(tmp) {
+								this.years--;
+							}
+						}
+					}
+				}
+			}
+		}
+		return this.years;
+	}
+	getMonths() {
+		if(this.months < 0) {
+			let this1 = this.begin;
+			let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+			let monthBegin = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1));
+			let this2 = this.end;
+			let days1 = ((this2 - 62135596800.0 - datetime_DateTime.yearStart(this2)) / 86400 | 0) + 1;
+			let monthEnd = datetime_utils_DateTimeMonthUtils.getMonth(days1,datetime_DateTime.isLeapYear(this2));
+			this.months = monthBegin <= monthEnd ? monthEnd - monthBegin : 12 - monthBegin + monthEnd;
+			let this3 = this.begin;
+			let days2 = ((this3 - 62135596800.0 - datetime_DateTime.yearStart(this3)) / 86400 | 0) + 1;
+			let d1 = datetime_utils_DateTimeMonthUtils.getMonthDay(days2,datetime_DateTime.isLeapYear(this3));
+			let this4 = this.end;
+			let days3 = ((this4 - 62135596800.0 - datetime_DateTime.yearStart(this4)) / 86400 | 0) + 1;
+			let d2 = datetime_utils_DateTimeMonthUtils.getMonthDay(days3,datetime_DateTime.isLeapYear(this4));
+			if(d2 < d1) {
+				this.months--;
+			} else if(d1 == d2) {
+				let this1 = this.begin;
+				let h1 = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+				let this2 = this.end;
+				let h2 = (this2 - Math.floor(this2 / 86400) * 86400) / 3600 | 0;
+				if(h2 < h1) {
+					this.months--;
+				} else if(h2 == h1) {
+					let this1 = this.begin;
+					let m1 = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+					let this2 = this.end;
+					let m2 = (this2 - Math.floor(this2 / 3600) * 3600) / 60 | 0;
+					if(m2 < m1) {
+						this.months--;
+					} else {
+						let tmp;
+						if(m2 == m1) {
+							let this1 = this.end;
+							let this2 = this.begin;
+							tmp = (this1 - Math.floor(this1 / 60) * 60 | 0) < (this2 - Math.floor(this2 / 60) * 60 | 0);
+						} else {
+							tmp = false;
+						}
+						if(tmp) {
+							this.months--;
+						}
+					}
+				}
+			}
+		}
+		return this.months;
+	}
+	getTotalMonths() {
+		return this.getYears() * 12 + this.getMonths();
+	}
+	getDays() {
+		if(this.days < 0) {
+			let this1 = this.begin;
+			let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+			let dayBegin = datetime_utils_DateTimeMonthUtils.getMonthDay(days,datetime_DateTime.isLeapYear(this1));
+			let this2 = this.end;
+			let days1 = ((this2 - 62135596800.0 - datetime_DateTime.yearStart(this2)) / 86400 | 0) + 1;
+			let dayEnd = datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(this2));
+			let tmp;
+			if(dayBegin <= dayEnd) {
+				tmp = dayEnd - dayBegin;
+			} else {
+				let this1 = this.begin;
+				let days = ((this1 - 62135596800.0 - datetime_DateTime.yearStart(this1)) / 86400 | 0) + 1;
+				tmp = datetime_utils_DateTimeMonthUtils.days(datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(this1)),datetime_DateTime.isLeapYear(this.begin)) - dayBegin + dayEnd;
+			}
+			this.days = tmp;
+			let this3 = this.begin;
+			let h1 = (this3 - Math.floor(this3 / 86400) * 86400) / 3600 | 0;
+			let this4 = this.end;
+			let h2 = (this4 - Math.floor(this4 / 86400) * 86400) / 3600 | 0;
+			if(h2 < h1) {
+				this.days--;
+			} else if(h2 == h1) {
+				let this1 = this.begin;
+				let m1 = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+				let this2 = this.end;
+				let m2 = (this2 - Math.floor(this2 / 3600) * 3600) / 60 | 0;
+				if(m2 < m1) {
+					this.days--;
+				} else {
+					let tmp;
+					if(m2 == m1) {
+						let this1 = this.end;
+						let this2 = this.begin;
+						tmp = (this1 - Math.floor(this1 / 60) * 60 | 0) < (this2 - Math.floor(this2 / 60) * 60 | 0);
+					} else {
+						tmp = false;
+					}
+					if(tmp) {
+						this.days--;
+					}
+				}
+			}
+		}
+		return this.days;
+	}
+	getTotalDays() {
+		return (this.end - 62135596800.0 - (this.begin - 62135596800.0)) / 86400 | 0;
+	}
+	getHours() {
+		if(this.hours < 0) {
+			let this1 = this.begin;
+			let hourBegin = (this1 - Math.floor(this1 / 86400) * 86400) / 3600 | 0;
+			let this2 = this.end;
+			let hourEnd = (this2 - Math.floor(this2 / 86400) * 86400) / 3600 | 0;
+			this.hours = hourBegin <= hourEnd ? hourEnd - hourBegin : 24 - hourBegin + hourEnd;
+			let this3 = this.begin;
+			let m1 = (this3 - Math.floor(this3 / 3600) * 3600) / 60 | 0;
+			let this4 = this.end;
+			let m2 = (this4 - Math.floor(this4 / 3600) * 3600) / 60 | 0;
+			if(m2 < m1) {
+				this.hours--;
+			} else {
+				let tmp;
+				if(m2 == m1) {
+					let this1 = this.end;
+					let this2 = this.begin;
+					tmp = (this1 - Math.floor(this1 / 60) * 60 | 0) < (this2 - Math.floor(this2 / 60) * 60 | 0);
+				} else {
+					tmp = false;
+				}
+				if(tmp) {
+					this.hours--;
+				}
+			}
+		}
+		return this.hours;
+	}
+	getTotalHours() {
+		return (this.end - 62135596800.0 - (this.begin - 62135596800.0)) / 3600 | 0;
+	}
+	getMinutes() {
+		if(this.minutes < 0) {
+			let this1 = this.begin;
+			let minuteBegin = (this1 - Math.floor(this1 / 3600) * 3600) / 60 | 0;
+			let this2 = this.end;
+			let minuteEnd = (this2 - Math.floor(this2 / 3600) * 3600) / 60 | 0;
+			this.minutes = minuteBegin <= minuteEnd ? minuteEnd - minuteBegin : 60 - minuteBegin + minuteEnd;
+			let this3 = this.end;
+			let this4 = this.begin;
+			if((this3 - Math.floor(this3 / 60) * 60 | 0) < (this4 - Math.floor(this4 / 60) * 60 | 0)) {
+				this.minutes--;
+			}
+		}
+		return this.minutes;
+	}
+	getTotalMinutes() {
+		return (this.end - 62135596800.0 - (this.begin - 62135596800.0)) / 60 | 0;
+	}
+	getSeconds() {
+		if(this.seconds < 0) {
+			let this1 = this.begin;
+			let secondBegin = this1 - Math.floor(this1 / 60) * 60 | 0;
+			let this2 = this.end;
+			let secondEnd = this2 - Math.floor(this2 / 60) * 60 | 0;
+			this.seconds = secondBegin <= secondEnd ? secondEnd - secondBegin : 60 - secondBegin + secondEnd;
+		}
+		return this.seconds;
+	}
+	getTotalSeconds() {
+		return this.end - 62135596800.0 - (this.begin - 62135596800.0);
+	}
+	getTotalWeeks() {
+		return (this.end - 62135596800.0 - (this.begin - 62135596800.0)) / 604800 | 0;
+	}
+}
+datetime_cores_DateTimeIntervalCore.__name__ = "datetime.cores.DateTimeIntervalCore";
+Object.assign(datetime_cores_DateTimeIntervalCore.prototype, {
+	__class__: datetime_cores_DateTimeIntervalCore
+});
+class datetime_utils_DateTimeIntervalUtils {
+	constructor() {
+	}
+	static strftime(dti,format) {
+		let prevPos = 0;
+		let pos = format.indexOf("%");
+		let str = "";
+		while(pos >= 0) {
+			str += format.substring(prevPos,pos);
+			++pos;
+			switch(format.charCodeAt(pos)) {
+			case 37:
+				str += "%";
+				break;
+			case 68:
+				str += StringTools.lpad(dti.getDays() + "","0",2);
+				break;
+			case 72:
+				str += StringTools.lpad(dti.getHours() + "","0",2);
+				break;
+			case 73:
+				str += StringTools.lpad(dti.getMinutes() + "","0",2);
+				break;
+			case 77:
+				str += StringTools.lpad(dti.getMonths() + "","0",2);
+				break;
+			case 82:
+				str += dti.negative ? "-" : "+";
+				break;
+			case 83:
+				str += StringTools.lpad(dti.getSeconds() + "","0",2);
+				break;
+			case 89:
+				str += StringTools.lpad(dti.getYears() + "","0",2);
+				break;
+			case 97:
+				str += dti.getTotalDays() + "";
+				break;
+			case 98:
+				str += dti.getTotalMonths() + "";
+				break;
+			case 99:
+				str += dti.getTotalHours() + "";
+				break;
+			case 100:
+				str += dti.getDays() + "";
+				break;
+			case 101:
+				str += dti.getTotalMinutes() + "";
+				break;
+			case 102:
+				str += dti.getTotalSeconds() + "";
+				break;
+			case 104:
+				str += dti.getHours() + "";
+				break;
+			case 105:
+				str += dti.getMinutes() + "";
+				break;
+			case 109:
+				str += dti.getMonths() + "";
+				break;
+			case 114:
+				str += dti.negative ? "-" : "";
+				break;
+			case 115:
+				str += dti.getSeconds() + "";
+				break;
+			case 121:
+				str += dti.getYears() + "";
+				break;
+			}
+			prevPos = pos + 1;
+			pos = format.indexOf("%",pos + 1);
+		}
+		str += format.substring(prevPos);
+		return str;
+	}
+	static formatPartial(dti,format) {
+		let result = [];
+		let pos = 0;
+		let str = "";
+		let _g = 0;
+		let _g1 = format.length;
+		while(_g < _g1) {
+			let f = _g++;
+			pos = format[f].indexOf("%");
+			if(pos >= 0) {
+				switch(format[f].charCodeAt(pos + 1)) {
+				case 68:
+					if(dti.getDays() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getDays() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 72:
+					if(dti.getHours() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getHours() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 73:
+					if(dti.getMinutes() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getMinutes() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 77:
+					if(dti.getMonths() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getMonths() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 83:
+					if(dti.getSeconds() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getSeconds() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 89:
+					if(dti.getYears() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + StringTools.lpad(dti.getYears() + "","0",2) + format[f].substring(pos + 2);
+					break;
+				case 97:
+					if(dti.getTotalDays() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalDays() + format[f].substring(pos + 2);
+					break;
+				case 98:
+					if(dti.getTotalMonths() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalMonths() + format[f].substring(pos + 2);
+					break;
+				case 99:
+					if(dti.getTotalHours() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalHours() + format[f].substring(pos + 2);
+					break;
+				case 100:
+					if(dti.getDays() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getDays() + format[f].substring(pos + 2);
+					break;
+				case 101:
+					if(dti.getTotalMinutes() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalMinutes() + format[f].substring(pos + 2);
+					break;
+				case 102:
+					if(dti.getTotalSeconds() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getTotalSeconds() + format[f].substring(pos + 2);
+					break;
+				case 104:
+					if(dti.getHours() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getHours() + format[f].substring(pos + 2);
+					break;
+				case 105:
+					if(dti.getMinutes() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getMinutes() + format[f].substring(pos + 2);
+					break;
+				case 109:
+					if(dti.getMonths() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getMonths() + format[f].substring(pos + 2);
+					break;
+				case 115:
+					if(dti.getSeconds() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getSeconds() + format[f].substring(pos + 2);
+					break;
+				case 121:
+					if(dti.getYears() == 0) {
+						continue;
+					}
+					str = format[f].substring(0,pos) + dti.getYears() + format[f].substring(pos + 2);
+					break;
+				default:
+					continue;
+				}
+				result.push(str);
+			}
+		}
+		return result;
+	}
+}
+datetime_utils_DateTimeIntervalUtils.__name__ = "datetime.utils.DateTimeIntervalUtils";
+Object.assign(datetime_utils_DateTimeIntervalUtils.prototype, {
+	__class__: datetime_utils_DateTimeIntervalUtils
+});
+class datetime_utils_DateTimeMonthUtils {
+	constructor() {
+	}
+	static days(month,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		if(month == 1) {
+			return 31;
+		} else if(month == 2 && isLeapYear) {
+			return 29;
+		} else if(month == 2) {
+			return 28;
+		} else if(month == 3) {
+			return 31;
+		} else if(month == 4) {
+			return 30;
+		} else if(month == 5) {
+			return 31;
+		} else if(month == 6) {
+			return 30;
+		} else if(month == 7) {
+			return 31;
+		} else if(month == 8) {
+			return 31;
+		} else if(month == 9) {
+			return 30;
+		} else if(month == 10) {
+			return 31;
+		} else if(month == 11) {
+			return 30;
+		} else {
+			return 31;
+		}
+	}
+	static getMonth(days,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		if(days < 32) {
+			return 1;
+		} else if(isLeapYear) {
+			if(days < 61) {
+				return 2;
+			} else if(days < 92) {
+				return 3;
+			} else if(days < 122) {
+				return 4;
+			} else if(days < 153) {
+				return 5;
+			} else if(days < 183) {
+				return 6;
+			} else if(days < 214) {
+				return 7;
+			} else if(days < 245) {
+				return 8;
+			} else if(days < 275) {
+				return 9;
+			} else if(days < 306) {
+				return 10;
+			} else if(days < 336) {
+				return 11;
+			} else {
+				return 12;
+			}
+		} else if(days < 60) {
+			return 2;
+		} else if(days < 91) {
+			return 3;
+		} else if(days < 121) {
+			return 4;
+		} else if(days < 152) {
+			return 5;
+		} else if(days < 182) {
+			return 6;
+		} else if(days < 213) {
+			return 7;
+		} else if(days < 244) {
+			return 8;
+		} else if(days < 274) {
+			return 9;
+		} else if(days < 305) {
+			return 10;
+		} else if(days < 335) {
+			return 11;
+		} else {
+			return 12;
+		}
+	}
+	static getMonthDay(days,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		if(days < 32) {
+			return days;
+		} else if(isLeapYear) {
+			if(days < 61) {
+				return days - 31;
+			} else if(days < 92) {
+				return days - 60;
+			} else if(days < 122) {
+				return days - 91;
+			} else if(days < 153) {
+				return days - 121;
+			} else if(days < 183) {
+				return days - 152;
+			} else if(days < 214) {
+				return days - 182;
+			} else if(days < 245) {
+				return days - 213;
+			} else if(days < 275) {
+				return days - 244;
+			} else if(days < 306) {
+				return days - 274;
+			} else if(days < 336) {
+				return days - 305;
+			} else {
+				return days - 335;
+			}
+		} else if(days < 60) {
+			return days - 31;
+		} else if(days < 91) {
+			return days - 59;
+		} else if(days < 121) {
+			return days - 90;
+		} else if(days < 152) {
+			return days - 120;
+		} else if(days < 182) {
+			return days - 151;
+		} else if(days < 213) {
+			return days - 181;
+		} else if(days < 244) {
+			return days - 212;
+		} else if(days < 274) {
+			return days - 243;
+		} else if(days < 305) {
+			return days - 273;
+		} else if(days < 335) {
+			return days - 304;
+		} else {
+			return days - 334;
+		}
+	}
+	static toSeconds(month,isLeapYear) {
+		if(isLeapYear == null) {
+			isLeapYear = false;
+		}
+		return 86400 * (month == 1 ? 0 : isLeapYear ? month == 2 ? 31 : month == 3 ? 60 : month == 4 ? 91 : month == 5 ? 121 : month == 6 ? 152 : month == 7 ? 182 : month == 8 ? 213 : month == 9 ? 244 : month == 10 ? 274 : month == 11 ? 305 : 335 : month == 2 ? 31 : month == 3 ? 59 : month == 4 ? 90 : month == 5 ? 120 : month == 6 ? 151 : month == 7 ? 181 : month == 8 ? 212 : month == 9 ? 243 : month == 10 ? 273 : month == 11 ? 304 : 334);
+	}
+}
+datetime_utils_DateTimeMonthUtils.__name__ = "datetime.utils.DateTimeMonthUtils";
+Object.assign(datetime_utils_DateTimeMonthUtils.prototype, {
+	__class__: datetime_utils_DateTimeMonthUtils
+});
+class datetime_utils_DateTimeSnapUtils {
+	constructor() {
+	}
+	static snapYear(dt,direction) {
+		switch(direction) {
+		case -1:
+			return datetime_DateTime.yearStart(dt);
+		case 0:
+			let next = datetime_DateTime.yearStart(datetime_utils_DateTimeUtils.addYear(dt,1) + 62135596800.0);
+			let previous = datetime_DateTime.yearStart(dt);
+			if(next - (dt - 62135596800.0) > dt - 62135596800.0 - previous) {
+				return previous;
+			} else {
+				return next;
+			}
+			break;
+		case 1:
+			let next1 = datetime_utils_DateTimeUtils.addYear(dt,1) + 62135596800.0;
+			return datetime_DateTime.yearStart(next1);
+		}
+	}
+	static snapMonth(dt,direction) {
+		let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt));
+		let isLeap = datetime_DateTime.isLeapYear(dt);
+		switch(direction) {
+		case -1:
+			return datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap);
+		case 0:
+			let previous = datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap);
+			let next = datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap) + datetime_utils_DateTimeMonthUtils.days(month,isLeap) * 86400;
+			if(next - (dt - 62135596800.0) > dt - 62135596800.0 - previous) {
+				return previous;
+			} else {
+				return next;
+			}
+			break;
+		case 1:
+			return datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap) + datetime_utils_DateTimeMonthUtils.days(month,isLeap) * 86400;
+		}
+	}
+	static snapDay(dt,direction) {
+		let days = (dt - 62135596800.0) / 86400;
+		switch(direction) {
+		case -1:
+			return Math.floor(days) * 86400;
+		case 0:
+			return Math.round(days) * 86400;
+		case 1:
+			return Math.ceil(days) * 86400;
+		}
+	}
+	static snapHour(dt,direction) {
+		let hours = (dt - 62135596800.0) / 3600;
+		switch(direction) {
+		case -1:
+			return Math.floor(hours) * 3600;
+		case 0:
+			return Math.round(hours) * 3600;
+		case 1:
+			return Math.ceil(hours) * 3600;
+		}
+	}
+	static snapMinute(dt,direction) {
+		let minutes = (dt - 62135596800.0) / 60;
+		switch(direction) {
+		case -1:
+			return Math.floor(minutes) * 60;
+		case 0:
+			return Math.round(minutes) * 60;
+		case 1:
+			return Math.ceil(minutes) * 60;
+		}
+	}
+	static snapWeek(dt,direction,required) {
+		let current = datetime_DateTime.getWeekDay(dt);
+		let days = Math.floor((dt - 62135596800.0) / 86400);
+		switch(direction) {
+		case -1:
+			let diff = current >= required ? current - required : current + 7 - required;
+			return (days - diff) * 86400;
+		case 0:
+			let diff1 = current >= required ? current - required : current + 7 - required;
+			let previous = (days - diff1) * 86400;
+			let diff2 = required > current ? required - current : required + 7 - current;
+			let next = (days + diff2) * 86400;
+			if(next - (dt - 62135596800.0) > dt - 62135596800.0 - previous) {
+				return previous;
+			} else {
+				return next;
+			}
+			break;
+		case 1:
+			let diff3 = required > current ? required - current : required + 7 - current;
+			return (days + diff3) * 86400;
+		}
+	}
+}
+datetime_utils_DateTimeSnapUtils.__name__ = "datetime.utils.DateTimeSnapUtils";
+Object.assign(datetime_utils_DateTimeSnapUtils.prototype, {
+	__class__: datetime_utils_DateTimeSnapUtils
+});
+class datetime_utils_DateTimeUtils {
+	constructor() {
+	}
+	static fromString(str) {
+		if(str.length == 10 || str.charCodeAt(10) == 32) {
+			return datetime_utils_DateTimeUtils.parse(str);
+		} else if(str.charCodeAt(10) == 84) {
+			return datetime_utils_DateTimeUtils.fromIsoString(str);
+		} else {
+			throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Should be either `YYYY-MM-DD hh:mm:ss` or `YYYY-MM-DD` or `YYYY-MM-DDThh:mm:ss[.SSS]Z`");
+		}
+	}
+	static parse(str) {
+		let ylength = str.indexOf("-");
+		if(ylength < 1 || str.length - ylength != 6 && str.length - ylength != 15) {
+			throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Should be either `YYYY-MM-DD hh:mm:ss` or `YYYY-MM-DD`");
+		}
+		if(str.length - ylength == 6) {
+			str += " 00:00:00";
+		}
+		let year = Std.parseInt(HxOverrides.substr(str,0,ylength));
+		let month = Std.parseInt(HxOverrides.substr(str,ylength + 1,2));
+		let day = Std.parseInt(HxOverrides.substr(str,ylength + 4,2));
+		let hour = Std.parseInt(HxOverrides.substr(str,ylength + 7,2));
+		let minute = Std.parseInt(HxOverrides.substr(str,ylength + 10,2));
+		let second = Std.parseInt(HxOverrides.substr(str,ylength + 13,2));
+		if(year == null || month == null || day == null || hour == null || minute == null || second == null) {
+			throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Should be either `YYYY-MM-DD hh:mm:ss` or `YYYY-MM-DD`");
+		}
+		let year1 = year;
+		let month1 = month;
+		let day1 = day;
+		let hour1 = hour;
+		let minute1 = minute;
+		let second1 = second;
+		if(second1 == null) {
+			second1 = 0;
+		}
+		if(minute1 == null) {
+			minute1 = 0;
+		}
+		if(hour1 == null) {
+			hour1 = 0;
+		}
+		if(day1 == null) {
+			day1 = 1;
+		}
+		if(month1 == null) {
+			month1 = 1;
+		}
+		if(year1 == null) {
+			year1 = 1970;
+		}
+		return datetime_utils_DateTimeUtils.yearToStamp(year1) + datetime_utils_DateTimeMonthUtils.toSeconds(month1,year1 % 4 == 0 && (year1 % 100 == 0 ? year1 % 400 == 0 : true)) + (day1 - 1) * 86400 + hour1 * 3600 + minute1 * 60 + second1 - 62135596800.0 + 62135596800.0;
+	}
+	static fromIsoString(str) {
+		let tz = null;
+		let tzSep = str.charCodeAt(str.length - 6);
+		if(str.charCodeAt(str.length - 1) == 90) {
+			tz = 0;
+		} else if(tzSep == 43 || tzSep == 45) {
+			let tzHour = Std.parseInt(HxOverrides.substr(str,str.length - 5,2));
+			let tzMin = Std.parseInt(HxOverrides.substr(str,str.length - 2,2));
+			tz = tzHour * 60 + tzMin;
+			if(tzSep == 43) {
+				tz = -1 * tz;
+			}
+		}
+		if(tz == null) {
+			throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Not an ISO 8601 string: No timezone.");
+		}
+		if(str.length > 20) {
+			if(str.charCodeAt(19) != 46 && str.charCodeAt(19) != tzSep) {
+				throw haxe_Exception.thrown("`" + str + "` - incorrect date/time format. Not an ISO 8601 string: Millisecond specification erroneous.");
+			}
+		}
+		return datetime_DateTime.add(datetime_utils_DateTimeUtils.parse(HxOverrides.substr(str,0,10) + " " + HxOverrides.substr(str,11,8)),datetime_DTPeriod.Minute(tz));
+	}
+	static clamp(value,min,max) {
+		if(value < min) {
+			return min;
+		} else if(value > max) {
+			return max;
+		} else {
+			return value;
+		}
+	}
+	static yearToStamp(year) {
+		--year;
+		let cquads = year / 400 | 0;
+		let quads = (year - cquads * 400) / 4 | 0;
+		let excessDays = quads / 25 | 0;
+		return cquads * 12622780800.0 + quads * 126230400.0 - excessDays * 86400 + (year - cquads * 400 - quads * 4) * 31536000;
+	}
+	static addYear(dt,amount) {
+		let year = datetime_DateTime.getYear(dt) + amount;
+		let time = datetime_DateTime.yearStart(dt);
+		let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let time1 = dt - 62135596800.0 - (time + datetime_utils_DateTimeMonthUtils.toSeconds(datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt)),datetime_DateTime.isLeapYear(dt)));
+		let tmp = datetime_utils_DateTimeUtils.yearToStamp(year);
+		let days1 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		return tmp + datetime_utils_DateTimeMonthUtils.toSeconds(datetime_utils_DateTimeMonthUtils.getMonth(days1,datetime_DateTime.isLeapYear(dt)),year % 4 == 0 && (year % 100 == 0 ? year % 400 == 0 : true)) + time1 - 62135596800.0;
+	}
+	static addMonth(dt,amount) {
+		let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt)) + amount;
+		if(month > 12) {
+			let years = month / 12 | 0;
+			dt = datetime_utils_DateTimeUtils.addYear(dt,years) + 62135596800.0;
+			month -= years * 12;
+		} else if(month <= 0) {
+			let years = (month / 12 | 0) - 1;
+			dt = datetime_utils_DateTimeUtils.addYear(dt,years) + 62135596800.0;
+			month -= years * 12;
+		}
+		let isLeap = datetime_DateTime.isLeapYear(dt);
+		let days1 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let value = datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(dt));
+		let max = datetime_utils_DateTimeMonthUtils.days(month,isLeap);
+		let day = value < 1 ? 1 : value > max ? max : value;
+		return datetime_DateTime.yearStart(dt) + datetime_utils_DateTimeMonthUtils.toSeconds(month,isLeap) + (day - 1) * 86400 + ((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) * 3600 + ((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) * 60 + (dt - Math.floor(dt / 60) * 60 | 0);
+	}
+	static getWeekDayNum(dt,weekDay,num) {
+		let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+		let month = datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt));
+		if(num > 0) {
+			let start = datetime_DateTime.monthStart(dt,month) - 1 + 62135596800.0;
+			let first = datetime_DateTime.snap(start,datetime_DTSnap.Week(1,weekDay));
+			return datetime_DateTime.add(first,datetime_DTPeriod.Week(num - 1)) - 62135596800.0;
+		} else if(num < 0) {
+			let start = datetime_DateTime.monthStart(dt,month + 1) - 1 + 62135596800.0;
+			let first = datetime_DateTime.snap(start,datetime_DTSnap.Week(-1,weekDay));
+			return datetime_DateTime.add(first,datetime_DTPeriod.Week(num + 1)) - 62135596800.0;
+		} else {
+			return dt - 62135596800.0;
+		}
+	}
+	static strftime(dt,format) {
+		let prevPos = 0;
+		let pos = format.indexOf("%");
+		let str = "";
+		while(pos >= 0) {
+			str += format.substring(prevPos,pos);
+			++pos;
+			switch(format.charCodeAt(pos)) {
+			case 37:
+				str += "%";
+				break;
+			case 67:
+				str += StringTools.lpad((datetime_DateTime.getYear(dt) / 100 | 0) + "","0",2);
+				break;
+			case 68:
+				let days = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				let str1 = StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonth(days,datetime_DateTime.isLeapYear(dt)) + "/","0",3);
+				let days1 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += str1 + StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonthDay(days1,datetime_DateTime.isLeapYear(dt)) + "/","0",3) + StringTools.lpad(HxOverrides.substr(datetime_DateTime.getYear(dt) + "",-2,null),"0",2);
+				break;
+			case 70:
+				let str2 = datetime_DateTime.getYear(dt) + "-";
+				let days2 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				let str3 = str2 + StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonth(days2,datetime_DateTime.isLeapYear(dt)) + "-","0",3);
+				let days3 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += str3 + StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonthDay(days3,datetime_DateTime.isLeapYear(dt)) + "","0",2);
+				break;
+			case 72:
+				str += StringTools.lpad(((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) + "","0",2);
+				break;
+			case 73:
+				str += StringTools.lpad(datetime_DateTime.getHour12(dt) + "","0",2);
+				break;
+			case 77:
+				str += StringTools.lpad(((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) + "","0",2);
+				break;
+			case 80:
+				str += ((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) < 12 ? "am" : "pm";
+				break;
+			case 82:
+				str += StringTools.lpad(((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) + ":","0",3) + StringTools.lpad(((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) + "","0",2);
+				break;
+			case 83:
+				str += StringTools.lpad((dt - Math.floor(dt / 60) * 60 | 0) + "","0",2);
+				break;
+			case 84:
+				str += StringTools.lpad(((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) + ":","0",3) + StringTools.lpad(((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) + ":","0",3) + StringTools.lpad((dt - Math.floor(dt / 60) * 60 | 0) + "","0",2);
+				break;
+			case 86:
+				str += StringTools.lpad(datetime_DateTime.getWeek(dt) + "","0",2);
+				break;
+			case 89:
+				str += datetime_DateTime.getYear(dt) + "";
+				break;
+			case 100:
+				let days4 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonthDay(days4,datetime_DateTime.isLeapYear(dt)) + "","0",2);
+				break;
+			case 101:
+				let days5 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonthDay(days5,datetime_DateTime.isLeapYear(dt)) + ""," ",2);
+				break;
+			case 106:
+				let day = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += StringTools.lpad("" + day,"0",3);
+				break;
+			case 107:
+				str += StringTools.lpad(((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) + ""," ",2);
+				break;
+			case 108:
+				str += StringTools.lpad(datetime_DateTime.getHour12(dt) + ""," ",2);
+				break;
+			case 109:
+				let days6 = ((dt - 62135596800.0 - datetime_DateTime.yearStart(dt)) / 86400 | 0) + 1;
+				str += StringTools.lpad(datetime_utils_DateTimeMonthUtils.getMonth(days6,datetime_DateTime.isLeapYear(dt)) + "","0",2);
+				break;
+			case 112:
+				str += ((dt - Math.floor(dt / 86400) * 86400) / 3600 | 0) < 12 ? "AM" : "PM";
+				break;
+			case 114:
+				str += StringTools.lpad(datetime_DateTime.getHour12(dt) + ":","0",3) + StringTools.lpad(((dt - Math.floor(dt / 3600) * 3600) / 60 | 0) + ":","0",3) + StringTools.lpad((dt - Math.floor(dt / 60) * 60 | 0) + "","0",2);
+				break;
+			case 115:
+				str += dt - 62135596800.0 + "";
+				break;
+			case 117:
+				str += datetime_DateTime.getWeekDay(dt,true) + "";
+				break;
+			case 119:
+				str += datetime_DateTime.getWeekDay(dt) + "";
+				break;
+			case 121:
+				str += StringTools.lpad(HxOverrides.substr(datetime_DateTime.getYear(dt) + "",-2,null),"0",2);
+				break;
+			}
+			prevPos = pos + 1;
+			pos = format.indexOf("%",pos + 1);
+		}
+		str += format.substring(prevPos);
+		return str;
+	}
+}
+datetime_utils_DateTimeUtils.__name__ = "datetime.utils.DateTimeUtils";
+Object.assign(datetime_utils_DateTimeUtils.prototype, {
+	__class__: datetime_utils_DateTimeUtils
+});
+var haxe_StackItem = $hxEnums["haxe.StackItem"] = { __ename__:true,__constructs__:null
+	,CFunction: {_hx_name:"CFunction",_hx_index:0,__enum__:"haxe.StackItem",toString:$estr}
+	,Module: ($_=function(m) { return {_hx_index:1,m:m,__enum__:"haxe.StackItem",toString:$estr}; },$_._hx_name="Module",$_.__params__ = ["m"],$_)
+	,FilePos: ($_=function(s,file,line,column) { return {_hx_index:2,s:s,file:file,line:line,column:column,__enum__:"haxe.StackItem",toString:$estr}; },$_._hx_name="FilePos",$_.__params__ = ["s","file","line","column"],$_)
+	,Method: ($_=function(classname,method) { return {_hx_index:3,classname:classname,method:method,__enum__:"haxe.StackItem",toString:$estr}; },$_._hx_name="Method",$_.__params__ = ["classname","method"],$_)
+	,LocalFunction: ($_=function(v) { return {_hx_index:4,v:v,__enum__:"haxe.StackItem",toString:$estr}; },$_._hx_name="LocalFunction",$_.__params__ = ["v"],$_)
+};
+haxe_StackItem.__constructs__ = [haxe_StackItem.CFunction,haxe_StackItem.Module,haxe_StackItem.FilePos,haxe_StackItem.Method,haxe_StackItem.LocalFunction];
+class haxe_IMap {
+}
+haxe_IMap.__name__ = "haxe.IMap";
+haxe_IMap.__isInterface__ = true;
+Object.assign(haxe_IMap.prototype, {
+	__class__: haxe_IMap
+});
+class haxe_Exception extends Error {
+	constructor(message,previous,native) {
+		super(message);
+		this.message = message;
+		this.__previousException = previous;
+		this.__nativeException = native != null ? native : this;
+	}
+	unwrap() {
+		return this.__nativeException;
+	}
+	toString() {
+		return this.get_message();
+	}
+	get_message() {
+		return this.message;
+	}
+	get_native() {
+		return this.__nativeException;
+	}
+	static caught(value) {
+		if(((value) instanceof haxe_Exception)) {
+			return value;
+		} else if(((value) instanceof Error)) {
+			return new haxe_Exception(value.message,null,value);
+		} else {
+			return new haxe_ValueException(value,null,value);
+		}
+	}
+	static thrown(value) {
+		if(((value) instanceof haxe_Exception)) {
+			return value.get_native();
+		} else if(((value) instanceof Error)) {
+			return value;
+		} else {
+			let e = new haxe_ValueException(value);
+			return e;
+		}
+	}
+}
+haxe_Exception.__name__ = "haxe.Exception";
+haxe_Exception.__super__ = Error;
+Object.assign(haxe_Exception.prototype, {
+	__class__: haxe_Exception
+});
+class haxe__$Int64__$_$_$Int64 {
+	constructor(high,low) {
+		this.high = high;
+		this.low = low;
+	}
+}
+haxe__$Int64__$_$_$Int64.__name__ = "haxe._Int64.___Int64";
+Object.assign(haxe__$Int64__$_$_$Int64.prototype, {
+	__class__: haxe__$Int64__$_$_$Int64
+});
+class haxe_Log {
+	static formatOutput(v,infos) {
+		let str = Std.string(v);
+		if(infos == null) {
+			return str;
+		}
+		let pstr = infos.fileName + ":" + infos.lineNumber;
+		if(infos.customParams != null) {
+			let _g = 0;
+			let _g1 = infos.customParams;
+			while(_g < _g1.length) {
+				let v = _g1[_g];
+				++_g;
+				str += ", " + Std.string(v);
+			}
+		}
+		return pstr + ": " + str;
+	}
+	static trace(v,infos) {
+		let str = haxe_Log.formatOutput(v,infos);
+		if(typeof(console) != "undefined" && console.log != null) {
+			console.log(str);
+		}
+	}
+}
+haxe_Log.__name__ = "haxe.Log";
+class haxe_Timer {
+	constructor(time_ms) {
+		let me = this;
+		this.id = setInterval(function() {
+			me.run();
+		},time_ms);
+	}
+	stop() {
+		if(this.id == null) {
+			return;
+		}
+		clearInterval(this.id);
+		this.id = null;
+	}
+	run() {
+	}
+	static delay(f,time_ms) {
+		let t = new haxe_Timer(time_ms);
+		t.run = function() {
+			t.stop();
+			f();
+		};
+		return t;
+	}
+}
+haxe_Timer.__name__ = "haxe.Timer";
+Object.assign(haxe_Timer.prototype, {
+	__class__: haxe_Timer
+});
+class haxe_ValueException extends haxe_Exception {
+	constructor(value,previous,native) {
+		super(String(value),previous,native);
+		this.value = value;
+	}
+	unwrap() {
+		return this.value;
+	}
+}
+haxe_ValueException.__name__ = "haxe.ValueException";
+haxe_ValueException.__super__ = haxe_Exception;
+Object.assign(haxe_ValueException.prototype, {
+	__class__: haxe_ValueException
+});
+class haxe_crypto_Adler32 {
+	constructor() {
+		this.a1 = 1;
+		this.a2 = 0;
+	}
+	get() {
+		return this.a2 << 16 | this.a1;
+	}
+	update(b,pos,len) {
+		let a1 = this.a1;
+		let a2 = this.a2;
+		let _g = pos;
+		let _g1 = pos + len;
+		while(_g < _g1) {
+			let p = _g++;
+			let c = b.b[p];
+			a1 = (a1 + c) % 65521;
+			a2 = (a2 + a1) % 65521;
+		}
+		this.a1 = a1;
+		this.a2 = a2;
+	}
+	static make(b) {
+		let a = new haxe_crypto_Adler32();
+		a.update(b,0,b.length);
+		return a.get();
+	}
+}
+haxe_crypto_Adler32.__name__ = "haxe.crypto.Adler32";
+Object.assign(haxe_crypto_Adler32.prototype, {
+	__class__: haxe_crypto_Adler32
+});
+class haxe_io_Bytes {
+	constructor(data) {
+		this.length = data.byteLength;
+		this.b = new Uint8Array(data);
+		this.b.bufferValue = data;
+		data.hxBytes = this;
+		data.bytes = this.b;
+	}
+	blit(pos,src,srcpos,len) {
+		if(pos < 0 || srcpos < 0 || len < 0 || pos + len > this.length || srcpos + len > src.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		if(srcpos == 0 && len == src.b.byteLength) {
+			this.b.set(src.b,pos);
+		} else {
+			this.b.set(src.b.subarray(srcpos,srcpos + len),pos);
+		}
+	}
+	fill(pos,len,value) {
+		let _g = 0;
+		let _g1 = len;
+		while(_g < _g1) {
+			let i = _g++;
+			this.b[pos++] = value;
+		}
+	}
+	sub(pos,len) {
+		if(pos < 0 || len < 0 || pos + len > this.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		return new haxe_io_Bytes(this.b.buffer.slice(pos + this.b.byteOffset,pos + this.b.byteOffset + len));
+	}
+	getUInt16(pos) {
+		if(this.data == null) {
+			this.data = new DataView(this.b.buffer,this.b.byteOffset,this.b.byteLength);
+		}
+		return this.data.getUint16(pos,true);
+	}
+	getString(pos,len,encoding) {
+		if(pos < 0 || len < 0 || pos + len > this.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		if(encoding == null) {
+			encoding = haxe_io_Encoding.UTF8;
+		}
+		let s = "";
+		let b = this.b;
+		let i = pos;
+		let max = pos + len;
+		switch(encoding._hx_index) {
+		case 0:
+			let debug = pos > 0;
+			while(i < max) {
+				let c = b[i++];
+				if(c < 128) {
+					if(c == 0) {
+						break;
+					}
+					s += String.fromCodePoint(c);
+				} else if(c < 224) {
+					let code = (c & 63) << 6 | b[i++] & 127;
+					s += String.fromCodePoint(code);
+				} else if(c < 240) {
+					let c2 = b[i++];
+					let code = (c & 31) << 12 | (c2 & 127) << 6 | b[i++] & 127;
+					s += String.fromCodePoint(code);
+				} else {
+					let c2 = b[i++];
+					let c3 = b[i++];
+					let u = (c & 15) << 18 | (c2 & 127) << 12 | (c3 & 127) << 6 | b[i++] & 127;
+					s += String.fromCodePoint(u);
+				}
+			}
+			break;
+		case 1:
+			while(i < max) {
+				let c = b[i++] | b[i++] << 8;
+				s += String.fromCodePoint(c);
+			}
+			break;
+		}
+		return s;
+	}
+	toString() {
+		return this.getString(0,this.length);
+	}
+	toHex() {
+		let s_b = "";
+		let chars = [];
+		let str = "0123456789abcdef";
+		let _g = 0;
+		let _g1 = str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			chars.push(HxOverrides.cca(str,i));
+		}
+		let _g2 = 0;
+		let _g3 = this.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			let c = this.b[i];
+			s_b += String.fromCodePoint(chars[c >> 4]);
+			s_b += String.fromCodePoint(chars[c & 15]);
+		}
+		return s_b;
+	}
+	static ofString(s,encoding) {
+		if(encoding == haxe_io_Encoding.RawNative) {
+			let buf = new Uint8Array(s.length << 1);
+			let _g = 0;
+			let _g1 = s.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let c = s.charCodeAt(i);
+				buf[i << 1] = c & 255;
+				buf[i << 1 | 1] = c >> 8;
+			}
+			return new haxe_io_Bytes(buf.buffer);
+		}
+		let a = [];
+		let i = 0;
+		while(i < s.length) {
+			let c = s.charCodeAt(i++);
+			if(55296 <= c && c <= 56319) {
+				c = c - 55232 << 10 | s.charCodeAt(i++) & 1023;
+			}
+			if(c <= 127) {
+				a.push(c);
+			} else if(c <= 2047) {
+				a.push(192 | c >> 6);
+				a.push(128 | c & 63);
+			} else if(c <= 65535) {
+				a.push(224 | c >> 12);
+				a.push(128 | c >> 6 & 63);
+				a.push(128 | c & 63);
+			} else {
+				a.push(240 | c >> 18);
+				a.push(128 | c >> 12 & 63);
+				a.push(128 | c >> 6 & 63);
+				a.push(128 | c & 63);
+			}
+		}
+		return new haxe_io_Bytes(new Uint8Array(a).buffer);
+	}
+	static ofData(b) {
+		let hb = b.hxBytes;
+		if(hb != null) {
+			return hb;
+		}
+		return new haxe_io_Bytes(b);
+	}
+	static ofHex(s) {
+		if((s.length & 1) != 0) {
+			throw haxe_Exception.thrown("Not a hex string (odd number of digits)");
+		}
+		let a = [];
+		let i = 0;
+		let len = s.length >> 1;
+		while(i < len) {
+			let high = s.charCodeAt(i * 2);
+			let low = s.charCodeAt(i * 2 + 1);
+			high = (high & 15) + ((high & 64) >> 6) * 9;
+			low = (low & 15) + ((low & 64) >> 6) * 9;
+			a.push((high << 4 | low) & 255);
+			++i;
+		}
+		return new haxe_io_Bytes(new Uint8Array(a).buffer);
+	}
+}
+haxe_io_Bytes.__name__ = "haxe.io.Bytes";
+Object.assign(haxe_io_Bytes.prototype, {
+	__class__: haxe_io_Bytes
+});
+var haxe_io_Encoding = $hxEnums["haxe.io.Encoding"] = { __ename__:true,__constructs__:null
+	,UTF8: {_hx_name:"UTF8",_hx_index:0,__enum__:"haxe.io.Encoding",toString:$estr}
+	,RawNative: {_hx_name:"RawNative",_hx_index:1,__enum__:"haxe.io.Encoding",toString:$estr}
+};
+haxe_io_Encoding.__constructs__ = [haxe_io_Encoding.UTF8,haxe_io_Encoding.RawNative];
+class haxe_crypto_Base64 {
+	static encode(bytes,complement) {
+		if(complement == null) {
+			complement = true;
+		}
+		let str = new haxe_crypto_BaseCode(haxe_crypto_Base64.BYTES).encodeBytes(bytes).toString();
+		if(complement) {
+			switch(bytes.length % 3) {
+			case 1:
+				str += "==";
+				break;
+			case 2:
+				str += "=";
+				break;
+			default:
+			}
+		}
+		return str;
+	}
+	static decode(str,complement) {
+		if(complement == null) {
+			complement = true;
+		}
+		if(complement) {
+			while(HxOverrides.cca(str,str.length - 1) == 61) str = HxOverrides.substr(str,0,-1);
+		}
+		return new haxe_crypto_BaseCode(haxe_crypto_Base64.BYTES).decodeBytes(haxe_io_Bytes.ofString(str));
+	}
+	static urlEncode(bytes,complement) {
+		if(complement == null) {
+			complement = false;
+		}
+		let str = new haxe_crypto_BaseCode(haxe_crypto_Base64.URL_BYTES).encodeBytes(bytes).toString();
+		if(complement) {
+			switch(bytes.length % 3) {
+			case 1:
+				str += "==";
+				break;
+			case 2:
+				str += "=";
+				break;
+			default:
+			}
+		}
+		return str;
+	}
+	static urlDecode(str,complement) {
+		if(complement == null) {
+			complement = false;
+		}
+		if(complement) {
+			while(HxOverrides.cca(str,str.length - 1) == 61) str = HxOverrides.substr(str,0,-1);
+		}
+		return new haxe_crypto_BaseCode(haxe_crypto_Base64.URL_BYTES).decodeBytes(haxe_io_Bytes.ofString(str));
+	}
+}
+haxe_crypto_Base64.__name__ = "haxe.crypto.Base64";
+class haxe_crypto_BaseCode {
+	constructor(base) {
+		let len = base.length;
+		let nbits = 1;
+		while(len > 1 << nbits) ++nbits;
+		if(nbits > 8 || len != 1 << nbits) {
+			throw haxe_Exception.thrown("BaseCode : base length must be a power of two.");
+		}
+		this.base = base;
+		this.nbits = nbits;
+	}
+	encodeBytes(b) {
+		let nbits = this.nbits;
+		let base = this.base;
+		let size = b.length * 8 / nbits | 0;
+		let out = new haxe_io_Bytes(new ArrayBuffer(size + (b.length * 8 % nbits == 0 ? 0 : 1)));
+		let buf = 0;
+		let curbits = 0;
+		let mask = (1 << nbits) - 1;
+		let pin = 0;
+		let pout = 0;
+		while(pout < size) {
+			while(curbits < nbits) {
+				curbits += 8;
+				buf <<= 8;
+				buf |= b.b[pin++];
+			}
+			curbits -= nbits;
+			out.b[pout++] = base.b[buf >> curbits & mask];
+		}
+		if(curbits > 0) {
+			out.b[pout++] = base.b[buf << nbits - curbits & mask];
+		}
+		return out;
+	}
+	initTable() {
+		let tbl = [];
+		let _g = 0;
+		while(_g < 256) {
+			let i = _g++;
+			tbl[i] = -1;
+		}
+		let _g1 = 0;
+		let _g2 = this.base.length;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			tbl[this.base.b[i]] = i;
+		}
+		this.tbl = tbl;
+	}
+	decodeBytes(b) {
+		let nbits = this.nbits;
+		let base = this.base;
+		if(this.tbl == null) {
+			this.initTable();
+		}
+		let tbl = this.tbl;
+		let size = b.length * nbits >> 3;
+		let out = new haxe_io_Bytes(new ArrayBuffer(size));
+		let buf = 0;
+		let curbits = 0;
+		let pin = 0;
+		let pout = 0;
+		while(pout < size) {
+			while(curbits < 8) {
+				curbits += nbits;
+				buf <<= nbits;
+				let i = tbl[b.b[pin++]];
+				if(i == -1) {
+					throw haxe_Exception.thrown("BaseCode : invalid encoded char");
+				}
+				buf |= i;
+			}
+			curbits -= 8;
+			out.b[pout++] = buf >> curbits & 255;
+		}
+		return out;
+	}
+}
+haxe_crypto_BaseCode.__name__ = "haxe.crypto.BaseCode";
+Object.assign(haxe_crypto_BaseCode.prototype, {
+	__class__: haxe_crypto_BaseCode
+});
+class haxe_crypto_Crc32 {
+	static make(data) {
+		let c_crc = -1;
+		let b = data.b.bufferValue;
+		let _g = 0;
+		let _g1 = data.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let tmp = (c_crc ^ b.bytes[i]) & 255;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			tmp = tmp >>> 1 ^ -(tmp & 1) & -306674912;
+			c_crc = c_crc >>> 8 ^ tmp;
+		}
+		return c_crc ^ -1;
+	}
+}
+haxe_crypto_Crc32.__name__ = "haxe.crypto.Crc32";
+class haxe_crypto_Sha1 {
+	constructor() {
+	}
+	doEncode(x) {
+		let w = [];
+		let a = 1732584193;
+		let b = -271733879;
+		let c = -1732584194;
+		let d = 271733878;
+		let e = -1009589776;
+		let i = 0;
+		while(i < x.length) {
+			let olda = a;
+			let oldb = b;
+			let oldc = c;
+			let oldd = d;
+			let olde = e;
+			let j = 0;
+			while(j < 80) {
+				if(j < 16) {
+					w[j] = x[i + j];
+				} else {
+					let num = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16];
+					w[j] = num << 1 | num >>> 31;
+				}
+				let t = (a << 5 | a >>> 27) + this.ft(j,b,c,d) + e + w[j] + this.kt(j);
+				e = d;
+				d = c;
+				c = b << 30 | b >>> 2;
+				b = a;
+				a = t;
+				++j;
+			}
+			a += olda;
+			b += oldb;
+			c += oldc;
+			d += oldd;
+			e += olde;
+			i += 16;
+		}
+		return [a,b,c,d,e];
+	}
+	ft(t,b,c,d) {
+		if(t < 20) {
+			return b & c | ~b & d;
+		}
+		if(t < 40) {
+			return b ^ c ^ d;
+		}
+		if(t < 60) {
+			return b & c | b & d | c & d;
+		}
+		return b ^ c ^ d;
+	}
+	kt(t) {
+		if(t < 20) {
+			return 1518500249;
+		}
+		if(t < 40) {
+			return 1859775393;
+		}
+		if(t < 60) {
+			return -1894007588;
+		}
+		return -899497514;
+	}
+	static make(b) {
+		let h = new haxe_crypto_Sha1().doEncode(haxe_crypto_Sha1.bytes2blks(b));
+		let out = new haxe_io_Bytes(new ArrayBuffer(20));
+		let p = 0;
+		out.b[p++] = h[0] >>> 24;
+		out.b[p++] = h[0] >> 16 & 255;
+		out.b[p++] = h[0] >> 8 & 255;
+		out.b[p++] = h[0] & 255;
+		out.b[p++] = h[1] >>> 24;
+		out.b[p++] = h[1] >> 16 & 255;
+		out.b[p++] = h[1] >> 8 & 255;
+		out.b[p++] = h[1] & 255;
+		out.b[p++] = h[2] >>> 24;
+		out.b[p++] = h[2] >> 16 & 255;
+		out.b[p++] = h[2] >> 8 & 255;
+		out.b[p++] = h[2] & 255;
+		out.b[p++] = h[3] >>> 24;
+		out.b[p++] = h[3] >> 16 & 255;
+		out.b[p++] = h[3] >> 8 & 255;
+		out.b[p++] = h[3] & 255;
+		out.b[p++] = h[4] >>> 24;
+		out.b[p++] = h[4] >> 16 & 255;
+		out.b[p++] = h[4] >> 8 & 255;
+		out.b[p++] = h[4] & 255;
+		return out;
+	}
+	static bytes2blks(b) {
+		let nblk = (b.length + 8 >> 6) + 1;
+		let blks = [];
+		let _g = 0;
+		let _g1 = nblk * 16;
+		while(_g < _g1) {
+			let i = _g++;
+			blks[i] = 0;
+		}
+		let _g2 = 0;
+		let _g3 = b.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			let p = i >> 2;
+			blks[p] |= b.b[i] << 24 - ((i & 3) << 3);
+		}
+		let i = b.length;
+		let p = i >> 2;
+		blks[p] |= 128 << 24 - ((i & 3) << 3);
+		blks[nblk * 16 - 1] = b.length * 8;
+		return blks;
+	}
+}
+haxe_crypto_Sha1.__name__ = "haxe.crypto.Sha1";
+Object.assign(haxe_crypto_Sha1.prototype, {
+	__class__: haxe_crypto_Sha1
+});
+class haxe_crypto_Sha256 {
+	constructor() {
+	}
+	doEncode(m,l) {
+		let K = [1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998];
+		let HASH = [1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225];
+		let W = [];
+		W[64] = 0;
+		let a;
+		let b;
+		let c;
+		let d;
+		let e;
+		let f;
+		let g;
+		let h;
+		let T1;
+		let T2;
+		m[l >> 5] |= 128 << 24 - l % 32;
+		m[(l + 64 >> 9 << 4) + 15] = l;
+		let i = 0;
+		while(i < m.length) {
+			a = HASH[0];
+			b = HASH[1];
+			c = HASH[2];
+			d = HASH[3];
+			e = HASH[4];
+			f = HASH[5];
+			g = HASH[6];
+			h = HASH[7];
+			let _g = 0;
+			while(_g < 64) {
+				let j = _g++;
+				if(j < 16) {
+					W[j] = m[j + i];
+				} else {
+					let x = W[j - 2];
+					let x1 = (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ x >>> 10;
+					let y = W[j - 7];
+					let lsw = (x1 & 65535) + (y & 65535);
+					let msw = (x1 >> 16) + (y >> 16) + (lsw >> 16);
+					let x2 = msw << 16 | lsw & 65535;
+					let x3 = W[j - 15];
+					let y1 = (x3 >>> 7 | x3 << 25) ^ (x3 >>> 18 | x3 << 14) ^ x3 >>> 3;
+					let lsw1 = (x2 & 65535) + (y1 & 65535);
+					let msw1 = (x2 >> 16) + (y1 >> 16) + (lsw1 >> 16);
+					let x4 = msw1 << 16 | lsw1 & 65535;
+					let y2 = W[j - 16];
+					let lsw2 = (x4 & 65535) + (y2 & 65535);
+					let msw2 = (x4 >> 16) + (y2 >> 16) + (lsw2 >> 16);
+					W[j] = msw2 << 16 | lsw2 & 65535;
+				}
+				let y = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
+				let lsw = (h & 65535) + (y & 65535);
+				let msw = (h >> 16) + (y >> 16) + (lsw >> 16);
+				let x = msw << 16 | lsw & 65535;
+				let y1 = e & f ^ ~e & g;
+				let lsw1 = (x & 65535) + (y1 & 65535);
+				let msw1 = (x >> 16) + (y1 >> 16) + (lsw1 >> 16);
+				let x1 = msw1 << 16 | lsw1 & 65535;
+				let y2 = K[j];
+				let lsw2 = (x1 & 65535) + (y2 & 65535);
+				let msw2 = (x1 >> 16) + (y2 >> 16) + (lsw2 >> 16);
+				let x2 = msw2 << 16 | lsw2 & 65535;
+				let y3 = W[j];
+				let lsw3 = (x2 & 65535) + (y3 & 65535);
+				let msw3 = (x2 >> 16) + (y3 >> 16) + (lsw3 >> 16);
+				T1 = msw3 << 16 | lsw3 & 65535;
+				let x3 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);
+				let y4 = a & b ^ a & c ^ b & c;
+				let lsw4 = (x3 & 65535) + (y4 & 65535);
+				let msw4 = (x3 >> 16) + (y4 >> 16) + (lsw4 >> 16);
+				T2 = msw4 << 16 | lsw4 & 65535;
+				h = g;
+				g = f;
+				f = e;
+				let lsw5 = (d & 65535) + (T1 & 65535);
+				let msw5 = (d >> 16) + (T1 >> 16) + (lsw5 >> 16);
+				e = msw5 << 16 | lsw5 & 65535;
+				d = c;
+				c = b;
+				b = a;
+				let lsw6 = (T1 & 65535) + (T2 & 65535);
+				let msw6 = (T1 >> 16) + (T2 >> 16) + (lsw6 >> 16);
+				a = msw6 << 16 | lsw6 & 65535;
+			}
+			let y = HASH[0];
+			let lsw = (a & 65535) + (y & 65535);
+			let msw = (a >> 16) + (y >> 16) + (lsw >> 16);
+			HASH[0] = msw << 16 | lsw & 65535;
+			let y1 = HASH[1];
+			let lsw1 = (b & 65535) + (y1 & 65535);
+			let msw1 = (b >> 16) + (y1 >> 16) + (lsw1 >> 16);
+			HASH[1] = msw1 << 16 | lsw1 & 65535;
+			let y2 = HASH[2];
+			let lsw2 = (c & 65535) + (y2 & 65535);
+			let msw2 = (c >> 16) + (y2 >> 16) + (lsw2 >> 16);
+			HASH[2] = msw2 << 16 | lsw2 & 65535;
+			let y3 = HASH[3];
+			let lsw3 = (d & 65535) + (y3 & 65535);
+			let msw3 = (d >> 16) + (y3 >> 16) + (lsw3 >> 16);
+			HASH[3] = msw3 << 16 | lsw3 & 65535;
+			let y4 = HASH[4];
+			let lsw4 = (e & 65535) + (y4 & 65535);
+			let msw4 = (e >> 16) + (y4 >> 16) + (lsw4 >> 16);
+			HASH[4] = msw4 << 16 | lsw4 & 65535;
+			let y5 = HASH[5];
+			let lsw5 = (f & 65535) + (y5 & 65535);
+			let msw5 = (f >> 16) + (y5 >> 16) + (lsw5 >> 16);
+			HASH[5] = msw5 << 16 | lsw5 & 65535;
+			let y6 = HASH[6];
+			let lsw6 = (g & 65535) + (y6 & 65535);
+			let msw6 = (g >> 16) + (y6 >> 16) + (lsw6 >> 16);
+			HASH[6] = msw6 << 16 | lsw6 & 65535;
+			let y7 = HASH[7];
+			let lsw7 = (h & 65535) + (y7 & 65535);
+			let msw7 = (h >> 16) + (y7 >> 16) + (lsw7 >> 16);
+			HASH[7] = msw7 << 16 | lsw7 & 65535;
+			i += 16;
+		}
+		return HASH;
+	}
+	static make(b) {
+		let h = new haxe_crypto_Sha256().doEncode(haxe_crypto_Sha256.bytes2blks(b),b.length * 8);
+		let out = new haxe_io_Bytes(new ArrayBuffer(32));
+		let p = 0;
+		let _g = 0;
+		while(_g < 8) {
+			let i = _g++;
+			out.b[p++] = h[i] >>> 24;
+			out.b[p++] = h[i] >> 16 & 255;
+			out.b[p++] = h[i] >> 8 & 255;
+			out.b[p++] = h[i] & 255;
+		}
+		return out;
+	}
+	static bytes2blks(b) {
+		let nblk = (b.length + 8 >> 6) + 1;
+		let blks = [];
+		let _g = 0;
+		let _g1 = nblk * 16;
+		while(_g < _g1) {
+			let i = _g++;
+			blks[i] = 0;
+		}
+		let _g2 = 0;
+		let _g3 = b.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			let p = i >> 2;
+			blks[p] |= b.b[i] << 24 - ((i & 3) << 3);
+		}
+		let i = b.length;
+		let p = i >> 2;
+		blks[p] |= 128 << 24 - ((i & 3) << 3);
+		blks[nblk * 16 - 1] = b.length * 8;
+		return blks;
+	}
+}
+haxe_crypto_Sha256.__name__ = "haxe.crypto.Sha256";
+Object.assign(haxe_crypto_Sha256.prototype, {
+	__class__: haxe_crypto_Sha256
+});
+class haxe_ds_BalancedTree {
+	constructor() {
+	}
+	set(key,value) {
+		this.root = this.setLoop(key,value,this.root);
+	}
+	get(key) {
+		let node = this.root;
+		while(node != null) {
+			let c = this.compare(key,node.key);
+			if(c == 0) {
+				return node.value;
+			}
+			if(c < 0) {
+				node = node.left;
+			} else {
+				node = node.right;
+			}
+		}
+		return null;
+	}
+	exists(key) {
+		let node = this.root;
+		while(node != null) {
+			let c = this.compare(key,node.key);
+			if(c == 0) {
+				return true;
+			} else if(c < 0) {
+				node = node.left;
+			} else {
+				node = node.right;
+			}
+		}
+		return false;
+	}
+	iterator() {
+		let ret = [];
+		haxe_ds_BalancedTree.iteratorLoop(this.root,ret);
+		return new haxe_iterators_ArrayIterator(ret);
+	}
+	keyValueIterator() {
+		return new haxe_iterators_MapKeyValueIterator(this);
+	}
+	keys() {
+		let ret = [];
+		this.keysLoop(this.root,ret);
+		return new haxe_iterators_ArrayIterator(ret);
+	}
+	setLoop(k,v,node) {
+		if(node == null) {
+			return new haxe_ds_TreeNode(null,k,v,null);
+		}
+		let c = this.compare(k,node.key);
+		if(c == 0) {
+			return new haxe_ds_TreeNode(node.left,k,v,node.right,node == null ? 0 : node._height);
+		} else if(c < 0) {
+			let nl = this.setLoop(k,v,node.left);
+			return this.balance(nl,node.key,node.value,node.right);
+		} else {
+			let nr = this.setLoop(k,v,node.right);
+			return this.balance(node.left,node.key,node.value,nr);
+		}
+	}
+	keysLoop(node,acc) {
+		if(node != null) {
+			this.keysLoop(node.left,acc);
+			acc.push(node.key);
+			this.keysLoop(node.right,acc);
+		}
+	}
+	balance(l,k,v,r) {
+		let hl = l == null ? 0 : l._height;
+		let hr = r == null ? 0 : r._height;
+		if(hl > hr + 2) {
+			let _this = l.left;
+			let _this1 = l.right;
+			if((_this == null ? 0 : _this._height) >= (_this1 == null ? 0 : _this1._height)) {
+				return new haxe_ds_TreeNode(l.left,l.key,l.value,new haxe_ds_TreeNode(l.right,k,v,r));
+			} else {
+				return new haxe_ds_TreeNode(new haxe_ds_TreeNode(l.left,l.key,l.value,l.right.left),l.right.key,l.right.value,new haxe_ds_TreeNode(l.right.right,k,v,r));
+			}
+		} else if(hr > hl + 2) {
+			let _this = r.right;
+			let _this1 = r.left;
+			if((_this == null ? 0 : _this._height) > (_this1 == null ? 0 : _this1._height)) {
+				return new haxe_ds_TreeNode(new haxe_ds_TreeNode(l,k,v,r.left),r.key,r.value,r.right);
+			} else {
+				return new haxe_ds_TreeNode(new haxe_ds_TreeNode(l,k,v,r.left.left),r.left.key,r.left.value,new haxe_ds_TreeNode(r.left.right,r.key,r.value,r.right));
+			}
+		} else {
+			return new haxe_ds_TreeNode(l,k,v,r,(hl > hr ? hl : hr) + 1);
+		}
+	}
+	compare(k1,k2) {
+		return Reflect.compare(k1,k2);
+	}
+	static iteratorLoop(node,acc) {
+		if(node != null) {
+			haxe_ds_BalancedTree.iteratorLoop(node.left,acc);
+			acc.push(node.value);
+			haxe_ds_BalancedTree.iteratorLoop(node.right,acc);
+		}
+	}
+}
+haxe_ds_BalancedTree.__name__ = "haxe.ds.BalancedTree";
+haxe_ds_BalancedTree.__interfaces__ = [haxe_IMap];
+Object.assign(haxe_ds_BalancedTree.prototype, {
+	__class__: haxe_ds_BalancedTree
+});
+class haxe_ds_TreeNode {
+	constructor(l,k,v,r,h) {
+		if(h == null) {
+			h = -1;
+		}
+		this.left = l;
+		this.key = k;
+		this.value = v;
+		this.right = r;
+		if(h == -1) {
+			let tmp;
+			let _this = this.left;
+			let _this1 = this.right;
+			if((_this == null ? 0 : _this._height) > (_this1 == null ? 0 : _this1._height)) {
+				let _this = this.left;
+				tmp = _this == null ? 0 : _this._height;
+			} else {
+				let _this = this.right;
+				tmp = _this == null ? 0 : _this._height;
+			}
+			this._height = tmp + 1;
+		} else {
+			this._height = h;
+		}
+	}
+}
+haxe_ds_TreeNode.__name__ = "haxe.ds.TreeNode";
+Object.assign(haxe_ds_TreeNode.prototype, {
+	__class__: haxe_ds_TreeNode
+});
+var haxe_ds_Either = $hxEnums["haxe.ds.Either"] = { __ename__:true,__constructs__:null
+	,Left: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"haxe.ds.Either",toString:$estr}; },$_._hx_name="Left",$_.__params__ = ["v"],$_)
+	,Right: ($_=function(v) { return {_hx_index:1,v:v,__enum__:"haxe.ds.Either",toString:$estr}; },$_._hx_name="Right",$_.__params__ = ["v"],$_)
+};
+haxe_ds_Either.__constructs__ = [haxe_ds_Either.Left,haxe_ds_Either.Right];
+class haxe_ds_EnumValueMap extends haxe_ds_BalancedTree {
+	constructor() {
+		super();
+	}
+	compare(k1,k2) {
+		let d = k1._hx_index - k2._hx_index;
+		if(d != 0) {
+			return d;
+		}
+		let p1 = Type.enumParameters(k1);
+		let p2 = Type.enumParameters(k2);
+		if(p1.length == 0 && p2.length == 0) {
+			return 0;
+		}
+		return this.compareArgs(p1,p2);
+	}
+	compareArgs(a1,a2) {
+		let ld = a1.length - a2.length;
+		if(ld != 0) {
+			return ld;
+		}
+		let _g = 0;
+		let _g1 = a1.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let d = this.compareArg(a1[i],a2[i]);
+			if(d != 0) {
+				return d;
+			}
+		}
+		return 0;
+	}
+	compareArg(v1,v2) {
+		if(Reflect.isEnumValue(v1) && Reflect.isEnumValue(v2)) {
+			return this.compare(v1,v2);
+		} else if(((v1) instanceof Array) && ((v2) instanceof Array)) {
+			return this.compareArgs(v1,v2);
+		} else {
+			return Reflect.compare(v1,v2);
+		}
+	}
+}
+haxe_ds_EnumValueMap.__name__ = "haxe.ds.EnumValueMap";
+haxe_ds_EnumValueMap.__interfaces__ = [haxe_IMap];
+haxe_ds_EnumValueMap.__super__ = haxe_ds_BalancedTree;
+Object.assign(haxe_ds_EnumValueMap.prototype, {
+	__class__: haxe_ds_EnumValueMap
+});
+class haxe_ds_IntMap {
+	constructor() {
+		this.h = { };
+	}
+	get(key) {
+		return this.h[key];
+	}
+	exists(key) {
+		return this.h.hasOwnProperty(key);
+	}
+	keys() {
+		let a = [];
+		for( var key in this.h ) if(this.h.hasOwnProperty(key)) a.push(+key);
+		return new haxe_iterators_ArrayIterator(a);
+	}
+	iterator() {
+		return { ref : this.h, it : this.keys(), hasNext : function() {
+			return this.it.hasNext();
+		}, next : function() {
+			let i = this.it.next();
+			return this.ref[i];
+		}};
+	}
+	keyValueIterator() {
+		return new haxe_iterators_MapKeyValueIterator(this);
+	}
+}
+haxe_ds_IntMap.__name__ = "haxe.ds.IntMap";
+haxe_ds_IntMap.__interfaces__ = [haxe_IMap];
+Object.assign(haxe_ds_IntMap.prototype, {
+	__class__: haxe_ds_IntMap
+});
+class haxe_ds_ObjectMap {
+	constructor() {
+		this.h = { __keys__ : { }};
+	}
+	get(key) {
+		return this.h[key.__id__];
+	}
+	exists(key) {
+		return this.h.__keys__[key.__id__] != null;
+	}
+	keys() {
+		let a = [];
+		for( var key in this.h.__keys__ ) {
+		if(this.h.hasOwnProperty(key)) {
+			a.push(this.h.__keys__[key]);
+		}
+		}
+		return new haxe_iterators_ArrayIterator(a);
+	}
+	iterator() {
+		return { ref : this.h, it : this.keys(), hasNext : function() {
+			return this.it.hasNext();
+		}, next : function() {
+			let i = this.it.next();
+			return this.ref[i.__id__];
+		}};
+	}
+	keyValueIterator() {
+		return new haxe_iterators_MapKeyValueIterator(this);
+	}
+}
+haxe_ds_ObjectMap.__name__ = "haxe.ds.ObjectMap";
+haxe_ds_ObjectMap.__interfaces__ = [haxe_IMap];
+Object.assign(haxe_ds_ObjectMap.prototype, {
+	__class__: haxe_ds_ObjectMap
+});
+var haxe_ds_Option = $hxEnums["haxe.ds.Option"] = { __ename__:true,__constructs__:null
+	,Some: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"haxe.ds.Option",toString:$estr}; },$_._hx_name="Some",$_.__params__ = ["v"],$_)
+	,None: {_hx_name:"None",_hx_index:1,__enum__:"haxe.ds.Option",toString:$estr}
+};
+haxe_ds_Option.__constructs__ = [haxe_ds_Option.Some,haxe_ds_Option.None];
+class haxe_ds_StringMap {
+	constructor() {
+		this.h = Object.create(null);
+	}
+	exists(key) {
+		return Object.prototype.hasOwnProperty.call(this.h,key);
+	}
+	get(key) {
+		return this.h[key];
+	}
+	keys() {
+		return new haxe_ds__$StringMap_StringMapKeyIterator(this.h);
+	}
+	iterator() {
+		return new haxe_ds__$StringMap_StringMapValueIterator(this.h);
+	}
+	keyValueIterator() {
+		return new haxe_ds__$StringMap_StringMapKeyValueIterator(this.h);
+	}
+}
+haxe_ds_StringMap.__name__ = "haxe.ds.StringMap";
+haxe_ds_StringMap.__interfaces__ = [haxe_IMap];
+Object.assign(haxe_ds_StringMap.prototype, {
+	__class__: haxe_ds_StringMap
+});
+class haxe_ds__$StringMap_StringMapKeyIterator {
+	constructor(h) {
+		this.h = h;
+		this.keys = Object.keys(h);
+		this.length = this.keys.length;
+		this.current = 0;
+	}
+	hasNext() {
+		return this.current < this.length;
+	}
+	next() {
+		return this.keys[this.current++];
+	}
+}
+haxe_ds__$StringMap_StringMapKeyIterator.__name__ = "haxe.ds._StringMap.StringMapKeyIterator";
+Object.assign(haxe_ds__$StringMap_StringMapKeyIterator.prototype, {
+	__class__: haxe_ds__$StringMap_StringMapKeyIterator
+});
+class haxe_ds__$StringMap_StringMapValueIterator {
+	constructor(h) {
+		this.h = h;
+		this.keys = Object.keys(h);
+		this.length = this.keys.length;
+		this.current = 0;
+	}
+	hasNext() {
+		return this.current < this.length;
+	}
+	next() {
+		return this.h[this.keys[this.current++]];
+	}
+}
+haxe_ds__$StringMap_StringMapValueIterator.__name__ = "haxe.ds._StringMap.StringMapValueIterator";
+Object.assign(haxe_ds__$StringMap_StringMapValueIterator.prototype, {
+	__class__: haxe_ds__$StringMap_StringMapValueIterator
+});
+class haxe_ds__$StringMap_StringMapKeyValueIterator {
+	constructor(h) {
+		this.h = h;
+		this.keys = Object.keys(h);
+		this.length = this.keys.length;
+		this.current = 0;
+	}
+	hasNext() {
+		return this.current < this.length;
+	}
+	next() {
+		let key = this.keys[this.current++];
+		return { key : key, value : this.h[key]};
+	}
+}
+haxe_ds__$StringMap_StringMapKeyValueIterator.__name__ = "haxe.ds._StringMap.StringMapKeyValueIterator";
+Object.assign(haxe_ds__$StringMap_StringMapKeyValueIterator.prototype, {
+	__class__: haxe_ds__$StringMap_StringMapKeyValueIterator
+});
+class haxe_exceptions_PosException extends haxe_Exception {
+	constructor(message,previous,pos) {
+		super(message,previous);
+		if(pos == null) {
+			this.posInfos = { fileName : "(unknown)", lineNumber : 0, className : "(unknown)", methodName : "(unknown)"};
+		} else {
+			this.posInfos = pos;
+		}
+	}
+	toString() {
+		return "" + super.toString() + " in " + this.posInfos.className + "." + this.posInfos.methodName + " at " + this.posInfos.fileName + ":" + this.posInfos.lineNumber;
+	}
+}
+haxe_exceptions_PosException.__name__ = "haxe.exceptions.PosException";
+haxe_exceptions_PosException.__super__ = haxe_Exception;
+Object.assign(haxe_exceptions_PosException.prototype, {
+	__class__: haxe_exceptions_PosException
+});
+class haxe_exceptions_NotImplementedException extends haxe_exceptions_PosException {
+	constructor(message,previous,pos) {
+		if(message == null) {
+			message = "Not implemented";
+		}
+		super(message,previous,pos);
+	}
+}
+haxe_exceptions_NotImplementedException.__name__ = "haxe.exceptions.NotImplementedException";
+haxe_exceptions_NotImplementedException.__super__ = haxe_exceptions_PosException;
+Object.assign(haxe_exceptions_NotImplementedException.prototype, {
+	__class__: haxe_exceptions_NotImplementedException
+});
+class haxe_http_HttpBase {
+	constructor(url) {
+		this.url = url;
+		this.headers = [];
+		this.params = [];
+		this.emptyOnData = $bind(this,this.onData);
+	}
+	setHeader(name,value) {
+		let _g = 0;
+		let _g1 = this.headers.length;
+		while(_g < _g1) {
+			let i = _g++;
+			if(this.headers[i].name == name) {
+				this.headers[i] = { name : name, value : value};
+				return;
+			}
+		}
+		this.headers.push({ name : name, value : value});
+	}
+	setPostData(data) {
+		this.postData = data;
+		this.postBytes = null;
+	}
+	onData(data) {
+	}
+	onBytes(data) {
+	}
+	onError(msg) {
+	}
+	onStatus(status) {
+	}
+	hasOnData() {
+		return $bind(this,this.onData) != this.emptyOnData;
+	}
+	success(data) {
+		this.responseBytes = data;
+		this.responseAsString = null;
+		if(this.hasOnData()) {
+			this.onData(this.get_responseData());
+		}
+		this.onBytes(this.responseBytes);
+	}
+	get_responseData() {
+		if(this.responseAsString == null && this.responseBytes != null) {
+			this.responseAsString = this.responseBytes.getString(0,this.responseBytes.length,haxe_io_Encoding.UTF8);
+		}
+		return this.responseAsString;
+	}
+}
+haxe_http_HttpBase.__name__ = "haxe.http.HttpBase";
+Object.assign(haxe_http_HttpBase.prototype, {
+	__class__: haxe_http_HttpBase
+});
+class haxe_http_HttpNodeJs extends haxe_http_HttpBase {
+	constructor(url) {
+		super(url);
+	}
+	request(post) {
+		this.responseAsString = null;
+		this.responseBytes = null;
+		this.responseHeaders = null;
+		let parsedUrl = new js_node_url_URL(this.url);
+		let secure = parsedUrl.protocol == "https:";
+		let host = parsedUrl.hostname;
+		let path = parsedUrl.pathname;
+		let port = parsedUrl.port != null ? Std.parseInt(parsedUrl.port) : secure ? 443 : 80;
+		let h = { };
+		let _g = 0;
+		let _g1 = this.headers;
+		while(_g < _g1.length) {
+			let i = _g1[_g];
+			++_g;
+			let arr = Reflect.field(h,i.name);
+			if(arr == null) {
+				arr = [];
+				h[i.name] = arr;
+			}
+			arr.push(i.value);
+		}
+		if(this.postData != null || this.postBytes != null) {
+			post = true;
+		}
+		let uri = null;
+		let _g2 = 0;
+		let _g3 = this.params;
+		while(_g2 < _g3.length) {
+			let p = _g3[_g2];
+			++_g2;
+			if(uri == null) {
+				uri = "";
+			} else {
+				uri += "&";
+			}
+			let s = p.name;
+			let uri1 = encodeURIComponent(s) + "=";
+			let s1 = p.value;
+			uri += uri1 + encodeURIComponent(s1);
+		}
+		let question = path.split("?").length <= 1;
+		if(uri != null) {
+			path += (question ? "?" : "&") + uri;
+		}
+		let opts = { protocol : parsedUrl.protocol, hostname : host, port : port, method : post ? "POST" : "GET", path : path, headers : h};
+		let _gthis = this;
+		let httpResponse = function(res) {
+			res.setEncoding("binary");
+			let s = res.statusCode;
+			if(s != null) {
+				_gthis.onStatus(s);
+			}
+			let data = [];
+			res.on("data",function(chunk) {
+				data.push(js_node_buffer_Buffer.from(chunk,"binary"));
+			});
+			res.on("end",function(_) {
+				let buf = data.length == 1 ? data[0] : js_node_buffer_Buffer.concat(data);
+				let httpResponse = buf.buffer.slice(buf.byteOffset,buf.byteOffset + buf.byteLength);
+				_gthis.responseBytes = haxe_io_Bytes.ofData(httpResponse);
+				_gthis.req = null;
+				let httpResponse1 = new haxe_ds_StringMap();
+				_gthis.responseHeaders = httpResponse1;
+				let _g = 0;
+				let _g1 = Reflect.fields(res.headers);
+				while(_g < _g1.length) {
+					let field = _g1[_g];
+					++_g;
+					_gthis.responseHeaders.h[field] = Reflect.field(res.headers,field);
+				}
+				if(s != null && s >= 200 && s < 400) {
+					_gthis.success(_gthis.responseBytes);
+				} else {
+					_gthis.onError("Http Error #" + s);
+				}
+			});
+		};
+		this.req = secure ? js_node_Https.request(opts,httpResponse) : js_node_Http.request(opts,httpResponse);
+		if(post) {
+			if(this.postData != null) {
+				this.req.write(this.postData);
+			} else if(this.postBytes != null) {
+				this.req.setHeader("Content-Length","" + this.postBytes.length);
+				this.req.write(js_node_buffer_Buffer.from(this.postBytes.b.bufferValue));
+			}
+		}
+		this.req.end();
+	}
+}
+haxe_http_HttpNodeJs.__name__ = "haxe.http.HttpNodeJs";
+haxe_http_HttpNodeJs.__super__ = haxe_http_HttpBase;
+Object.assign(haxe_http_HttpNodeJs.prototype, {
+	__class__: haxe_http_HttpNodeJs
+});
+class haxe_io_BytesBuffer {
+	constructor() {
+		this.pos = 0;
+		this.size = 0;
+	}
+	addByte(byte) {
+		if(this.pos == this.size) {
+			this.grow(1);
+		}
+		this.view.setUint8(this.pos++,byte);
+	}
+	addBytes(src,pos,len) {
+		if(pos < 0 || len < 0 || pos + len > src.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		if(this.pos + len > this.size) {
+			this.grow(len);
+		}
+		if(this.size == 0) {
+			return;
+		}
+		let sub = new Uint8Array(src.b.buffer,src.b.byteOffset + pos,len);
+		this.u8.set(sub,this.pos);
+		this.pos += len;
+	}
+	grow(delta) {
+		let req = this.pos + delta;
+		let nsize = this.size == 0 ? 16 : this.size;
+		while(nsize < req) nsize = nsize * 3 >> 1;
+		let nbuf = new ArrayBuffer(nsize);
+		let nu8 = new Uint8Array(nbuf);
+		if(this.size > 0) {
+			nu8.set(this.u8);
+		}
+		this.size = nsize;
+		this.buffer = nbuf;
+		this.u8 = nu8;
+		this.view = new DataView(this.buffer);
+	}
+	getBytes() {
+		if(this.size == 0) {
+			return new haxe_io_Bytes(new ArrayBuffer(0));
+		}
+		let b = new haxe_io_Bytes(this.buffer);
+		b.length = this.pos;
+		return b;
+	}
+}
+haxe_io_BytesBuffer.__name__ = "haxe.io.BytesBuffer";
+Object.assign(haxe_io_BytesBuffer.prototype, {
+	__class__: haxe_io_BytesBuffer
+});
+class haxe_io_Input {
+	readByte() {
+		throw new haxe_exceptions_NotImplementedException(null,null,{ fileName : "haxe/io/Input.hx", lineNumber : 53, className : "haxe.io.Input", methodName : "readByte"});
+	}
+	readBytes(s,pos,len) {
+		let k = len;
+		let b = s.b;
+		if(pos < 0 || len < 0 || pos + len > s.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		try {
+			while(k > 0) {
+				b[pos] = this.readByte();
+				++pos;
+				--k;
+			}
+		} catch( _g ) {
+			if(!((haxe_Exception.caught(_g).unwrap()) instanceof haxe_io_Eof)) {
+				throw _g;
+			}
+		}
+		return len - k;
+	}
+	close() {
+	}
+	set_bigEndian(b) {
+		this.bigEndian = b;
+		return b;
+	}
+	readUntil(end) {
+		let buf = new haxe_io_BytesBuffer();
+		let last;
+		while(true) {
+			last = this.readByte();
+			if(!(last != end)) {
+				break;
+			}
+			buf.addByte(last);
+		}
+		return buf.getBytes().toString();
+	}
+	readInt32() {
+		let ch1 = this.readByte();
+		let ch2 = this.readByte();
+		let ch3 = this.readByte();
+		let ch4 = this.readByte();
+		if(this.bigEndian) {
+			return ch4 | ch3 << 8 | ch2 << 16 | ch1 << 24;
+		} else {
+			return ch1 | ch2 << 8 | ch3 << 16 | ch4 << 24;
+		}
+	}
+}
+haxe_io_Input.__name__ = "haxe.io.Input";
+Object.assign(haxe_io_Input.prototype, {
+	__class__: haxe_io_Input
+});
+class haxe_io_BytesInput extends haxe_io_Input {
+	constructor(b,pos,len) {
+		super();
+		if(pos == null) {
+			pos = 0;
+		}
+		if(len == null) {
+			len = b.length - pos;
+		}
+		if(pos < 0 || len < 0 || pos + len > b.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		this.b = b.b;
+		this.pos = pos;
+		this.len = len;
+		this.totlen = len;
+	}
+	readByte() {
+		if(this.len == 0) {
+			throw haxe_Exception.thrown(new haxe_io_Eof());
+		}
+		this.len--;
+		return this.b[this.pos++];
+	}
+	readBytes(buf,pos,len) {
+		if(pos < 0 || len < 0 || pos + len > buf.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		if(this.len == 0 && len > 0) {
+			throw haxe_Exception.thrown(new haxe_io_Eof());
+		}
+		if(this.len < len) {
+			len = this.len;
+		}
+		let b1 = this.b;
+		let b2 = buf.b;
+		let _g = 0;
+		let _g1 = len;
+		while(_g < _g1) {
+			let i = _g++;
+			b2[pos + i] = b1[this.pos + i];
+		}
+		this.pos += len;
+		this.len -= len;
+		return len;
+	}
+}
+haxe_io_BytesInput.__name__ = "haxe.io.BytesInput";
+haxe_io_BytesInput.__super__ = haxe_io_Input;
+Object.assign(haxe_io_BytesInput.prototype, {
+	__class__: haxe_io_BytesInput
+});
+class haxe_io_Output {
+	writeByte(c) {
+		throw new haxe_exceptions_NotImplementedException(null,null,{ fileName : "haxe/io/Output.hx", lineNumber : 47, className : "haxe.io.Output", methodName : "writeByte"});
+	}
+	writeBytes(s,pos,len) {
+		if(pos < 0 || len < 0 || pos + len > s.length) {
+			throw haxe_Exception.thrown(haxe_io_Error.OutsideBounds);
+		}
+		let b = s.b;
+		let k = len;
+		while(k > 0) {
+			this.writeByte(b[pos]);
+			++pos;
+			--k;
+		}
+		return len;
+	}
+	close() {
+	}
+}
+haxe_io_Output.__name__ = "haxe.io.Output";
+Object.assign(haxe_io_Output.prototype, {
+	__class__: haxe_io_Output
+});
+class haxe_io_BytesOutput extends haxe_io_Output {
+	constructor() {
+		super();
+		this.b = new haxe_io_BytesBuffer();
+	}
+	writeByte(c) {
+		this.b.addByte(c);
+	}
+	writeBytes(buf,pos,len) {
+		this.b.addBytes(buf,pos,len);
+		return len;
+	}
+	getBytes() {
+		return this.b.getBytes();
+	}
+}
+haxe_io_BytesOutput.__name__ = "haxe.io.BytesOutput";
+haxe_io_BytesOutput.__super__ = haxe_io_Output;
+Object.assign(haxe_io_BytesOutput.prototype, {
+	__class__: haxe_io_BytesOutput
+});
+class haxe_io_Eof {
+	constructor() {
+	}
+	toString() {
+		return "Eof";
+	}
+}
+haxe_io_Eof.__name__ = "haxe.io.Eof";
+Object.assign(haxe_io_Eof.prototype, {
+	__class__: haxe_io_Eof
+});
+var haxe_io_Error = $hxEnums["haxe.io.Error"] = { __ename__:true,__constructs__:null
+	,Blocked: {_hx_name:"Blocked",_hx_index:0,__enum__:"haxe.io.Error",toString:$estr}
+	,Overflow: {_hx_name:"Overflow",_hx_index:1,__enum__:"haxe.io.Error",toString:$estr}
+	,OutsideBounds: {_hx_name:"OutsideBounds",_hx_index:2,__enum__:"haxe.io.Error",toString:$estr}
+	,Custom: ($_=function(e) { return {_hx_index:3,e:e,__enum__:"haxe.io.Error",toString:$estr}; },$_._hx_name="Custom",$_.__params__ = ["e"],$_)
+};
+haxe_io_Error.__constructs__ = [haxe_io_Error.Blocked,haxe_io_Error.Overflow,haxe_io_Error.OutsideBounds,haxe_io_Error.Custom];
+class haxe_io_FPHelper {
+	static i64ToDouble(low,high) {
+		haxe_io_FPHelper.helper.setInt32(0,low,true);
+		haxe_io_FPHelper.helper.setInt32(4,high,true);
+		return haxe_io_FPHelper.helper.getFloat64(0,true);
+	}
+	static doubleToI64(v) {
+		let i64 = haxe_io_FPHelper.i64tmp;
+		haxe_io_FPHelper.helper.setFloat64(0,v,true);
+		i64.low = haxe_io_FPHelper.helper.getInt32(0,true);
+		i64.high = haxe_io_FPHelper.helper.getInt32(4,true);
+		return i64;
+	}
+}
+haxe_io_FPHelper.__name__ = "haxe.io.FPHelper";
+class haxe_iterators_ArrayIterator {
+	constructor(array) {
+		this.current = 0;
+		this.array = array;
+	}
+	hasNext() {
+		return this.current < this.array.length;
+	}
+	next() {
+		return this.array[this.current++];
+	}
+}
+haxe_iterators_ArrayIterator.__name__ = "haxe.iterators.ArrayIterator";
+Object.assign(haxe_iterators_ArrayIterator.prototype, {
+	__class__: haxe_iterators_ArrayIterator
+});
+class haxe_iterators_MapKeyValueIterator {
+	constructor(map) {
+		this.map = map;
+		this.keys = map.keys();
+	}
+	hasNext() {
+		return this.keys.hasNext();
+	}
+	next() {
+		let key = this.keys.next();
+		return { value : this.map.get(key), key : key};
+	}
+}
+haxe_iterators_MapKeyValueIterator.__name__ = "haxe.iterators.MapKeyValueIterator";
+Object.assign(haxe_iterators_MapKeyValueIterator.prototype, {
+	__class__: haxe_iterators_MapKeyValueIterator
+});
+class haxe_xml_XmlParserException {
+	constructor(message,xml,position) {
+		this.xml = xml;
+		this.message = message;
+		this.position = position;
+		this.lineNumber = 1;
+		this.positionAtLine = 0;
+		let _g = 0;
+		let _g1 = position;
+		while(_g < _g1) {
+			let i = _g++;
+			let c = xml.charCodeAt(i);
+			if(c == 10) {
+				this.lineNumber++;
+				this.positionAtLine = 0;
+			} else if(c != 13) {
+				this.positionAtLine++;
+			}
+		}
+	}
+	toString() {
+		let c = js_Boot.getClass(this);
+		return c.__name__ + ": " + this.message + " at line " + this.lineNumber + " char " + this.positionAtLine;
+	}
+}
+haxe_xml_XmlParserException.__name__ = "haxe.xml.XmlParserException";
+Object.assign(haxe_xml_XmlParserException.prototype, {
+	__class__: haxe_xml_XmlParserException
+});
+class haxe_xml_Parser {
+	static parse(str,strict) {
+		if(strict == null) {
+			strict = false;
+		}
+		let doc = Xml.createDocument();
+		haxe_xml_Parser.doParse(str,strict,0,doc);
+		return doc;
+	}
+	static doParse(str,strict,p,parent) {
+		if(p == null) {
+			p = 0;
+		}
+		let xml = null;
+		let state = 1;
+		let next = 1;
+		let aname = null;
+		let start = 0;
+		let nsubs = 0;
+		let nbrackets = 0;
+		let buf = new StringBuf();
+		let escapeNext = 1;
+		let attrValQuote = -1;
+		while(p < str.length) {
+			let c = str.charCodeAt(p);
+			switch(state) {
+			case 0:
+				switch(c) {
+				case 9:case 10:case 13:case 32:
+					break;
+				default:
+					state = next;
+					continue;
+				}
+				break;
+			case 1:
+				if(c == 60) {
+					state = 0;
+					next = 2;
+				} else {
+					start = p;
+					state = 13;
+					continue;
+				}
+				break;
+			case 2:
+				switch(c) {
+				case 33:
+					if(str.charCodeAt(p + 1) == 91) {
+						p += 2;
+						if(HxOverrides.substr(str,p,6).toUpperCase() != "CDATA[") {
+							throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected <![CDATA[",str,p));
+						}
+						p += 5;
+						state = 17;
+						start = p + 1;
+					} else if(str.charCodeAt(p + 1) == 68 || str.charCodeAt(p + 1) == 100) {
+						if(HxOverrides.substr(str,p + 2,6).toUpperCase() != "OCTYPE") {
+							throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected <!DOCTYPE",str,p));
+						}
+						p += 8;
+						state = 16;
+						start = p + 1;
+					} else if(str.charCodeAt(p + 1) != 45 || str.charCodeAt(p + 2) != 45) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected <!--",str,p));
+					} else {
+						p += 2;
+						state = 15;
+						start = p + 1;
+					}
+					break;
+				case 47:
+					if(parent == null) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected node name",str,p));
+					}
+					start = p + 1;
+					state = 0;
+					next = 10;
+					break;
+				case 63:
+					state = 14;
+					start = p;
+					break;
+				default:
+					state = 3;
+					start = p;
+					continue;
+				}
+				break;
+			case 3:
+				if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c == 58 || c == 46 || c == 95 || c == 45)) {
+					if(p == start) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected node name",str,p));
+					}
+					xml = Xml.createElement(HxOverrides.substr(str,start,p - start));
+					parent.addChild(xml);
+					++nsubs;
+					state = 0;
+					next = 4;
+					continue;
+				}
+				break;
+			case 4:
+				switch(c) {
+				case 47:
+					state = 11;
+					break;
+				case 62:
+					state = 9;
+					break;
+				default:
+					state = 5;
+					start = p;
+					continue;
+				}
+				break;
+			case 5:
+				if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c == 58 || c == 46 || c == 95 || c == 45)) {
+					if(start == p) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected attribute name",str,p));
+					}
+					let tmp = HxOverrides.substr(str,start,p - start);
+					aname = tmp;
+					if(xml.exists(aname)) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Duplicate attribute [" + aname + "]",str,p));
+					}
+					state = 0;
+					next = 6;
+					continue;
+				}
+				break;
+			case 6:
+				if(c == 61) {
+					state = 0;
+					next = 7;
+				} else {
+					throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected =",str,p));
+				}
+				break;
+			case 7:
+				switch(c) {
+				case 34:case 39:
+					buf = new StringBuf();
+					state = 8;
+					start = p + 1;
+					attrValQuote = c;
+					break;
+				default:
+					throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected \"",str,p));
+				}
+				break;
+			case 8:
+				switch(c) {
+				case 38:
+					let len = p - start;
+					buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+					state = 18;
+					escapeNext = 8;
+					start = p + 1;
+					break;
+				case 60:case 62:
+					if(strict) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Invalid unescaped " + String.fromCodePoint(c) + " in attribute value",str,p));
+					} else if(c == attrValQuote) {
+						let len = p - start;
+						buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+						let val = buf.b;
+						buf = new StringBuf();
+						xml.set(aname,val);
+						state = 0;
+						next = 4;
+					}
+					break;
+				default:
+					if(c == attrValQuote) {
+						let len = p - start;
+						buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+						let val = buf.b;
+						buf = new StringBuf();
+						xml.set(aname,val);
+						state = 0;
+						next = 4;
+					}
+				}
+				break;
+			case 9:
+				p = haxe_xml_Parser.doParse(str,strict,p,xml);
+				start = p;
+				state = 1;
+				break;
+			case 10:
+				if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c == 58 || c == 46 || c == 95 || c == 45)) {
+					if(start == p) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected node name",str,p));
+					}
+					let v = HxOverrides.substr(str,start,p - start);
+					if(parent == null || parent.nodeType != 0) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Unexpected </" + v + ">, tag is not open",str,p));
+					}
+					if(parent.nodeType != Xml.Element) {
+						throw haxe_Exception.thrown("Bad node type, expected Element but found " + (parent.nodeType == null ? "null" : XmlType.toString(parent.nodeType)));
+					}
+					if(v != parent.nodeName) {
+						if(parent.nodeType != Xml.Element) {
+							throw haxe_Exception.thrown("Bad node type, expected Element but found " + (parent.nodeType == null ? "null" : XmlType.toString(parent.nodeType)));
+						}
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected </" + parent.nodeName + ">",str,p));
+					}
+					state = 0;
+					next = 12;
+					continue;
+				}
+				break;
+			case 11:
+				if(c == 62) {
+					state = 1;
+				} else {
+					throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected >",str,p));
+				}
+				break;
+			case 12:
+				if(c == 62) {
+					if(nsubs == 0) {
+						parent.addChild(Xml.createPCData(""));
+					}
+					return p;
+				} else {
+					throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Expected >",str,p));
+				}
+				break;
+			case 13:
+				if(c == 60) {
+					let len = p - start;
+					buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+					let child = Xml.createPCData(buf.b);
+					buf = new StringBuf();
+					parent.addChild(child);
+					++nsubs;
+					state = 0;
+					next = 2;
+				} else if(c == 38) {
+					let len = p - start;
+					buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+					state = 18;
+					escapeNext = 13;
+					start = p + 1;
+				}
+				break;
+			case 14:
+				if(c == 63 && str.charCodeAt(p + 1) == 62) {
+					++p;
+					let str1 = HxOverrides.substr(str,start + 1,p - start - 2);
+					parent.addChild(Xml.createProcessingInstruction(str1));
+					++nsubs;
+					state = 1;
+				}
+				break;
+			case 15:
+				if(c == 45 && str.charCodeAt(p + 1) == 45 && str.charCodeAt(p + 2) == 62) {
+					parent.addChild(Xml.createComment(HxOverrides.substr(str,start,p - start)));
+					++nsubs;
+					p += 2;
+					state = 1;
+				}
+				break;
+			case 16:
+				if(c == 91) {
+					++nbrackets;
+				} else if(c == 93) {
+					--nbrackets;
+				} else if(c == 62 && nbrackets == 0) {
+					parent.addChild(Xml.createDocType(HxOverrides.substr(str,start,p - start)));
+					++nsubs;
+					state = 1;
+				}
+				break;
+			case 17:
+				if(c == 93 && str.charCodeAt(p + 1) == 93 && str.charCodeAt(p + 2) == 62) {
+					let child = Xml.createCData(HxOverrides.substr(str,start,p - start));
+					parent.addChild(child);
+					++nsubs;
+					p += 2;
+					state = 1;
+				}
+				break;
+			case 18:
+				if(c == 59) {
+					let s = HxOverrides.substr(str,start,p - start);
+					if(s.charCodeAt(0) == 35) {
+						let c = s.charCodeAt(1) == 120 ? Std.parseInt("0" + HxOverrides.substr(s,1,s.length - 1)) : Std.parseInt(HxOverrides.substr(s,1,s.length - 1));
+						buf.b += String.fromCodePoint(c);
+					} else if(!Object.prototype.hasOwnProperty.call(haxe_xml_Parser.escapes.h,s)) {
+						if(strict) {
+							throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Undefined entity: " + s,str,p));
+						}
+						buf.b += Std.string("&" + s + ";");
+					} else {
+						buf.b += Std.string(haxe_xml_Parser.escapes.h[s]);
+					}
+					start = p + 1;
+					state = escapeNext;
+				} else if(!(c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c == 58 || c == 46 || c == 95 || c == 45) && c != 35) {
+					if(strict) {
+						throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Invalid character in entity: " + String.fromCodePoint(c),str,p));
+					}
+					buf.b += String.fromCodePoint(38);
+					let len = p - start;
+					buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+					--p;
+					start = p + 1;
+					state = escapeNext;
+				}
+				break;
+			}
+			++p;
+		}
+		if(state == 1) {
+			start = p;
+			state = 13;
+		}
+		if(state == 13) {
+			if(parent.nodeType == 0) {
+				if(parent.nodeType != Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, expected Element but found " + (parent.nodeType == null ? "null" : XmlType.toString(parent.nodeType)));
+				}
+				throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Unclosed node <" + parent.nodeName + ">",str,p));
+			}
+			if(p != start || nsubs == 0) {
+				let len = p - start;
+				buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+				parent.addChild(Xml.createPCData(buf.b));
+				++nsubs;
+			}
+			return p;
+		}
+		if(!strict && state == 18 && escapeNext == 13) {
+			buf.b += String.fromCodePoint(38);
+			let len = p - start;
+			buf.b += len == null ? HxOverrides.substr(str,start,null) : HxOverrides.substr(str,start,len);
+			parent.addChild(Xml.createPCData(buf.b));
+			++nsubs;
+			return p;
+		}
+		throw haxe_Exception.thrown(new haxe_xml_XmlParserException("Unexpected end",str,p));
+	}
+}
+haxe_xml_Parser.__name__ = "haxe.xml.Parser";
+class haxe_xml_Printer {
+	constructor(pretty) {
+		this.output = new StringBuf();
+		this.pretty = pretty;
+	}
+	writeNode(value,tabs) {
+		switch(value.nodeType) {
+		case 0:
+			this.output.b += Std.string(tabs + "<");
+			if(value.nodeType != Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, expected Element but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			this.output.b += Std.string(value.nodeName);
+			let attribute = value.attributes();
+			while(attribute.hasNext()) {
+				let attribute1 = attribute.next();
+				this.output.b += Std.string(" " + attribute1 + "=\"");
+				let input = StringTools.htmlEscape(value.get(attribute1),true);
+				this.output.b += Std.string(input);
+				this.output.b += "\"";
+			}
+			if(this.hasChildren(value)) {
+				this.output.b += ">";
+				if(this.pretty) {
+					this.output.b += "\n";
+				}
+				if(value.nodeType != Xml.Document && value.nodeType != Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+				}
+				let _g_current = 0;
+				let _g_array = value.children;
+				while(_g_current < _g_array.length) {
+					let child = _g_array[_g_current++];
+					this.writeNode(child,this.pretty ? tabs + "\t" : tabs);
+				}
+				this.output.b += Std.string(tabs + "</");
+				if(value.nodeType != Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, expected Element but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+				}
+				this.output.b += Std.string(value.nodeName);
+				this.output.b += ">";
+				if(this.pretty) {
+					this.output.b += "\n";
+				}
+			} else {
+				this.output.b += "/>";
+				if(this.pretty) {
+					this.output.b += "\n";
+				}
+			}
+			break;
+		case 1:
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			let nodeValue = value.nodeValue;
+			if(nodeValue.length != 0) {
+				let input = tabs + StringTools.htmlEscape(nodeValue);
+				this.output.b += Std.string(input);
+				if(this.pretty) {
+					this.output.b += "\n";
+				}
+			}
+			break;
+		case 2:
+			this.output.b += Std.string(tabs + "<![CDATA[");
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			this.output.b += Std.string(value.nodeValue);
+			this.output.b += "]]>";
+			if(this.pretty) {
+				this.output.b += "\n";
+			}
+			break;
+		case 3:
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			let commentContent = value.nodeValue;
+			let _this_r = new RegExp("[\n\r\t]+","g".split("u").join(""));
+			commentContent = commentContent.replace(_this_r,"");
+			commentContent = "<!--" + commentContent + "-->";
+			this.output.b += tabs == null ? "null" : "" + tabs;
+			let input = StringTools.trim(commentContent);
+			this.output.b += Std.string(input);
+			if(this.pretty) {
+				this.output.b += "\n";
+			}
+			break;
+		case 4:
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			this.output.b += Std.string("<!DOCTYPE " + value.nodeValue + ">");
+			if(this.pretty) {
+				this.output.b += "\n";
+			}
+			break;
+		case 5:
+			if(value.nodeType == Xml.Document || value.nodeType == Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, unexpected " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			this.output.b += Std.string("<?" + value.nodeValue + "?>");
+			if(this.pretty) {
+				this.output.b += "\n";
+			}
+			break;
+		case 6:
+			if(value.nodeType != Xml.Document && value.nodeType != Xml.Element) {
+				throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+			}
+			let _g_current = 0;
+			let _g_array = value.children;
+			while(_g_current < _g_array.length) {
+				let child = _g_array[_g_current++];
+				this.writeNode(child,tabs);
+			}
+			break;
+		}
+	}
+	hasChildren(value) {
+		if(value.nodeType != Xml.Document && value.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (value.nodeType == null ? "null" : XmlType.toString(value.nodeType)));
+		}
+		let _g_current = 0;
+		let _g_array = value.children;
+		while(_g_current < _g_array.length) {
+			let child = _g_array[_g_current++];
+			switch(child.nodeType) {
+			case 0:case 1:
+				return true;
+			case 2:case 3:
+				if(child.nodeType == Xml.Document || child.nodeType == Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, unexpected " + (child.nodeType == null ? "null" : XmlType.toString(child.nodeType)));
+				}
+				if(StringTools.ltrim(child.nodeValue).length != 0) {
+					return true;
+				}
+				break;
+			default:
+			}
+		}
+		return false;
+	}
+	static print(xml,pretty) {
+		if(pretty == null) {
+			pretty = false;
+		}
+		let printer = new haxe_xml_Printer(pretty);
+		printer.writeNode(xml,"");
+		return printer.output.b;
+	}
+}
+haxe_xml_Printer.__name__ = "haxe.xml.Printer";
+Object.assign(haxe_xml_Printer.prototype, {
+	__class__: haxe_xml_Printer
+});
+class hsluv_Hsluv {
+	constructor() {
+	}
+	rgbToHex() {
+		this.hex = "#";
+		this.hex += hsluv_Hsluv.rgbChannelToHex(this.rgb_r);
+		this.hex += hsluv_Hsluv.rgbChannelToHex(this.rgb_g);
+		this.hex += hsluv_Hsluv.rgbChannelToHex(this.rgb_b);
+	}
+	hexToRgb() {
+		this.hex = this.hex.toLowerCase();
+		this.rgb_r = hsluv_Hsluv.hexToRgbChannel(this.hex,1);
+		this.rgb_g = hsluv_Hsluv.hexToRgbChannel(this.hex,3);
+		this.rgb_b = hsluv_Hsluv.hexToRgbChannel(this.hex,5);
+	}
+	xyzToRgb() {
+		this.rgb_r = hsluv_Hsluv.fromLinear(hsluv_Hsluv.m_r0 * this.xyz_x + hsluv_Hsluv.m_r1 * this.xyz_y + hsluv_Hsluv.m_r2 * this.xyz_z);
+		this.rgb_g = hsluv_Hsluv.fromLinear(hsluv_Hsluv.m_g0 * this.xyz_x + hsluv_Hsluv.m_g1 * this.xyz_y + hsluv_Hsluv.m_g2 * this.xyz_z);
+		this.rgb_b = hsluv_Hsluv.fromLinear(hsluv_Hsluv.m_b0 * this.xyz_x + hsluv_Hsluv.m_b1 * this.xyz_y + hsluv_Hsluv.m_b2 * this.xyz_z);
+	}
+	rgbToXyz() {
+		let lr = hsluv_Hsluv.toLinear(this.rgb_r);
+		let lg = hsluv_Hsluv.toLinear(this.rgb_g);
+		let lb = hsluv_Hsluv.toLinear(this.rgb_b);
+		this.xyz_x = 0.41239079926595 * lr + 0.35758433938387 * lg + 0.18048078840183 * lb;
+		this.xyz_y = 0.21263900587151 * lr + 0.71516867876775 * lg + 0.072192315360733 * lb;
+		this.xyz_z = 0.019330818715591 * lr + 0.11919477979462 * lg + 0.95053215224966 * lb;
+	}
+	xyzToLuv() {
+		let divider = this.xyz_x + 15 * this.xyz_y + 3 * this.xyz_z;
+		let varU = 4 * this.xyz_x;
+		let varV = 9 * this.xyz_y;
+		if(divider != 0) {
+			varU /= divider;
+			varV /= divider;
+		} else {
+			varU = NaN;
+			varV = NaN;
+		}
+		this.luv_l = hsluv_Hsluv.yToL(this.xyz_y);
+		if(this.luv_l == 0) {
+			this.luv_u = 0;
+			this.luv_v = 0;
+		} else {
+			this.luv_u = 13 * this.luv_l * (varU - hsluv_Hsluv.refU);
+			this.luv_v = 13 * this.luv_l * (varV - hsluv_Hsluv.refV);
+		}
+	}
+	luvToXyz() {
+		if(this.luv_l == 0) {
+			this.xyz_x = 0;
+			this.xyz_y = 0;
+			this.xyz_z = 0;
+			return;
+		}
+		let varU = this.luv_u / (13 * this.luv_l) + hsluv_Hsluv.refU;
+		let varV = this.luv_v / (13 * this.luv_l) + hsluv_Hsluv.refV;
+		this.xyz_y = hsluv_Hsluv.lToY(this.luv_l);
+		this.xyz_x = 0 - 9 * this.xyz_y * varU / ((varU - 4) * varV - varU * varV);
+		this.xyz_z = (9 * this.xyz_y - 15 * varV * this.xyz_y - varV * this.xyz_x) / (3 * varV);
+	}
+	luvToLch() {
+		this.lch_l = this.luv_l;
+		this.lch_c = Math.sqrt(this.luv_u * this.luv_u + this.luv_v * this.luv_v);
+		if(this.lch_c < 0.00000001) {
+			this.lch_h = 0;
+		} else {
+			let Hrad = Math.atan2(this.luv_v,this.luv_u);
+			this.lch_h = Hrad * 180.0 / Math.PI;
+			if(this.lch_h < 0) {
+				this.lch_h = 360 + this.lch_h;
+			}
+		}
+	}
+	lchToLuv() {
+		let Hrad = this.lch_h / 180.0 * Math.PI;
+		this.luv_l = this.lch_l;
+		this.luv_u = Math.cos(Hrad) * this.lch_c;
+		this.luv_v = Math.sin(Hrad) * this.lch_c;
+	}
+	calculateBoundingLines(l) {
+		let sub1 = Math.pow(l + 16,3) / 1560896;
+		let sub2 = sub1 > hsluv_Hsluv.epsilon ? sub1 : l / hsluv_Hsluv.kappa;
+		let s1r = sub2 * (284517 * hsluv_Hsluv.m_r0 - 94839 * hsluv_Hsluv.m_r2);
+		let s2r = sub2 * (838422 * hsluv_Hsluv.m_r2 + 769860 * hsluv_Hsluv.m_r1 + 731718 * hsluv_Hsluv.m_r0);
+		let s3r = sub2 * (632260 * hsluv_Hsluv.m_r2 - 126452 * hsluv_Hsluv.m_r1);
+		let s1g = sub2 * (284517 * hsluv_Hsluv.m_g0 - 94839 * hsluv_Hsluv.m_g2);
+		let s2g = sub2 * (838422 * hsluv_Hsluv.m_g2 + 769860 * hsluv_Hsluv.m_g1 + 731718 * hsluv_Hsluv.m_g0);
+		let s3g = sub2 * (632260 * hsluv_Hsluv.m_g2 - 126452 * hsluv_Hsluv.m_g1);
+		let s1b = sub2 * (284517 * hsluv_Hsluv.m_b0 - 94839 * hsluv_Hsluv.m_b2);
+		let s2b = sub2 * (838422 * hsluv_Hsluv.m_b2 + 769860 * hsluv_Hsluv.m_b1 + 731718 * hsluv_Hsluv.m_b0);
+		let s3b = sub2 * (632260 * hsluv_Hsluv.m_b2 - 126452 * hsluv_Hsluv.m_b1);
+		this.r0s = s1r / s3r;
+		this.r0i = s2r * l / s3r;
+		this.r1s = s1r / (s3r + 126452);
+		this.r1i = (s2r - 769860) * l / (s3r + 126452);
+		this.g0s = s1g / s3g;
+		this.g0i = s2g * l / s3g;
+		this.g1s = s1g / (s3g + 126452);
+		this.g1i = (s2g - 769860) * l / (s3g + 126452);
+		this.b0s = s1b / s3b;
+		this.b0i = s2b * l / s3b;
+		this.b1s = s1b / (s3b + 126452);
+		this.b1i = (s2b - 769860) * l / (s3b + 126452);
+	}
+	calcMaxChromaHpluv() {
+		let r0 = hsluv_Hsluv.distanceFromOrigin(this.r0s,this.r0i);
+		let r1 = hsluv_Hsluv.distanceFromOrigin(this.r1s,this.r1i);
+		let g0 = hsluv_Hsluv.distanceFromOrigin(this.g0s,this.g0i);
+		let g1 = hsluv_Hsluv.distanceFromOrigin(this.g1s,this.g1i);
+		let b0 = hsluv_Hsluv.distanceFromOrigin(this.b0s,this.b0i);
+		let b1 = hsluv_Hsluv.distanceFromOrigin(this.b1s,this.b1i);
+		return hsluv_Hsluv.min6(r0,r1,g0,g1,b0,b1);
+	}
+	calcMaxChromaHsluv(h) {
+		let hueRad = h / 360 * Math.PI * 2;
+		let r0 = hsluv_Hsluv.distanceFromOriginAngle(this.r0s,this.r0i,hueRad);
+		let r1 = hsluv_Hsluv.distanceFromOriginAngle(this.r1s,this.r1i,hueRad);
+		let g0 = hsluv_Hsluv.distanceFromOriginAngle(this.g0s,this.g0i,hueRad);
+		let g1 = hsluv_Hsluv.distanceFromOriginAngle(this.g1s,this.g1i,hueRad);
+		let b0 = hsluv_Hsluv.distanceFromOriginAngle(this.b0s,this.b0i,hueRad);
+		let b1 = hsluv_Hsluv.distanceFromOriginAngle(this.b1s,this.b1i,hueRad);
+		return hsluv_Hsluv.min6(r0,r1,g0,g1,b0,b1);
+	}
+	hsluvToLch() {
+		if(this.hsluv_l > 99.9999999) {
+			this.lch_l = 100;
+			this.lch_c = 0;
+		} else if(this.hsluv_l < 0.00000001) {
+			this.lch_l = 0;
+			this.lch_c = 0;
+		} else {
+			this.lch_l = this.hsluv_l;
+			this.calculateBoundingLines(this.hsluv_l);
+			let max = this.calcMaxChromaHsluv(this.hsluv_h);
+			this.lch_c = max / 100 * this.hsluv_s;
+		}
+		this.lch_h = this.hsluv_h;
+	}
+	lchToHsluv() {
+		if(this.lch_l > 99.9999999) {
+			this.hsluv_s = 0;
+			this.hsluv_l = 100;
+		} else if(this.lch_l < 0.00000001) {
+			this.hsluv_s = 0;
+			this.hsluv_l = 0;
+		} else {
+			this.calculateBoundingLines(this.lch_l);
+			let max = this.calcMaxChromaHsluv(this.lch_h);
+			this.hsluv_s = this.lch_c / max * 100;
+			this.hsluv_l = this.lch_l;
+		}
+		this.hsluv_h = this.lch_h;
+	}
+	hpluvToLch() {
+		if(this.hpluv_l > 99.9999999) {
+			this.lch_l = 100;
+			this.lch_c = 0;
+		} else if(this.hpluv_l < 0.00000001) {
+			this.lch_l = 0;
+			this.lch_c = 0;
+		} else {
+			this.lch_l = this.hpluv_l;
+			this.calculateBoundingLines(this.hpluv_l);
+			let max = this.calcMaxChromaHpluv();
+			this.lch_c = max / 100 * this.hpluv_p;
+		}
+		this.lch_h = this.hpluv_h;
+	}
+	lchToHpluv() {
+		if(this.lch_l > 99.9999999) {
+			this.hpluv_p = 0;
+			this.hpluv_l = 100;
+		} else if(this.lch_l < 0.00000001) {
+			this.hpluv_p = 0;
+			this.hpluv_l = 0;
+		} else {
+			this.calculateBoundingLines(this.lch_l);
+			let max = this.calcMaxChromaHpluv();
+			this.hpluv_p = this.lch_c / max * 100;
+			this.hpluv_l = this.lch_l;
+		}
+		this.hpluv_h = this.lch_h;
+	}
+	hsluvToRgb() {
+		this.hsluvToLch();
+		this.lchToLuv();
+		this.luvToXyz();
+		this.xyzToRgb();
+	}
+	hpluvToRgb() {
+		this.hpluvToLch();
+		this.lchToLuv();
+		this.luvToXyz();
+		this.xyzToRgb();
+	}
+	hsluvToHex() {
+		this.hsluvToRgb();
+		this.rgbToHex();
+	}
+	hpluvToHex() {
+		this.hpluvToRgb();
+		this.rgbToHex();
+	}
+	rgbToHsluv() {
+		this.rgbToXyz();
+		this.xyzToLuv();
+		this.luvToLch();
+		this.lchToHpluv();
+		this.lchToHsluv();
+	}
+	rgbToHpluv() {
+		this.rgbToXyz();
+		this.xyzToLuv();
+		this.luvToLch();
+		this.lchToHpluv();
+		this.lchToHpluv();
+	}
+	hexToHsluv() {
+		this.hexToRgb();
+		this.rgbToHsluv();
+	}
+	hexToHpluv() {
+		this.hexToRgb();
+		this.rgbToHpluv();
+	}
+	static fromLinear(c) {
+		if(c <= 0.0031308) {
+			return 12.92 * c;
+		} else {
+			return 1.055 * Math.pow(c,0.416666666666666685) - 0.055;
+		}
+	}
+	static toLinear(c) {
+		if(c > 0.04045) {
+			return Math.pow((c + 0.055) / 1.055,2.4);
+		} else {
+			return c / 12.92;
+		}
+	}
+	static yToL(Y) {
+		if(Y <= hsluv_Hsluv.epsilon) {
+			return Y / hsluv_Hsluv.refY * hsluv_Hsluv.kappa;
+		} else {
+			return 116 * Math.pow(Y / hsluv_Hsluv.refY,0.333333333333333315) - 16;
+		}
+	}
+	static lToY(L) {
+		if(L <= 8) {
+			return hsluv_Hsluv.refY * L / hsluv_Hsluv.kappa;
+		} else {
+			return hsluv_Hsluv.refY * Math.pow((L + 16) / 116,3);
+		}
+	}
+	static rgbChannelToHex(chan) {
+		let c = Math.round(chan * 255);
+		let digit2 = c % 16;
+		let digit1 = (c - digit2) / 16 | 0;
+		return hsluv_Hsluv.hexChars.charAt(digit1) + hsluv_Hsluv.hexChars.charAt(digit2);
+	}
+	static hexToRgbChannel(hex,offset) {
+		let digit1 = hsluv_Hsluv.hexChars.indexOf(hex.charAt(offset));
+		let digit2 = hsluv_Hsluv.hexChars.indexOf(hex.charAt(offset + 1));
+		let n = digit1 * 16 + digit2;
+		return n / 255.0;
+	}
+	static distanceFromOriginAngle(slope,intercept,angle) {
+		let d = intercept / (Math.sin(angle) - slope * Math.cos(angle));
+		if(d < 0) {
+			return Infinity;
+		} else {
+			return d;
+		}
+	}
+	static distanceFromOrigin(slope,intercept) {
+		return Math.abs(intercept) / Math.sqrt(Math.pow(slope,2) + 1);
+	}
+	static min6(f1,f2,f3,f4,f5,f6) {
+		return Math.min(f1,Math.min(f2,Math.min(f3,Math.min(f4,Math.min(f5,f6)))));
+	}
+}
+hsluv_Hsluv.__name__ = "hsluv.Hsluv";
+Object.assign(hsluv_Hsluv.prototype, {
+	__class__: hsluv_Hsluv
+});
+class htmlparser_CssSelector {
+	constructor(type) {
+		this.classes = [];
+		this.type = type;
+	}
+	static parse(selector) {
+		let r = [];
+		let selectors = new EReg("\\s*,\\s*","g").split(selector);
+		let _g = 0;
+		while(_g < selectors.length) {
+			let s = selectors[_g];
+			++_g;
+			if(s != "") {
+				r.push(htmlparser_CssSelector.parseInner(s));
+			}
+		}
+		return r;
+	}
+	static parseInner(selector) {
+		let rr = [];
+		selector = " " + selector;
+		let r = null;
+		let re = new EReg(htmlparser_CssSelector.reSelector,"gi");
+		let pos = 0;
+		while(re.matchSub(selector,pos)) {
+			let type1;
+			try {
+				type1 = re.matched(1);
+			} catch( _g ) {
+				type1 = null;
+			}
+			if(type1 == null) {
+				type1 = "";
+			}
+			let type2;
+			try {
+				type2 = re.matched(2);
+			} catch( _g ) {
+				type2 = null;
+			}
+			if(type2 == null) {
+				type2 = "";
+			}
+			if(type1.length > 0 || type2.length > 0) {
+				if(r != null) {
+					rr.push(r);
+				}
+				r = new htmlparser_CssSelector(type2.length > 0 ? ">" : " ");
+			}
+			let name = re.matched(4);
+			if(name != "*") {
+				let s = re.matched(3);
+				if(s == "#") {
+					r.id = name;
+				} else if(s == ".") {
+					r.classes.push(name);
+				} else {
+					r.tagNameLC = name.toLowerCase();
+				}
+				let sIndex;
+				try {
+					sIndex = re.matched(5);
+				} catch( _g ) {
+					sIndex = null;
+				}
+				if(sIndex != null && sIndex != "") {
+					r.index = Std.parseInt(sIndex.substring(1,sIndex.length - 1));
+					let f = r.index;
+					if(isNaN(f)) {
+						r.index = null;
+					}
+				}
+			}
+			let p = re.matchedPos();
+			pos = p.pos + p.len;
+		}
+		if(r != null) {
+			rr.push(r);
+		}
+		return rr;
+	}
+	static getMatched(re,n) {
+		try {
+			return re.matched(n);
+		} catch( _g ) {
+			return null;
+		}
+	}
+}
+htmlparser_CssSelector.__name__ = "htmlparser.CssSelector";
+Object.assign(htmlparser_CssSelector.prototype, {
+	__class__: htmlparser_CssSelector
+});
+class htmlparser_HtmlAttribute {
+	constructor(name,value,quote) {
+		this.name = name;
+		this.value = value;
+		this.quote = quote;
+	}
+	toString() {
+		if(this.value != null && this.quote != null) {
+			return this.name + "=" + this.quote + htmlparser_HtmlTools.escape(this.value,"\r\n" + (this.quote == "'" ? "\"" : "'")) + this.quote;
+		} else {
+			return this.name;
+		}
+	}
+}
+htmlparser_HtmlAttribute.__name__ = "htmlparser.HtmlAttribute";
+Object.assign(htmlparser_HtmlAttribute.prototype, {
+	__class__: htmlparser_HtmlAttribute
+});
+class htmlparser_HtmlNode {
+	remove() {
+		if(this.parent != null) {
+			this.parent.removeChild(this);
+		}
+	}
+	getPrevSiblingNode() {
+		if(this.parent == null) {
+			return null;
+		}
+		let siblings = this.parent.nodes;
+		let n = Lambda.indexOf(siblings,this);
+		if(n <= 0) {
+			return null;
+		}
+		if(n > 0) {
+			return siblings[n - 1];
+		}
+		return null;
+	}
+	getNextSiblingNode() {
+		if(this.parent == null) {
+			return null;
+		}
+		let siblings = this.parent.nodes;
+		let n = Lambda.indexOf(siblings,this);
+		if(n < 0) {
+			return null;
+		}
+		if(n + 1 < siblings.length) {
+			return siblings[n + 1];
+		}
+		return null;
+	}
+	toString() {
+		return "";
+	}
+	toText() {
+		return "";
+	}
+	hxSerialize(s) {
+	}
+	hxUnserialize(s) {
+	}
+}
+htmlparser_HtmlNode.__name__ = "htmlparser.HtmlNode";
+Object.assign(htmlparser_HtmlNode.prototype, {
+	__class__: htmlparser_HtmlNode
+});
+class htmlparser_HtmlNodeElement extends htmlparser_HtmlNode {
+	constructor(name,attributes) {
+		super();
+		this.name = name;
+		this.attributes = attributes;
+		this.nodes = [];
+		this.children = [];
+	}
+	getPrevSiblingElement() {
+		if(this.parent == null) {
+			return null;
+		}
+		let n = this.parent.children.indexOf(this);
+		if(n < 0) {
+			return null;
+		}
+		if(n > 0) {
+			return this.parent.children[n - 1];
+		}
+		return null;
+	}
+	getNextSiblingElement() {
+		if(this.parent == null) {
+			return null;
+		}
+		let n = this.parent.children.indexOf(this);
+		if(n < 0) {
+			return null;
+		}
+		if(n + 1 < this.parent.children.length) {
+			return this.parent.children[n + 1];
+		}
+		return null;
+	}
+	addChild(node,beforeNode) {
+		if(beforeNode == null) {
+			this.nodes.push(node);
+			node.parent = this;
+			if(((node) instanceof htmlparser_HtmlNodeElement)) {
+				this.children.push(node);
+			}
+		} else {
+			let n = this.nodes.indexOf(beforeNode);
+			if(n < 0) {
+				throw new haxe_Exception("`beforeNode` is not found.");
+			}
+			this.nodes.splice(n,0,node);
+			node.parent = this;
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = this.nodes;
+			while(_g1 < _g2.length) {
+				let v = _g2[_g1];
+				++_g1;
+				if(((v) instanceof htmlparser_HtmlNodeElement)) {
+					_g.push(v);
+				}
+			}
+			this.children = _g;
+		}
+	}
+	addChildren(nodesToAdd,beforeNode) {
+		let n = beforeNode != null ? this.nodes.indexOf(beforeNode) : 0;
+		if(n < 0) {
+			throw new haxe_Exception("`beforeNode` is not found.");
+		}
+		this.nodes = (n > 0 ? this.nodes.slice(0,n) : []).concat(nodesToAdd).concat(this.nodes.slice(n));
+		let _g = 0;
+		while(_g < nodesToAdd.length) {
+			let node = nodesToAdd[_g];
+			++_g;
+			node.parent = this;
+		}
+		let _g1 = [];
+		let _g2 = 0;
+		let _g3 = this.nodes;
+		while(_g2 < _g3.length) {
+			let v = _g3[_g2];
+			++_g2;
+			if(((v) instanceof htmlparser_HtmlNodeElement)) {
+				_g1.push(v);
+			}
+		}
+		this.children = _g1;
+	}
+	toString() {
+		let sAttrs_b = "";
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let a = _g1[_g];
+			++_g;
+			sAttrs_b += " ";
+			sAttrs_b += Std.string(a.toString());
+		}
+		let innerBuf_b = "";
+		let _g2 = 0;
+		let _g3 = this.nodes;
+		while(_g2 < _g3.length) {
+			let node = _g3[_g2];
+			++_g2;
+			innerBuf_b += Std.string(node.toString());
+		}
+		let inner = innerBuf_b;
+		if(inner == "" && this.isSelfClosing()) {
+			return "<" + this.name + sAttrs_b + " />";
+		}
+		if(this.name != null && this.name != "") {
+			return "<" + this.name + sAttrs_b + ">" + inner + "</" + this.name + ">";
+		} else {
+			return inner;
+		}
+	}
+	getAttribute(name) {
+		let nameLC = name.toLowerCase();
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let a = _g1[_g];
+			++_g;
+			if(a.name.toLowerCase() == nameLC) {
+				return a.value;
+			}
+		}
+		return null;
+	}
+	setAttribute(name,value) {
+		let nameLC = name.toLowerCase();
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let a = _g1[_g];
+			++_g;
+			if(a.name.toLowerCase() == nameLC) {
+				a.value = value;
+				return;
+			}
+		}
+		this.attributes.push(new htmlparser_HtmlAttribute(name,value,"\""));
+	}
+	removeAttribute(name) {
+		let nameLC = name.toLowerCase();
+		let _g = 0;
+		let _g1 = this.attributes.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let a = this.attributes[i];
+			if(a.name.toLowerCase() == nameLC) {
+				this.attributes.splice(i,1);
+				return;
+			}
+		}
+	}
+	hasAttribute(name) {
+		let nameLC = name.toLowerCase();
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let a = _g1[_g];
+			++_g;
+			if(a.name.toLowerCase() == nameLC) {
+				return true;
+			}
+		}
+		return false;
+	}
+	get_innerHTML() {
+		let r_b = "";
+		let _g = 0;
+		let _g1 = this.nodes;
+		while(_g < _g1.length) {
+			let node = _g1[_g];
+			++_g;
+			r_b += Std.string(node.toString());
+		}
+		return r_b;
+	}
+	set_innerHTML(value) {
+		let newNodes = htmlparser_HtmlParser.run(value);
+		this.nodes = [];
+		this.children = [];
+		let _g = 0;
+		while(_g < newNodes.length) {
+			let node = newNodes[_g];
+			++_g;
+			this.addChild(node);
+		}
+		return value;
+	}
+	get_innerText() {
+		return this.toText();
+	}
+	set_innerText(text) {
+		this.fastSetInnerHTML(htmlparser_HtmlTools.escape(text));
+		return text;
+	}
+	fastSetInnerHTML(html) {
+		this.nodes = [];
+		this.children = [];
+		this.addChild(new htmlparser_HtmlNodeText(html));
+	}
+	toText() {
+		let r_b = "";
+		let _g = 0;
+		let _g1 = this.nodes;
+		while(_g < _g1.length) {
+			let node = _g1[_g];
+			++_g;
+			r_b += Std.string(node.toText());
+		}
+		return r_b;
+	}
+	find(selector) {
+		let parsedSelectors = htmlparser_CssSelector.parse(selector);
+		let resNodes = [];
+		let _g = 0;
+		while(_g < parsedSelectors.length) {
+			let s = parsedSelectors[_g];
+			++_g;
+			let _g1 = 0;
+			let _g2 = this.children;
+			while(_g1 < _g2.length) {
+				let node = _g2[_g1];
+				++_g1;
+				let nodesToAdd = node.findInner(s);
+				let _g = 0;
+				while(_g < nodesToAdd.length) {
+					let nodeToAdd = nodesToAdd[_g];
+					++_g;
+					if(resNodes.indexOf(nodeToAdd) < 0) {
+						resNodes.push(nodeToAdd);
+					}
+				}
+			}
+		}
+		return resNodes;
+	}
+	findInner(selectors) {
+		if(selectors.length == 0) {
+			return [];
+		}
+		let nodes = [];
+		if(selectors[0].type == " ") {
+			let _g = 0;
+			let _g1 = this.children;
+			while(_g < _g1.length) {
+				let child = _g1[_g];
+				++_g;
+				nodes = nodes.concat(child.findInner(selectors));
+			}
+		}
+		if(this.isSelectorTrue(selectors[0])) {
+			if(selectors.length > 1) {
+				let subSelectors = selectors.slice(1);
+				let _g = 0;
+				let _g1 = this.children;
+				while(_g < _g1.length) {
+					let child = _g1[_g];
+					++_g;
+					nodes = nodes.concat(child.findInner(subSelectors));
+				}
+			} else if(selectors.length == 1) {
+				if(this.parent != null) {
+					nodes.push(this);
+				}
+			}
+		}
+		return nodes;
+	}
+	isSelectorTrue(selector) {
+		if(selector.tagNameLC != null && this.name.toLowerCase() != selector.tagNameLC) {
+			return false;
+		}
+		if(selector.id != null && this.getAttribute("id") != selector.id) {
+			return false;
+		}
+		let _g = 0;
+		let _g1 = selector.classes;
+		while(_g < _g1.length) {
+			let clas = _g1[_g];
+			++_g;
+			let reg = new EReg("(?:^|\\s)" + clas + "(?:$|\\s)","");
+			let classAttr = this.getAttribute("class");
+			if(classAttr == null || !reg.match(classAttr)) {
+				return false;
+			}
+		}
+		if(selector.index != null && (this.parent == null || this.parent.children.indexOf(this) + 1 != selector.index)) {
+			return false;
+		}
+		return true;
+	}
+	replaceChild(node,newNode) {
+		if(((newNode) instanceof Array)) {
+			this.replaceChildByMany(node,newNode);
+		} else {
+			this.replaceChildByOne(node,newNode);
+		}
+	}
+	replaceChildByOne(node,newNode) {
+		let n = this.nodes.indexOf(node);
+		if(n < 0) {
+			throw new haxe_Exception("Node to replace is not found.");
+		}
+		this.nodes[n].parent = null;
+		this.nodes[n] = newNode;
+		newNode.parent = this;
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.nodes;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(((v) instanceof htmlparser_HtmlNodeElement)) {
+				_g.push(v);
+			}
+		}
+		this.children = _g;
+	}
+	replaceChildByMany(node,newNodes) {
+		let n = this.nodes.indexOf(node);
+		if(n < 0) {
+			throw new haxe_Exception("Node to replace is not found.");
+		}
+		this.nodes[n].parent = null;
+		let lastNodes = this.nodes.slice(n + 1,this.nodes.length);
+		this.nodes = (n > 0 ? this.nodes.slice(0,n) : []).concat(newNodes).concat(lastNodes);
+		let _g = 0;
+		while(_g < newNodes.length) {
+			let n = newNodes[_g];
+			++_g;
+			n.parent = this;
+		}
+		let _g1 = [];
+		let _g2 = 0;
+		let _g3 = this.nodes;
+		while(_g2 < _g3.length) {
+			let v = _g3[_g2];
+			++_g2;
+			if(((v) instanceof htmlparser_HtmlNodeElement)) {
+				_g1.push(v);
+			}
+		}
+		this.children = _g1;
+	}
+	removeChild(node) {
+		let n = this.nodes.indexOf(node);
+		if(n < 0) {
+			throw new haxe_Exception("Node to remove is not found.");
+		}
+		this.nodes.splice(n,1);
+		node.parent = null;
+		if(((node) instanceof htmlparser_HtmlNodeElement)) {
+			n = this.children.indexOf(node);
+			if(n >= 0) {
+				this.children.splice(n,1);
+			}
+		}
+	}
+	getAttributesAssoc() {
+		let attrs = new haxe_ds_StringMap();
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let attr = _g1[_g];
+			++_g;
+			attrs.h[attr.name] = attr.value;
+		}
+		return attrs;
+	}
+	getAttributesObject() {
+		let attrs = { };
+		let _g = 0;
+		let _g1 = this.attributes;
+		while(_g < _g1.length) {
+			let attr = _g1[_g];
+			++_g;
+			attrs[attr.name] = attr.value;
+		}
+		return attrs;
+	}
+	isSelfClosing() {
+		if(!Object.prototype.hasOwnProperty.call(htmlparser_HtmlParser.SELF_CLOSING_TAGS_HTML,this.name)) {
+			return this.name.indexOf(":") >= 0;
+		} else {
+			return true;
+		}
+	}
+	hxSerialize(s) {
+		s.serialize(this.name);
+		s.serialize(this.attributes);
+		s.serialize(this.nodes);
+	}
+	hxUnserialize(s) {
+		this.name = s.unserialize();
+		this.attributes = s.unserialize();
+		this.nodes = [];
+		this.children = [];
+		let ns = s.unserialize();
+		let _g = 0;
+		while(_g < ns.length) {
+			let n = ns[_g];
+			++_g;
+			this.addChild(n);
+		}
+	}
+}
+htmlparser_HtmlNodeElement.__name__ = "htmlparser.HtmlNodeElement";
+htmlparser_HtmlNodeElement.__super__ = htmlparser_HtmlNode;
+Object.assign(htmlparser_HtmlNodeElement.prototype, {
+	__class__: htmlparser_HtmlNodeElement
+});
+class htmlparser_HtmlNodeText extends htmlparser_HtmlNode {
+	constructor(text) {
+		super();
+		this.text = text;
+	}
+	toString() {
+		return this.text;
+	}
+	toText() {
+		return htmlparser_HtmlTools.unescape(this.text);
+	}
+	hxSerialize(s) {
+		s.serialize(this.text);
+	}
+	hxUnserialize(s) {
+		this.text = s.unserialize();
+	}
+}
+htmlparser_HtmlNodeText.__name__ = "htmlparser.HtmlNodeText";
+htmlparser_HtmlNodeText.__super__ = htmlparser_HtmlNode;
+Object.assign(htmlparser_HtmlNodeText.prototype, {
+	__class__: htmlparser_HtmlNodeText
+});
+class htmlparser_HtmlParser {
+	constructor() {
+	}
+	parse(str,tolerant) {
+		if(tolerant == null) {
+			tolerant = false;
+		}
+		this.tolerant = tolerant;
+		this.matches = [];
+		let pos = 0;
+		while(pos < str.length && htmlparser_HtmlParser.reMain.matchSub(str,pos)) {
+			let p = htmlparser_HtmlParser.reMain.matchedPos();
+			let re = htmlparser_HtmlParser.reMain;
+			let cdata;
+			try {
+				cdata = re.matched(1);
+			} catch( _g ) {
+				cdata = null;
+			}
+			if(cdata == null || cdata == "") {
+				let r = htmlparser_HtmlParser.reMain.matched(0);
+				let p1 = p.pos;
+				let re = htmlparser_HtmlParser.reMain;
+				let r1;
+				try {
+					r1 = re.matched(2);
+				} catch( _g ) {
+					r1 = null;
+				}
+				let re1 = htmlparser_HtmlParser.reMain;
+				let r2;
+				try {
+					r2 = re1.matched(3);
+				} catch( _g ) {
+					r2 = null;
+				}
+				let re2 = htmlparser_HtmlParser.reMain;
+				let r3;
+				try {
+					r3 = re2.matched(4);
+				} catch( _g ) {
+					r3 = null;
+				}
+				let re3 = htmlparser_HtmlParser.reMain;
+				let r4;
+				try {
+					r4 = re3.matched(5);
+				} catch( _g ) {
+					r4 = null;
+				}
+				let re4 = htmlparser_HtmlParser.reMain;
+				let r5;
+				try {
+					r5 = re4.matched(6);
+				} catch( _g ) {
+					r5 = null;
+				}
+				let re5 = htmlparser_HtmlParser.reMain;
+				let r6;
+				try {
+					r6 = re5.matched(7);
+				} catch( _g ) {
+					r6 = null;
+				}
+				let re6 = htmlparser_HtmlParser.reMain;
+				let r7;
+				try {
+					r7 = re6.matched(8);
+				} catch( _g ) {
+					r7 = null;
+				}
+				let re7 = htmlparser_HtmlParser.reMain;
+				let r8;
+				try {
+					r8 = re7.matched(9);
+				} catch( _g ) {
+					r8 = null;
+				}
+				let re8 = htmlparser_HtmlParser.reMain;
+				let r9;
+				try {
+					r9 = re8.matched(10);
+				} catch( _g ) {
+					r9 = null;
+				}
+				let re9 = htmlparser_HtmlParser.reMain;
+				let r10;
+				try {
+					r10 = re9.matched(11);
+				} catch( _g ) {
+					r10 = null;
+				}
+				let re10 = htmlparser_HtmlParser.reMain;
+				let r11;
+				try {
+					r11 = re10.matched(12);
+				} catch( _g ) {
+					r11 = null;
+				}
+				let re11 = htmlparser_HtmlParser.reMain;
+				let r12;
+				try {
+					r12 = re11.matched(13);
+				} catch( _g ) {
+					r12 = null;
+				}
+				let re12 = htmlparser_HtmlParser.reMain;
+				let r13;
+				try {
+					r13 = re12.matched(14);
+				} catch( _g ) {
+					r13 = null;
+				}
+				let r14 = { all : r, allPos : p1, script : r1, scriptAttrs : r2, scriptText : r3, style : r4, styleAttrs : r5, styleText : r6, elem : r7, tagOpen : r8, attrs : r9, tagEnd : r10, close : r11, tagClose : r12, comment : r13, tagOpenLC : null, tagCloseLC : null};
+				if(r14.tagOpen != null) {
+					r14.tagOpenLC = r14.tagOpen.toLowerCase();
+				}
+				if(r14.tagClose != null) {
+					r14.tagCloseLC = r14.tagClose.toLowerCase();
+				}
+				this.matches.push(r14);
+			}
+			pos = p.pos + p.len;
+		}
+		if(this.matches.length > 0) {
+			this.str = str;
+			this.i = 0;
+			let nodes = this.processMatches([]).nodes;
+			if(this.i < this.matches.length) {
+				throw haxe_Exception.thrown(new htmlparser_HtmlParserException("Not all nodes processed.",this.getPosition(this.i)));
+			}
+			return nodes;
+		}
+		if(str.length > 0) {
+			return [new htmlparser_HtmlNodeText(str)];
+		} else {
+			return [];
+		}
+	}
+	processMatches(openedTagsLC) {
+		let nodes = [];
+		let prevEnd = this.i > 0 ? this.matches[this.i - 1].allPos + this.matches[this.i - 1].all.length : 0;
+		let curStart = this.matches[this.i].allPos;
+		if(prevEnd < curStart) {
+			nodes.push(new htmlparser_HtmlNodeText(HxOverrides.substr(this.str,prevEnd,curStart - prevEnd)));
+		}
+		while(this.i < this.matches.length) {
+			let m = this.matches[this.i];
+			if(m.elem != null && m.elem != "") {
+				let ee = this.parseElement(openedTagsLC);
+				nodes.push(ee.element);
+				if(ee.closeTagLC != "") {
+					return { nodes : nodes, closeTagLC : ee.closeTagLC};
+				}
+			} else if(m.script != null && m.script != "") {
+				let scriptNode = this.newElement("script",htmlparser_HtmlParser.parseAttrs(m.scriptAttrs));
+				scriptNode.addChild(new htmlparser_HtmlNodeText(m.scriptText));
+				nodes.push(scriptNode);
+			} else if(m.style != null && m.style != "") {
+				let styleNode = this.newElement("style",htmlparser_HtmlParser.parseAttrs(m.styleAttrs));
+				styleNode.addChild(new htmlparser_HtmlNodeText(m.styleText));
+				nodes.push(styleNode);
+			} else if(m.close != null && m.close != "") {
+				if(m.tagCloseLC == openedTagsLC[openedTagsLC.length - 1]) {
+					break;
+				}
+				if(this.tolerant) {
+					if(openedTagsLC.lastIndexOf(m.tagCloseLC) >= 0) {
+						break;
+					}
+				} else {
+					throw haxe_Exception.thrown(new htmlparser_HtmlParserException("Closed tag <" + m.tagClose + "> don't match to open tag <" + openedTagsLC[openedTagsLC.length - 1] + ">.",this.getPosition(this.i)));
+				}
+			} else if(m.comment != null && m.comment != "") {
+				nodes.push(new htmlparser_HtmlNodeText(m.comment));
+			} else {
+				throw haxe_Exception.thrown(new htmlparser_HtmlParserException("Unexpected XML node.",this.getPosition(this.i)));
+			}
+			if(this.tolerant && this.i >= this.matches.length) {
+				break;
+			}
+			let curEnd = this.matches[this.i].allPos + this.matches[this.i].all.length;
+			let nextStart = this.i + 1 < this.matches.length ? this.matches[this.i + 1].allPos : this.str.length;
+			if(curEnd < nextStart) {
+				nodes.push(new htmlparser_HtmlNodeText(HxOverrides.substr(this.str,curEnd,nextStart - curEnd)));
+			}
+			this.i++;
+		}
+		return { nodes : nodes, closeTagLC : ""};
+	}
+	parseElement(openedTagsLC) {
+		let tag = this.matches[this.i].tagOpen;
+		let tagLC = this.matches[this.i].tagOpenLC;
+		let attrs = this.matches[this.i].attrs;
+		let isWithClose = this.matches[this.i].tagEnd != null && this.matches[this.i].tagEnd != "" || this.isSelfClosingTag(tagLC);
+		let elem = this.newElement(tag,htmlparser_HtmlParser.parseAttrs(attrs));
+		let closeTagLC = "";
+		if(!isWithClose) {
+			this.i++;
+			openedTagsLC.push(tagLC);
+			let m = this.processMatches(openedTagsLC);
+			let _g = 0;
+			let _g1 = m.nodes;
+			while(_g < _g1.length) {
+				let node = _g1[_g];
+				++_g;
+				elem.addChild(node);
+			}
+			openedTagsLC.pop();
+			closeTagLC = m.closeTagLC != tagLC ? m.closeTagLC : "";
+			if(this.i < this.matches.length || !this.tolerant) {
+				if(this.matches[this.i].close == null || this.matches[this.i].close == "" || this.matches[this.i].tagCloseLC != tagLC) {
+					if(!this.tolerant) {
+						throw haxe_Exception.thrown(new htmlparser_HtmlParserException("Tag <" + tag + "> not closed.",this.getPosition(this.i)));
+					} else {
+						closeTagLC = this.matches[this.i].tagCloseLC;
+					}
+				}
+			}
+		}
+		return { element : elem, closeTagLC : closeTagLC};
+	}
+	isSelfClosingTag(tag) {
+		return Object.prototype.hasOwnProperty.call(htmlparser_HtmlParser.SELF_CLOSING_TAGS_HTML,tag);
+	}
+	newElement(name,attributes) {
+		return new htmlparser_HtmlNodeElement(name,attributes);
+	}
+	getPosition(matchIndex) {
+		let m = this.matches[matchIndex];
+		let line = 1;
+		let lastNewLinePos = -1;
+		let i = 0;
+		while(i < m.allPos) {
+			let chars = i + 1 < this.str.length ? this.str.substring(i,i + 2) : this.str.charAt(i);
+			if(chars == "\r\n") {
+				i += 2;
+				lastNewLinePos = i;
+				++line;
+			} else if(chars.charAt(0) == "\n" || chars.charAt(0) == "\r") {
+				++i;
+				lastNewLinePos = i;
+				++line;
+			} else {
+				++i;
+			}
+		}
+		return { line : line, column : m.allPos - lastNewLinePos, length : m.all.length};
+	}
+	static run(str,tolerant) {
+		if(tolerant == null) {
+			tolerant = false;
+		}
+		return new htmlparser_HtmlParser().parse(str,tolerant);
+	}
+	static parseAttrs(str) {
+		let attributes = [];
+		let pos = 0;
+		while(pos < str.length && htmlparser_HtmlParser.reParseAttrs.matchSub(str,pos)) {
+			let name = htmlparser_HtmlParser.reParseAttrs.matched(1);
+			let value = htmlparser_HtmlParser.reParseAttrs.matched(2);
+			let quote = null;
+			let unescaped = null;
+			if(value != null) {
+				quote = HxOverrides.substr(value,0,1);
+				if(quote == "\"" || quote == "'") {
+					value = HxOverrides.substr(value,1,value.length - 2);
+				} else {
+					quote = "";
+				}
+				unescaped = htmlparser_HtmlTools.unescape(value);
+			}
+			attributes.push(new htmlparser_HtmlAttribute(name,unescaped,quote));
+			let p = htmlparser_HtmlParser.reParseAttrs.matchedPos();
+			pos = p.pos + p.len;
+		}
+		return attributes;
+	}
+	static getMatched(re,n) {
+		try {
+			return re.matched(n);
+		} catch( _g ) {
+			return null;
+		}
+	}
+}
+htmlparser_HtmlParser.__name__ = "htmlparser.HtmlParser";
+Object.assign(htmlparser_HtmlParser.prototype, {
+	__class__: htmlparser_HtmlParser
+});
+class htmlparser_HtmlParserException {
+	constructor(message,pos) {
+		this.message = message;
+		this.line = pos.line;
+		this.column = pos.column;
+		this.length = pos.length;
+	}
+	toString() {
+		return "Parse error at " + this.line + ":" + this.column + ". " + this.message;
+	}
+}
+htmlparser_HtmlParserException.__name__ = "htmlparser.HtmlParserException";
+Object.assign(htmlparser_HtmlParserException.prototype, {
+	__class__: htmlparser_HtmlParserException
+});
+class htmlparser_HtmlTools {
+	static get_htmlUnescapeMap() {
+		if(htmlparser_HtmlTools.htmlUnescapeMap == null) {
+			let _g = new haxe_ds_StringMap();
+			_g.h["nbsp"] = " ";
+			_g.h["amp"] = "&";
+			_g.h["lt"] = "<";
+			_g.h["gt"] = ">";
+			_g.h["quot"] = "\"";
+			_g.h["apos"] = "'";
+			_g.h["euro"] = "€";
+			_g.h["iexcl"] = "¡";
+			_g.h["cent"] = "¢";
+			_g.h["pound"] = "£";
+			_g.h["curren"] = "¤";
+			_g.h["yen"] = "¥";
+			_g.h["brvbar"] = "¦";
+			_g.h["sect"] = "§";
+			_g.h["uml"] = "¨";
+			_g.h["copy"] = "©";
+			_g.h["ordf"] = "ª";
+			_g.h["not"] = "¬";
+			_g.h["shy"] = "­";
+			_g.h["reg"] = "®";
+			_g.h["macr"] = "¯";
+			_g.h["deg"] = "°";
+			_g.h["plusmn"] = "±";
+			_g.h["sup2"] = "²";
+			_g.h["sup3"] = "³";
+			_g.h["acute"] = "´";
+			_g.h["micro"] = "µ";
+			_g.h["para"] = "¶";
+			_g.h["middot"] = "·";
+			_g.h["cedil"] = "¸";
+			_g.h["sup1"] = "¹";
+			_g.h["ordm"] = "º";
+			_g.h["raquo"] = "»";
+			_g.h["frac14"] = "¼";
+			_g.h["frac12"] = "½";
+			_g.h["frac34"] = "¾";
+			_g.h["iquest"] = "¿";
+			_g.h["Agrave"] = "À";
+			_g.h["Aacute"] = "Á";
+			_g.h["Acirc"] = "Â";
+			_g.h["Atilde"] = "Ã";
+			_g.h["Auml"] = "Ä";
+			_g.h["Aring"] = "Å";
+			_g.h["AElig"] = "Æ";
+			_g.h["Ccedil"] = "Ç";
+			_g.h["Egrave"] = "È";
+			_g.h["Eacute"] = "É";
+			_g.h["Ecirc"] = "Ê";
+			_g.h["Euml"] = "Ë";
+			_g.h["Igrave"] = "Ì";
+			_g.h["Iacute"] = "Í";
+			_g.h["Icirc"] = "Î";
+			_g.h["Iuml"] = "Ï";
+			_g.h["ETH"] = "Ð";
+			_g.h["Ntilde"] = "Ñ";
+			_g.h["Ograve"] = "Ò";
+			_g.h["Oacute"] = "Ó";
+			_g.h["Ocirc"] = "Ô";
+			_g.h["Otilde"] = "Õ";
+			_g.h["Ouml"] = "Ö";
+			_g.h["times"] = "×";
+			_g.h["Oslash"] = "Ø";
+			_g.h["Ugrave"] = "Ù";
+			_g.h["Uacute"] = "Ú";
+			_g.h["Ucirc"] = "Û";
+			_g.h["Uuml"] = "Ü";
+			_g.h["Yacute"] = "Ý";
+			_g.h["THORN"] = "Þ";
+			_g.h["szlig"] = "ß";
+			_g.h["agrave"] = "à";
+			_g.h["aacute"] = "á";
+			_g.h["acirc"] = "â";
+			_g.h["atilde"] = "ã";
+			_g.h["auml"] = "ä";
+			_g.h["aring"] = "å";
+			_g.h["aelig"] = "æ";
+			_g.h["ccedil"] = "ç";
+			_g.h["egrave"] = "è";
+			_g.h["eacute"] = "é";
+			_g.h["ecirc"] = "ê";
+			_g.h["euml"] = "ë";
+			_g.h["igrave"] = "ì";
+			_g.h["iacute"] = "í";
+			_g.h["icirc"] = "î";
+			_g.h["iuml"] = "ï";
+			_g.h["eth"] = "ð";
+			_g.h["ntilde"] = "ñ";
+			_g.h["ograve"] = "ò";
+			_g.h["oacute"] = "ó";
+			_g.h["ocirc"] = "ô";
+			_g.h["otilde"] = "õ";
+			_g.h["ouml"] = "ö";
+			_g.h["divide"] = "÷";
+			_g.h["oslash"] = "ø";
+			_g.h["ugrave"] = "ù";
+			_g.h["uacute"] = "ú";
+			_g.h["ucirc"] = "û";
+			_g.h["uuml"] = "ü";
+			_g.h["yacute"] = "ý";
+			_g.h["thorn"] = "þ";
+			htmlparser_HtmlTools.htmlUnescapeMap = _g;
+		}
+		return htmlparser_HtmlTools.htmlUnescapeMap;
+	}
+	static escape(text,chars) {
+		if(chars == null) {
+			chars = "";
+		}
+		let r = text.split("&").join("&amp;");
+		r = r.split("<").join("&lt;");
+		r = r.split(">").join("&gt;");
+		if(chars.indexOf("\"") >= 0) {
+			r = r.split("\"").join("&quot;");
+		}
+		if(chars.indexOf("'") >= 0) {
+			r = r.split("'").join("&apos;");
+		}
+		if(chars.indexOf(" ") >= 0) {
+			r = r.split(" ").join("&nbsp;");
+		}
+		if(chars.indexOf("\n") >= 0) {
+			r = r.split("\n").join("&#xA;");
+		}
+		if(chars.indexOf("\r") >= 0) {
+			r = r.split("\r").join("&#xD;");
+		}
+		return r;
+	}
+	static unescape(text) {
+		return new EReg("[<]!\\[CDATA\\[((?:.|[\r\n])*?)\\]\\][>]|&[^;]+;","g").map(text,function(re) {
+			let s = re.matched(0);
+			if(s.charAt(0) == "&") {
+				if(s.charAt(1) == "#") {
+					let numbers = s.substring(2,s.length - 1);
+					if(numbers.charAt(0) == "x") {
+						numbers = "0" + numbers;
+					}
+					let code = Std.parseInt(numbers);
+					if(code != null && code != 0) {
+						return String.fromCodePoint(code);
+					} else {
+						return s;
+					}
+				} else {
+					let r = htmlparser_HtmlTools.get_htmlUnescapeMap().h[s.substring(1,s.length - 1)];
+					if(r != null) {
+						return r;
+					} else {
+						return s;
+					}
+				}
+			}
+			return re.matched(1);
+		});
+	}
+}
+htmlparser_HtmlTools.__name__ = "htmlparser.HtmlTools";
+class httpstatus_HttpStatusCode {
+	static toMessage(this1) {
+		return httpstatus_HttpStatusMessage.fromCode(this1);
+	}
+	static toInt(this1) {
+		return this1;
+	}
+	static fromErrorCode(code) {
+		return code;
+	}
+	static toOutgoingResponse(this1) {
+		return new tink_http__$Response_OutgoingResponseData(new tink_http_ResponseHeaderBase(this1,httpstatus_HttpStatusMessage.fromCode(this1),[new tink_http_HeaderField("content-length","0")],"HTTP/1.1"),tink_io_Source.EMPTY);
+	}
+	static fromIncomingResponse(res) {
+		return res.header.statusCode;
+	}
+}
+class httpstatus_HttpStatusMessage {
+	static _new(statusCode) {
+		return httpstatus_HttpStatusMessage.fromCode(statusCode);
+	}
+	static fromCode(statusCode) {
+		switch(statusCode) {
+		case 100:
+			return "Continue";
+		case 101:
+			return "Switching Protocols";
+		case 102:
+			return "Processing";
+		case 200:
+			return "OK";
+		case 201:
+			return "Created";
+		case 202:
+			return "Accepted";
+		case 203:
+			return "Non-Authoritative Information";
+		case 204:
+			return "No Content";
+		case 205:
+			return "Reset Content";
+		case 206:
+			return "Partial Content";
+		case 207:
+			return "Multi-Status";
+		case 208:
+			return "Already Reported";
+		case 226:
+			return "IM Used";
+		case 300:
+			return "Multiple Choices";
+		case 301:
+			return "Moved Permanently";
+		case 302:
+			return "Found";
+		case 303:
+			return "See Other";
+		case 304:
+			return "Not Modified";
+		case 305:
+			return "Use Proxy";
+		case 306:
+			return "Switch Proxy";
+		case 307:
+			return "Temporary Redirect";
+		case 308:
+			return "Permanent Redirect";
+		case 400:
+			return "Bad Request";
+		case 401:
+			return "Unauthorized";
+		case 402:
+			return "Payment Required";
+		case 403:
+			return "Forbidden";
+		case 404:
+			return "Not Found";
+		case 405:
+			return "Method Not Allowed";
+		case 406:
+			return "Not Acceptable";
+		case 407:
+			return "Proxy Authentication Required";
+		case 408:
+			return "Request Timeout";
+		case 409:
+			return "Conflict";
+		case 410:
+			return "Gone";
+		case 411:
+			return "Length Required";
+		case 412:
+			return "Precondition Failed";
+		case 413:
+			return "Payload Too Large";
+		case 414:
+			return "URI Too Long";
+		case 415:
+			return "Unsupported Media Type";
+		case 416:
+			return "Range Not Satisfiable";
+		case 417:
+			return "Expectation Failed";
+		case 418:
+			return "I'm a teapot";
+		case 421:
+			return "Misdirected Request";
+		case 422:
+			return "Unprocessable Entity";
+		case 423:
+			return "Locked";
+		case 424:
+			return "Failed Dependency";
+		case 426:
+			return "Upgrade Required";
+		case 428:
+			return "Precondition Required";
+		case 429:
+			return "Too Many Requests";
+		case 431:
+			return "Request Header Fields Too Large";
+		case 451:
+			return "Unavailable For Legal Reasons";
+		case 500:
+			return "Internal Server Error";
+		case 501:
+			return "Not Implemented";
+		case 502:
+			return "Bad Gateway";
+		case 503:
+			return "Service Unavailable";
+		case 504:
+			return "Gateway Timeout";
+		case 505:
+			return "HTTP Version Not Supported";
+		case 506:
+			return "Variant Also Negotiates";
+		case 507:
+			return "Insufficient Storage";
+		case 508:
+			return "Loop Detected";
+		case 510:
+			return "Not Extended";
+		case 511:
+			return "Network Authentication Required";
+		default:
+			return "Unknown Status";
+		}
+	}
+}
+class hx_strings_AnyAsString {
+	static fromBool(value) {
+		if(value) {
+			return "true";
+		} else {
+			return "false";
+		}
+	}
+	static fromAny(value) {
+		return Std.string(value);
+	}
+}
+class hx_strings__$Char_CharCaseMapper {
+	constructor() {
+		this.mapL2U = new haxe_ds_IntMap();
+		this.mapU2L = new haxe_ds_IntMap();
+		this._addCaseMapping(97,65);
+		this._addCaseMapping(98,66);
+		this._addCaseMapping(99,67);
+		this._addCaseMapping(100,68);
+		this._addCaseMapping(101,69);
+		this._addCaseMapping(102,70);
+		this._addCaseMapping(103,71);
+		this._addCaseMapping(104,72);
+		this._addCaseMapping(105,73);
+		this._addCaseMapping(106,74);
+		this._addCaseMapping(107,75);
+		this._addCaseMapping(108,76);
+		this._addCaseMapping(109,77);
+		this._addCaseMapping(110,78);
+		this._addCaseMapping(111,79);
+		this._addCaseMapping(112,80);
+		this._addCaseMapping(113,81);
+		this._addCaseMapping(114,82);
+		this._addCaseMapping(115,83);
+		this._addCaseMapping(116,84);
+		this._addCaseMapping(117,85);
+		this._addCaseMapping(118,86);
+		this._addCaseMapping(119,87);
+		this._addCaseMapping(120,88);
+		this._addCaseMapping(121,89);
+		this._addCaseMapping(122,90);
+		this._addCaseMapping(224,192);
+		this._addCaseMapping(225,193);
+		this._addCaseMapping(226,194);
+		this._addCaseMapping(227,195);
+		this._addCaseMapping(228,196);
+		this._addCaseMapping(229,197);
+		this._addCaseMapping(230,198);
+		this._addCaseMapping(231,199);
+		this._addCaseMapping(232,200);
+		this._addCaseMapping(233,201);
+		this._addCaseMapping(234,202);
+		this._addCaseMapping(235,203);
+		this._addCaseMapping(236,204);
+		this._addCaseMapping(237,205);
+		this._addCaseMapping(238,206);
+		this._addCaseMapping(239,207);
+		this._addCaseMapping(240,208);
+		this._addCaseMapping(241,209);
+		this._addCaseMapping(242,210);
+		this._addCaseMapping(243,211);
+		this._addCaseMapping(244,212);
+		this._addCaseMapping(245,213);
+		this._addCaseMapping(246,214);
+		this._addCaseMapping(248,216);
+		this._addCaseMapping(249,217);
+		this._addCaseMapping(250,218);
+		this._addCaseMapping(251,219);
+		this._addCaseMapping(252,220);
+		this._addCaseMapping(253,221);
+		this._addCaseMapping(254,222);
+		this._addCaseMapping(255,376);
+		this._addCaseMapping(257,256);
+		this._addCaseMapping(259,258);
+		this._addCaseMapping(261,260);
+		this._addCaseMapping(263,262);
+		this._addCaseMapping(265,264);
+		this._addCaseMapping(267,266);
+		this._addCaseMapping(269,268);
+		this._addCaseMapping(271,270);
+		this._addCaseMapping(273,272);
+		this._addCaseMapping(275,274);
+		this._addCaseMapping(277,276);
+		this._addCaseMapping(279,278);
+		this._addCaseMapping(281,280);
+		this._addCaseMapping(283,282);
+		this._addCaseMapping(285,284);
+		this._addCaseMapping(287,286);
+		this._addCaseMapping(289,288);
+		this._addCaseMapping(291,290);
+		this._addCaseMapping(293,292);
+		this._addCaseMapping(295,294);
+		this._addCaseMapping(297,296);
+		this._addCaseMapping(299,298);
+		this._addCaseMapping(301,300);
+		this._addCaseMapping(303,302);
+		this._addCaseMapping(305,73);
+		this._addCaseMapping(307,306);
+		this._addCaseMapping(309,308);
+		this._addCaseMapping(311,310);
+		this._addCaseMapping(314,313);
+		this._addCaseMapping(316,315);
+		this._addCaseMapping(318,317);
+		this._addCaseMapping(320,319);
+		this._addCaseMapping(322,321);
+		this._addCaseMapping(324,323);
+		this._addCaseMapping(326,325);
+		this._addCaseMapping(328,327);
+		this._addCaseMapping(331,330);
+		this._addCaseMapping(333,332);
+		this._addCaseMapping(335,334);
+		this._addCaseMapping(337,336);
+		this._addCaseMapping(339,338);
+		this._addCaseMapping(341,340);
+		this._addCaseMapping(343,342);
+		this._addCaseMapping(345,344);
+		this._addCaseMapping(347,346);
+		this._addCaseMapping(349,348);
+		this._addCaseMapping(351,350);
+		this._addCaseMapping(353,352);
+		this._addCaseMapping(355,354);
+		this._addCaseMapping(357,356);
+		this._addCaseMapping(359,358);
+		this._addCaseMapping(361,360);
+		this._addCaseMapping(363,362);
+		this._addCaseMapping(365,364);
+		this._addCaseMapping(367,366);
+		this._addCaseMapping(369,368);
+		this._addCaseMapping(371,370);
+		this._addCaseMapping(373,372);
+		this._addCaseMapping(375,374);
+		this._addCaseMapping(378,377);
+		this._addCaseMapping(380,379);
+		this._addCaseMapping(382,381);
+		this._addCaseMapping(387,386);
+		this._addCaseMapping(389,388);
+		this._addCaseMapping(392,391);
+		this._addCaseMapping(396,395);
+		this._addCaseMapping(402,401);
+		this._addCaseMapping(409,408);
+		this._addCaseMapping(417,416);
+		this._addCaseMapping(419,418);
+		this._addCaseMapping(421,420);
+		this._addCaseMapping(424,423);
+		this._addCaseMapping(429,428);
+		this._addCaseMapping(432,431);
+		this._addCaseMapping(436,435);
+		this._addCaseMapping(438,437);
+		this._addCaseMapping(441,440);
+		this._addCaseMapping(445,444);
+		this._addCaseMapping(454,452);
+		this._addCaseMapping(457,455);
+		this._addCaseMapping(460,458);
+		this._addCaseMapping(462,461);
+		this._addCaseMapping(464,463);
+		this._addCaseMapping(466,465);
+		this._addCaseMapping(468,467);
+		this._addCaseMapping(470,469);
+		this._addCaseMapping(472,471);
+		this._addCaseMapping(474,473);
+		this._addCaseMapping(476,475);
+		this._addCaseMapping(479,478);
+		this._addCaseMapping(481,480);
+		this._addCaseMapping(483,482);
+		this._addCaseMapping(485,484);
+		this._addCaseMapping(487,486);
+		this._addCaseMapping(489,488);
+		this._addCaseMapping(491,490);
+		this._addCaseMapping(493,492);
+		this._addCaseMapping(495,494);
+		this._addCaseMapping(499,497);
+		this._addCaseMapping(501,500);
+		this._addCaseMapping(507,506);
+		this._addCaseMapping(509,508);
+		this._addCaseMapping(511,510);
+		this._addCaseMapping(513,512);
+		this._addCaseMapping(515,514);
+		this._addCaseMapping(517,516);
+		this._addCaseMapping(519,518);
+		this._addCaseMapping(521,520);
+		this._addCaseMapping(523,522);
+		this._addCaseMapping(525,524);
+		this._addCaseMapping(527,526);
+		this._addCaseMapping(529,528);
+		this._addCaseMapping(531,530);
+		this._addCaseMapping(533,532);
+		this._addCaseMapping(535,534);
+		this._addCaseMapping(595,385);
+		this._addCaseMapping(596,390);
+		this._addCaseMapping(599,394);
+		this._addCaseMapping(600,398);
+		this._addCaseMapping(601,399);
+		this._addCaseMapping(603,400);
+		this._addCaseMapping(608,403);
+		this._addCaseMapping(611,404);
+		this._addCaseMapping(616,407);
+		this._addCaseMapping(617,406);
+		this._addCaseMapping(623,412);
+		this._addCaseMapping(626,413);
+		this._addCaseMapping(629,415);
+		this._addCaseMapping(643,425);
+		this._addCaseMapping(648,430);
+		this._addCaseMapping(650,433);
+		this._addCaseMapping(651,434);
+		this._addCaseMapping(658,439);
+		this._addCaseMapping(924,181);
+		this._addCaseMapping(940,902);
+		this._addCaseMapping(941,904);
+		this._addCaseMapping(942,905);
+		this._addCaseMapping(943,906);
+		this._addCaseMapping(945,913);
+		this._addCaseMapping(946,914);
+		this._addCaseMapping(947,915);
+		this._addCaseMapping(948,916);
+		this._addCaseMapping(949,917);
+		this._addCaseMapping(950,918);
+		this._addCaseMapping(951,919);
+		this._addCaseMapping(952,920);
+		this._addCaseMapping(953,921);
+		this._addCaseMapping(954,922);
+		this._addCaseMapping(955,923);
+		this._addCaseMapping(956,924);
+		this._addCaseMapping(957,925);
+		this._addCaseMapping(958,926);
+		this._addCaseMapping(959,927);
+		this._addCaseMapping(960,928);
+		this._addCaseMapping(961,929);
+		this._addCaseMapping(963,931);
+		this._addCaseMapping(964,932);
+		this._addCaseMapping(965,933);
+		this._addCaseMapping(966,934);
+		this._addCaseMapping(967,935);
+		this._addCaseMapping(968,936);
+		this._addCaseMapping(969,937);
+		this._addCaseMapping(970,938);
+		this._addCaseMapping(971,939);
+		this._addCaseMapping(972,908);
+		this._addCaseMapping(973,910);
+		this._addCaseMapping(974,911);
+		this._addCaseMapping(995,994);
+		this._addCaseMapping(997,996);
+		this._addCaseMapping(999,998);
+		this._addCaseMapping(1001,1000);
+		this._addCaseMapping(1003,1002);
+		this._addCaseMapping(1005,1004);
+		this._addCaseMapping(1007,1006);
+		this._addCaseMapping(1072,1040);
+		this._addCaseMapping(1073,1041);
+		this._addCaseMapping(1074,1042);
+		this._addCaseMapping(1075,1043);
+		this._addCaseMapping(1076,1044);
+		this._addCaseMapping(1077,1045);
+		this._addCaseMapping(1078,1046);
+		this._addCaseMapping(1079,1047);
+		this._addCaseMapping(1080,1048);
+		this._addCaseMapping(1081,1049);
+		this._addCaseMapping(1082,1050);
+		this._addCaseMapping(1083,1051);
+		this._addCaseMapping(1084,1052);
+		this._addCaseMapping(1085,1053);
+		this._addCaseMapping(1086,1054);
+		this._addCaseMapping(1087,1055);
+		this._addCaseMapping(1088,1056);
+		this._addCaseMapping(1089,1057);
+		this._addCaseMapping(1090,1058);
+		this._addCaseMapping(1091,1059);
+		this._addCaseMapping(1092,1060);
+		this._addCaseMapping(1093,1061);
+		this._addCaseMapping(1094,1062);
+		this._addCaseMapping(1095,1063);
+		this._addCaseMapping(1096,1064);
+		this._addCaseMapping(1097,1065);
+		this._addCaseMapping(1098,1066);
+		this._addCaseMapping(1099,1067);
+		this._addCaseMapping(1100,1068);
+		this._addCaseMapping(1101,1069);
+		this._addCaseMapping(1102,1070);
+		this._addCaseMapping(1103,1071);
+		this._addCaseMapping(1105,1025);
+		this._addCaseMapping(1106,1026);
+		this._addCaseMapping(1107,1027);
+		this._addCaseMapping(1108,1028);
+		this._addCaseMapping(1109,1029);
+		this._addCaseMapping(1110,1030);
+		this._addCaseMapping(1111,1031);
+		this._addCaseMapping(1112,1032);
+		this._addCaseMapping(1113,1033);
+		this._addCaseMapping(1114,1034);
+		this._addCaseMapping(1115,1035);
+		this._addCaseMapping(1116,1036);
+		this._addCaseMapping(1118,1038);
+		this._addCaseMapping(1119,1039);
+		this._addCaseMapping(1121,1120);
+		this._addCaseMapping(1123,1122);
+		this._addCaseMapping(1125,1124);
+		this._addCaseMapping(1127,1126);
+		this._addCaseMapping(1129,1128);
+		this._addCaseMapping(1131,1130);
+		this._addCaseMapping(1133,1132);
+		this._addCaseMapping(1135,1134);
+		this._addCaseMapping(1137,1136);
+		this._addCaseMapping(1139,1138);
+		this._addCaseMapping(1141,1140);
+		this._addCaseMapping(1143,1142);
+		this._addCaseMapping(1145,1144);
+		this._addCaseMapping(1147,1146);
+		this._addCaseMapping(1149,1148);
+		this._addCaseMapping(1151,1150);
+		this._addCaseMapping(1153,1152);
+		this._addCaseMapping(1169,1168);
+		this._addCaseMapping(1171,1170);
+		this._addCaseMapping(1173,1172);
+		this._addCaseMapping(1175,1174);
+		this._addCaseMapping(1177,1176);
+		this._addCaseMapping(1179,1178);
+		this._addCaseMapping(1181,1180);
+		this._addCaseMapping(1183,1182);
+		this._addCaseMapping(1185,1184);
+		this._addCaseMapping(1187,1186);
+		this._addCaseMapping(1189,1188);
+		this._addCaseMapping(1191,1190);
+		this._addCaseMapping(1193,1192);
+		this._addCaseMapping(1195,1194);
+		this._addCaseMapping(1197,1196);
+		this._addCaseMapping(1199,1198);
+		this._addCaseMapping(1201,1200);
+		this._addCaseMapping(1203,1202);
+		this._addCaseMapping(1205,1204);
+		this._addCaseMapping(1207,1206);
+		this._addCaseMapping(1209,1208);
+		this._addCaseMapping(1211,1210);
+		this._addCaseMapping(1213,1212);
+		this._addCaseMapping(1215,1214);
+		this._addCaseMapping(1218,1217);
+		this._addCaseMapping(1220,1219);
+		this._addCaseMapping(1224,1223);
+		this._addCaseMapping(1228,1227);
+		this._addCaseMapping(1233,1232);
+		this._addCaseMapping(1235,1234);
+		this._addCaseMapping(1237,1236);
+		this._addCaseMapping(1239,1238);
+		this._addCaseMapping(1241,1240);
+		this._addCaseMapping(1243,1242);
+		this._addCaseMapping(1245,1244);
+		this._addCaseMapping(1247,1246);
+		this._addCaseMapping(1249,1248);
+		this._addCaseMapping(1251,1250);
+		this._addCaseMapping(1253,1252);
+		this._addCaseMapping(1255,1254);
+		this._addCaseMapping(1257,1256);
+		this._addCaseMapping(1259,1258);
+		this._addCaseMapping(1263,1262);
+		this._addCaseMapping(1265,1264);
+		this._addCaseMapping(1267,1266);
+		this._addCaseMapping(1269,1268);
+		this._addCaseMapping(1273,1272);
+		this._addCaseMapping(1377,1329);
+		this._addCaseMapping(1378,1330);
+		this._addCaseMapping(1379,1331);
+		this._addCaseMapping(1380,1332);
+		this._addCaseMapping(1381,1333);
+		this._addCaseMapping(1382,1334);
+		this._addCaseMapping(1383,1335);
+		this._addCaseMapping(1384,1336);
+		this._addCaseMapping(1385,1337);
+		this._addCaseMapping(1386,1338);
+		this._addCaseMapping(1387,1339);
+		this._addCaseMapping(1388,1340);
+		this._addCaseMapping(1389,1341);
+		this._addCaseMapping(1390,1342);
+		this._addCaseMapping(1391,1343);
+		this._addCaseMapping(1392,1344);
+		this._addCaseMapping(1393,1345);
+		this._addCaseMapping(1394,1346);
+		this._addCaseMapping(1395,1347);
+		this._addCaseMapping(1396,1348);
+		this._addCaseMapping(1397,1349);
+		this._addCaseMapping(1398,1350);
+		this._addCaseMapping(1399,1351);
+		this._addCaseMapping(1400,1352);
+		this._addCaseMapping(1401,1353);
+		this._addCaseMapping(1402,1354);
+		this._addCaseMapping(1403,1355);
+		this._addCaseMapping(1404,1356);
+		this._addCaseMapping(1405,1357);
+		this._addCaseMapping(1406,1358);
+		this._addCaseMapping(1407,1359);
+		this._addCaseMapping(1408,1360);
+		this._addCaseMapping(1409,1361);
+		this._addCaseMapping(1410,1362);
+		this._addCaseMapping(1411,1363);
+		this._addCaseMapping(1412,1364);
+		this._addCaseMapping(1413,1365);
+		this._addCaseMapping(1414,1366);
+		this._addCaseMapping(4304,4256);
+		this._addCaseMapping(4305,4257);
+		this._addCaseMapping(4306,4258);
+		this._addCaseMapping(4307,4259);
+		this._addCaseMapping(4308,4260);
+		this._addCaseMapping(4309,4261);
+		this._addCaseMapping(4310,4262);
+		this._addCaseMapping(4311,4263);
+		this._addCaseMapping(4312,4264);
+		this._addCaseMapping(4313,4265);
+		this._addCaseMapping(4314,4266);
+		this._addCaseMapping(4315,4267);
+		this._addCaseMapping(4316,4268);
+		this._addCaseMapping(4317,4269);
+		this._addCaseMapping(4318,4270);
+		this._addCaseMapping(4319,4271);
+		this._addCaseMapping(4320,4272);
+		this._addCaseMapping(4321,4273);
+		this._addCaseMapping(4322,4274);
+		this._addCaseMapping(4323,4275);
+		this._addCaseMapping(4324,4276);
+		this._addCaseMapping(4325,4277);
+		this._addCaseMapping(4326,4278);
+		this._addCaseMapping(4327,4279);
+		this._addCaseMapping(4328,4280);
+		this._addCaseMapping(4329,4281);
+		this._addCaseMapping(4330,4282);
+		this._addCaseMapping(4331,4283);
+		this._addCaseMapping(4332,4284);
+		this._addCaseMapping(4333,4285);
+		this._addCaseMapping(4334,4286);
+		this._addCaseMapping(4335,4287);
+		this._addCaseMapping(4336,4288);
+		this._addCaseMapping(4337,4289);
+		this._addCaseMapping(4338,4290);
+		this._addCaseMapping(4339,4291);
+		this._addCaseMapping(4340,4292);
+		this._addCaseMapping(4341,4293);
+		this._addCaseMapping(7681,7680);
+		this._addCaseMapping(7683,7682);
+		this._addCaseMapping(7685,7684);
+		this._addCaseMapping(7687,7686);
+		this._addCaseMapping(7689,7688);
+		this._addCaseMapping(7691,7690);
+		this._addCaseMapping(7693,7692);
+		this._addCaseMapping(7695,7694);
+		this._addCaseMapping(7697,7696);
+		this._addCaseMapping(7699,7698);
+		this._addCaseMapping(7701,7700);
+		this._addCaseMapping(7703,7702);
+		this._addCaseMapping(7705,7704);
+		this._addCaseMapping(7707,7706);
+		this._addCaseMapping(7709,7708);
+		this._addCaseMapping(7711,7710);
+		this._addCaseMapping(7713,7712);
+		this._addCaseMapping(7715,7714);
+		this._addCaseMapping(7717,7716);
+		this._addCaseMapping(7719,7718);
+		this._addCaseMapping(7721,7720);
+		this._addCaseMapping(7723,7722);
+		this._addCaseMapping(7725,7724);
+		this._addCaseMapping(7727,7726);
+		this._addCaseMapping(7729,7728);
+		this._addCaseMapping(7731,7730);
+		this._addCaseMapping(7733,7732);
+		this._addCaseMapping(7735,7734);
+		this._addCaseMapping(7737,7736);
+		this._addCaseMapping(7739,7738);
+		this._addCaseMapping(7741,7740);
+		this._addCaseMapping(7743,7742);
+		this._addCaseMapping(7745,7744);
+		this._addCaseMapping(7747,7746);
+		this._addCaseMapping(7749,7748);
+		this._addCaseMapping(7751,7750);
+		this._addCaseMapping(7753,7752);
+		this._addCaseMapping(7755,7754);
+		this._addCaseMapping(7757,7756);
+		this._addCaseMapping(7759,7758);
+		this._addCaseMapping(7761,7760);
+		this._addCaseMapping(7763,7762);
+		this._addCaseMapping(7765,7764);
+		this._addCaseMapping(7767,7766);
+		this._addCaseMapping(7769,7768);
+		this._addCaseMapping(7771,7770);
+		this._addCaseMapping(7773,7772);
+		this._addCaseMapping(7775,7774);
+		this._addCaseMapping(7777,7776);
+		this._addCaseMapping(7779,7778);
+		this._addCaseMapping(7781,7780);
+		this._addCaseMapping(7783,7782);
+		this._addCaseMapping(7785,7784);
+		this._addCaseMapping(7787,7786);
+		this._addCaseMapping(7789,7788);
+		this._addCaseMapping(7791,7790);
+		this._addCaseMapping(7793,7792);
+		this._addCaseMapping(7795,7794);
+		this._addCaseMapping(7797,7796);
+		this._addCaseMapping(7799,7798);
+		this._addCaseMapping(7801,7800);
+		this._addCaseMapping(7803,7802);
+		this._addCaseMapping(7805,7804);
+		this._addCaseMapping(7807,7806);
+		this._addCaseMapping(7809,7808);
+		this._addCaseMapping(7811,7810);
+		this._addCaseMapping(7813,7812);
+		this._addCaseMapping(7815,7814);
+		this._addCaseMapping(7817,7816);
+		this._addCaseMapping(7819,7818);
+		this._addCaseMapping(7821,7820);
+		this._addCaseMapping(7823,7822);
+		this._addCaseMapping(7825,7824);
+		this._addCaseMapping(7827,7826);
+		this._addCaseMapping(7829,7828);
+		this._addCaseMapping(7841,7840);
+		this._addCaseMapping(7843,7842);
+		this._addCaseMapping(7845,7844);
+		this._addCaseMapping(7847,7846);
+		this._addCaseMapping(7849,7848);
+		this._addCaseMapping(7851,7850);
+		this._addCaseMapping(7853,7852);
+		this._addCaseMapping(7855,7854);
+		this._addCaseMapping(7857,7856);
+		this._addCaseMapping(7859,7858);
+		this._addCaseMapping(7861,7860);
+		this._addCaseMapping(7863,7862);
+		this._addCaseMapping(7865,7864);
+		this._addCaseMapping(7867,7866);
+		this._addCaseMapping(7869,7868);
+		this._addCaseMapping(7871,7870);
+		this._addCaseMapping(7873,7872);
+		this._addCaseMapping(7875,7874);
+		this._addCaseMapping(7877,7876);
+		this._addCaseMapping(7879,7878);
+		this._addCaseMapping(7881,7880);
+		this._addCaseMapping(7883,7882);
+		this._addCaseMapping(7885,7884);
+		this._addCaseMapping(7887,7886);
+		this._addCaseMapping(7889,7888);
+		this._addCaseMapping(7891,7890);
+		this._addCaseMapping(7893,7892);
+		this._addCaseMapping(7895,7894);
+		this._addCaseMapping(7897,7896);
+		this._addCaseMapping(7899,7898);
+		this._addCaseMapping(7901,7900);
+		this._addCaseMapping(7903,7902);
+		this._addCaseMapping(7905,7904);
+		this._addCaseMapping(7907,7906);
+		this._addCaseMapping(7909,7908);
+		this._addCaseMapping(7911,7910);
+		this._addCaseMapping(7913,7912);
+		this._addCaseMapping(7915,7914);
+		this._addCaseMapping(7917,7916);
+		this._addCaseMapping(7919,7918);
+		this._addCaseMapping(7921,7920);
+		this._addCaseMapping(7923,7922);
+		this._addCaseMapping(7925,7924);
+		this._addCaseMapping(7927,7926);
+		this._addCaseMapping(7929,7928);
+		this._addCaseMapping(7936,7944);
+		this._addCaseMapping(7937,7945);
+		this._addCaseMapping(7938,7946);
+		this._addCaseMapping(7939,7947);
+		this._addCaseMapping(7940,7948);
+		this._addCaseMapping(7941,7949);
+		this._addCaseMapping(7942,7950);
+		this._addCaseMapping(7943,7951);
+		this._addCaseMapping(7952,7960);
+		this._addCaseMapping(7953,7961);
+		this._addCaseMapping(7954,7962);
+		this._addCaseMapping(7955,7963);
+		this._addCaseMapping(7956,7964);
+		this._addCaseMapping(7957,7965);
+		this._addCaseMapping(7968,7976);
+		this._addCaseMapping(7969,7977);
+		this._addCaseMapping(7970,7978);
+		this._addCaseMapping(7971,7979);
+		this._addCaseMapping(7972,7980);
+		this._addCaseMapping(7973,7981);
+		this._addCaseMapping(7974,7982);
+		this._addCaseMapping(7975,7983);
+		this._addCaseMapping(7984,7992);
+		this._addCaseMapping(7985,7993);
+		this._addCaseMapping(7986,7994);
+		this._addCaseMapping(7987,7995);
+		this._addCaseMapping(7988,7996);
+		this._addCaseMapping(7989,7997);
+		this._addCaseMapping(7990,7998);
+		this._addCaseMapping(7991,7999);
+		this._addCaseMapping(8000,8008);
+		this._addCaseMapping(8001,8009);
+		this._addCaseMapping(8002,8010);
+		this._addCaseMapping(8003,8011);
+		this._addCaseMapping(8004,8012);
+		this._addCaseMapping(8005,8013);
+		this._addCaseMapping(8017,8025);
+		this._addCaseMapping(8019,8027);
+		this._addCaseMapping(8021,8029);
+		this._addCaseMapping(8023,8031);
+		this._addCaseMapping(8032,8040);
+		this._addCaseMapping(8033,8041);
+		this._addCaseMapping(8034,8042);
+		this._addCaseMapping(8035,8043);
+		this._addCaseMapping(8036,8044);
+		this._addCaseMapping(8037,8045);
+		this._addCaseMapping(8038,8046);
+		this._addCaseMapping(8039,8047);
+		this._addCaseMapping(8064,8072);
+		this._addCaseMapping(8065,8073);
+		this._addCaseMapping(8066,8074);
+		this._addCaseMapping(8067,8075);
+		this._addCaseMapping(8068,8076);
+		this._addCaseMapping(8069,8077);
+		this._addCaseMapping(8070,8078);
+		this._addCaseMapping(8071,8079);
+		this._addCaseMapping(8080,8088);
+		this._addCaseMapping(8081,8089);
+		this._addCaseMapping(8082,8090);
+		this._addCaseMapping(8083,8091);
+		this._addCaseMapping(8084,8092);
+		this._addCaseMapping(8085,8093);
+		this._addCaseMapping(8086,8094);
+		this._addCaseMapping(8087,8095);
+		this._addCaseMapping(8096,8104);
+		this._addCaseMapping(8097,8105);
+		this._addCaseMapping(8098,8106);
+		this._addCaseMapping(8099,8107);
+		this._addCaseMapping(8100,8108);
+		this._addCaseMapping(8101,8109);
+		this._addCaseMapping(8102,8110);
+		this._addCaseMapping(8103,8111);
+		this._addCaseMapping(8112,8120);
+		this._addCaseMapping(8113,8121);
+		this._addCaseMapping(8144,8152);
+		this._addCaseMapping(8145,8153);
+		this._addCaseMapping(8160,8168);
+		this._addCaseMapping(8161,8169);
+		this._addCaseMapping(9424,9398);
+		this._addCaseMapping(9425,9399);
+		this._addCaseMapping(9426,9400);
+		this._addCaseMapping(9427,9401);
+		this._addCaseMapping(9428,9402);
+		this._addCaseMapping(9429,9403);
+		this._addCaseMapping(9430,9404);
+		this._addCaseMapping(9431,9405);
+		this._addCaseMapping(9432,9406);
+		this._addCaseMapping(9433,9407);
+		this._addCaseMapping(9434,9408);
+		this._addCaseMapping(9435,9409);
+		this._addCaseMapping(9436,9410);
+		this._addCaseMapping(9437,9411);
+		this._addCaseMapping(9438,9412);
+		this._addCaseMapping(9439,9413);
+		this._addCaseMapping(9440,9414);
+		this._addCaseMapping(9441,9415);
+		this._addCaseMapping(9442,9416);
+		this._addCaseMapping(9443,9417);
+		this._addCaseMapping(9444,9418);
+		this._addCaseMapping(9445,9419);
+		this._addCaseMapping(9446,9420);
+		this._addCaseMapping(9447,9421);
+		this._addCaseMapping(9448,9422);
+		this._addCaseMapping(9449,9423);
+		this._addCaseMapping(65345,65313);
+		this._addCaseMapping(65346,65314);
+		this._addCaseMapping(65347,65315);
+		this._addCaseMapping(65348,65316);
+		this._addCaseMapping(65349,65317);
+		this._addCaseMapping(65350,65318);
+		this._addCaseMapping(65351,65319);
+		this._addCaseMapping(65352,65320);
+		this._addCaseMapping(65353,65321);
+		this._addCaseMapping(65354,65322);
+		this._addCaseMapping(65355,65323);
+		this._addCaseMapping(65356,65324);
+		this._addCaseMapping(65357,65325);
+		this._addCaseMapping(65358,65326);
+		this._addCaseMapping(65359,65327);
+		this._addCaseMapping(65360,65328);
+		this._addCaseMapping(65361,65329);
+		this._addCaseMapping(65362,65330);
+		this._addCaseMapping(65363,65331);
+		this._addCaseMapping(65364,65332);
+		this._addCaseMapping(65365,65333);
+		this._addCaseMapping(65366,65334);
+		this._addCaseMapping(65367,65335);
+		this._addCaseMapping(65368,65336);
+		this._addCaseMapping(65369,65337);
+		this._addCaseMapping(65370,65338);
+	}
+	_addCaseMapping(lowerChar,upperChar) {
+		if(!this.mapU2L.h.hasOwnProperty(upperChar)) {
+			this.mapU2L.h[upperChar] = lowerChar;
+		}
+		if(!this.mapL2U.h.hasOwnProperty(lowerChar)) {
+			this.mapL2U.h[lowerChar] = upperChar;
+		}
+	}
+	isLowerCase(ch) {
+		return this.mapL2U.h.hasOwnProperty(ch);
+	}
+	isUpperCase(ch) {
+		return this.mapU2L.h.hasOwnProperty(ch);
+	}
+	toLowerCase(ch) {
+		let lowerChar = this.mapU2L.h[ch];
+		if(lowerChar == null) {
+			return ch;
+		} else {
+			return lowerChar;
+		}
+	}
+	toUpperCase(ch) {
+		let upperChar = this.mapL2U.h[ch];
+		if(upperChar == null) {
+			return ch;
+		} else {
+			return upperChar;
+		}
+	}
+}
+hx_strings__$Char_CharCaseMapper.__name__ = "hx.strings._Char.CharCaseMapper";
+Object.assign(hx_strings__$Char_CharCaseMapper.prototype, {
+	__class__: hx_strings__$Char_CharCaseMapper
+});
+class hx_strings_Char {
+	static fromString(str) {
+		return hx_strings_Strings.charCodeAt8(str,0);
+	}
+	static of(ch) {
+		return ch;
+	}
+	static op_plus_string(ch,other) {
+		return String.fromCodePoint(ch) + other;
+	}
+	static op_plus_string2(str,ch) {
+		return str + String.fromCodePoint(ch);
+	}
+	static op_plus(ch,other) {
+		return ch + other;
+	}
+	static isAscii(this1) {
+		if(this1 > -1) {
+			return this1 < 128;
+		} else {
+			return false;
+		}
+	}
+	static isAsciiAlpha(this1) {
+		if(!(this1 > 64 && this1 < 91)) {
+			if(this1 > 96) {
+				return this1 < 123;
+			} else {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+	static isAsciiAlphanumeric(this1) {
+		if(!(this1 > 64 && this1 < 91 || this1 > 96 && this1 < 123)) {
+			if(this1 > 47) {
+				return this1 < 58;
+			} else {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+	static isAsciiControl(this1) {
+		if(!(this1 > -1 && this1 < 32)) {
+			return this1 == 127;
+		} else {
+			return true;
+		}
+	}
+	static isAsciiPrintable(this1) {
+		if(this1 > 31) {
+			return this1 < 127;
+		} else {
+			return false;
+		}
+	}
+	static isDigit(this1) {
+		if(this1 > 47) {
+			return this1 < 58;
+		} else {
+			return false;
+		}
+	}
+	static isEOF(this1) {
+		return this1 != this1;
+	}
+	static isSpace(this1) {
+		return this1 == 32;
+	}
+	static isUTF8(this1) {
+		if(this1 > -1) {
+			return this1 < 1114112;
+		} else {
+			return false;
+		}
+	}
+	static isWhitespace(this1) {
+		if(!(this1 > 8 && this1 < 14)) {
+			return this1 == 32;
+		} else {
+			return true;
+		}
+	}
+	static isLowerCase(this1) {
+		return hx_strings_Char.CHAR_CASE_MAPPER.mapL2U.h.hasOwnProperty(this1);
+	}
+	static isUpperCase(this1) {
+		return hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(this1);
+	}
+	static toLowerCase(this1) {
+		let lowerChar = hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h[this1];
+		if(lowerChar == null) {
+			return this1;
+		} else {
+			return lowerChar;
+		}
+	}
+	static toUpperCase(this1) {
+		let upperChar = hx_strings_Char.CHAR_CASE_MAPPER.mapL2U.h[this1];
+		if(upperChar == null) {
+			return this1;
+		} else {
+			return upperChar;
+		}
+	}
+	static toInt(this1) {
+		return this1;
+	}
+	static toString(this1) {
+		return String.fromCodePoint(this1);
+	}
+}
+class hx_strings_CharIterator {
+	constructor(prevBufferSize) {
+		if(hx_strings_CharIterator._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(prevBufferSize);
+	}
+	_hx_constructor(prevBufferSize) {
+		this.prevBufferNextIdx = -1;
+		this.prevBufferPrevIdx = -1;
+		this.currChar = -1;
+		this.col = 0;
+		this.line = 0;
+		this.index = -1;
+		this.prevBuffer = prevBufferSize > 0 ? new hx_strings_internal__$RingBuffer_RingBufferImpl(prevBufferSize + 1) : null;
+	}
+	get_prevBufferLength() {
+		return this.prevBuffer.length;
+	}
+	get_current() {
+		if(this.index > -1) {
+			return this.currChar;
+		} else {
+			return null;
+		}
+	}
+	get_pos() {
+		return new hx_strings_CharPos(this.index,this.line,this.col);
+	}
+	hasPrev() {
+		return this.prevBufferPrevIdx > -1;
+	}
+	prev() {
+		if(this.prevBufferPrevIdx <= -1) {
+			throw haxe_Exception.thrown(new haxe_io_Eof());
+		}
+		let prevChar = this.prevBuffer.get(this.prevBufferPrevIdx);
+		this.currChar = prevChar.char;
+		this.index = prevChar.index;
+		this.line = prevChar.line;
+		this.col = prevChar.col;
+		this.prevBufferNextIdx = this.prevBufferPrevIdx + 1 < this.prevBuffer.length ? this.prevBufferPrevIdx + 1 : -1;
+		this.prevBufferPrevIdx--;
+		return this.currChar;
+	}
+	hasNext() {
+		if(this.prevBufferNextIdx > -1) {
+			return true;
+		} else {
+			return !this.isEOF();
+		}
+	}
+	next() {
+		if(this.prevBufferNextIdx > -1) {
+			let prevChar = this.prevBuffer.get(this.prevBufferNextIdx);
+			this.currChar = prevChar.char;
+			this.index = prevChar.index;
+			this.line = prevChar.line;
+			this.col = prevChar.col;
+			this.prevBufferPrevIdx = this.prevBufferNextIdx - 1;
+			this.prevBufferNextIdx = this.prevBufferNextIdx + 1 < this.prevBuffer.length ? this.prevBufferNextIdx + 1 : -1;
+			return this.currChar;
+		}
+		if(this.isEOF()) {
+			throw haxe_Exception.thrown(new haxe_io_Eof());
+		}
+		if(this.currChar == 10 || this.currChar < 0) {
+			this.line++;
+			this.col = 0;
+		}
+		this.index++;
+		this.col++;
+		this.currChar = this.getChar();
+		if(this.prevBuffer != null) {
+			this.prevBuffer.add(new hx_strings__$CharIterator_CharWithPos(this.currChar,this.index,this.col,this.line));
+			this.prevBufferPrevIdx = this.prevBuffer.length - 2;
+			this.prevBufferNextIdx = -1;
+		}
+		return this.currChar;
+	}
+	getChar() {
+		throw haxe_Exception.thrown("Not implemented");
+	}
+	isEOF() {
+		throw haxe_Exception.thrown("Not implemented");
+	}
+	static fromString(chars,prevBufferSize) {
+		if(prevBufferSize == null) {
+			prevBufferSize = 0;
+		}
+		if(chars == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		}
+		return new hx_strings__$CharIterator_StringCharIterator(chars,prevBufferSize);
+	}
+	static fromArray(chars,prevBufferSize) {
+		if(prevBufferSize == null) {
+			prevBufferSize = 0;
+		}
+		if(chars == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		}
+		return new hx_strings__$CharIterator_ArrayCharIterator(chars,prevBufferSize);
+	}
+	static fromInput(chars,prevBufferSize) {
+		if(prevBufferSize == null) {
+			prevBufferSize = 0;
+		}
+		if(chars == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		}
+		return new hx_strings__$CharIterator_InputCharIterator(chars,prevBufferSize);
+	}
+	static fromIterator(chars,prevBufferSize) {
+		if(prevBufferSize == null) {
+			prevBufferSize = 0;
+		}
+		if(chars == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		}
+		return new hx_strings__$CharIterator_IteratorCharIterator(chars,prevBufferSize);
+	}
+}
+hx_strings_CharIterator.__name__ = "hx.strings.CharIterator";
+Object.assign(hx_strings_CharIterator.prototype, {
+	__class__: hx_strings_CharIterator
+});
+class hx_strings_CharPos {
+	constructor(index,line,col) {
+		this.index = index;
+		this.line = line;
+		this.col = col;
+	}
+	toString() {
+		return "CharPos[index=" + this.index + ", line=" + this.line + ", col=" + this.col + "]";
+	}
+}
+hx_strings_CharPos.__name__ = "hx.strings.CharPos";
+Object.assign(hx_strings_CharPos.prototype, {
+	__class__: hx_strings_CharPos
+});
+class hx_strings__$CharIterator_CharWithPos extends hx_strings_CharPos {
+	constructor(char,index,line,col) {
+		super(index,line,col);
+		this.char = char;
+	}
+}
+hx_strings__$CharIterator_CharWithPos.__name__ = "hx.strings._CharIterator.CharWithPos";
+hx_strings__$CharIterator_CharWithPos.__super__ = hx_strings_CharPos;
+Object.assign(hx_strings__$CharIterator_CharWithPos.prototype, {
+	__class__: hx_strings__$CharIterator_CharWithPos
+});
+class hx_strings_internal__$RingBuffer_RingBufferImpl {
+	constructor(size) {
+		this.length = 0;
+		this.bufferEndIdx = -1;
+		this.bufferStartIdx = 0;
+		if(size < 1) {
+			throw haxe_Exception.thrown("[size] must be > 0");
+		}
+		this.buffer = new Array(size);
+		this.size = size;
+		this.bufferMaxIdx = size - 1;
+	}
+	add(item) {
+		if(this.length == this.size) {
+			this.bufferEndIdx = this.bufferStartIdx;
+			this.bufferStartIdx++;
+			if(this.bufferStartIdx > this.bufferMaxIdx) {
+				this.bufferStartIdx = 0;
+			}
+		} else {
+			this.bufferEndIdx++;
+			this.length++;
+		}
+		this.buffer[this.bufferEndIdx] = item;
+	}
+	get(index) {
+		if(index < 0 || index > this.bufferMaxIdx) {
+			throw haxe_Exception.thrown("[index] " + index + " is out of bound");
+		}
+		let realIdx = this.bufferStartIdx + index;
+		if(realIdx > this.bufferMaxIdx) {
+			realIdx -= this.length;
+		}
+		return this.buffer[realIdx];
+	}
+	iterator() {
+		return new hx_strings_internal__$RingBuffer_RingBufferIterator(this);
+	}
+	toArray() {
+		let arr = [];
+		let i = this.iterator();
+		while(i.hasNext()) {
+			let i1 = i.next();
+			arr.push(i1);
+		}
+		return arr;
+	}
+}
+hx_strings_internal__$RingBuffer_RingBufferImpl.__name__ = "hx.strings.internal._RingBuffer.RingBufferImpl";
+Object.assign(hx_strings_internal__$RingBuffer_RingBufferImpl.prototype, {
+	__class__: hx_strings_internal__$RingBuffer_RingBufferImpl
+});
+class hx_strings__$CharIterator_NullCharIterator extends hx_strings_CharIterator {
+	constructor() {
+		super(0);
+	}
+	isEOF() {
+		return true;
+	}
+}
+hx_strings__$CharIterator_NullCharIterator.__name__ = "hx.strings._CharIterator.NullCharIterator";
+hx_strings__$CharIterator_NullCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_NullCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_NullCharIterator
+});
+class hx_strings__$CharIterator_ArrayCharIterator extends hx_strings_CharIterator {
+	constructor(chars,prevBufferSize) {
+		super(prevBufferSize);
+		this.chars = chars;
+		this.charsMaxIndex = chars.length - 1;
+	}
+	isEOF() {
+		return this.index >= this.charsMaxIndex;
+	}
+	getChar() {
+		return this.chars[this.index];
+	}
+}
+hx_strings__$CharIterator_ArrayCharIterator.__name__ = "hx.strings._CharIterator.ArrayCharIterator";
+hx_strings__$CharIterator_ArrayCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_ArrayCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_ArrayCharIterator
+});
+class hx_strings__$CharIterator_IteratorCharIterator extends hx_strings_CharIterator {
+	constructor(chars,prevBufferSize) {
+		super(prevBufferSize);
+		this.chars = chars;
+	}
+	isEOF() {
+		return !this.chars.hasNext();
+	}
+	getChar() {
+		return this.chars.next();
+	}
+}
+hx_strings__$CharIterator_IteratorCharIterator.__name__ = "hx.strings._CharIterator.IteratorCharIterator";
+hx_strings__$CharIterator_IteratorCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_IteratorCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_IteratorCharIterator
+});
+class hx_strings__$CharIterator_InputCharIterator extends hx_strings_CharIterator {
+	constructor(chars,prevBufferSize) {
+		hx_strings_CharIterator._hx_skip_constructor = true;
+		super();
+		hx_strings_CharIterator._hx_skip_constructor = false;
+		this._hx_constructor(chars,prevBufferSize);
+	}
+	_hx_constructor(chars,prevBufferSize) {
+		this.nextCharAvailable = null;
+		this.nextChar = -1;
+		this.currCharIndex = -1;
+		this.byteIndex = 0;
+		super._hx_constructor(prevBufferSize);
+		this.input = chars;
+	}
+	isEOF() {
+		if(this.nextCharAvailable == null) {
+			try {
+				let byte1 = this.input.readByte();
+				this.byteIndex++;
+				let tmp;
+				if(byte1 <= 127) {
+					tmp = byte1;
+				} else {
+					byte1 &= -129;
+					byte1 &= -65;
+					let totalBytes = 2;
+					let isBit6Set = 1 == (byte1 >> 5 & 1);
+					let isBit5Set = false;
+					if(isBit6Set) {
+						byte1 &= -33;
+						++totalBytes;
+						isBit5Set = 1 == (byte1 >> 4 & 1);
+						if(isBit5Set) {
+							byte1 &= -17;
+							++totalBytes;
+							if(1 == (byte1 >> 3 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte1 + "]!");
+							}
+						}
+					}
+					let result = byte1 << 6 * (totalBytes - 1);
+					let byte = this.input.readByte();
+					this.byteIndex++;
+					if(1 != (byte >> 7 & 1)) {
+						throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+					}
+					if(1 == (byte >> 6 & 1)) {
+						throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+					}
+					let byte2 = byte & -129;
+					result += byte2 << 6 * (totalBytes - 2);
+					if(isBit6Set) {
+						let byte = this.input.readByte();
+						this.byteIndex++;
+						if(1 != (byte >> 7 & 1)) {
+							throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+						}
+						if(1 == (byte >> 6 & 1)) {
+							throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+						}
+						let byte3 = byte & -129;
+						result += byte3 << 6 * (totalBytes - 3);
+						if(isBit5Set) {
+							let byte = this.input.readByte();
+							this.byteIndex++;
+							if(1 != (byte >> 7 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+							}
+							if(1 == (byte >> 6 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+							}
+							let byte4 = byte & -129;
+							result += byte4 << 6 * (totalBytes - 4);
+						}
+					}
+					if(this.index == 0 && result == 65279) {
+						let byte1 = this.input.readByte();
+						this.byteIndex++;
+						if(byte1 <= 127) {
+							tmp = byte1;
+						} else {
+							byte1 &= -129;
+							byte1 &= -65;
+							let totalBytes = 2;
+							let isBit6Set = 1 == (byte1 >> 5 & 1);
+							let isBit5Set = false;
+							if(isBit6Set) {
+								byte1 &= -33;
+								++totalBytes;
+								isBit5Set = 1 == (byte1 >> 4 & 1);
+								if(isBit5Set) {
+									byte1 &= -17;
+									++totalBytes;
+									if(1 == (byte1 >> 3 & 1)) {
+										throw haxe_Exception.thrown("Valid UTF-8 byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte1 + "]!");
+									}
+								}
+							}
+							let result = byte1 << 6 * (totalBytes - 1);
+							let byte = this.input.readByte();
+							this.byteIndex++;
+							if(1 != (byte >> 7 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+							}
+							if(1 == (byte >> 6 & 1)) {
+								throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+							}
+							let byte2 = byte & -129;
+							result += byte2 << 6 * (totalBytes - 2);
+							if(isBit6Set) {
+								let byte = this.input.readByte();
+								this.byteIndex++;
+								if(1 != (byte >> 7 & 1)) {
+									throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+								}
+								if(1 == (byte >> 6 & 1)) {
+									throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+								}
+								let byte3 = byte & -129;
+								result += byte3 << 6 * (totalBytes - 3);
+								if(isBit5Set) {
+									let byte = this.input.readByte();
+									this.byteIndex++;
+									if(1 != (byte >> 7 & 1)) {
+										throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+									}
+									if(1 == (byte >> 6 & 1)) {
+										throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+									}
+									let byte4 = byte & -129;
+									result += byte4 << 6 * (totalBytes - 4);
+								}
+							}
+							tmp = this.index == 0 && result == 65279 ? this.readUtf8Char() : result;
+						}
+					} else {
+						tmp = result;
+					}
+				}
+				this.nextChar = tmp;
+				this.nextCharAvailable = true;
+			} catch( _g ) {
+				if(((haxe_Exception.caught(_g).unwrap()) instanceof haxe_io_Eof)) {
+					this.nextCharAvailable = false;
+				} else {
+					throw _g;
+				}
+			}
+		}
+		return this.nextCharAvailable != true;
+	}
+	getChar() {
+		if(this.index != this.currCharIndex) {
+			this.currCharIndex = this.index;
+			this.nextCharAvailable = null;
+			return this.nextChar;
+		}
+		return this.currChar;
+	}
+	readUtf8Char() {
+		let byte1 = this.input.readByte();
+		this.byteIndex++;
+		if(byte1 <= 127) {
+			return byte1;
+		}
+		byte1 &= -129;
+		byte1 &= -65;
+		let totalBytes = 2;
+		let isBit6Set = 1 == (byte1 >> 5 & 1);
+		let isBit5Set = false;
+		if(isBit6Set) {
+			byte1 &= -33;
+			++totalBytes;
+			isBit5Set = 1 == (byte1 >> 4 & 1);
+			if(isBit5Set) {
+				byte1 &= -17;
+				++totalBytes;
+				if(1 == (byte1 >> 3 & 1)) {
+					throw haxe_Exception.thrown("Valid UTF-8 byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte1 + "]!");
+				}
+			}
+		}
+		let result = byte1 << 6 * (totalBytes - 1);
+		let byte = this.input.readByte();
+		this.byteIndex++;
+		if(1 != (byte >> 7 & 1)) {
+			throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+		}
+		if(1 == (byte >> 6 & 1)) {
+			throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+		}
+		let byte2 = byte & -129;
+		result += byte2 << 6 * (totalBytes - 2);
+		if(isBit6Set) {
+			let byte = this.input.readByte();
+			this.byteIndex++;
+			if(1 != (byte >> 7 & 1)) {
+				throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+			}
+			if(1 == (byte >> 6 & 1)) {
+				throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+			}
+			let byte3 = byte & -129;
+			result += byte3 << 6 * (totalBytes - 3);
+			if(isBit5Set) {
+				let byte = this.input.readByte();
+				this.byteIndex++;
+				if(1 != (byte >> 7 & 1)) {
+					throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+				}
+				if(1 == (byte >> 6 & 1)) {
+					throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+				}
+				let byte4 = byte & -129;
+				result += byte4 << 6 * (totalBytes - 4);
+			}
+		}
+		if(this.index == 0 && result == 65279) {
+			return this.readUtf8Char();
+		}
+		return result;
+	}
+	readUtf8MultiSequenceByte() {
+		let byte = this.input.readByte();
+		this.byteIndex++;
+		if(1 != (byte >> 7 & 1)) {
+			throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+		}
+		if(1 == (byte >> 6 & 1)) {
+			throw haxe_Exception.thrown("Valid UTF-8 multi-sequence byte expected at position [" + this.byteIndex + "] but found byte with value [" + byte + "]!");
+		}
+		return byte & -129;
+	}
+}
+hx_strings__$CharIterator_InputCharIterator.__name__ = "hx.strings._CharIterator.InputCharIterator";
+hx_strings__$CharIterator_InputCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_InputCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_InputCharIterator
+});
+class hx_strings__$CharIterator_StringCharIterator extends hx_strings_CharIterator {
+	constructor(chars,prevBufferSize) {
+		super(prevBufferSize);
+		this.chars = chars;
+		this.charsMaxIndex = (chars == null ? 0 : chars.length) - 1;
+	}
+	isEOF() {
+		return this.index >= this.charsMaxIndex;
+	}
+	getChar() {
+		return HxOverrides.cca(this.chars,this.index);
+	}
+}
+hx_strings__$CharIterator_StringCharIterator.__name__ = "hx.strings._CharIterator.StringCharIterator";
+hx_strings__$CharIterator_StringCharIterator.__super__ = hx_strings_CharIterator;
+Object.assign(hx_strings__$CharIterator_StringCharIterator.prototype, {
+	__class__: hx_strings__$CharIterator_StringCharIterator
+});
+class hx_strings_Pattern {
+	constructor(pattern,options) {
+		this.pattern = pattern;
+		this.options = options;
+		this.ereg = new EReg(pattern,options);
+		this.options += "u";
+	}
+	matcher(str) {
+		return new hx_strings__$Pattern_MatcherImpl(this.ereg,this.pattern,this.options,str);
+	}
+	replace(str,replaceWith) {
+		return str.replace(this.ereg.r,replaceWith);
+	}
+	remove(str) {
+		return str.replace(this.ereg.r,"");
+	}
+	split(str) {
+		return this.ereg.split(str);
+	}
+	static compile(pattern,options) {
+		if(options == null) {
+			return new hx_strings_Pattern(pattern,"");
+		}
+		let _g = options;
+		let tmp;
+		switch(_g._hx_index) {
+		case 0:
+			let str = _g.v;
+			let str1 = hx_strings_Strings.toLowerCase8(str);
+			if(str1 == null || str1.length == 0) {
+				tmp = str1;
+			} else {
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = hx_strings_Strings.toChars(str1);
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(v == hx_strings_Strings.charCodeAt8("i",0) || v == hx_strings_Strings.charCodeAt8("m",0) || v == hx_strings_Strings.charCodeAt8("g",0)) {
+						_g.push(v);
+					}
+				}
+				let _this = _g;
+				let result = new Array(_this.length);
+				let _g3 = 0;
+				let _g4 = _this.length;
+				while(_g3 < _g4) {
+					let i = _g3++;
+					result[i] = String.fromCodePoint(_this[i]);
+				}
+				tmp = result.join("");
+			}
+			break;
+		case 1:
+			let opt = _g.v;
+			tmp = Std.string(opt);
+			break;
+		case 2:
+			let arr = _g.v;
+			let _g1 = [];
+			let _g2 = 0;
+			let _g3 = arr;
+			while(_g2 < _g3.length) {
+				let v = _g3[_g2];
+				++_g2;
+				if(v != null) {
+					_g1.push(v);
+				}
+			}
+			tmp = _g1.join("");
+			break;
+		}
+		return new hx_strings_Pattern(pattern,tmp);
+	}
+}
+hx_strings_Pattern.__name__ = "hx.strings.Pattern";
+Object.assign(hx_strings_Pattern.prototype, {
+	__class__: hx_strings_Pattern
+});
+class hx_strings_Matcher {
+}
+hx_strings_Matcher.__name__ = "hx.strings.Matcher";
+hx_strings_Matcher.__isInterface__ = true;
+Object.assign(hx_strings_Matcher.prototype, {
+	__class__: hx_strings_Matcher
+});
+class hx_strings__$Pattern_MatcherImpl {
+	constructor(ereg,pattern,options,str) {
+		let clone = new EReg(pattern,options);
+		this.ereg = clone;
+		this.str = str;
+	}
+	reset(str) {
+		this.str = str;
+		this.isMatch = null;
+		return this;
+	}
+	iterate(onMatch) {
+		let startAt = 0;
+		while(this.ereg.matchSub(this.str,startAt)) {
+			this.isMatch = true;
+			let matchedPos = this.ereg.matchedPos();
+			onMatch(this);
+			startAt = matchedPos.pos + matchedPos.len;
+		}
+		this.isMatch = false;
+	}
+	map(mapper) {
+		let _gthis = this;
+		return this.ereg.map(this.str,function(ereg) {
+			_gthis.isMatch = true;
+			return mapper(_gthis);
+		});
+	}
+	matched(n) {
+		if(n == null) {
+			n = 0;
+		}
+		if(!this.matches()) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		let result = this.ereg.matched(n);
+		return result;
+	}
+	matches() {
+		if(this.isMatch == null) {
+			this.isMatch = this.ereg.match(this.str);
+		}
+		return this.isMatch;
+	}
+	matchesInRegion(pos,len) {
+		if(len == null) {
+			len = -1;
+		}
+		return this.isMatch = this.ereg.matchSub(this.str,pos,len);
+	}
+	matchedPos() {
+		if(!this.matches()) {
+			throw haxe_Exception.thrown("No string matched");
+		}
+		return this.ereg.matchedPos();
+	}
+	substringAfterMatch() {
+		if(!this.matches()) {
+			return "";
+		}
+		return this.ereg.matchedRight();
+	}
+	substringBeforeMatch() {
+		if(!this.matches()) {
+			return "";
+		}
+		return this.ereg.matchedLeft();
+	}
+	_cloneEReg(from,pattern,options) {
+		let clone = new EReg(pattern,options);
+		return clone;
+	}
+}
+hx_strings__$Pattern_MatcherImpl.__name__ = "hx.strings._Pattern.MatcherImpl";
+hx_strings__$Pattern_MatcherImpl.__interfaces__ = [hx_strings_Matcher];
+Object.assign(hx_strings__$Pattern_MatcherImpl.prototype, {
+	__class__: hx_strings__$Pattern_MatcherImpl
+});
+class hx_strings_internal_OS {
+}
+hx_strings_internal_OS.__name__ = "hx.strings.internal.OS";
+class js_Boot {
+	static getClass(o) {
+		if(o == null) {
+			return null;
+		} else if(((o) instanceof Array)) {
+			return Array;
+		} else {
+			let cl = o.__class__;
+			if(cl != null) {
+				return cl;
+			}
+			let name = js_Boot.__nativeClassName(o);
+			if(name != null) {
+				return js_Boot.__resolveNativeClass(name);
+			}
+			return null;
+		}
+	}
+	static __string_rec(o,s) {
+		if(o == null) {
+			return "null";
+		}
+		if(s.length >= 5) {
+			return "<...>";
+		}
+		let t = typeof(o);
+		if(t == "function" && (o.__name__ || o.__ename__)) {
+			t = "object";
+		}
+		switch(t) {
+		case "function":
+			return "<function>";
+		case "object":
+			if(o.__enum__) {
+				let e = $hxEnums[o.__enum__];
+				let con = e.__constructs__[o._hx_index];
+				let n = con._hx_name;
+				if(con.__params__) {
+					s = s + "\t";
+					return n + "(" + ((function($this) {
+						var $r;
+						let _g = [];
+						{
+							let _g1 = 0;
+							let _g2 = con.__params__;
+							while(true) {
+								if(!(_g1 < _g2.length)) {
+									break;
+								}
+								let p = _g2[_g1];
+								_g1 = _g1 + 1;
+								_g.push(js_Boot.__string_rec(o[p],s));
+							}
+						}
+						$r = _g;
+						return $r;
+					}(this))).join(",") + ")";
+				} else {
+					return n;
+				}
+			}
+			if(((o) instanceof Array)) {
+				let str = "[";
+				s += "\t";
+				let _g = 0;
+				let _g1 = o.length;
+				while(_g < _g1) {
+					let i = _g++;
+					str += (i > 0 ? "," : "") + js_Boot.__string_rec(o[i],s);
+				}
+				str += "]";
+				return str;
+			}
+			let tostr;
+			try {
+				tostr = o.toString;
+			} catch( _g ) {
+				return "???";
+			}
+			if(tostr != null && tostr != Object.toString && typeof(tostr) == "function") {
+				let s2 = o.toString();
+				if(s2 != "[object Object]") {
+					return s2;
+				}
+			}
+			let str = "{\n";
+			s += "\t";
+			let hasp = o.hasOwnProperty != null;
+			let k = null;
+			for( k in o ) {
+			if(hasp && !o.hasOwnProperty(k)) {
+				continue;
+			}
+			if(k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__") {
+				continue;
+			}
+			if(str.length != 2) {
+				str += ", \n";
+			}
+			str += s + k + " : " + js_Boot.__string_rec(o[k],s);
+			}
+			s = s.substring(1);
+			str += "\n" + s + "}";
+			return str;
+		case "string":
+			return o;
+		default:
+			return String(o);
+		}
+	}
+	static __interfLoop(cc,cl) {
+		if(cc == null) {
+			return false;
+		}
+		if(cc == cl) {
+			return true;
+		}
+		let intf = cc.__interfaces__;
+		if(intf != null && (cc.__super__ == null || cc.__super__.__interfaces__ != intf)) {
+			let _g = 0;
+			let _g1 = intf.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let i1 = intf[i];
+				if(i1 == cl || js_Boot.__interfLoop(i1,cl)) {
+					return true;
+				}
+			}
+		}
+		return js_Boot.__interfLoop(cc.__super__,cl);
+	}
+	static __instanceof(o,cl) {
+		if(cl == null) {
+			return false;
+		}
+		switch(cl) {
+		case Array:
+			return ((o) instanceof Array);
+		case Bool:
+			return typeof(o) == "boolean";
+		case Dynamic:
+			return o != null;
+		case Float:
+			return typeof(o) == "number";
+		case Int:
+			if(typeof(o) == "number") {
+				return ((o | 0) === o);
+			} else {
+				return false;
+			}
+			break;
+		case String:
+			return typeof(o) == "string";
+		default:
+			if(o != null) {
+				if(typeof(cl) == "function") {
+					if(js_Boot.__downcastCheck(o,cl)) {
+						return true;
+					}
+				} else if(typeof(cl) == "object" && js_Boot.__isNativeObj(cl)) {
+					if(((o) instanceof cl)) {
+						return true;
+					}
+				}
+			} else {
+				return false;
+			}
+			if(cl == Class ? o.__name__ != null : false) {
+				return true;
+			}
+			if(cl == Enum ? o.__ename__ != null : false) {
+				return true;
+			}
+			return o.__enum__ != null ? $hxEnums[o.__enum__] == cl : false;
+		}
+	}
+	static __downcastCheck(o,cl) {
+		if(!((o) instanceof cl)) {
+			if(cl.__isInterface__) {
+				return js_Boot.__interfLoop(js_Boot.getClass(o),cl);
+			} else {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+	static __cast(o,t) {
+		if(o == null || js_Boot.__instanceof(o,t)) {
+			return o;
+		} else {
+			throw haxe_Exception.thrown("Cannot cast " + Std.string(o) + " to " + Std.string(t));
+		}
+	}
+	static __nativeClassName(o) {
+		let name = js_Boot.__toStr.call(o).slice(8,-1);
+		if(name == "Object" || name == "Function" || name == "Math" || name == "JSON") {
+			return null;
+		}
+		return name;
+	}
+	static __isNativeObj(o) {
+		return js_Boot.__nativeClassName(o) != null;
+	}
+	static __resolveNativeClass(name) {
+		return $global[name];
+	}
+}
+js_Boot.__name__ = "js.Boot";
+var hx_strings_internal__$Either3__$Either3 = $hxEnums["hx.strings.internal._Either3._Either3"] = { __ename__:true,__constructs__:null
+	,a: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"hx.strings.internal._Either3._Either3",toString:$estr}; },$_._hx_name="a",$_.__params__ = ["v"],$_)
+	,b: ($_=function(v) { return {_hx_index:1,v:v,__enum__:"hx.strings.internal._Either3._Either3",toString:$estr}; },$_._hx_name="b",$_.__params__ = ["v"],$_)
+	,c: ($_=function(v) { return {_hx_index:2,v:v,__enum__:"hx.strings.internal._Either3._Either3",toString:$estr}; },$_._hx_name="c",$_.__params__ = ["v"],$_)
+};
+hx_strings_internal__$Either3__$Either3.__constructs__ = [hx_strings_internal__$Either3__$Either3.a,hx_strings_internal__$Either3__$Either3.b,hx_strings_internal__$Either3__$Either3.c];
+class hx_strings_Strings {
+	static _length(str) {
+		return str.length;
+	}
+	static _getNotFoundDefault(str,notFoundDefault) {
+		switch(notFoundDefault) {
+		case 1:
+			return null;
+		case 2:
+			return "";
+		case 3:
+			return str;
+		}
+	}
+	static _charCodeAt8Unsafe(str,pos) {
+		return HxOverrides.cca(str,pos);
+	}
+	static _splitAsciiWordsUnsafe(str) {
+		let words = [];
+		let currentWord = new hx_strings_StringBuilder();
+		let chars = hx_strings_Strings.toChars(str);
+		let len = chars.length;
+		let lastIndex = len - 1;
+		let _g = 0;
+		let _g1 = len;
+		while(_g < _g1) {
+			let i = _g++;
+			let ch = chars[i];
+			if(ch > 64 && ch < 91 || ch > 96 && ch < 123) {
+				let chNext = i < lastIndex ? chars[i + 1] : -1;
+				currentWord.addChar(ch);
+				if(chNext > 47 && chNext < 58) {
+					words.push(currentWord.toString());
+					currentWord.clear();
+				} else if(hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(ch)) {
+					if(hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(chNext) && chars.length > i + 2) {
+						if(!hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(chars[i + 2])) {
+							words.push(currentWord.toString());
+							currentWord.clear();
+						}
+					}
+				} else if(hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h.hasOwnProperty(chNext)) {
+					words.push(currentWord.toString());
+					currentWord.clear();
+				}
+			} else if(ch > 47 && ch < 58) {
+				currentWord.addChar(ch);
+				let chNext = i < lastIndex ? chars[i + 1] : -1;
+				if(!(chNext > 47 && chNext < 58)) {
+					words.push(currentWord.toString());
+					currentWord.clear();
+				}
+			} else if(currentWord.len > 0) {
+				words.push(currentWord.toString());
+				currentWord.clear();
+			}
+		}
+		if(currentWord.len > 0) {
+			words.push(currentWord.toString());
+		}
+		return words;
+	}
+	static ansiToHtml(str,renderMethod,initialState) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(renderMethod == null) {
+			renderMethod = hx_strings_AnsiToHtmlRenderMethod.StyleAttributes;
+		}
+		let styleOrClassAttribute;
+		switch(renderMethod._hx_index) {
+		case 0:
+			styleOrClassAttribute = "style";
+			break;
+		case 1:
+			styleOrClassAttribute = "class";
+			break;
+		case 2:
+			let cb = renderMethod.func;
+			styleOrClassAttribute = "class";
+			break;
+		}
+		let sb = new hx_strings_StringBuilder();
+		if(initialState != null && (initialState.fgcolor != null || initialState.bgcolor != null || initialState.bold || initialState.underline || initialState.blink)) {
+			sb.add("<span " + styleOrClassAttribute + "=\"").add(initialState.toCSS(renderMethod)).add("\">");
+		}
+		let effectiveState = new hx_strings_AnsiState(initialState);
+		let strLenMinus1 = (str == null ? 0 : str.length) - 1;
+		let i = -1;
+		let lookAhead = new hx_strings_StringBuilder();
+		while(i < strLenMinus1) {
+			++i;
+			let ch = HxOverrides.cca(str,i);
+			if(ch == 27 && i < strLenMinus1 && HxOverrides.cca(str,i + 1) == 91) {
+				lookAhead.clear();
+				let currentState = new hx_strings_AnsiState(effectiveState);
+				let currentGraphicModeParam = 0;
+				let isValidEscapeSequence = false;
+				++i;
+				_hx_loop2: while(i < strLenMinus1) {
+					++i;
+					let ch2 = HxOverrides.cca(str,i);
+					lookAhead.addChar(ch2);
+					switch(ch2) {
+					case 48:
+						currentGraphicModeParam *= 10;
+						break;
+					case 49:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 1;
+						break;
+					case 50:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 2;
+						break;
+					case 51:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 3;
+						break;
+					case 52:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 4;
+						break;
+					case 53:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 5;
+						break;
+					case 54:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 6;
+						break;
+					case 55:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 7;
+						break;
+					case 56:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 8;
+						break;
+					case 57:
+						currentGraphicModeParam = currentGraphicModeParam * 10 + 9;
+						break;
+					case 59:
+						currentState.setGraphicModeParameter(currentGraphicModeParam);
+						currentGraphicModeParam = 0;
+						break;
+					case 109:
+						currentState.setGraphicModeParameter(currentGraphicModeParam);
+						if(effectiveState.fgcolor != null || effectiveState.bgcolor != null || effectiveState.bold || effectiveState.underline || effectiveState.blink) {
+							sb.add("</span>");
+						}
+						if(currentState.fgcolor != null || currentState.bgcolor != null || currentState.bold || currentState.underline || currentState.blink) {
+							sb.add("<span " + styleOrClassAttribute + "=\"").add(currentState.toCSS(renderMethod)).add("\">");
+						}
+						effectiveState = currentState;
+						isValidEscapeSequence = true;
+						break _hx_loop2;
+					default:
+						break _hx_loop2;
+					}
+				}
+				if(!isValidEscapeSequence) {
+					sb.addChar(27).add("[").add(Std.string(lookAhead));
+				}
+			} else {
+				sb.addChar(ch);
+			}
+		}
+		if(effectiveState.fgcolor != null || effectiveState.bgcolor != null || effectiveState.bold || effectiveState.underline || effectiveState.blink) {
+			sb.add("</span>");
+		}
+		return sb.toString();
+	}
+	static appendIfMissing(str,suffix) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0) {
+			return Std.string(str) + Std.string(suffix);
+		}
+		if(hx_strings_Strings.endsWith(str,suffix)) {
+			return str;
+		}
+		return Std.string(str) + Std.string(suffix);
+	}
+	static base64Encode(plain) {
+		if(plain == null) {
+			return null;
+		}
+		return haxe_crypto_Base64.encode(plain == null ? null : haxe_io_Bytes.ofString(plain));
+	}
+	static base64Decode(encoded) {
+		if(encoded == null) {
+			return null;
+		}
+		return haxe_crypto_Base64.decode(encoded).toString();
+	}
+	static charAt8(str,pos,resultIfOutOfBound) {
+		if(resultIfOutOfBound == null) {
+			resultIfOutOfBound = "";
+		}
+		if(str == null || str.length == 0 || pos < 0 || pos >= (str == null ? 0 : str.length)) {
+			return resultIfOutOfBound;
+		}
+		return str.charAt(pos);
+	}
+	static charCodeAt8(str,pos,resultIfOutOfBound) {
+		if(resultIfOutOfBound == null) {
+			resultIfOutOfBound = -1;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0 || pos < 0 || pos >= strLen) {
+			return resultIfOutOfBound;
+		}
+		return HxOverrides.cca(str,pos);
+	}
+	static compact(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		let needWhiteSpace = false;
+		let _g = 0;
+		let _g1 = hx_strings_Strings.toChars(str);
+		while(_g < _g1.length) {
+			let char = _g1[_g];
+			++_g;
+			if(char > 8 && char < 14 || char == 32) {
+				if(sb.len != 0) {
+					needWhiteSpace = true;
+				}
+				continue;
+			} else if(needWhiteSpace) {
+				sb.addChar(32);
+				needWhiteSpace = false;
+			}
+			sb.addChar(char);
+		}
+		return sb.toString();
+	}
+	static contains(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		if(searchFor == "") {
+			return true;
+		}
+		return searchIn.indexOf(searchFor) > -1;
+	}
+	static containsOnly(searchIn,allowedChars) {
+		if(searchIn == null || searchIn.length == 0) {
+			return true;
+		}
+		if(allowedChars == null) {
+			return false;
+		}
+		let allowedCharsArray;
+		let _g = allowedChars;
+		switch(_g._hx_index) {
+		case 0:
+			let str = _g.v;
+			allowedCharsArray = hx_strings_Strings.toChars(str);
+			break;
+		case 1:
+			let chars = _g.v;
+			allowedCharsArray = chars;
+			break;
+		}
+		let _g1 = 0;
+		let _g2 = hx_strings_Strings.toChars(searchIn);
+		while(_g1 < _g2.length) {
+			let ch = _g2[_g1];
+			++_g1;
+			if(allowedCharsArray.indexOf(ch) < 0) {
+				return false;
+			}
+		}
+		return true;
+	}
+	static containsAll(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(!(searchIn == null || candidate == null ? false : candidate == "" ? true : searchIn.indexOf(candidate) > -1)) {
+				return false;
+			}
+		}
+		return true;
+	}
+	static containsAllIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		searchIn = searchIn.toLowerCase();
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			let searchFor1 = candidate.toLowerCase();
+			if(!(searchIn == null || searchFor1 == null ? false : searchFor1 == "" ? true : searchIn.indexOf(searchFor1) > -1)) {
+				return false;
+			}
+		}
+		return true;
+	}
+	static containsAny(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(searchIn == null || candidate == null ? false : candidate == "" ? true : searchIn.indexOf(candidate) > -1) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static containsAnyIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		searchIn = searchIn.toLowerCase();
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			let searchFor1 = candidate.toLowerCase();
+			if(searchIn == null || searchFor1 == null ? false : searchFor1 == "" ? true : searchIn.indexOf(searchFor1) > -1) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static containsNone(searchIn,searchFor) {
+		return !hx_strings_Strings.containsAny(searchIn,searchFor);
+	}
+	static containsNoneIgnoreCase(searchIn,searchFor) {
+		return !hx_strings_Strings.containsAnyIgnoreCase(searchIn,searchFor);
+	}
+	static containsWhitespaces(searchIn) {
+		if(searchIn == null) {
+			return false;
+		}
+		let _g = 0;
+		let _g1 = hx_strings_Strings.toChars(searchIn);
+		while(_g < _g1.length) {
+			let ch = _g1[_g];
+			++_g;
+			if(ch > 8 && ch < 14 || ch == 32) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static countMatches(searchIn,searchFor,startAt) {
+		if(startAt == null) {
+			startAt = 0;
+		}
+		if(searchIn == null || searchIn.length == 0 || (searchFor == null || searchFor.length == 0) || startAt >= searchIn.length) {
+			return 0;
+		}
+		if(startAt < 0) {
+			startAt = 0;
+		}
+		let count = 0;
+		let foundAt = startAt > -1 ? startAt - 1 : 0;
+		while(true) {
+			foundAt = searchIn.indexOf(searchFor,foundAt + 1);
+			if(!(foundAt > -1)) {
+				break;
+			}
+			++count;
+		}
+		return count;
+	}
+	static countMatchesIgnoreCase(searchIn,searchFor,startAt) {
+		if(startAt == null) {
+			startAt = 0;
+		}
+		if(searchIn == null || searchIn.length == 0 || (searchFor == null || searchFor.length == 0) || startAt >= searchIn.length) {
+			return 0;
+		}
+		if(startAt < 0) {
+			startAt = 0;
+		}
+		searchIn = searchIn.toLowerCase();
+		searchFor = searchFor.toLowerCase();
+		let count = 0;
+		let foundAt = startAt > -1 ? startAt - 1 : 0;
+		while(true) {
+			foundAt = searchIn.indexOf(searchFor,foundAt + 1);
+			if(!(foundAt > -1)) {
+				break;
+			}
+			++count;
+		}
+		return count;
+	}
+	static compare(str,other) {
+		if(str == null) {
+			if(other == null) {
+				return 0;
+			} else {
+				return -1;
+			}
+		}
+		if(other == null) {
+			if(str == null) {
+				return 0;
+			} else {
+				return 1;
+			}
+		}
+		if(str > other) {
+			return 1;
+		} else if(str == other) {
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+	static compareIgnoreCase(str,other) {
+		if(str == null) {
+			if(other == null) {
+				return 0;
+			} else {
+				return -1;
+			}
+		}
+		if(other == null) {
+			if(str == null) {
+				return 0;
+			} else {
+				return 1;
+			}
+		}
+		let str1 = hx_strings_Strings.toLowerCase8(str);
+		let other1 = hx_strings_Strings.toLowerCase8(other);
+		if(str1 > other1) {
+			return 1;
+		} else if(str1 == other1) {
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+	static diff(left,right) {
+		let diff = new hx_strings_StringDiff();
+		diff.at = hx_strings_Strings.diffAt(left,right);
+		diff.left = hx_strings_Strings.substr8(left,diff.at);
+		diff.right = hx_strings_Strings.substr8(right,diff.at);
+		return diff;
+	}
+	static diffAt(str,other) {
+		if(str == other) {
+			return -1;
+		}
+		let strLen = str == null ? 0 : str.length;
+		let otherLen = other == null ? 0 : other.length;
+		if(strLen == 0 || otherLen == 0) {
+			return 0;
+		}
+		let checkLen = strLen > otherLen ? otherLen : strLen;
+		let _g = 0;
+		let _g1 = checkLen;
+		while(_g < _g1) {
+			let i = _g++;
+			if(HxOverrides.cca(str,i) != HxOverrides.cca(other,i)) {
+				return i;
+			}
+		}
+		return checkLen;
+	}
+	static ellipsizeLeft(str,maxLength,ellipsis) {
+		if(ellipsis == null) {
+			ellipsis = "...";
+		}
+		if((str == null ? 0 : str.length) <= maxLength) {
+			return str;
+		}
+		let ellipsisLen = ellipsis == null ? 0 : ellipsis.length;
+		if(maxLength < ellipsisLen) {
+			throw haxe_Exception.thrown("[maxLength] must not be smaller than " + ellipsisLen);
+		}
+		return ellipsis + Std.string(hx_strings_Strings.right(str,maxLength - ellipsisLen));
+	}
+	static ellipsizeMiddle(str,maxLength,ellipsis) {
+		if(ellipsis == null) {
+			ellipsis = "...";
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen <= maxLength) {
+			return str;
+		}
+		let ellipsisLen = ellipsis == null ? 0 : ellipsis.length;
+		if(maxLength < ellipsisLen) {
+			throw haxe_Exception.thrown("[maxLength] must not be smaller than " + ellipsisLen);
+		}
+		let maxStrLen = maxLength - ellipsisLen;
+		let leftLen = Math.round(maxStrLen / 2);
+		let rightLen = maxStrLen - leftLen;
+		return Std.string((str == null ? 0 : str.length) <= leftLen ? str : hx_strings_Strings.substring8(str,0,leftLen)) + ellipsis + Std.string(hx_strings_Strings.right(str,rightLen));
+	}
+	static ellipsizeRight(str,maxLength,ellipsis) {
+		if(ellipsis == null) {
+			ellipsis = "...";
+		}
+		if((str == null ? 0 : str.length) <= maxLength) {
+			return str;
+		}
+		let ellipsisLen = ellipsis == null ? 0 : ellipsis.length;
+		if(maxLength < ellipsisLen) {
+			throw haxe_Exception.thrown("[maxLength] must not be smaller than " + ellipsisLen);
+		}
+		let len = maxLength - ellipsisLen;
+		return Std.string((str == null ? 0 : str.length) <= len ? str : hx_strings_Strings.substring8(str,0,len)) + ellipsis;
+	}
+	static endsWith(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		return searchIn.endsWith(searchFor);
+	}
+	static endsWithAny(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(candidate != null && hx_strings_Strings.endsWith(searchIn,candidate)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static endsWithAnyIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		searchIn = hx_strings_Strings.toLowerCase8(searchIn);
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(candidate != null && hx_strings_Strings.endsWith(searchIn,hx_strings_Strings.toLowerCase8(candidate))) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static endsWithIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		return hx_strings_Strings.endsWith(searchIn.toLowerCase(),searchFor.toLowerCase());
+	}
+	static equals(str,other) {
+		return str == other;
+	}
+	static equalsIgnoreCase(str,other) {
+		return hx_strings_Strings.toLowerCase8(str) == hx_strings_Strings.toLowerCase8(other);
+	}
+	static filter(str,filter,separator) {
+		if(separator == null) {
+			separator = "";
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = hx_strings_Strings.split8(str,[separator]);
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(filter(v)) {
+				_g.push(v);
+			}
+		}
+		return _g.join(separator);
+	}
+	static filterChars(str,filter) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = hx_strings_Strings.toChars(str);
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(filter(v)) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			result[i] = String.fromCodePoint(_this[i]);
+		}
+		return result.join("");
+	}
+	static getFuzzyDistance(left,right) {
+		if(left == null || left.length == 0 || (right == null || right.length == 0)) {
+			return 0;
+		}
+		left = hx_strings_Strings.toLowerCase8(left);
+		right = hx_strings_Strings.toLowerCase8(right);
+		let leftChars = hx_strings_Strings.toChars(left);
+		let rightChars = hx_strings_Strings.toChars(right);
+		let leftLastMatchAt = -100;
+		let rightLastMatchAt = -100;
+		let score = 0;
+		let _g = 0;
+		let _g1 = leftChars.length;
+		while(_g < _g1) {
+			let leftIdx = _g++;
+			let leftChar = leftChars[leftIdx];
+			let _g1 = rightLastMatchAt > -1 ? rightLastMatchAt + 1 : 0;
+			let _g2 = rightChars.length;
+			while(_g1 < _g2) {
+				let rightIdx = _g1++;
+				let rightChar = rightChars[rightIdx];
+				if(leftChar == rightChar) {
+					++score;
+					if(leftLastMatchAt == leftIdx - 1 && rightLastMatchAt == rightIdx - 1) {
+						score += 2;
+					}
+					leftLastMatchAt = leftIdx;
+					rightLastMatchAt = rightIdx;
+					break;
+				}
+			}
+		}
+		return score;
+	}
+	static getLevenshteinDistance(left,right) {
+		let leftLen = left == null ? 0 : left.length;
+		let rightLen = right == null ? 0 : right.length;
+		if(leftLen == 0) {
+			return rightLen;
+		}
+		if(rightLen == 0) {
+			return leftLen;
+		}
+		if(leftLen > rightLen) {
+			let tmp = left;
+			left = right;
+			right = tmp;
+			let tmpLen = leftLen;
+			leftLen = rightLen;
+			rightLen = tmpLen;
+		}
+		let prevCosts = [];
+		let costs = [];
+		let _g = 0;
+		let _g1 = leftLen + 1;
+		while(_g < _g1) {
+			let leftIdx = _g++;
+			prevCosts.push(leftIdx);
+			costs.push(0);
+		}
+		let leftChars = hx_strings_Strings.toChars(left);
+		let rightChars = hx_strings_Strings.toChars(right);
+		let min = function(a,b) {
+			if(a > b) {
+				return b;
+			} else {
+				return a;
+			}
+		};
+		let _g2 = 1;
+		let _g3 = rightLen + 1;
+		while(_g2 < _g3) {
+			let rightIdx = _g2++;
+			let rightChar = rightChars[rightIdx - 1];
+			costs[0] = rightIdx;
+			let _g = 1;
+			let _g1 = leftLen + 1;
+			while(_g < _g1) {
+				let leftIdx = _g++;
+				let leftIdxMinus1 = leftIdx - 1;
+				let cost = leftChars[leftIdxMinus1] == rightChar ? 0 : 1;
+				costs[leftIdx] = min(min(costs[leftIdxMinus1] + 1,prevCosts[leftIdx] + 1),prevCosts[leftIdxMinus1] + cost);
+			}
+			let tmp = prevCosts;
+			prevCosts = costs;
+			costs = tmp;
+		}
+		return prevCosts[leftLen];
+	}
+	static getLongestCommonSubstring(left,right) {
+		if(left == null || right == null) {
+			return null;
+		}
+		let leftLen = left == null ? 0 : left.length;
+		let rightLen = right == null ? 0 : right.length;
+		if(leftLen == 0 || rightLen == 0) {
+			return "";
+		}
+		let leftChars = hx_strings_Strings.toChars(left);
+		let rightChars = hx_strings_Strings.toChars(right);
+		let leftSubStartAt = 0;
+		let leftSubLen = 0;
+		let _g = 0;
+		let _g1 = leftLen;
+		while(_g < _g1) {
+			let leftIdx = _g++;
+			let _g1 = 0;
+			let _g2 = rightLen;
+			while(_g1 < _g2) {
+				let rightIdx = _g1++;
+				let currLen = 0;
+				while(leftChars[leftIdx + currLen] == rightChars[rightIdx + currLen]) {
+					++currLen;
+					if(leftIdx + currLen >= leftLen || rightIdx + currLen >= rightLen) {
+						break;
+					}
+				}
+				if(currLen > leftSubLen) {
+					leftSubLen = currLen;
+					leftSubStartAt = leftIdx;
+				}
+			}
+		}
+		return hx_strings_Strings.substr8(left,leftSubStartAt,leftSubLen);
+	}
+	static hashCode(str,algo) {
+		if(str == null || str.length == 0) {
+			return 0;
+		}
+		if(algo == null) {
+			algo = hx_strings_HashCodeAlgorithm.PLATFORM_SPECIFIC;
+		}
+		if(algo == null) {
+			return haxe_crypto_Crc32.make(str == null ? null : haxe_io_Bytes.ofString(str));
+		} else {
+			switch(algo._hx_index) {
+			case 1:
+				return haxe_crypto_Adler32.make(str == null ? null : haxe_io_Bytes.ofString(str));
+			case 2:
+				return haxe_crypto_Crc32.make(str == null ? null : haxe_io_Bytes.ofString(str));
+			case 3:
+				let hc = 5381;
+				let _g = 0;
+				let _g1 = hx_strings_Strings.toChars(str);
+				while(_g < _g1.length) {
+					let ch = _g1[_g];
+					++_g;
+					hc = ((hc << 5) + hc | 0) ^ ch;
+				}
+				return hc;
+			case 4:
+				let hc1 = 0;
+				let _g2 = 0;
+				let _g3 = hx_strings_Strings.toChars(str);
+				while(_g2 < _g3.length) {
+					let ch = _g3[_g2];
+					++_g2;
+					hc1 = ((hc1 << 5) - hc1 | 0) + ch | 0;
+				}
+				return hc1;
+			case 5:
+				let hc2 = 0;
+				let _g4 = 0;
+				let _g5 = hx_strings_Strings.toChars(str);
+				while(_g4 < _g5.length) {
+					let ch = _g5[_g4];
+					++_g4;
+					hc2 = (((hc2 << 6) + (hc2 << 16) | 0) - hc2 | 0) + ch | 0;
+				}
+				return hc2;
+			default:
+				return haxe_crypto_Crc32.make(str == null ? null : haxe_io_Bytes.ofString(str));
+			}
+		}
+	}
+	static htmlDecode(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings.REGEX_HTML_UNESCAPE;
+		return new hx_strings__$Pattern_MatcherImpl(_this.ereg,_this.pattern,_this.options,str).map(function(m) {
+			let match = m.matched();
+			switch(match) {
+			case "&amp;":
+				return "&";
+			case "&apos;":
+				return "'";
+			case "&gt;":
+				return ">";
+			case "&lt;":
+				return "<";
+			case "&nbsp;":
+				return " ";
+			case "&quot;":
+				return "\"";
+			default:
+				let number = Std.parseInt(hx_strings_Strings.substr8(match,2,(match == null ? 0 : match.length) - 3));
+				if(number == null) {
+					throw haxe_Exception.thrown("Invalid HTML value " + match);
+				}
+				let this1 = number;
+				return String.fromCodePoint(this1);
+			}
+		});
+	}
+	static htmlEncode(str,escapeQuotes) {
+		if(escapeQuotes == null) {
+			escapeQuotes = false;
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		let isFirstSpace = true;
+		let _g = 0;
+		let _g1 = str == null ? 0 : str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let ch = HxOverrides.cca(str,i);
+			switch(ch) {
+			case 32:
+				if(isFirstSpace) {
+					sb.add(" ");
+					isFirstSpace = false;
+				} else {
+					sb.add("&nbsp;");
+				}
+				break;
+			case 34:
+				sb.add(escapeQuotes ? "&quot;" : "\"");
+				break;
+			case 38:
+				sb.add("&amp;");
+				break;
+			case 39:
+				sb.add(escapeQuotes ? "&#039;" : "'");
+				break;
+			case 60:
+				sb.add("&lt;");
+				break;
+			case 62:
+				sb.add("&gt;");
+				break;
+			default:
+				if(ch > 127) {
+					sb.add("&#").add(Std.string(ch)).add(";");
+				} else {
+					sb.addChar(ch);
+				}
+			}
+			if(ch != 32) {
+				isFirstSpace = true;
+			}
+		}
+		return sb.toString();
+	}
+	static insertAt(str,pos,insertion) {
+		if(str == null) {
+			return null;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(pos < 0) {
+			pos = strLen + pos;
+		}
+		if(pos < 0 || pos > strLen) {
+			throw haxe_Exception.thrown("Absolute value of [pos] must be <= str.length");
+		}
+		if(insertion == null || insertion.length == 0) {
+			return str;
+		}
+		return Std.string(hx_strings_Strings.substring8(str,0,pos)) + insertion + Std.string(hx_strings_Strings.substring8(str,pos));
+	}
+	static ifBlank(str,fallback) {
+		if(str == null ? true : StringTools.trim(str).length == 0) {
+			return fallback;
+		} else {
+			return str;
+		}
+	}
+	static ifEmpty(str,fallback) {
+		if(str == null || str.length == 0) {
+			return fallback;
+		} else {
+			return str;
+		}
+	}
+	static ifNull(str,fallback) {
+		if(str == null) {
+			return fallback;
+		} else {
+			return str;
+		}
+	}
+	static indentLines(str,indentWith) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0 || (indentWith == null || indentWith.length == 0)) {
+			return str;
+		}
+		let isFirstLine = true;
+		let sb = new hx_strings_StringBuilder();
+		let _g = 0;
+		let _g1 = hx_strings_Strings.REGEX_SPLIT_LINES.ereg.split(str);
+		while(_g < _g1.length) {
+			let line = _g1[_g];
+			++_g;
+			if(isFirstLine) {
+				isFirstLine = false;
+			} else {
+				sb.newLine();
+			}
+			sb.add(indentWith);
+			sb.add(line);
+		}
+		return sb.toString();
+	}
+	static indexOf8(str,searchFor,startAt) {
+		if(startAt == null) {
+			startAt = 0;
+		}
+		if(str == null || searchFor == null) {
+			return -1;
+		}
+		let strLen = str == null ? 0 : str.length;
+		let searchForLen = searchFor == null ? 0 : searchFor.length;
+		if(startAt < 0) {
+			startAt = 0;
+		}
+		if(searchForLen == 0) {
+			if(startAt == 0) {
+				return 0;
+			}
+			if(startAt > 0 && startAt < strLen) {
+				return startAt;
+			}
+			return strLen;
+		}
+		if(startAt >= strLen) {
+			return -1;
+		}
+		return str.indexOf(searchFor,startAt);
+	}
+	static isBlank(str) {
+		if(str == null) {
+			return true;
+		} else {
+			return StringTools.trim(str).length == 0;
+		}
+	}
+	static isDigits(str) {
+		if(str == null || str.length == 0) {
+			return false;
+		}
+		let _g = 0;
+		let _g1 = str == null ? 0 : str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let this1 = HxOverrides.cca(str,i);
+			if(!(this1 > 47 && this1 < 58)) {
+				return false;
+			}
+		}
+		return true;
+	}
+	static isEmpty(str) {
+		if(str != null) {
+			return str.length == 0;
+		} else {
+			return true;
+		}
+	}
+	static isNotBlank(str) {
+		if(str != null) {
+			return StringTools.trim(str).length > 0;
+		} else {
+			return false;
+		}
+	}
+	static isNotEmpty(str) {
+		if(str != null) {
+			return str.length > 0;
+		} else {
+			return false;
+		}
+	}
+	static isLowerCase(str) {
+		if(str == null || str.length == 0) {
+			return false;
+		}
+		return str == hx_strings_Strings.toLowerCase8(str);
+	}
+	static isUpperCase(str) {
+		if(str == null || str.length == 0) {
+			return false;
+		}
+		return str == hx_strings_Strings.toUpperCase8(str);
+	}
+	static iterate(str,callback,separator) {
+		if(separator == null) {
+			separator = "";
+		}
+		if(str == null || str.length == 0) {
+			return;
+		}
+		let _g = 0;
+		let _g1 = hx_strings_Strings.split8(str,[separator]);
+		while(_g < _g1.length) {
+			let sub = _g1[_g];
+			++_g;
+			callback(sub);
+		}
+	}
+	static iterateChars(str,callback) {
+		if(str == null || str.length == 0) {
+			return;
+		}
+		let _g = 0;
+		let _g1 = str == null ? 0 : str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			callback(HxOverrides.cca(str,i));
+		}
+	}
+	static lastIndexOf8(str,searchFor,startAt) {
+		if(str == null || searchFor == null) {
+			return -1;
+		}
+		let strLen = str == null ? 0 : str.length;
+		let searchForLen = searchFor == null ? 0 : searchFor.length;
+		if(startAt == null) {
+			startAt = strLen;
+		}
+		if(searchForLen == 0) {
+			if(startAt < 0) {
+				return 0;
+			}
+			if(startAt > strLen) {
+				return strLen;
+			}
+			return startAt;
+		}
+		if(startAt < 0) {
+			return -1;
+		} else if(startAt >= strLen) {
+			startAt = strLen - 1;
+		}
+		let strNeedsUTF8Workaround = str.length != strLen;
+		let searchForNeedsUTF8Workaround = searchFor.length != searchForLen;
+		if(!strNeedsUTF8Workaround && !searchForNeedsUTF8Workaround) {
+			return str.lastIndexOf(searchFor,startAt);
+		}
+		if(searchForNeedsUTF8Workaround && !strNeedsUTF8Workaround) {
+			return -1;
+		}
+		let searchForChars = hx_strings_Strings.toChars(searchFor);
+		startAt += searchForLen - 1;
+		let searchForPosToCheck = searchForLen - 1;
+		let strPos = strLen;
+		while(strPos-- > 0) {
+			if(strPos > startAt) {
+				continue;
+			}
+			let strCh = HxOverrides.cca(str,strPos);
+			if(strCh == searchForChars[searchForPosToCheck]) {
+				if(searchForPosToCheck == 0) {
+					return strPos;
+				}
+				--searchForPosToCheck;
+			} else {
+				searchForPosToCheck = searchForLen - 1;
+			}
+		}
+		return -1;
+	}
+	static length8(str) {
+		if(str == null) {
+			return 0;
+		}
+		return str.length;
+	}
+	static left(str,len) {
+		if((str == null ? 0 : str.length) <= len) {
+			return str;
+		}
+		return hx_strings_Strings.substring8(str,0,len);
+	}
+	static lpad(str,targetLength,padStr,canOverflow) {
+		if(canOverflow == null) {
+			canOverflow = true;
+		}
+		if(padStr == null) {
+			padStr = " ";
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(str == null || strLen > targetLength) {
+			return str;
+		}
+		if(padStr == null || padStr.length == 0) {
+			padStr = " ";
+		}
+		let sb = [str];
+		let padLen = padStr == null ? 0 : padStr.length;
+		while(strLen < targetLength) {
+			sb.unshift(padStr);
+			strLen += padLen;
+		}
+		if(canOverflow) {
+			return sb.join("");
+		}
+		return hx_strings_Strings.right(sb.join(""),targetLength);
+	}
+	static map(str,mapper,separator) {
+		if(separator == null) {
+			separator = "";
+		}
+		if(str == null) {
+			return null;
+		}
+		if(separator == null) {
+			throw haxe_Exception.thrown("[separator] must not be null");
+		}
+		let _this = hx_strings_Strings.split8(str,[separator]);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = mapper(_this[i]);
+		}
+		return result;
+	}
+	static prependIfMissing(str,suffix) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0) {
+			return suffix + Std.string(str);
+		}
+		if(hx_strings_Strings.startsWith(str,suffix)) {
+			return str;
+		}
+		return suffix + Std.string(str);
+	}
+	static quoteDouble(str) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0) {
+			return "\"\"";
+		}
+		if(!(str == null ? false : str.indexOf("\"") > -1)) {
+			return "\"" + Std.string(str) + "\"";
+		}
+		return "\"" + Std.string(hx_strings_Strings.replaceAll(str,"\"","\\\"")) + "\"";
+	}
+	static quoteSingle(str) {
+		if(str == null) {
+			return null;
+		}
+		if(str.length == 0) {
+			return "''";
+		}
+		if(!(str == null ? false : str.indexOf("'") > -1)) {
+			return "'" + Std.string(str) + "'";
+		}
+		return "'" + Std.string(hx_strings_Strings.replaceAll(str,"'","\\'")) + "'";
+	}
+	static removeAfter(str,searchFor) {
+		return hx_strings_Strings.substringBefore(str,searchFor);
+	}
+	static removeAfterLast(str,searchFor) {
+		return hx_strings_Strings.substringBeforeLast(str,searchFor);
+	}
+	static removeAfterIgnoreCase(str,searchFor) {
+		return hx_strings_Strings.substringBeforeIgnoreCase(str,searchFor);
+	}
+	static removeAfterLastIgnoreCase(str,searchFor) {
+		return hx_strings_Strings.substringBeforeLastIgnoreCase(str,searchFor);
+	}
+	static removeAt(str,pos,length) {
+		if(str == null || str.length == 0 || length < 1) {
+			return str;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(pos < 0) {
+			pos = strLen + pos;
+		}
+		if(pos < 0) {
+			throw haxe_Exception.thrown("[pos] must be smaller than -1 * str.length");
+		}
+		if(pos + length >= strLen) {
+			return hx_strings_Strings.substring8(str,0,pos);
+		}
+		return Std.string(hx_strings_Strings.substring8(str,0,pos)) + Std.string(hx_strings_Strings.substring8(str,pos + length));
+	}
+	static removeBefore(str,searchFor) {
+		return hx_strings_Strings.substringAfter(str,searchFor);
+	}
+	static removeBeforeLast(str,searchFor) {
+		return hx_strings_Strings.substringAfterLast(str,searchFor);
+	}
+	static removeBeforeIgnoreCase(str,searchFor) {
+		return hx_strings_Strings.substringAfterIgnoreCase(str,searchFor);
+	}
+	static removeBeforeLastIgnoreCase(str,searchFor) {
+		return hx_strings_Strings.substringAfterLastIgnoreCase(str,searchFor);
+	}
+	static removeAll(searchIn,searchFor) {
+		return hx_strings_Strings.replaceAll(searchIn,searchFor,"");
+	}
+	static removeFirst(searchIn,searchFor) {
+		return hx_strings_Strings.replaceFirst(searchIn,searchFor,"");
+	}
+	static removeFirstIgnoreCase(searchIn,searchFor) {
+		return hx_strings_Strings.replaceFirstIgnoreCase(searchIn,searchFor,"");
+	}
+	static removeAnsi(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return str.replace(hx_strings_Strings.REGEX_ANSI_ESC.ereg.r,"");
+	}
+	static removeLeading(searchIn,searchFor) {
+		if(searchIn == null || searchIn.length == 0 || (searchFor == null || searchFor.length == 0)) {
+			return searchIn;
+		}
+		while(hx_strings_Strings.startsWith(searchIn,searchFor)) searchIn = searchIn.substring(searchFor.length,searchIn.length);
+		return searchIn;
+	}
+	static removeTags(xml) {
+		if(xml == null || xml.length == 0) {
+			return xml;
+		}
+		return xml.replace(hx_strings_Strings.REGEX_REMOVE_XML_TAGS.ereg.r,"");
+	}
+	static removeTrailing(searchIn,searchFor) {
+		if(searchIn == null || searchIn.length == 0 || (searchFor == null || searchFor.length == 0)) {
+			return searchIn;
+		}
+		while(hx_strings_Strings.endsWith(searchIn,searchFor)) searchIn = searchIn.substring(0,searchIn.length - searchFor.length);
+		return searchIn;
+	}
+	static repeat(str,count,separator) {
+		if(separator == null) {
+			separator = "";
+		}
+		if(str == null) {
+			return null;
+		}
+		if(count < 1) {
+			return "";
+		}
+		if(count == 1) {
+			return str;
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = count;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(str);
+		}
+		return _g.join(separator);
+	}
+	static replaceAll(searchIn,searchFor,replaceWith) {
+		if(searchIn == null || (searchIn == null || searchIn.length == 0) || searchFor == null) {
+			return searchIn;
+		}
+		if(replaceWith == null) {
+			replaceWith = "null";
+		}
+		return StringTools.replace(searchIn,searchFor,replaceWith);
+	}
+	static replaceFirst(searchIn,searchFor,replaceWith) {
+		if(searchIn == null || (searchIn == null || searchIn.length == 0) || searchFor == null) {
+			return searchIn;
+		}
+		if(replaceWith == null) {
+			replaceWith = "null";
+		}
+		let foundAt;
+		if(searchFor.length == 0) {
+			if((searchIn == null ? 0 : searchIn.length) > 1) {
+				foundAt = 1;
+			} else {
+				return searchIn;
+			}
+		} else {
+			foundAt = hx_strings_Strings.indexOf8(searchIn,searchFor);
+		}
+		return Std.string(hx_strings_Strings.substr8(searchIn,0,foundAt)) + replaceWith + Std.string(hx_strings_Strings.substr8(searchIn,foundAt + (searchFor == null ? 0 : searchFor.length)));
+	}
+	static replaceFirstIgnoreCase(searchIn,searchFor,replaceWith) {
+		if(searchIn == null || (searchIn == null || searchIn.length == 0) || searchFor == null) {
+			return searchIn;
+		}
+		if(replaceWith == null) {
+			replaceWith = "null";
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt;
+		if(searchFor.length == 0) {
+			if((searchIn == null ? 0 : searchIn.length) > 1) {
+				foundAt = 1;
+			} else {
+				return searchIn;
+			}
+		} else {
+			foundAt = hx_strings_Strings.indexOf8(searchIn.toLowerCase(),searchFor);
+		}
+		return Std.string(hx_strings_Strings.substr8(searchIn,0,foundAt)) + replaceWith + Std.string(hx_strings_Strings.substr8(searchIn,foundAt + (searchFor == null ? 0 : searchFor.length)));
+	}
+	static reverse(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let chars = hx_strings_Strings.split8(str,[""]);
+		chars.reverse();
+		return chars.join("");
+	}
+	static right(str,len) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return hx_strings_Strings.substring8(str,(str == null ? 0 : str.length) - len);
+	}
+	static rpad(str,targetLength,padStr,canOverflow) {
+		if(canOverflow == null) {
+			canOverflow = true;
+		}
+		if(padStr == null) {
+			padStr = " ";
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(str == null || strLen > targetLength) {
+			return str;
+		}
+		if(padStr == null || padStr.length == 0) {
+			padStr = " ";
+		}
+		let padLen = padStr == null ? 0 : padStr.length;
+		let sb = new hx_strings_StringBuilder(str);
+		while(strLen < targetLength) {
+			sb.add(padStr);
+			strLen += padLen;
+		}
+		if(canOverflow) {
+			return sb.toString();
+		}
+		let str1 = sb.toString();
+		return (str1 == null ? 0 : str1.length) <= targetLength ? str1 : hx_strings_Strings.substring8(str1,0,targetLength);
+	}
+	static split8(str,separator,maxParts) {
+		if(maxParts == null) {
+			maxParts = 0;
+		}
+		if(str == null || separator == null) {
+			return null;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0) {
+			return [];
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = separator;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v != null) {
+				_g.push(v);
+			}
+		}
+		let separators = _g;
+		if(separators.length == 0) {
+			return null;
+		}
+		if(maxParts <= 0 && separators.length == 1) {
+			return str.split(separators[0]);
+		}
+		if(separators.indexOf("") > -1) {
+			if(maxParts <= 0) {
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = strLen;
+				while(_g1 < _g2) {
+					let i = _g1++;
+					_g.push(HxOverrides.substr(str,i,1));
+				}
+				return _g;
+			}
+			if(maxParts > strLen) {
+				maxParts = strLen;
+			}
+			--maxParts;
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = maxParts;
+			while(_g1 < _g2) {
+				let i = _g1++;
+				_g.push(HxOverrides.substr(str,i,1));
+			}
+			let result = _g;
+			result.push(HxOverrides.substr(str,maxParts,strLen - maxParts));
+			return result;
+		}
+		let _g3 = [];
+		let _g4 = 0;
+		while(_g4 < separators.length) {
+			let sep = separators[_g4];
+			++_g4;
+			_g3.push(sep == null ? 0 : sep.length);
+		}
+		let separatorsLengths = _g3;
+		let lastFoundAt = 0;
+		let result = [];
+		let resultCount = 0;
+		while(true) {
+			let separatorLen = 0;
+			let foundAt = -1;
+			let _g = 0;
+			let _g1 = separators.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let sepFoundAt = hx_strings_Strings.indexOf8(str,separators[i],lastFoundAt);
+				if(sepFoundAt != -1) {
+					if(foundAt == -1 || sepFoundAt < foundAt) {
+						foundAt = sepFoundAt;
+						separatorLen = separatorsLengths[i];
+					}
+				}
+			}
+			++resultCount;
+			if(foundAt == -1 || resultCount == maxParts) {
+				result.push(HxOverrides.substr(str,lastFoundAt,strLen - lastFoundAt));
+				break;
+			}
+			result.push(HxOverrides.substr(str,lastFoundAt,foundAt - lastFoundAt));
+			lastFoundAt = foundAt + separatorLen;
+		}
+		return result;
+	}
+	static splitAt(str,splitPos) {
+		if(str == null) {
+			return null;
+		}
+		if(splitPos == null || splitPos.length == 0) {
+			return [str];
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0) {
+			return [str];
+		}
+		let pos = [];
+		let _g = 0;
+		let _g1 = splitPos;
+		while(_g < _g1.length) {
+			let p = _g1[_g];
+			++_g;
+			if(p < 0) {
+				p = strLen + p;
+			}
+			if(p < 0 || p >= strLen) {
+				continue;
+			}
+			if(pos.indexOf(p) > -1) {
+				continue;
+			}
+			pos.push(p);
+		}
+		pos.sort(function(a,b) {
+			if(a < b) {
+				return -1;
+			} else if(a > b) {
+				return 1;
+			} else {
+				return 0;
+			}
+		});
+		let result = [];
+		let lastPos = 0;
+		let _g2 = 0;
+		while(_g2 < pos.length) {
+			let p = pos[_g2];
+			++_g2;
+			let chunk = hx_strings_Strings.substring8(str,lastPos,p);
+			if(chunk != null && chunk.length > 0) {
+				result.push(chunk);
+			}
+			lastPos = p;
+		}
+		let chunk = hx_strings_Strings.substring8(str,lastPos);
+		if(chunk != null && chunk.length > 0) {
+			result.push(chunk);
+		}
+		return result;
+	}
+	static splitEvery(str,count) {
+		if(str == null) {
+			return null;
+		}
+		if(count < 1) {
+			throw haxe_Exception.thrown("[count] must be greater than 0");
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0 || count >= strLen) {
+			return [str];
+		}
+		let result = [];
+		let pos = 0;
+		while(true) {
+			let chunk = hx_strings_Strings.substr8(str,pos,count);
+			pos += count;
+			if(chunk == null || chunk.length == 0) {
+				break;
+			}
+			result.push(chunk);
+		}
+		return result;
+	}
+	static splitLines(str) {
+		if(str == null || str.length == 0) {
+			return [];
+		} else {
+			return hx_strings_Strings.REGEX_SPLIT_LINES.ereg.split(str);
+		}
+	}
+	static startsWith(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		if(searchFor == null || searchFor.length == 0 || searchIn == searchFor) {
+			return true;
+		}
+		return searchIn.startsWith(searchFor);
+	}
+	static startsWithAny(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(candidate != null && hx_strings_Strings.startsWith(searchIn,candidate)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static startsWithAnyIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		searchIn = hx_strings_Strings.toLowerCase8(searchIn);
+		let _g = 0;
+		while(_g < searchFor.length) {
+			let candidate = searchFor[_g];
+			++_g;
+			if(candidate != null && hx_strings_Strings.startsWith(searchIn,hx_strings_Strings.toLowerCase8(candidate))) {
+				return true;
+			}
+		}
+		return false;
+	}
+	static startsWithIgnoreCase(searchIn,searchFor) {
+		if(searchIn == null || searchFor == null) {
+			return false;
+		}
+		if(searchFor == null || searchFor.length == 0) {
+			return true;
+		}
+		return hx_strings_Strings.startsWith(searchIn.toLowerCase(),searchFor.toLowerCase());
+	}
+	static substr8(str,startAt,len) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(len == null) {
+			len = str == null ? 0 : str.length;
+		}
+		if(len <= 0) {
+			return "";
+		}
+		if(startAt < 0) {
+			startAt += str == null ? 0 : str.length;
+			if(startAt < 0) {
+				startAt = 0;
+			}
+		}
+		return HxOverrides.substr(str,startAt,len);
+	}
+	static substring8(str,startAt,endAt) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(endAt == null) {
+			endAt = str == null ? 0 : str.length;
+		}
+		return str.substring(startAt,endAt);
+	}
+	static substringAfter(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return str;
+		}
+		if(str == "" || searchFor == null || searchFor == "") {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAt = str.indexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAt + searchFor.length);
+	}
+	static substringAfterIgnoreCase(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt = str.toLowerCase().indexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAt + searchFor.length);
+	}
+	static substringBetween(str,after,before,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(before == null) {
+			before = after;
+		}
+		if(str == "" || (after == null || after.length == 0) || (before == null || before.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAfterAt = str.indexOf(after);
+		if(foundAfterAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundBeforeAt = str.indexOf(before,foundAfterAt + after.length);
+		if(foundBeforeAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAfterAt + after.length,foundBeforeAt);
+	}
+	static substringBetweenIgnoreCase(str,after,before,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(before == null) {
+			before = after;
+		}
+		if(str == "" || (after == null || after.length == 0) || (before == null || before.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let strLower = hx_strings_Strings.toLowerCase8(str);
+		let after1 = hx_strings_Strings.toLowerCase8(after);
+		let before1 = hx_strings_Strings.toLowerCase8(before);
+		let foundAfterAt = strLower.indexOf(after1);
+		if(foundAfterAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundBeforeAt = strLower.indexOf(before1,foundAfterAt + after1.length);
+		if(foundBeforeAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAfterAt + after1.length,foundBeforeAt);
+	}
+	static substringAfterLast(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAt = str.lastIndexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAt + searchFor.length);
+	}
+	static substringAfterLastIgnoreCase(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt = str.toLowerCase().lastIndexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(foundAt + searchFor.length);
+	}
+	static substringBefore(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAt = str.indexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(0,foundAt);
+	}
+	static substringBeforeIgnoreCase(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt = str.toLowerCase().indexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(0,foundAt);
+	}
+	static substringBeforeLast(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		let foundAt = str.lastIndexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(0,foundAt);
+	}
+	static substringBeforeLastIgnoreCase(str,searchFor,notFoundDefault) {
+		if(notFoundDefault == null) {
+			notFoundDefault = 2;
+		}
+		if(str == null) {
+			return null;
+		}
+		if(str == "" || (searchFor == null || searchFor.length == 0)) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		searchFor = searchFor.toLowerCase();
+		let foundAt = str.toLowerCase().lastIndexOf(searchFor);
+		if(foundAt == -1) {
+			let tmp;
+			switch(notFoundDefault) {
+			case 1:
+				tmp = null;
+				break;
+			case 2:
+				tmp = "";
+				break;
+			case 3:
+				tmp = str;
+				break;
+			}
+			return tmp;
+		}
+		return str.substring(0,foundAt);
+	}
+	static toBool(str) {
+		if(str == null || str.length == 0) {
+			return false;
+		}
+		switch(str.toLowerCase()) {
+		case "0":case "false":case "no":
+			return false;
+		default:
+			return true;
+		}
+	}
+	static toBytes(str) {
+		if(str == null) {
+			return null;
+		}
+		return haxe_io_Bytes.ofString(str);
+	}
+	static toChar(charCode) {
+		return charCode;
+	}
+	static toCharIterator(str) {
+		if(str == null) {
+			return hx_strings__$CharIterator_NullCharIterator.INSTANCE;
+		} else {
+			return new hx_strings__$CharIterator_StringCharIterator(str,0);
+		}
+	}
+	static toChars(str) {
+		if(str == null) {
+			return null;
+		}
+		let strLen = str == null ? 0 : str.length;
+		if(strLen == 0) {
+			return [];
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = strLen;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(HxOverrides.cca(str,i));
+		}
+		return _g;
+	}
+	static toPattern(str,options) {
+		if(str == null) {
+			return null;
+		}
+		return hx_strings_Pattern.compile(str,options);
+	}
+	static toEReg(str,opt) {
+		if(opt == null) {
+			opt = "";
+		}
+		if(str == null) {
+			throw haxe_Exception.thrown("[str] must not be null");
+		}
+		return new EReg(str,opt);
+	}
+	static toFloat(str,ifUnparseable) {
+		if(str == null) {
+			return ifUnparseable;
+		}
+		let result = parseFloat(str);
+		if(isNaN(result)) {
+			return ifUnparseable;
+		} else {
+			return result;
+		}
+	}
+	static toFloatOrNull(str,ifUnparseable) {
+		if(str == null) {
+			return ifUnparseable;
+		}
+		let result = parseFloat(str);
+		if(isNaN(result)) {
+			return ifUnparseable;
+		} else {
+			return result;
+		}
+	}
+	static toHex(num,minDigits,upperCase) {
+		if(upperCase == null) {
+			upperCase = true;
+		}
+		if(minDigits == null) {
+			minDigits = 0;
+		}
+		let hexed = StringTools.hex(num,0);
+		if(!upperCase) {
+			return hexed.toLowerCase();
+		}
+		if(hexed.length >= minDigits) {
+			return hexed;
+		}
+		return hx_strings_Strings.lpad(hexed,minDigits,"0");
+	}
+	static toInt(str,ifUnparseable) {
+		if(str == null) {
+			return ifUnparseable;
+		}
+		let result = Std.parseInt(str);
+		if(result == null) {
+			return ifUnparseable;
+		} else {
+			return result;
+		}
+	}
+	static toIntOrNull(str,ifUnparseable) {
+		if(str == null) {
+			return ifUnparseable;
+		}
+		let result = Std.parseInt(str);
+		if(result == null) {
+			return ifUnparseable;
+		} else {
+			return result;
+		}
+	}
+	static toLowerCase8(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return str.toLowerCase();
+	}
+	static toLowerCaseFirstChar(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let this1 = HxOverrides.cca(str,0);
+		let lowerChar = hx_strings_Char.CHAR_CASE_MAPPER.mapU2L.h[this1];
+		let firstChar = lowerChar == null ? this1 : lowerChar;
+		if(str.length == 1) {
+			return String.fromCodePoint(firstChar);
+		}
+		let other = hx_strings_Strings.substr8(str,1);
+		return String.fromCodePoint(firstChar) + other;
+	}
+	static toLowerCamel(str,keepUppercasedWords) {
+		if(keepUppercasedWords == null) {
+			keepUppercasedWords = true;
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		if(keepUppercasedWords) {
+			let _g = 0;
+			let _g1 = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			while(_g < _g1.length) {
+				let word = _g1[_g];
+				++_g;
+				sb.add(hx_strings_Strings.toUpperCaseFirstChar(word));
+			}
+		} else {
+			let _g = 0;
+			let _g1 = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			while(_g < _g1.length) {
+				let word = _g1[_g];
+				++_g;
+				sb.add(hx_strings_Strings.toUpperCaseFirstChar(hx_strings_Strings.toLowerCase8(word)));
+			}
+		}
+		return hx_strings_Strings.toLowerCaseFirstChar(sb.toString());
+	}
+	static toLowerHyphen(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.toLowerCase8(_this[i]);
+		}
+		return result.join("-");
+	}
+	static toLowerUnderscore(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.toLowerCase8(_this[i]);
+		}
+		return result.join("_");
+	}
+	static toTitle(str,keepUppercasedWords) {
+		if(keepUppercasedWords == null) {
+			keepUppercasedWords = true;
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(keepUppercasedWords) {
+			let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let s = _this[i];
+				result[i] = hx_strings_Strings.toUpperCase8(s) == s ? s : hx_strings_Strings.toUpperCaseFirstChar(hx_strings_Strings.toLowerCase8(s));
+			}
+			return result.join(" ");
+		}
+		let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.toUpperCaseFirstChar(hx_strings_Strings.toLowerCase8(_this[i]));
+		}
+		return result.join(" ");
+	}
+	static toUpperCamel(str,keepUppercasedWords) {
+		if(keepUppercasedWords == null) {
+			keepUppercasedWords = true;
+		}
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		if(keepUppercasedWords) {
+			let _g = 0;
+			let _g1 = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			while(_g < _g1.length) {
+				let word = _g1[_g];
+				++_g;
+				sb.add(hx_strings_Strings.toUpperCaseFirstChar(word));
+			}
+		} else {
+			let _g = 0;
+			let _g1 = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+			while(_g < _g1.length) {
+				let word = _g1[_g];
+				++_g;
+				sb.add(hx_strings_Strings.toUpperCaseFirstChar(hx_strings_Strings.toLowerCase8(word)));
+			}
+		}
+		return sb.toString();
+	}
+	static toUpperUnderscore(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings._splitAsciiWordsUnsafe(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.toUpperCase8(_this[i]);
+		}
+		return result.join("_");
+	}
+	static toString(str) {
+		if(str == null) {
+			return "null";
+		} else {
+			return str;
+		}
+	}
+	static toUpperCase8(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		let _g = 0;
+		let _g1 = str == null ? 0 : str.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let this1 = HxOverrides.cca(str,i);
+			let upperChar = hx_strings_Char.CHAR_CASE_MAPPER.mapL2U.h[this1];
+			sb.addChar(upperChar == null ? this1 : upperChar);
+		}
+		return sb.toString();
+	}
+	static toUpperCaseFirstChar(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let this1 = HxOverrides.cca(str,0);
+		let upperChar = hx_strings_Char.CHAR_CASE_MAPPER.mapL2U.h[this1];
+		let firstChar = upperChar == null ? this1 : upperChar;
+		if(str.length == 1) {
+			return String.fromCodePoint(firstChar);
+		}
+		let other = hx_strings_Strings.substr8(str,1);
+		return String.fromCodePoint(firstChar) + other;
+	}
+	static trim(str,charsToRemove) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(charsToRemove == null) {
+			return StringTools.trim(str);
+		}
+		let removableChars;
+		let _g = charsToRemove;
+		switch(_g._hx_index) {
+		case 0:
+			let str1 = _g.v;
+			removableChars = hx_strings_Strings.toChars(str1);
+			break;
+		case 1:
+			let chars = _g.v;
+			removableChars = chars;
+			break;
+		}
+		return hx_strings_Strings.trimLeft(hx_strings_Strings.trimRight(str,hx_strings_internal__$Either2__$Either2.b(removableChars)),hx_strings_internal__$Either2__$Either2.b(removableChars));
+	}
+	static trimRight(str,charsToRemove) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		if(charsToRemove == null) {
+			return StringTools.rtrim(str);
+		}
+		let removableChars;
+		let _g = charsToRemove;
+		switch(_g._hx_index) {
+		case 0:
+			let str1 = _g.v;
+			removableChars = hx_strings_Strings.toChars(str1);
+			break;
+		case 1:
+			let chars = _g.v;
+			removableChars = chars;
+			break;
+		}
+		if(removableChars.length == 0) {
+			return str;
+		}
+		let len = str == null ? 0 : str.length;
+		let i = len - 1;
+		while(i > -1 && removableChars.indexOf(hx_strings_Strings.charCodeAt8(hx_strings_Strings.charAt8(str,i),0)) > -1) --i;
+		if(i < len - 1) {
+			return hx_strings_Strings.substring8(str,0,i + 1);
+		}
+		return str;
+	}
+	static trimLeft(str,charsToRemove) {
+		if(str == null) {
+			return str;
+		}
+		if(charsToRemove == null) {
+			return StringTools.ltrim(str);
+		}
+		let removableChars;
+		let _g = charsToRemove;
+		switch(_g._hx_index) {
+		case 0:
+			let str1 = _g.v;
+			removableChars = hx_strings_Strings.toChars(str1);
+			break;
+		case 1:
+			let chars = _g.v;
+			removableChars = chars;
+			break;
+		}
+		if(removableChars.length == 0) {
+			return str;
+		}
+		let len = str == null ? 0 : str.length;
+		let i = 0;
+		while(i < len && removableChars.indexOf(hx_strings_Strings.charCodeAt8(hx_strings_Strings.charAt8(str,i),0)) > -1) ++i;
+		if(i > 0) {
+			return hx_strings_Strings.substring8(str,i,len);
+		}
+		return str;
+	}
+	static trimLines(str,charsToRemove) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		let _this = hx_strings_Strings.REGEX_SPLIT_LINES.ereg.split(str);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = hx_strings_Strings.trim(_this[i],charsToRemove);
+		}
+		return result.join("\n");
+	}
+	static trimToNull(str) {
+		if(str == null) {
+			return null;
+		}
+		let trimmed = hx_strings_Strings.trim(str);
+		if(trimmed == null || trimmed.length == 0) {
+			return null;
+		}
+		return trimmed;
+	}
+	static trimToEmpty(str) {
+		let trimmed = hx_strings_Strings.trim(str);
+		if(trimmed == null || trimmed.length == 0) {
+			return "";
+		}
+		return trimmed;
+	}
+	static truncate(str,maxLength) {
+		if((str == null ? 0 : str.length) <= maxLength) {
+			return str;
+		} else {
+			return hx_strings_Strings.substring8(str,0,maxLength);
+		}
+	}
+	static urlDecode(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return decodeURIComponent(str.split("+").join(" "));
+	}
+	static urlEncode(str) {
+		if(str == null || str.length == 0) {
+			return str;
+		}
+		return encodeURIComponent(str);
+	}
+	static wrap(str,maxLineLength,splitLongWords,newLineSeparator) {
+		if(newLineSeparator == null) {
+			newLineSeparator = "\n";
+		}
+		if(splitLongWords == null) {
+			splitLongWords = true;
+		}
+		if((str == null ? 0 : str.length) <= maxLineLength || maxLineLength < 1) {
+			return str;
+		}
+		let sb = new hx_strings_StringBuilder();
+		let wordChars = [];
+		let currLineLength = 0;
+		let _g = 0;
+		let _g1 = hx_strings_Strings.toChars(str);
+		while(_g < _g1.length) {
+			let ch = _g1[_g];
+			++_g;
+			if(ch > 8 && ch < 14 || ch == 32) {
+				if(wordChars.length > 0) {
+					let _g = 0;
+					while(_g < wordChars.length) {
+						let wordCh = wordChars[_g];
+						++_g;
+						if(currLineLength == maxLineLength && splitLongWords) {
+							sb.add(newLineSeparator);
+							currLineLength = 0;
+						}
+						++currLineLength;
+						sb.addChar(wordCh);
+					}
+					wordChars = [];
+				}
+				if(currLineLength >= maxLineLength) {
+					sb.add(newLineSeparator);
+					currLineLength = 0;
+				}
+				sb.addChar(ch);
+				++currLineLength;
+			} else {
+				wordChars.push(ch);
+			}
+		}
+		if(wordChars.length > 0) {
+			let _g = 0;
+			while(_g < wordChars.length) {
+				let wordCh = wordChars[_g];
+				++_g;
+				if(currLineLength == maxLineLength && splitLongWords) {
+					sb.add(newLineSeparator);
+					currLineLength = 0;
+				}
+				++currLineLength;
+				sb.addChar(wordCh);
+			}
+		}
+		return sb.toString();
+	}
+}
+hx_strings_Strings.__name__ = "hx.strings.Strings";
+class hx_strings_RandomStrings {
+	static _genAsciiAlpha() {
+		let chars = [];
+		chars.push(65);
+		chars.push(66);
+		chars.push(67);
+		chars.push(68);
+		chars.push(69);
+		chars.push(70);
+		chars.push(71);
+		chars.push(72);
+		chars.push(73);
+		chars.push(74);
+		chars.push(75);
+		chars.push(76);
+		chars.push(77);
+		chars.push(78);
+		chars.push(79);
+		chars.push(80);
+		chars.push(81);
+		chars.push(82);
+		chars.push(83);
+		chars.push(84);
+		chars.push(85);
+		chars.push(86);
+		chars.push(87);
+		chars.push(88);
+		chars.push(89);
+		chars.push(90);
+		chars.push(97);
+		chars.push(98);
+		chars.push(99);
+		chars.push(100);
+		chars.push(101);
+		chars.push(102);
+		chars.push(103);
+		chars.push(104);
+		chars.push(105);
+		chars.push(106);
+		chars.push(107);
+		chars.push(108);
+		chars.push(109);
+		chars.push(110);
+		chars.push(111);
+		chars.push(112);
+		chars.push(113);
+		chars.push(114);
+		chars.push(115);
+		chars.push(116);
+		chars.push(117);
+		chars.push(118);
+		chars.push(119);
+		chars.push(120);
+		chars.push(121);
+		chars.push(122);
+		return chars;
+	}
+	static randomAsciiAlpha(length) {
+		return hx_strings_RandomStrings.random(length,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA));
+	}
+	static randomAsciiAlphaNumeric(length) {
+		return hx_strings_RandomStrings.random(length,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC));
+	}
+	static randomDigits(length) {
+		return hx_strings_RandomStrings.random(length,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.DIGITS));
+	}
+	static random(length,chars) {
+		if(length == 0) {
+			return "";
+		}
+		if(length < 0) {
+			throw haxe_Exception.thrown("[count] must be positive value");
+		}
+		if(chars == null) {
+			throw haxe_Exception.thrown("[chars] must not be null");
+		}
+		let charsArray;
+		let _g = chars;
+		switch(_g._hx_index) {
+		case 0:
+			let str = _g.v;
+			charsArray = hx_strings_Strings.toChars(str);
+			break;
+		case 1:
+			let chars1 = _g.v;
+			charsArray = chars1;
+			break;
+		}
+		if(charsArray.length == 0) {
+			throw haxe_Exception.thrown("[chars] must not be empty");
+		}
+		let result = new hx_strings_StringBuilder();
+		let _g1 = 0;
+		let _g2 = length;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			result.addChar(charsArray[Math.floor(charsArray.length * Math.random())]);
+		}
+		return result.toString();
+	}
+	static randomSubstring(str,substringLength) {
+		if(substringLength == null) {
+			substringLength = 1;
+		}
+		if(str == null || str.length == 0) {
+			throw haxe_Exception.thrown("[str] must not be null or empty");
+		}
+		if(substringLength < 1) {
+			throw haxe_Exception.thrown("[substringLength] must not be smaller than 1");
+		}
+		let len = str == null ? 0 : str.length;
+		if(substringLength > len) {
+			throw haxe_Exception.thrown("[substringLength] must not be larger than str.length");
+		}
+		if(substringLength == len) {
+			return str;
+		}
+		let startAt = Math.floor((len - substringLength + 1) * Math.random());
+		return hx_strings_Strings.substr8(str,startAt,substringLength);
+	}
+	static randomUUIDv4(separator) {
+		if(separator == null) {
+			separator = "-";
+		}
+		if(separator == null) {
+			throw haxe_Exception.thrown("[separator] must not be null");
+		}
+		let variantByte = Math.floor(Math.random() * 16);
+		variantByte |= 8;
+		variantByte &= -5;
+		return (StringTools.hex(Math.floor(Math.random() * 65536),4) + StringTools.hex(Math.floor(Math.random() * 65536),4) + separator + StringTools.hex(Math.floor(Math.random() * 65536),4) + separator + "4" + StringTools.hex(Math.floor(Math.random() * 4096),3) + separator + StringTools.hex(variantByte) + StringTools.hex(Math.floor(Math.random() * 4096),3) + separator + StringTools.hex(Math.floor(Math.random() * 65536),4) + StringTools.hex(Math.floor(Math.random() * 65536),4) + StringTools.hex(Math.floor(Math.random() * 65536),4)).toLowerCase();
+	}
+}
+hx_strings_RandomStrings.__name__ = "hx.strings.RandomStrings";
+class hx_strings_StringBuilder {
+	constructor(initialContent) {
+		this.len = 0;
+		this.pre = null;
+		this.sb = new StringBuf();
+		if(initialContent != null) {
+			this.add(initialContent);
+		}
+	}
+	get_length() {
+		return this.len;
+	}
+	add(item) {
+		this.sb.b += Std.string(item == null ? "null" : item);
+		this.len += item == null ? 0 : item.length;
+		return this;
+	}
+	addChar(ch) {
+		if(ch > -1 && ch < 128) {
+			this.sb.b += String.fromCodePoint(ch);
+		} else {
+			let _this = this.sb;
+			let x = String.fromCodePoint(ch);
+			_this.b += Std.string(x);
+		}
+		this.len++;
+		return this;
+	}
+	addAll(items) {
+		let _g = 0;
+		while(_g < items.length) {
+			let item = items[_g];
+			++_g;
+			this.sb.b += Std.string(item);
+			this.len += item == null ? 0 : item.length;
+		}
+		return this;
+	}
+	clear() {
+		this.pre = null;
+		this.sb = new StringBuf();
+		this.len = 0;
+		return this;
+	}
+	isEmpty() {
+		return this.len == 0;
+	}
+	newLine() {
+		this.sb.b += "\n";
+		this.len++;
+		return this;
+	}
+	insert(pos,item) {
+		if(pos < 0) {
+			throw haxe_Exception.thrown("[pos] must not be negative");
+		}
+		if(pos > this.len) {
+			throw haxe_Exception.thrown("[pos] must not be greater than this.length");
+		}
+		if(pos == this.len) {
+			this.add(item);
+			return this;
+		}
+		if(pos == 0) {
+			if(this.pre == null) {
+				this.pre = [];
+			}
+			this.pre.unshift(item);
+			this.len += item == null ? 0 : item.length;
+			return this;
+		}
+		let pre_len = 0;
+		if(this.pre != null) {
+			let pre = this.pre;
+			let i = pre.length;
+			let _g = 0;
+			let _g1 = pre.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let str = pre[i];
+				let next_pre_len = pre_len + (str == null ? 0 : str.length);
+				if(next_pre_len == pos) {
+					pre.splice(i + 1,0,item);
+					this.len += item == null ? 0 : item.length;
+					return this;
+				}
+				if(next_pre_len > pos) {
+					let preSplitted = hx_strings_Strings.splitAt(pre[i],[pos - pre_len]);
+					pre[i] = preSplitted[0];
+					pre.splice(i + 1,0,item);
+					pre.splice(i + 2,0,preSplitted[1]);
+					this.len += item == null ? 0 : item.length;
+					return this;
+				}
+				pre_len = next_pre_len;
+			}
+		}
+		if(this.sb.b.length == 0) {
+			this.add(item);
+			return this;
+		}
+		let sbSplitted = hx_strings_Strings.splitAt(this.sb.b,[pos - pre_len]);
+		this.sb = new StringBuf();
+		this.sb.b += Std.string(sbSplitted[0]);
+		this.sb.b += Std.string(item);
+		this.len += item == null ? 0 : item.length;
+		this.sb.b += Std.string(sbSplitted[1]);
+		return this;
+	}
+	insertChar(pos,ch) {
+		if(pos < 0) {
+			throw haxe_Exception.thrown("[pos] must not be negative");
+		}
+		if(pos > this.len) {
+			throw haxe_Exception.thrown("[pos] must not be greater than this.length");
+		}
+		if(pos == this.len) {
+			this.addChar(ch);
+			return this;
+		}
+		if(pos == 0) {
+			if(this.pre == null) {
+				this.pre = [];
+			}
+			this.pre.unshift(String.fromCodePoint(ch));
+			this.len++;
+			return this;
+		}
+		let pre_len = 0;
+		if(this.pre != null) {
+			let pre = this.pre;
+			let i = pre.length;
+			let _g = 0;
+			let _g1 = pre.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let str = pre[i];
+				let next_pre_len = pre_len + (str == null ? 0 : str.length);
+				if(next_pre_len == pos) {
+					let x = String.fromCodePoint(ch);
+					pre.splice(i + 1,0,x);
+					this.len++;
+					return this;
+				}
+				if(next_pre_len > pos) {
+					let preSplitted = hx_strings_Strings.splitAt(pre[i],[pos - pre_len]);
+					pre[i] = preSplitted[0];
+					let x = String.fromCodePoint(ch);
+					pre.splice(i + 1,0,x);
+					pre.splice(i + 2,0,preSplitted[1]);
+					this.len++;
+					return this;
+				}
+				pre_len = next_pre_len;
+			}
+		}
+		if(this.sb.b.length == 0) {
+			this.addChar(ch);
+			return this;
+		}
+		let sbSplitted = hx_strings_Strings.splitAt(this.sb.b,[pos - pre_len]);
+		this.sb = new StringBuf();
+		this.sb.b += Std.string(sbSplitted[0]);
+		this.addChar(ch);
+		this.sb.b += Std.string(sbSplitted[1]);
+		return this;
+	}
+	insertAll(pos,items) {
+		if(pos < 0) {
+			throw haxe_Exception.thrown("[pos] must not be negative");
+		}
+		if(pos > this.len) {
+			throw haxe_Exception.thrown("[pos] must not be greater than this.length");
+		}
+		if(pos == this.len) {
+			this.addAll(items);
+			return this;
+		}
+		if(pos == 0) {
+			if(this.pre == null) {
+				this.pre = [];
+			}
+			let pre = this.pre;
+			let i = items.length;
+			while(i-- > 0) {
+				let item = items[i];
+				pre.unshift(item);
+				this.len += item == null ? 0 : item.length;
+			}
+			return this;
+		}
+		let pre_len = 0;
+		if(this.pre != null) {
+			let pre = this.pre;
+			let i = pre.length;
+			let _g = 0;
+			let _g1 = pre.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let str = pre[i];
+				let next_pre_len = pre_len + (str == null ? 0 : str.length);
+				if(next_pre_len == pos) {
+					let j = items.length;
+					while(j-- > 0) {
+						let item = items[j];
+						pre.splice(i + 1,0,item);
+						this.len += item == null ? 0 : item.length;
+					}
+					return this;
+				}
+				if(next_pre_len > pos) {
+					let preSplitted = hx_strings_Strings.splitAt(pre[i],[pos - pre_len]);
+					pre[i] = preSplitted[0];
+					pre.splice(i + 1,0,preSplitted[1]);
+					let j = items.length;
+					while(j-- > 0) {
+						let item = items[j];
+						pre.splice(i + 1,0,item);
+						this.len += item == null ? 0 : item.length;
+					}
+					return this;
+				}
+				pre_len = next_pre_len;
+			}
+		}
+		if(this.sb.b.length == 0) {
+			let _g = 0;
+			while(_g < items.length) {
+				let item = items[_g];
+				++_g;
+				this.add(item);
+			}
+			return this;
+		}
+		let sbSplitted = hx_strings_Strings.splitAt(this.sb.b,[pos - pre_len]);
+		this.sb = new StringBuf();
+		this.sb.b += Std.string(sbSplitted[0]);
+		let _g = 0;
+		while(_g < items.length) {
+			let item = items[_g];
+			++_g;
+			this.sb.b += Std.string(item);
+			this.len += item == null ? 0 : item.length;
+		}
+		this.sb.b += Std.string(sbSplitted[1]);
+		return this;
+	}
+	asOutput() {
+		return new hx_strings__$StringBuilder_OutputWrapper(this);
+	}
+	toString() {
+		if(this.pre == null) {
+			return this.sb.b;
+		}
+		let str = this.pre.join("") + this.sb.b;
+		this.clear();
+		this.add(str);
+		return str;
+	}
+}
+hx_strings_StringBuilder.__name__ = "hx.strings.StringBuilder";
+Object.assign(hx_strings_StringBuilder.prototype, {
+	__class__: hx_strings_StringBuilder
+});
+class hx_strings__$StringBuilder_OutputWrapper extends haxe_io_Output {
+	constructor(sb) {
+		super();
+		this.sb = sb;
+	}
+	flush() {
+		if(this.bo != null && this.bo.b.pos > 0) {
+			this.sb.add(this.bo.getBytes().toString());
+		}
+	}
+	writeByte(c) {
+		if(this.bo == null) {
+			this.bo = new haxe_io_BytesOutput();
+		}
+		this.bo.writeByte(c);
+	}
+	writeString(str,encoding) {
+		this.flush();
+		this.sb.add(str);
+	}
+}
+hx_strings__$StringBuilder_OutputWrapper.__name__ = "hx.strings._StringBuilder.OutputWrapper";
+hx_strings__$StringBuilder_OutputWrapper.__super__ = haxe_io_Output;
+Object.assign(hx_strings__$StringBuilder_OutputWrapper.prototype, {
+	__class__: hx_strings__$StringBuilder_OutputWrapper
+});
+class hx_strings_StringDiff {
+	constructor() {
+		this.at = -1;
+	}
+	toString() {
+		return "StringDiff[at=" + this.at + ", left=" + this.left + ", right=" + this.right + "]";
+	}
+}
+hx_strings_StringDiff.__name__ = "hx.strings.StringDiff";
+Object.assign(hx_strings_StringDiff.prototype, {
+	__class__: hx_strings_StringDiff
+});
+var hx_strings_HashCodeAlgorithm = $hxEnums["hx.strings.HashCodeAlgorithm"] = { __ename__:true,__constructs__:null
+	,PLATFORM_SPECIFIC: {_hx_name:"PLATFORM_SPECIFIC",_hx_index:0,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,ADLER32: {_hx_name:"ADLER32",_hx_index:1,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,CRC32B: {_hx_name:"CRC32B",_hx_index:2,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,DJB2A: {_hx_name:"DJB2A",_hx_index:3,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,JAVA: {_hx_name:"JAVA",_hx_index:4,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+	,SDBM: {_hx_name:"SDBM",_hx_index:5,__enum__:"hx.strings.HashCodeAlgorithm",toString:$estr}
+};
+hx_strings_HashCodeAlgorithm.__constructs__ = [hx_strings_HashCodeAlgorithm.PLATFORM_SPECIFIC,hx_strings_HashCodeAlgorithm.ADLER32,hx_strings_HashCodeAlgorithm.CRC32B,hx_strings_HashCodeAlgorithm.DJB2A,hx_strings_HashCodeAlgorithm.JAVA,hx_strings_HashCodeAlgorithm.SDBM];
+var hx_strings_AnsiToHtmlRenderMethod = $hxEnums["hx.strings.AnsiToHtmlRenderMethod"] = { __ename__:true,__constructs__:null
+	,StyleAttributes: {_hx_name:"StyleAttributes",_hx_index:0,__enum__:"hx.strings.AnsiToHtmlRenderMethod",toString:$estr}
+	,CssClasses: {_hx_name:"CssClasses",_hx_index:1,__enum__:"hx.strings.AnsiToHtmlRenderMethod",toString:$estr}
+	,CssClassesCallback: ($_=function(func) { return {_hx_index:2,func:func,__enum__:"hx.strings.AnsiToHtmlRenderMethod",toString:$estr}; },$_._hx_name="CssClassesCallback",$_.__params__ = ["func"],$_)
+};
+hx_strings_AnsiToHtmlRenderMethod.__constructs__ = [hx_strings_AnsiToHtmlRenderMethod.StyleAttributes,hx_strings_AnsiToHtmlRenderMethod.CssClasses,hx_strings_AnsiToHtmlRenderMethod.CssClassesCallback];
+class hx_strings_AnsiState {
+	constructor(copyFrom) {
+		this.underline = false;
+		this.bold = false;
+		this.blink = false;
+		if(copyFrom == null) {
+			this.reset();
+		} else {
+			this.copyFrom(copyFrom);
+		}
+	}
+	isActive() {
+		if(!(this.fgcolor != null || this.bgcolor != null || this.bold || this.underline)) {
+			return this.blink;
+		} else {
+			return true;
+		}
+	}
+	reset() {
+		this.fgcolor = null;
+		this.bgcolor = null;
+		this.bold = false;
+		this.underline = false;
+		this.blink = false;
+	}
+	copyFrom(other) {
+		this.fgcolor = other.fgcolor;
+		this.bgcolor = other.bgcolor;
+		this.bold = other.bold;
+		this.underline = other.underline;
+		this.blink = other.blink;
+	}
+	setGraphicModeParameter(param) {
+		switch(param) {
+		case 0:
+			this.reset();
+			break;
+		case 1:
+			this.bold = true;
+			break;
+		case 4:
+			this.underline = true;
+			break;
+		case 5:
+			this.blink = true;
+			break;
+		case 30:
+			this.fgcolor = "black";
+			break;
+		case 31:
+			this.fgcolor = "red";
+			break;
+		case 32:
+			this.fgcolor = "green";
+			break;
+		case 33:
+			this.fgcolor = "yellow";
+			break;
+		case 34:
+			this.fgcolor = "blue";
+			break;
+		case 35:
+			this.fgcolor = "magenta";
+			break;
+		case 36:
+			this.fgcolor = "cyan";
+			break;
+		case 37:
+			this.fgcolor = "white";
+			break;
+		case 40:
+			this.bgcolor = "black";
+			break;
+		case 41:
+			this.bgcolor = "red";
+			break;
+		case 42:
+			this.bgcolor = "green";
+			break;
+		case 43:
+			this.bgcolor = "yellow";
+			break;
+		case 44:
+			this.bgcolor = "blue";
+			break;
+		case 45:
+			this.bgcolor = "magenta";
+			break;
+		case 46:
+			this.bgcolor = "cyan";
+			break;
+		case 47:
+			this.bgcolor = "white";
+			break;
+		}
+	}
+	toCSS(renderMethod) {
+		if(this.fgcolor != null || this.bgcolor != null || this.bold || this.underline || this.blink) {
+			let sb = new hx_strings_StringBuilder();
+			if(renderMethod == null) {
+				renderMethod = hx_strings_AnsiToHtmlRenderMethod.StyleAttributes;
+			}
+			switch(renderMethod._hx_index) {
+			case 0:
+				if(this.fgcolor != null) {
+					sb.add("color:").add(this.fgcolor).add(";");
+				}
+				if(this.bgcolor != null) {
+					sb.add("background-color:").add(this.bgcolor).add(";");
+				}
+				if(this.bold) {
+					sb.add("font-weight:bold;");
+				}
+				if(this.underline) {
+					sb.add("text-decoration:underline;");
+				}
+				if(this.blink) {
+					sb.add("text-decoration:blink;");
+				}
+				break;
+			case 1:
+				sb.add(hx_strings_AnsiState.defaultCssClassesCallback(this));
+				break;
+			case 2:
+				let func = renderMethod.func;
+				sb.add(func(this));
+				break;
+			}
+			return sb.toString();
+		}
+		return "";
+	}
+	static defaultCssClassesCallback(state) {
+		let classes = [];
+		if(state.fgcolor != null) {
+			classes.push("ansi_fg_" + state.fgcolor);
+		}
+		if(state.bgcolor != null) {
+			classes.push("ansi_bg_" + state.bgcolor);
+		}
+		if(state.bold) {
+			classes.push("ansi_bold");
+		}
+		if(state.underline) {
+			classes.push("ansi_underline");
+		}
+		if(state.blink) {
+			classes.push("ansi_blink");
+		}
+		return classes.join(" ");
+	}
+}
+hx_strings_AnsiState.__name__ = "hx.strings.AnsiState";
+Object.assign(hx_strings_AnsiState.prototype, {
+	__class__: hx_strings_AnsiState
+});
+class hx_strings_internal_Bits {
+	static clearBit(num,bitPos) {
+		return num & ~(1 << bitPos - 1);
+	}
+	static setBit(num,bitPos) {
+		return num | 1 << bitPos - 1;
+	}
+	static toggleBit(num,bitPos) {
+		return num ^ 1 << bitPos - 1;
+	}
+	static getBit(num,bitPos) {
+		return 1 == (num >> bitPos - 1 & 1);
+	}
+}
+hx_strings_internal_Bits.__name__ = "hx.strings.internal.Bits";
+class hx_strings_internal_Either2 {
+	static _new(value) {
+		return value;
+	}
+	static get_value(this1) {
+		return this1;
+	}
+	static fromA(value) {
+		return hx_strings_internal__$Either2__$Either2.a(value);
+	}
+	static fromB(value) {
+		return hx_strings_internal__$Either2__$Either2.b(value);
+	}
+}
+var hx_strings_internal__$Either2__$Either2 = $hxEnums["hx.strings.internal._Either2._Either2"] = { __ename__:true,__constructs__:null
+	,a: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"hx.strings.internal._Either2._Either2",toString:$estr}; },$_._hx_name="a",$_.__params__ = ["v"],$_)
+	,b: ($_=function(v) { return {_hx_index:1,v:v,__enum__:"hx.strings.internal._Either2._Either2",toString:$estr}; },$_._hx_name="b",$_.__params__ = ["v"],$_)
+};
+hx_strings_internal__$Either2__$Either2.__constructs__ = [hx_strings_internal__$Either2__$Either2.a,hx_strings_internal__$Either2__$Either2.b];
+class hx_strings_internal_Either3 {
+	static _new(value) {
+		return value;
+	}
+	static get_value(this1) {
+		return this1;
+	}
+	static fromA(value) {
+		return hx_strings_internal__$Either3__$Either3.a(value);
+	}
+	static fromB(value) {
+		return hx_strings_internal__$Either3__$Either3.b(value);
+	}
+	static fromC(value) {
+		return hx_strings_internal__$Either3__$Either3.c(value);
+	}
+}
+class hx_strings_internal_OneOrMany {
+	static fromSingle(value) {
+		return [value];
+	}
+}
+class hx_strings_internal_RingBuffer {
+	static _new(size) {
+		return new hx_strings_internal__$RingBuffer_RingBufferImpl(size);
+	}
+	static get(this1,index) {
+		return this1.get(index);
+	}
+}
+class hx_strings_internal__$RingBuffer_RingBufferIterator {
+	constructor(buff) {
+		this.idx = -1;
+		this.buff = buff;
+	}
+	hasNext() {
+		return this.idx + 1 < this.buff.length;
+	}
+	next() {
+		this.idx++;
+		return this.buff.get(this.idx);
+	}
+}
+hx_strings_internal__$RingBuffer_RingBufferIterator.__name__ = "hx.strings.internal._RingBuffer.RingBufferIterator";
+Object.assign(hx_strings_internal__$RingBuffer_RingBufferIterator.prototype, {
+	__class__: hx_strings_internal__$RingBuffer_RingBufferIterator
+});
+class js_lib_HaxeIterator {
+	constructor(jsIterator) {
+		this.jsIterator = jsIterator;
+		this.lastStep = jsIterator.next();
+	}
+	hasNext() {
+		return !this.lastStep.done;
+	}
+	next() {
+		let v = this.lastStep.value;
+		this.lastStep = this.jsIterator.next();
+		return v;
+	}
+}
+js_lib_HaxeIterator.__name__ = "js.lib.HaxeIterator";
+Object.assign(js_lib_HaxeIterator.prototype, {
+	__class__: js_lib_HaxeIterator
+});
+var js_node_ChildProcess = require("child_process");
+var js_node_Fs = require("fs");
+var js_node_Http = require("http");
+var js_node_Https = require("https");
+class js_node_KeyValue {
+	static get_key(this1) {
+		return this1[0];
+	}
+	static get_value(this1) {
+		return this1[1];
+	}
+}
+var js_node_buffer_Buffer = require("buffer").Buffer;
+class js_node_buffer__$Buffer_Helper {
+	static bytesOfBuffer(b) {
+		let o = Object.create(haxe_io_Bytes.prototype);
+		o.length = b.byteLength;
+		o.b = b;
+		b.bufferValue = b;
+		b.hxBytes = o;
+		b.bytes = b;
+		return o;
+	}
+}
+js_node_buffer__$Buffer_Helper.__name__ = "js.node.buffer._Buffer.Helper";
+var js_node_stream_PassThrough = require("stream").PassThrough;
+class js_node_stream_WritableNewOptionsAdapter {
+	static from(options) {
+		if(!Object.prototype.hasOwnProperty.call(options,"final")) {
+			Object.defineProperty(options,"final",{ get : function() {
+				return options.final_;
+			}});
+		}
+		return options;
+	}
+}
+var js_node_url_URL = require("url").URL;
+class js_node_url_URLSearchParamsEntry {
+	static _new(name,value) {
+		return [name,value];
+	}
+	static get_name(this1) {
+		return this1[0];
+	}
+	static get_value(this1) {
+		return this1[1];
+	}
+}
+class sha_Hash {
+	constructor(blockSize,finalSize) {
+		if(sha_Hash._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(blockSize,finalSize);
+	}
+	_hx_constructor(blockSize,finalSize) {
+		this.finalSize = finalSize;
+		this.block = new haxe_io_Bytes(new ArrayBuffer(blockSize));
+		this.length = 0;
+	}
+	min(a,b) {
+		if(a < b) {
+			return a;
+		}
+		return b;
+	}
+	writeInt(b,i,pos) {
+		b.b[pos] = i >> 24;
+		b.b[pos + 1] = i >> 16 & 255;
+		b.b[pos + 2] = i >> 8 & 255;
+		b.b[pos + 3] = i & 255;
+	}
+	update(data) {
+		let accum = this.length;
+		let offset = 0;
+		while(offset < data.length) {
+			let assigned = accum % this.block.length;
+			let a = data.length - offset;
+			let b = this.block.length - assigned;
+			let remainder = a < b ? a : b;
+			let _g = 0;
+			let _g1 = remainder;
+			while(_g < _g1) {
+				let i = _g++;
+				this.block.b[assigned + i] = data.b[offset + i];
+			}
+			accum += remainder;
+			offset += remainder;
+			if(accum % this.block.length == 0) {
+				this._update(this.block);
+			}
+		}
+		this.length += data.length;
+		return this;
+	}
+	digest() {
+		let rem = this.length % this.block.length;
+		this.block.b[rem] = 128;
+		this.block.fill(rem + 1,this.block.length - (rem + 1),0);
+		if(rem >= this.finalSize) {
+			this._update(this.block);
+			this.block.fill(0,this.block.length,0);
+		}
+		let bits = this.length * 8;
+		if(bits <= -1) {
+			let b = this.block;
+			let pos = this.block.length - 4;
+			b.b[pos] = bits >> 24;
+			b.b[pos + 1] = bits >> 16 & 255;
+			b.b[pos + 2] = bits >> 8 & 255;
+			b.b[pos + 3] = bits & 255;
+		} else {
+			let lowBits = (bits & -1) >>> 0;
+			let highBits = (bits - lowBits) / 4294967296 | 0;
+			let b = this.block;
+			let pos = this.block.length - 8;
+			b.b[pos] = highBits >> 24;
+			b.b[pos + 1] = highBits >> 16 & 255;
+			b.b[pos + 2] = highBits >> 8 & 255;
+			b.b[pos + 3] = highBits & 255;
+			let b1 = this.block;
+			let pos1 = this.block.length - 4;
+			b1.b[pos1] = lowBits >> 24;
+			b1.b[pos1 + 1] = lowBits >> 16 & 255;
+			b1.b[pos1 + 2] = lowBits >> 8 & 255;
+			b1.b[pos1 + 3] = lowBits & 255;
+		}
+		this._update(this.block);
+		return this._hash();
+	}
+}
+sha_Hash.__name__ = "sha.Hash";
+Object.assign(sha_Hash.prototype, {
+	__class__: sha_Hash
+});
+class sha_SHA256 extends sha_Hash {
+	constructor() {
+		sha_Hash._hx_skip_constructor = true;
+		super();
+		sha_Hash._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this._w = [];
+		this._h = 1541459225;
+		this._g = 528734635;
+		this._f = -1694144372;
+		this._e = 1359893119;
+		this._d = -1521486534;
+		this._c = 1013904242;
+		this._b = -1150833019;
+		this._a = 1779033703;
+		super._hx_constructor(64,56);
+	}
+	sigma0(x) {
+		return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10);
+	}
+	sigma1(x) {
+		return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7);
+	}
+	gamma0(x) {
+		return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ x >>> 3;
+	}
+	gamma1(x) {
+		return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ x >>> 10;
+	}
+	ch(x,y,z) {
+		return z ^ x & (y ^ z);
+	}
+	maj(x,y,z) {
+		return x & y | z & (x | y);
+	}
+	_update(data) {
+		let W = this._w;
+		let a = this._a | 0;
+		let b = this._b | 0;
+		let c = this._c | 0;
+		let d = this._d | 0;
+		let e = this._e | 0;
+		let f = this._f | 0;
+		let g = this._g | 0;
+		let h = this._h | 0;
+		let _g = 0;
+		while(_g < 16) {
+			let i = _g++;
+			W[i] = data.b[i * 4] << 24 | data.b[i * 4 + 1] << 16 | data.b[i * 4 + 2] << 8 | data.b[i * 4 + 3];
+		}
+		let _g1 = 16;
+		while(_g1 < 64) {
+			let i = _g1++;
+			W[i] = this.gamma1(W[i - 2]) + W[i - 7] + this.gamma0(W[i - 15]) + W[i - 16] | 0;
+		}
+		let _g2 = 0;
+		while(_g2 < 64) {
+			let j = _g2++;
+			let T1 = h + this.sigma1(e) + this.ch(e,f,g) + sha_SHA256_K[j] + W[j] | 0;
+			let T2 = this.sigma0(a) + this.maj(a,b,c) | 0;
+			h = g;
+			g = f;
+			f = e;
+			e = d + T1 | 0;
+			d = c;
+			c = b;
+			b = a;
+			a = T1 + T2 | 0;
+		}
+		this._a = a + this._a | 0;
+		this._b = b + this._b | 0;
+		this._c = c + this._c | 0;
+		this._d = d + this._d | 0;
+		this._e = e + this._e | 0;
+		this._f = f + this._f | 0;
+		this._g = g + this._g | 0;
+		this._h = h + this._h | 0;
+	}
+	_hash() {
+		let b = new haxe_io_Bytes(new ArrayBuffer(32));
+		let i = this._a;
+		b.b[0] = i >> 24;
+		b.b[1] = i >> 16 & 255;
+		b.b[2] = i >> 8 & 255;
+		b.b[3] = i & 255;
+		let i1 = this._b;
+		b.b[4] = i1 >> 24;
+		b.b[5] = i1 >> 16 & 255;
+		b.b[6] = i1 >> 8 & 255;
+		b.b[7] = i1 & 255;
+		let i2 = this._c;
+		b.b[8] = i2 >> 24;
+		b.b[9] = i2 >> 16 & 255;
+		b.b[10] = i2 >> 8 & 255;
+		b.b[11] = i2 & 255;
+		let i3 = this._d;
+		b.b[12] = i3 >> 24;
+		b.b[13] = i3 >> 16 & 255;
+		b.b[14] = i3 >> 8 & 255;
+		b.b[15] = i3 & 255;
+		let i4 = this._e;
+		b.b[16] = i4 >> 24;
+		b.b[17] = i4 >> 16 & 255;
+		b.b[18] = i4 >> 8 & 255;
+		b.b[19] = i4 & 255;
+		let i5 = this._f;
+		b.b[20] = i5 >> 24;
+		b.b[21] = i5 >> 16 & 255;
+		b.b[22] = i5 >> 8 & 255;
+		b.b[23] = i5 & 255;
+		let i6 = this._g;
+		b.b[24] = i6 >> 24;
+		b.b[25] = i6 >> 16 & 255;
+		b.b[26] = i6 >> 8 & 255;
+		b.b[27] = i6 & 255;
+		let i7 = this._h;
+		b.b[28] = i7 >> 24;
+		b.b[29] = i7 >> 16 & 255;
+		b.b[30] = i7 >> 8 & 255;
+		b.b[31] = i7 & 255;
+		return b;
+	}
+}
+sha_SHA256.__name__ = "sha.SHA256";
+sha_SHA256.__super__ = sha_Hash;
+Object.assign(sha_SHA256.prototype, {
+	__class__: sha_SHA256
+});
+class snikket_AttachmentSource {
+	static tinkSource(this1) {
+		let options = null;
+		let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+		return new tink_io_js_BlobSource(this1.name,this1,0,chunkSize);
+	}
+}
+class snikket_Autolink {
+	static one(s,start) {
+		let matches = [snikket_Autolink.match(s,start,snikket_Autolink.XMPP_URI,false),snikket_Autolink.match(s,start,snikket_Autolink.TEL_URI,false),snikket_Autolink.match(s,start,snikket_Autolink.SMS_URI,false),snikket_Autolink.match(s,start,snikket_Autolink.AUTOLINK_WEB_URL,true)];
+		matches.sort(function(x,y) {
+			return x.start - y.start;
+		});
+		let tmp = Lambda.find(matches,function(match) {
+			return match.span != null;
+		});
+		if(tmp != null) {
+			return tmp;
+		} else {
+			return matches[0];
+		}
+	}
+	static match(s,start,pattern,addHttps) {
+		let pattern1 = new EReg(pattern,"u");
+		if(pattern1.matchSub(s,start)) {
+			let pos = pattern1.matchedPos();
+			let link = pattern1.matched(0);
+			let uri = !addHttps || link.includes("://") ? link : "https://" + link;
+			return { span : snikket_Node.Element(new snikket_Stanza("a",{ href : uri}).text(link)), start : pos.pos, end : pos.pos + pos.len};
+		} else {
+			return { span : null, start : s.length, end : s.length};
+		}
+	}
+}
+snikket_Autolink.__name__ = "snikket.Autolink";
+class snikket_Caps {
+	constructor(node,identities,features) {
+		this._ver = null;
+		this.node = node;
+		this.identities = identities;
+		this.features = features;
+	}
+	isChannel(chatId) {
+		if(chatId.indexOf("@") < 0) {
+			return false;
+		}
+		if(this.features.includes("http://jabber.org/protocol/muc")) {
+			return Lambda.find(this.identities,function(identity) {
+				return identity.category == "conference";
+			}) != null;
+		} else {
+			return false;
+		}
+	}
+	discoReply() {
+		let query = new snikket_Stanza("query",{ xmlns : "http://jabber.org/protocol/disco#info"});
+		let _g = 0;
+		let _g1 = this.identities;
+		while(_g < _g1.length) {
+			let identity = _g1[_g];
+			++_g;
+			identity.addToDisco(query);
+		}
+		let _g2 = 0;
+		let _g3 = this.features;
+		while(_g2 < _g3.length) {
+			let feature = _g3[_g2];
+			++_g2;
+			query.tag("feature",{ "var" : feature}).up();
+		}
+		return query;
+	}
+	addC(stanza) {
+		stanza.tag("c",{ xmlns : "http://jabber.org/protocol/caps", hash : "sha-1", node : this.node, ver : this.ver()}).up();
+		return stanza;
+	}
+	computeVer() {
+		this.features.sort(function(x,y) {
+			if(x == y) {
+				return 0;
+			} else if(x < y) {
+				return -1;
+			} else {
+				return 1;
+			}
+		});
+		this.identities.sort(function(x,y) {
+			if(x.ver() == y.ver()) {
+				return 0;
+			} else if(x.ver() < y.ver()) {
+				return -1;
+			} else {
+				return 1;
+			}
+		});
+		let s = "";
+		let _g = 0;
+		let _g1 = this.identities;
+		while(_g < _g1.length) {
+			let identity = _g1[_g];
+			++_g;
+			s += identity.ver() + "<";
+		}
+		let _g2 = 0;
+		let _g3 = this.features;
+		while(_g2 < _g3.length) {
+			let feature = _g3[_g2];
+			++_g2;
+			s += feature + "<";
+		}
+		return snikket_Hash.sha1(haxe_io_Bytes.ofString(s));
+	}
+	verRaw() {
+		if(this._ver == null) {
+			this._ver = this.computeVer();
+		}
+		return this._ver;
+	}
+	ver() {
+		return this.verRaw().toBase64();
+	}
+	static withIdentity(caps,category,type) {
+		let result = [];
+		let cap = caps;
+		while(cap.hasNext()) {
+			let cap1 = cap.next();
+			if(cap1.value != null) {
+				let _g = 0;
+				let _g1 = cap1.value.identities;
+				while(_g < _g1.length) {
+					let identity = _g1[_g];
+					++_g;
+					if((category == null || category == identity.category) && (type == null || type == identity.type)) {
+						result.push(cap1.key);
+					}
+				}
+			}
+		}
+		return result;
+	}
+	static withFeature(caps,feature) {
+		let result = [];
+		let cap = caps;
+		while(cap.hasNext()) {
+			let cap1 = cap.next();
+			if(cap1.value != null) {
+				let _g = 0;
+				let _g1 = cap1.value.features;
+				while(_g < _g1.length) {
+					let feat = _g1[_g];
+					++_g;
+					if(feature == feat) {
+						result.push(cap1.key);
+					}
+				}
+			}
+		}
+		return result;
+	}
+}
+$hx_exports["snikket"]["Caps"] = snikket_Caps;
+snikket_Caps.__name__ = "snikket.Caps";
+Object.assign(snikket_Caps.prototype, {
+	__class__: snikket_Caps
+});
+class snikket_Identity {
+	constructor(category,type,name) {
+		this.category = category;
+		this.type = type;
+		this.name = name;
+	}
+	addToDisco(stanza) {
+		stanza.tag("identity",{ category : this.category, type : this.type, name : this.name}).up();
+	}
+	ver() {
+		return this.category + "/" + this.type + "//" + this.name;
+	}
+}
+$hx_exports["snikket"]["Identity"] = snikket_Identity;
+snikket_Identity.__name__ = "snikket.Identity";
+Object.assign(snikket_Identity.prototype, {
+	__class__: snikket_Identity
+});
+class snikket_Chat {
+	constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy) {
+		if(snikket_Chat._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy);
+	}
+	_hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy) {
+		if(isBlocked == null) {
+			isBlocked = false;
+		}
+		if(uiState == null) {
+			uiState = 1;
+		}
+		this.activeThread = null;
+		this.isActive = null;
+		this.typingTimer = null;
+		this.typingThread = null;
+		this.isTyping = false;
+		this._unreadCount = 0;
+		this.isBlocked = false;
+		this.uiState = 1;
+		this.jingleSessions = new Map([]);
+		this.trusted = false;
+		this.presence = new Map([]);
+		this.avatarSha1 = null;
+		this.client = client;
+		this.stream = stream;
+		this.persistence = persistence;
+		this.chatId = chatId;
+		this.uiState = uiState;
+		this.isBlocked = isBlocked;
+		let tmp = extensions;
+		this.extensions = tmp != null ? tmp : new snikket_Stanza("extensions",{ xmlns : "urn:xmpp:bookmarks:1"});
+		this.readUpToId = readUpToId;
+		this.readUpToBy = readUpToBy;
+		this.displayName = chatId;
+	}
+	fetchFromSync(sync,callback) {
+		let _gthis = this;
+		sync.onMessages(function(messageList) {
+			let chatMessages = [];
+			let _g = 0;
+			let _g1 = messageList.messages;
+			while(_g < _g1.length) {
+				let m = _g1[_g];
+				++_g;
+				switch(m._hx_index) {
+				case 1:
+					let message = m.message;
+					chatMessages.push(message);
+					break;
+				case 2:
+					let action = m.action;
+					_gthis.client.moderateMessage(action);
+					break;
+				case 3:
+					let update = m.update;
+					_gthis.persistence.storeReaction(_gthis.client.accountId(),update,function(m) {
+					});
+					break;
+				default:
+				}
+			}
+			_gthis.client.storeMessages(chatMessages,function(chatMessages) {
+				let callback1 = callback;
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = chatMessages;
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(v != null && v.chatId() == _gthis.chatId) {
+						_g.push(v);
+					}
+				}
+				callback1(_g);
+			});
+		});
+		sync.fetchNext();
+	}
+	addReaction(m,reaction) {
+		let toSend = m.reply();
+		toSend.localId = snikket_ID.long();
+		reaction.render(function(text) {
+			toSend.text = StringTools.replace(text,"️","");
+		},function(text,uri) {
+			let hash = snikket_Hash.fromUri(uri);
+			toSend.setHtml("<img alt=\"" + snikket_Util_xmlEscape(text) + "\" src=\"" + snikket_Util_xmlEscape(hash == null ? uri : hash.bobUri()) + "\" />");
+		});
+		this.sendMessage(toSend);
+	}
+	typing(threadId,content) {
+		if(threadId != this.typingThread && this.isTyping) {
+			this.sendChatState("paused",this.typingThread);
+			this.isTyping = false;
+		}
+		this.typingThread = threadId;
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		let _gthis = this;
+		if(content == "") {
+			this.isTyping = false;
+			this.sendChatState("active",this.typingThread);
+			if(this.isActive == null) {
+				this.typingTimer = haxe_Timer.delay(function() {
+					_gthis.sendChatState("inactive",_gthis.typingThread);
+				},30000);
+			}
+			return;
+		}
+		this.typingTimer = haxe_Timer.delay(function() {
+			_gthis.sendChatState("paused",_gthis.typingThread);
+			_gthis.isTyping = false;
+		},10000);
+		if(this.isTyping) {
+			return;
+		}
+		this.isTyping = true;
+		this.sendChatState("composing",this.typingThread);
+	}
+	setActive(active,threadId) {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.isTyping = false;
+		if(this.isActive && active && threadId != this.activeThread) {
+			this.sendChatState("inactive",this.activeThread);
+			this.isActive = false;
+		}
+		if(this.isActive != null) {
+			if(this.isActive && active) {
+				return;
+			}
+			if(!this.isActive && !active) {
+				return;
+			}
+		}
+		this.isActive = active;
+		this.activeThread = threadId;
+		this.sendChatState(active ? "active" : "inactive",this.activeThread);
+	}
+	togglePinned() {
+		this.uiState = this.uiState == 0 ? 1 : 0;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		this.client.sortChats();
+		this.client.trigger("chats/update",[this]);
+	}
+	block(reportSpam,onServer) {
+		if(reportSpam != null && !onServer) {
+			throw haxe_Exception.thrown("Can't report SPAM if not sending to server");
+		}
+		this.isBlocked = true;
+		if(this.uiState == 2) {
+			this.persistence.storeChats(this.client.accountId(),[this]);
+		} else {
+			this.close();
+		}
+		if(onServer) {
+			let iq = new snikket_Stanza("iq",{ type : "set", id : snikket_ID.short()}).tag("block",{ xmlns : "urn:xmpp:blocking"}).tag("item",{ jid : this.chatId});
+			if(reportSpam != null) {
+				iq.tag("report",{ xmlns : "urn:xmpp:reporting:1", reason : "urn:xmpp:reporting:spam"}).tag("stanza-id",{ xmlns : "urn:xmpp:sid:0", by : reportSpam.serverIdBy, id : reportSpam.serverId});
+			}
+			this.stream.sendIq(iq,function(response) {
+			});
+		}
+	}
+	unblock(onServer) {
+		this.isBlocked = false;
+		this.uiState = 1;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		this.client.trigger("chats/update",[this]);
+		if(onServer) {
+			this.stream.sendIq(new snikket_Stanza("iq",{ type : "set", id : snikket_ID.short()}).tag("unblock",{ xmlns : "urn:xmpp:blocking"}).tag("item",{ jid : this.chatId}).up().up(),function(response) {
+			});
+		}
+	}
+	lastMessageTimestamp() {
+		let tmp = this.lastMessage;
+		if(tmp != null) {
+			return tmp.timestamp;
+		} else {
+			return null;
+		}
+	}
+	updateFromBookmark(item) {
+		let conf = item.getChild("conference","urn:xmpp:bookmarks:1");
+		let fn = conf.attr["name"];
+		if(fn != null) {
+			this.displayName = fn;
+		}
+		this.uiState = conf.attr["autojoin"] == "1" || conf.attr["autojoin"] == "true" ? this.uiState == 0 ? 0 : 1 : 2;
+		let tmp = conf.getChild("extensions");
+		this.extensions = tmp != null ? tmp : new snikket_Stanza("extensions",{ xmlns : "urn:xmpp:bookmarks:1"});
+	}
+	updateFromRoster(item) {
+		this.setTrusted(item.subscription == "both" || item.subscription == "from");
+		if(item.fn != null && item.fn != "") {
+			this.displayName = item.fn;
+		}
+	}
+	getPhoto() {
+		if(this.avatarSha1 == null || haxe_io_Bytes.ofData(this.avatarSha1).length < 1) {
+			return null;
+		}
+		return new snikket_Hash("sha-1",this.avatarSha1).toUri();
+	}
+	getPlaceholder() {
+		return snikket_Color.defaultPhoto(this.chatId,this.getDisplayName().charAt(0).toUpperCase());
+	}
+	readUpTo() {
+		return this.readUpToId;
+	}
+	unreadCount() {
+		return this._unreadCount;
+	}
+	setUnreadCount(count) {
+		this._unreadCount = count;
+	}
+	preview() {
+		if(this.lastMessage == null) {
+			return "";
+		}
+		if(this.lastMessage.type == 1) {
+			if(this.lastMessage.isIncoming()) {
+				return "Incoming Call";
+			} else {
+				return "Outgoing Call";
+			}
+		} else {
+			return this.lastMessage.text;
+		}
+	}
+	setLastMessage(message) {
+		this.lastMessage = message;
+	}
+	setDisplayName(fn) {
+		this.displayName = fn;
+		this.bookmark();
+	}
+	getDisplayName() {
+		return this.displayName;
+	}
+	setPresence(resource,presence) {
+		this.presence.set(resource,presence);
+	}
+	setCaps(resource,caps) {
+		let presence = this.presence.get(resource);
+		if(presence != null) {
+			presence.caps = caps;
+			this.setPresence(resource,presence);
+		} else {
+			this.setPresence(resource,new snikket_Presence(caps,null));
+		}
+	}
+	removePresence(resource) {
+		this.presence.delete(resource);
+	}
+	getCaps() {
+		let iter = new snikket_HaxeKVIterator(this.presence.entries());
+		return { hasNext : $bind(iter,iter.hasNext), next : function() {
+			let n = iter.next();
+			return { key : n.key, value : n.value.caps};
+		}};
+	}
+	getResourceCaps(resource) {
+		let tmp = this.presence.get(resource);
+		let tmp1 = tmp != null ? tmp.caps : null;
+		if(tmp1 != null) {
+			return tmp1;
+		} else {
+			return new snikket_Caps("",[],[]);
+		}
+	}
+	setAvatarSha1(sha1) {
+		this.avatarSha1 = sha1;
+	}
+	setTrusted(trusted) {
+		this.trusted = trusted;
+	}
+	isTrusted() {
+		return this.trusted;
+	}
+	livePresence() {
+		return true;
+	}
+	syncing() {
+		return !this.client.inSync;
+	}
+	canAudioCall() {
+		let jsIterator = this.presence.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let resource = _g_key;
+			let p = _g_value;
+			let tmp = p.caps;
+			let tmp1 = tmp != null ? tmp.features : null;
+			let tmp2 = tmp1 != null ? tmp1.includes("urn:xmpp:jingle:apps:rtp:audio") : null;
+			if(tmp2 != null && tmp2) {
+				return true;
+			}
+		}
+		return false;
+	}
+	canVideoCall() {
+		let jsIterator = this.presence.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let resource = _g_key;
+			let p = _g_value;
+			let tmp = p.caps;
+			let tmp1 = tmp != null ? tmp.features : null;
+			let tmp2 = tmp1 != null ? tmp1.includes("urn:xmpp:jingle:apps:rtp:video") : null;
+			if(tmp2 != null && tmp2) {
+				return true;
+			}
+		}
+		return false;
+	}
+	startCall(audio,video) {
+		let session = new snikket_jingle_OutgoingProposedSession(this.client,snikket_JID.parse(this.chatId));
+		this.jingleSessions.set(session.get_sid(),session);
+		session.propose(audio,video);
+	}
+	addMedia(streams) {
+		if(this.callStatus() != "ongoing") {
+			throw haxe_Exception.thrown("cannot add media when no call ongoing");
+		}
+		let jsIterator = this.jingleSessions.values();
+		let inlHaxeIterator_jsIterator = jsIterator;
+		let inlHaxeIterator_lastStep = jsIterator.next();
+		let v = inlHaxeIterator_lastStep.value;
+		inlHaxeIterator_lastStep = inlHaxeIterator_jsIterator.next();
+		v.addMedia(streams);
+	}
+	acceptCall() {
+		let jsIterator = this.jingleSessions.values();
+		let session_jsIterator = jsIterator;
+		let session_lastStep = jsIterator.next();
+		while(!session_lastStep.done) {
+			let v = session_lastStep.value;
+			session_lastStep = session_jsIterator.next();
+			let session = v;
+			session.accept();
+		}
+	}
+	hangup() {
+		let jsIterator = this.jingleSessions.values();
+		let session_jsIterator = jsIterator;
+		let session_lastStep = jsIterator.next();
+		while(!session_lastStep.done) {
+			let v = session_lastStep.value;
+			session_lastStep = session_jsIterator.next();
+			let session = v;
+			session.hangup();
+			this.jingleSessions.delete(session.get_sid());
+		}
+	}
+	callStatus() {
+		let jsIterator = this.jingleSessions.values();
+		let session_jsIterator = jsIterator;
+		let session_lastStep = jsIterator.next();
+		while(!session_lastStep.done) {
+			let v = session_lastStep.value;
+			session_lastStep = session_jsIterator.next();
+			let session = v;
+			return session.callStatus();
+		}
+		return "none";
+	}
+	dtmf() {
+		let jsIterator = this.jingleSessions.values();
+		let session_jsIterator = jsIterator;
+		let session_lastStep = jsIterator.next();
+		while(!session_lastStep.done) {
+			let v = session_lastStep.value;
+			session_lastStep = session_jsIterator.next();
+			let session = v;
+			let dtmf = session.dtmf();
+			if(dtmf != null) {
+				return dtmf;
+			}
+		}
+		return null;
+	}
+	videoTracks() {
+		let this1 = this.jingleSessions;
+		let _g = [];
+		let x = $getIterator({ iterator : function() {
+			return new js_lib_HaxeIterator(this1.values());
+		}});
+		while(x.hasNext()) {
+			let x1 = x.next();
+			_g.push(x1.videoTracks());
+		}
+		let _g1 = [];
+		let e = $getIterator(_g);
+		while(e.hasNext()) {
+			let e1 = e.next();
+			let x = $getIterator(e1);
+			while(x.hasNext()) {
+				let x1 = x.next();
+				_g1.push(x1);
+			}
+		}
+		return _g1;
+	}
+	markReadUpToId(upTo,upToBy,callback) {
+		if(upTo == null) {
+			return;
+		}
+		if(this.readUpTo() == upTo) {
+			return;
+		}
+		this.readUpToId = upTo;
+		this.readUpToBy = upToBy;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		let _gthis = this;
+		this.persistence.getMessagesBefore(this.client.accountId(),this.chatId,null,null,function(messages) {
+			let i = messages.length;
+			while(--i >= 0) if(messages[i].serverId == _gthis.readUpToId || !messages[i].isIncoming()) {
+				break;
+			}
+			_gthis.setUnreadCount(messages.length - (i + 1));
+			if(callback != null) {
+				callback();
+			}
+		});
+	}
+	markReadUpToMessage(message,callback) {
+		if(message.serverId == null || message.chatId() != this.chatId) {
+			return;
+		}
+		if(this.readUpTo() == message.serverId) {
+			return;
+		}
+		let _gthis = this;
+		this.persistence.getMessage(this.client.accountId(),this.chatId,this.readUpTo(),null,function(readMessage) {
+			if(readMessage != null && Reflect.compare(message.timestamp,readMessage.timestamp) <= 0) {
+				return;
+			}
+			_gthis.markReadUpToId(message.serverId,message.serverIdBy,callback);
+		});
+	}
+	publishMds() {
+		let _gthis = this;
+		this.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub"}).tag("publish",{ node : "urn:xmpp:mds:displayed:0"}).tag("item",{ id : this.chatId}).tag("displayed",{ xmlns : "urn:xmpp:mds:displayed:0"}).tag("stanza-id",{ xmlns : "urn:xmpp:sid:0", id : this.readUpTo(), by : this.readUpToBy}).up().up().up().tag("publish-options").tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value","http://jabber.org/protocol/pubsub#publish-options").up().tag("field",{ "var" : "pubsub#persist_items"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#max_items"}).textTag("value","max").up().tag("field",{ "var" : "pubsub#send_last_published_item"}).textTag("value","never").up().tag("field",{ "var" : "pubsub#access_model"}).textTag("value","whitelist").up().up().up(),function(response) {
+			if(response.attr["type"] == "error") {
+				let tmp = response.getChild("error");
+				let preconditionError = tmp != null ? tmp.getChild("precondition-not-met","http://jabber.org/protocol/pubsub#errors") : null;
+				if(preconditionError != null) {
+					_gthis.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub#owner"}).tag("configure",{ node : "urn:xmpp:mds:displayed:0"}).tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value","http://jabber.org/protocol/pubsub#publish-options").up().tag("field",{ "var" : "pubsub#persist_items"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#max_items"}).textTag("value","max").up().tag("field",{ "var" : "pubsub#send_last_published_item"}).textTag("value","never").up().tag("field",{ "var" : "pubsub#access_model"}).textTag("value","whitelist").up().up().up().up(),function(response) {
+						if(response.attr["type"] == "result") {
+							_gthis.publishMds();
+						}
+					});
+				}
+			}
+		});
+	}
+}
+snikket_Chat.__name__ = "snikket.Chat";
+Object.assign(snikket_Chat.prototype, {
+	__class__: snikket_Chat
+});
+class snikket_DirectChat extends snikket_Chat {
+	constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy) {
+		if(isBlocked == null) {
+			isBlocked = false;
+		}
+		if(uiState == null) {
+			uiState = 1;
+		}
+		super(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy);
+	}
+	getParticipants() {
+		return this.chatId.split("\n");
+	}
+	getParticipantDetails(participantId) {
+		let chat = this.client.getDirectChat(participantId);
+		return new snikket_Participant(chat.getDisplayName(),chat.getPhoto(),chat.getPlaceholder(),chat.chatId == this.client.accountId());
+	}
+	getMessagesBefore(beforeId,beforeTime,handler) {
+		let _gthis = this;
+		this.persistence.getMessagesBefore(this.client.accountId(),this.chatId,beforeId,beforeTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				let filter = { 'with' : _gthis.chatId};
+				if(beforeId != null) {
+					filter.page = { before : beforeId};
+				}
+				let sync = new snikket_MessageSync(_gthis.client,_gthis.stream,filter);
+				_gthis.fetchFromSync(sync,handler);
+			}
+		});
+	}
+	getMessagesAfter(afterId,afterTime,handler) {
+		if(afterId == this.lastMessageId() && !this.syncing()) {
+			handler([]);
+			return;
+		}
+		let _gthis = this;
+		this.persistence.getMessagesAfter(this.client.accountId(),this.chatId,afterId,afterTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				let filter = { 'with' : _gthis.chatId};
+				if(afterId != null) {
+					filter.page = { after : afterId};
+				}
+				let sync = new snikket_MessageSync(_gthis.client,_gthis.stream,filter);
+				_gthis.fetchFromSync(sync,handler);
+			}
+		});
+	}
+	getMessagesAround(aroundId,aroundTime,handler) {
+		this.persistence.getMessagesAround(this.client.accountId(),this.chatId,aroundId,aroundTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				handler([]);
+			}
+		});
+	}
+	prepareIncomingMessage(message,stanza) {
+		message.syncPoint = !this.syncing();
+		return message;
+	}
+	prepareOutgoingMessage(message) {
+		let tmp = message.timestamp;
+		message.timestamp = tmp != null ? tmp : snikket_Date.format(new Date());
+		message.direction = 1;
+		message.from = this.client.jid;
+		message.sender = message.from.asBare();
+		message.replyTo = [message.sender];
+		let _this = this.getParticipants();
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = snikket_JID.parse(_this[i]);
+		}
+		message.recipients = result;
+		return message;
+	}
+	correctMessage(localId,message) {
+		let toSendId = message.localId;
+		message = this.prepareOutgoingMessage(message);
+		let tmp = message.build();
+		message.versions = [tmp];
+		message.localId = localId;
+		let _gthis = this;
+		this.client.storeMessages([message.build()],function(corrected) {
+			let tmp = corrected[0].versions[corrected[0].versions.length - 1];
+			let tmp1 = (tmp != null ? tmp.localId : null) == localId ? corrected[0].versions : [message.build()];
+			message.versions = tmp1;
+			message.localId = toSendId;
+			let _g = 0;
+			let _g1 = message.recipients;
+			while(_g < _g1.length) {
+				let recipient = _g1[_g];
+				++_g;
+				message.to = recipient;
+				_gthis.client.sendStanza(message.build().asStanza());
+			}
+			let tmp2 = _gthis.lastMessage;
+			if(localId == (tmp2 != null ? tmp2.localId : null)) {
+				_gthis.setLastMessage(corrected[0]);
+				_gthis.client.trigger("chats/update",[_gthis]);
+			}
+			_gthis.client.notifyMessageHandlers(corrected[0],1);
+		});
+	}
+	sendMessage(message) {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.client.chatActivity(this);
+		message = this.prepareOutgoingMessage(message);
+		message.to = message.recipients[0];
+		let fromStanza = snikket_Message.fromStanza(message.build().asStanza(),this.client.jid).parsed;
+		let _gthis = this;
+		switch(fromStanza._hx_index) {
+		case 1:
+			let _g = fromStanza.message;
+			this.client.storeMessages([message.build()],function(stored) {
+				let _g = 0;
+				let _g1 = message.recipients;
+				while(_g < _g1.length) {
+					let recipient = _g1[_g];
+					++_g;
+					message.to = recipient;
+					let stanza = message.build().asStanza();
+					if(_gthis.isActive != null) {
+						_gthis.isActive = true;
+						_gthis.activeThread = message.threadId;
+						stanza.tag("active",{ xmlns : "http://jabber.org/protocol/chatstates"}).up();
+					}
+					_gthis.client.sendStanza(stanza);
+				}
+				_gthis.setLastMessage(message.build());
+				_gthis.client.trigger("chats/update",[_gthis]);
+				_gthis.client.notifyMessageHandlers(stored[0],stored[0].versions.length > 1 ? 1 : 0);
+			});
+			break;
+		case 3:
+			let update = fromStanza.update;
+			this.persistence.storeReaction(this.client.accountId(),update,function(stored) {
+				let _g = 0;
+				let _g1 = message.recipients;
+				while(_g < _g1.length) {
+					let recipient = _g1[_g];
+					++_g;
+					message.to = recipient;
+					_gthis.client.sendStanza(message.build().asStanza());
+				}
+				if(stored != null) {
+					_gthis.client.notifyMessageHandlers(stored,2);
+				}
+			});
+			break;
+		default:
+			haxe_Log.trace("Invalid message",{ fileName : "snikket/Chat.hx", lineNumber : 797, className : "snikket.DirectChat", methodName : "sendMessage", customParams : [fromStanza]});
+			throw haxe_Exception.thrown("Trying to send invalid message.");
+		}
+	}
+	removeReaction(m,reaction) {
+		if(((reaction) instanceof snikket_CustomEmojiReaction)) {
+			if(reaction.envelopeId == null) {
+				throw haxe_Exception.thrown("Cannot remove custom emoji reaction without envelopeId");
+			}
+			let correct = m.reply();
+			correct.localId = snikket_ID.long();
+			correct.setHtml("");
+			correct.text = null;
+			this.correctMessage(reaction.envelopeId,correct);
+			return;
+		}
+		let reactions = [];
+		let _gthis = this;
+		let jsIterator = m.reactions.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let areaction = _g_key;
+			let reacts = _g_value;
+			if(areaction != reaction.key) {
+				let react = Lambda.find(reacts,function(r) {
+					return r.senderId == _gthis.client.accountId();
+				});
+				if(react != null && !((react) instanceof snikket_CustomEmojiReaction)) {
+					reactions.push(react);
+				}
+			}
+		}
+		let update = new snikket_ReactionUpdate(snikket_ID.long(),null,null,m.localId,m.chatId(),this.client.accountId(),snikket_Date.format(new Date()),reactions,0);
+		this.persistence.storeReaction(this.client.accountId(),update,function(stored) {
+			let stanza = update.asStanza();
+			let _g = 0;
+			let _g1 = _gthis.getParticipants();
+			while(_g < _g1.length) {
+				let recipient = _g1[_g];
+				++_g;
+				stanza.attr["to"] = recipient;
+				_gthis.client.sendStanza(stanza);
+			}
+			if(stored != null) {
+				_gthis.client.notifyMessageHandlers(stored,2);
+			}
+		});
+	}
+	lastMessageId() {
+		let tmp = this.lastMessage;
+		let tmp1 = tmp != null ? tmp.localId : null;
+		if(tmp1 != null) {
+			return tmp1;
+		} else {
+			let tmp = this.lastMessage;
+			if(tmp != null) {
+				return tmp.serverId;
+			} else {
+				return null;
+			}
+		}
+	}
+	markReadUpTo(message) {
+		let _gthis = this;
+		this.markReadUpToMessage(message,function() {
+			if(message.isIncoming() && message.localId != null) {
+				let _g = 0;
+				let _g1 = _gthis.getParticipants();
+				while(_g < _g1.length) {
+					let recipient = _g1[_g];
+					++_g;
+					let stanza = new snikket_Stanza("message",{ to : recipient, id : snikket_ID.long()}).tag("displayed",{ xmlns : "urn:xmpp:chat-markers:0", id : message.localId}).up();
+					if(message.threadId != null) {
+						stanza.textTag("thread",message.threadId);
+					}
+					_gthis.client.sendStanza(stanza);
+				}
+			}
+			_gthis.publishMds();
+			_gthis.client.trigger("chats/update",[_gthis]);
+		});
+	}
+	bookmark() {
+		let attr = { jid : this.chatId};
+		if(this.displayName != null && this.displayName != "" && this.displayName != this.chatId) {
+			attr["name"] = this.displayName;
+		}
+		let _gthis = this;
+		this.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("query",{ xmlns : "jabber:iq:roster"}).tag("item",attr).up().up(),function(response) {
+			if(response.attr["type"] == "error") {
+				return;
+			}
+			_gthis.stream.sendStanza(new snikket_Stanza("presence",{ to : _gthis.chatId, type : "subscribe", id : snikket_ID.short()}));
+			if(_gthis.isTrusted()) {
+				_gthis.stream.sendStanza(new snikket_Stanza("presence",{ to : _gthis.chatId, type : "subscribed", id : snikket_ID.short()}));
+			}
+		});
+	}
+	sendChatState(state,threadId) {
+		let _g = 0;
+		let _g1 = this.getParticipants();
+		while(_g < _g1.length) {
+			let recipient = _g1[_g];
+			++_g;
+			let stanza = new snikket_Stanza("message",{ id : snikket_ID.long(), type : "chat", from : this.client.jid.asString(), to : recipient}).tag(state,{ xmlns : "http://jabber.org/protocol/chatstates"}).up();
+			if(threadId != null) {
+				stanza.textTag("thread",threadId);
+			}
+			this.stream.sendStanza(stanza);
+		}
+	}
+	close() {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.uiState = 2;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		if(!this.isBlocked) {
+			this.sendChatState("gone",null);
+		}
+		this.client.trigger("chats/update",[this]);
+	}
+}
+$hx_exports["snikket"]["DirectChat"] = snikket_DirectChat;
+snikket_DirectChat.__name__ = "snikket.DirectChat";
+snikket_DirectChat.__super__ = snikket_Chat;
+Object.assign(snikket_DirectChat.prototype, {
+	__class__: snikket_DirectChat
+});
+class snikket_Channel extends snikket_Chat {
+	constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy,disco) {
+		snikket_Chat._hx_skip_constructor = true;
+		super();
+		snikket_Chat._hx_skip_constructor = false;
+		this._hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy,disco);
+	}
+	_hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy,disco) {
+		if(isBlocked == null) {
+			isBlocked = false;
+		}
+		if(uiState == null) {
+			uiState = 1;
+		}
+		this._nickInUse = null;
+		this.forceLive = false;
+		this.sync = null;
+		this.inSync = true;
+		this.disco = new snikket_Caps("",[],["http://jabber.org/protocol/muc"]);
+		super._hx_constructor(client,stream,persistence,chatId,uiState,isBlocked,extensions,readUpToId,readUpToBy);
+		if(disco != null) {
+			this.disco = disco;
+			if(!disco.features.includes("http://jabber.org/protocol/muc")) {
+				this.forceLive = true;
+			}
+		}
+	}
+	selfPing(refresh) {
+		if(this.uiState == 2) {
+			this.client.sendPresence(this.getFullJid().asString(),function(stanza) {
+				stanza.attr["type"] = "unavailable";
+				return stanza;
+			});
+			return;
+		}
+		let _gthis = this;
+		(refresh ? $bind(this,this.refreshDisco) : function(cb) {
+			cb();
+		})(function() {
+			if(!_gthis.disco.features.includes("http://jabber.org/protocol/muc")) {
+				_gthis.forceLive = true;
+				return;
+			}
+			_gthis.stream.sendIq(new snikket_Stanza("iq",{ type : "get", to : _gthis.getFullJid().asString()}).tag("ping",{ xmlns : "urn:xmpp:ping"}).up(),function(response) {
+				if(response.attr["type"] == "error") {
+					let tmp = response.getChild("error");
+					let err = tmp != null ? tmp.getChild(null,"urn:ietf:params:xml:ns:xmpp-stanzas") : null;
+					if(err.name == "service-unavailable" || err.name == "feature-not-implemented") {
+						_gthis.selfPingSuccess();
+						return;
+					}
+					if(err.name == "remote-server-not-found" || err.name == "remote-server-timeout") {
+						_gthis.selfPingSuccess();
+						return;
+					}
+					if(err.name == "item-not-found") {
+						_gthis.selfPingSuccess();
+						return;
+					}
+					_gthis.presence = new Map([]);
+					_gthis._nickInUse = null;
+					_gthis.inSync = false;
+					_gthis.client.trigger("chats/update",[_gthis]);
+					let desiredFullJid = snikket_JID.parse(_gthis.chatId).withResource(_gthis.client.displayName());
+					_gthis.client.sendPresence(desiredFullJid.asString(),function(stanza) {
+						stanza.tag("x",{ xmlns : "http://jabber.org/protocol/muc"});
+						if(_gthis.disco.features.includes("urn:xmpp:mam:2")) {
+							stanza.tag("history",{ maxchars : "0"}).up();
+						}
+						stanza.up();
+						return stanza;
+					});
+				} else {
+					_gthis.selfPingSuccess();
+				}
+			});
+		});
+	}
+	selfPingSuccess() {
+		if(this.nickInUse() != this.client.displayName()) {
+			let desiredFullJid = snikket_JID.parse(this.chatId).withResource(this.client.displayName());
+			this.client.sendPresence(desiredFullJid.asString());
+		}
+		this.inSync = false;
+		this.persistence.lastId(this.client.accountId(),this.chatId,$bind(this,this.doSync));
+	}
+	setPresence(resource,presence) {
+		let tmp = presence != null ? presence.mucUser : null;
+		let oneTen = tmp != null ? Lambda.find(tmp.allTags("status"),function(status) {
+			return status.attr["code"] == "110";
+		}) : null;
+		if(oneTen != null) {
+			this._nickInUse = resource;
+		} else if(resource == this._nickInUse) {
+			this._nickInUse = null;
+		}
+		if(presence != null && presence.mucUser != null && oneTen == null) {
+			let existing = this.presence.get(resource);
+			let tmp;
+			if(existing != null) {
+				let tmp1 = existing != null ? existing.mucUser : null;
+				tmp = (tmp1 != null ? Lambda.find(tmp1.allTags("status"),function(status) {
+					return status.attr["code"] == "110";
+				}) : null) != null;
+			} else {
+				tmp = false;
+			}
+			if(tmp) {
+				presence.mucUser.tag("status",{ code : "110"});
+				this.setPresence(resource,presence);
+				return;
+			}
+		}
+		super.setPresence(resource,presence);
+		let tmp1 = presence != null ? presence.mucUser : null;
+		let tripleThree = tmp1 != null ? Lambda.find(tmp1.allTags("status"),function(status) {
+			return status.attr["code"] == "333";
+		}) : null;
+		if(!this.inSync && this.sync == null && oneTen != null) {
+			this.persistence.lastId(this.client.accountId(),this.chatId,$bind(this,this.doSync));
+		}
+		if(oneTen != null && tripleThree != null) {
+			this.selfPing(true);
+		}
+	}
+	doSync(lastId) {
+		if(!this.disco.features.includes("urn:xmpp:mam:2")) {
+			this.inSync = true;
+			return;
+		}
+		if(this.sync != null) {
+			return;
+		}
+		let threeDaysAgo = snikket_Date.format(new Date(new Date().getTime() + (-259200000.)));
+		this.sync = new snikket_MessageSync(this.client,this.stream,lastId == null ? { startTime : threeDaysAgo} : { page : { after : lastId}},this.chatId);
+		this.sync.setNewestPageFirst(false);
+		let _gthis = this;
+		this.sync.addContext(function(builder,stanza) {
+			builder = _gthis.prepareIncomingMessage(builder,stanza);
+			builder.syncPoint = true;
+			return builder;
+		});
+		let chatMessages = [];
+		this.sync.onMessages(function(messageList) {
+			let promises = [];
+			let pageChatMessages = [];
+			let _g = 0;
+			let _g1 = messageList.messages;
+			while(_g < _g1.length) {
+				let m = _g1[_g];
+				++_g;
+				switch(m._hx_index) {
+				case 1:
+					let message = m.message;
+					let _g2 = 0;
+					let _g3 = message.inlineHashReferences();
+					while(_g2 < _g3.length) {
+						let hash = _g3[_g2];
+						++_g2;
+						_gthis.client.fetchMediaByHash([hash],[message.from]);
+					}
+					pageChatMessages.push(message);
+					break;
+				case 2:
+					let action = m.action;
+					promises.push(thenshim_Promise._new(function(resolve,reject) {
+						_gthis.client.moderateMessage(action).then(function(_) {
+							resolve(null);
+						});
+					}));
+					break;
+				case 3:
+					let update = m.update;
+					promises.push(thenshim_Promise._new(function(resolve,reject) {
+						_gthis.persistence.storeReaction(_gthis.client.accountId(),update,function(_) {
+							resolve(null);
+						});
+					}));
+					break;
+				default:
+				}
+			}
+			promises.push(thenshim_Promise._new(function(resolve,reject) {
+				_gthis.client.storeMessages(pageChatMessages,resolve);
+			}));
+			thenshim_Promise.then(thenshim_PromiseTools.all(promises),function(stored) {
+				let _g = 0;
+				while(_g < stored.length) {
+					let messages = stored[_g];
+					++_g;
+					if(messages != null) {
+						let _g = 0;
+						while(_g < messages.length) {
+							let message = messages[_g];
+							++_g;
+							_gthis.client.notifySyncMessageHandlers(message);
+							if(message != null && message.chatId() == _gthis.chatId) {
+								chatMessages.push(message);
+							}
+							if(chatMessages.length > 1000) {
+								chatMessages.shift();
+							}
+						}
+					}
+				}
+				if(_gthis.sync.hasMore()) {
+					_gthis.sync.fetchNext();
+				} else {
+					_gthis.inSync = true;
+					_gthis.sync = null;
+					let lastFromSync = chatMessages[chatMessages.length - 1];
+					if(lastFromSync != null && (_gthis.lastMessageTimestamp() == null || Reflect.compare(lastFromSync.timestamp,_gthis.lastMessageTimestamp()) > 0)) {
+						_gthis.setLastMessage(lastFromSync);
+						_gthis.client.sortChats();
+					}
+					let serverIds = new Map([]);
+					let dedupedMessages = [];
+					chatMessages.reverse();
+					let _g = 0;
+					while(_g < chatMessages.length) {
+						let m = chatMessages[_g];
+						++_g;
+						let tmp = serverIds.get(m.serverId);
+						if(!(tmp != null && tmp)) {
+							dedupedMessages.unshift(m);
+							serverIds.set(m.serverId,true);
+						}
+					}
+					let readIndex = Lambda.findIndex(dedupedMessages,function(m) {
+						if(m.serverId != _gthis.readUpTo()) {
+							return !m.isIncoming();
+						} else {
+							return true;
+						}
+					});
+					if(readIndex < 0) {
+						_gthis.setUnreadCount(_gthis.unreadCount() + dedupedMessages.length);
+					} else {
+						_gthis.setUnreadCount(dedupedMessages.length - readIndex - 1);
+					}
+					_gthis.client.trigger("chats/update",[_gthis]);
+				}
+			});
+		});
+		this.sync.onError(function(stanza) {
+			_gthis.sync = null;
+			if(lastId != null) {
+				_gthis.doSync(null);
+			} else {
+				haxe_Log.trace("SYNC failed",{ fileName : "snikket/Chat.hx", lineNumber : 1114, className : "snikket.Channel", methodName : "doSync", customParams : [_gthis.chatId,stanza]});
+			}
+		});
+		this.sync.fetchNext();
+	}
+	isTrusted() {
+		return this.uiState != 2;
+	}
+	refreshDisco(callback) {
+		let discoGet = new snikket_queries_DiscoInfoGet(this.chatId);
+		let _gthis = this;
+		discoGet.onFinished(function() {
+			if(discoGet.getResult() != null) {
+				_gthis.disco = discoGet.getResult();
+				_gthis.persistence.storeCaps(discoGet.getResult());
+				_gthis.persistence.storeChats(_gthis.client.accountId(),[_gthis]);
+			}
+			if(callback != null) {
+				callback();
+			}
+		});
+		this.client.sendQuery(discoGet);
+	}
+	preview() {
+		if(this.lastMessage == null) {
+			return super.preview();
+		}
+		return this.getParticipantDetails(this.lastMessage.senderId).displayName + ": " + super.preview();
+	}
+	livePresence() {
+		if(this.forceLive) {
+			return true;
+		}
+		return this._nickInUse != null;
+	}
+	syncing() {
+		if(this.inSync) {
+			return !this.livePresence();
+		} else {
+			return true;
+		}
+	}
+	canAudioCall() {
+		let tmp = this.disco;
+		let tmp1 = tmp != null ? tmp.features : null;
+		let tmp2 = tmp1 != null ? tmp1.includes("urn:xmpp:jingle:apps:rtp:audio") : null;
+		if(tmp2 != null) {
+			return tmp2;
+		} else {
+			return false;
+		}
+	}
+	canVideoCall() {
+		let tmp = this.disco;
+		let tmp1 = tmp != null ? tmp.features : null;
+		let tmp2 = tmp1 != null ? tmp1.includes("urn:xmpp:jingle:apps:rtp:video") : null;
+		if(tmp2 != null) {
+			return tmp2;
+		} else {
+			return false;
+		}
+	}
+	nickInUse() {
+		let tmp = this._nickInUse;
+		if(tmp != null) {
+			return tmp;
+		} else {
+			return this.client.displayName();
+		}
+	}
+	getFullJid() {
+		return snikket_JID.parse(this.chatId).withResource(this.nickInUse());
+	}
+	getParticipants() {
+		let jid = snikket_JID.parse(this.chatId);
+		let _gthis = this;
+		let _g = [];
+		let inlobj_iterator = function() {
+			return new js_lib_HaxeIterator(_gthis.presence.keys());
+		};
+		let x = inlobj_iterator();
+		while(x.hasNext()) {
+			let x1 = x.next();
+			_g.push(new snikket_JID(jid.node,jid.domain,x1).asString());
+		}
+		return _g;
+	}
+	getParticipantDetails(participantId) {
+		if(participantId == this.getFullJid().asString()) {
+			let chat = this.client.getDirectChat(this.client.accountId(),false);
+			return new snikket_Participant(this.client.displayName(),chat.getPhoto(),chat.getPlaceholder(),true);
+		} else {
+			let nick = snikket_JID.parse(participantId).resource;
+			let placeholderUri = snikket_Color.defaultPhoto(participantId,nick == null ? " " : nick.charAt(0));
+			return new snikket_Participant(nick,null,placeholderUri,false);
+		}
+	}
+	getMessagesBefore(beforeId,beforeTime,handler) {
+		let _gthis = this;
+		this.persistence.getMessagesBefore(this.client.accountId(),this.chatId,beforeId,beforeTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				let filter = { };
+				if(beforeId != null) {
+					filter.page = { before : beforeId};
+				}
+				let sync = new snikket_MessageSync(_gthis.client,_gthis.stream,filter,_gthis.chatId);
+				sync.addContext(function(builder,stanza) {
+					builder = _gthis.prepareIncomingMessage(builder,stanza);
+					builder.syncPoint = false;
+					return builder;
+				});
+				_gthis.fetchFromSync(sync,handler);
+			}
+		});
+	}
+	getMessagesAfter(afterId,afterTime,handler) {
+		if(afterId == this.lastMessageId() && !this.syncing()) {
+			handler([]);
+			return;
+		}
+		let _gthis = this;
+		this.persistence.getMessagesAfter(this.client.accountId(),this.chatId,afterId,afterTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				let filter = { };
+				if(afterId != null) {
+					filter.page = { after : afterId};
+				}
+				let sync = new snikket_MessageSync(_gthis.client,_gthis.stream,filter,_gthis.chatId);
+				sync.addContext(function(builder,stanza) {
+					builder = _gthis.prepareIncomingMessage(builder,stanza);
+					builder.syncPoint = false;
+					return builder;
+				});
+				_gthis.fetchFromSync(sync,handler);
+			}
+		});
+	}
+	getMessagesAround(aroundId,aroundTime,handler) {
+		this.persistence.getMessagesAround(this.client.accountId(),this.chatId,aroundId,aroundTime,function(messages) {
+			if(messages.length > 0) {
+				handler(messages);
+			} else {
+				handler([]);
+			}
+		});
+	}
+	prepareIncomingMessage(message,stanza) {
+		message.syncPoint = !this.syncing();
+		if(message.type == 0) {
+			message.type = 3;
+		}
+		message.sender = snikket_JID.parse(stanza.attr["from"]);
+		if(message.get_senderId() == this.getFullJid().asString()) {
+			message.recipients = message.replyTo;
+			message.direction = 1;
+		}
+		return message;
+	}
+	prepareOutgoingMessage(message) {
+		message.type = 2;
+		let tmp = message.timestamp;
+		message.timestamp = tmp != null ? tmp : snikket_Date.format(new Date());
+		message.direction = 1;
+		message.from = this.client.jid;
+		message.sender = this.getFullJid();
+		message.replyTo = [message.sender];
+		message.to = snikket_JID.parse(this.chatId);
+		message.recipients = [message.to];
+		return message;
+	}
+	correctMessage(localId,message) {
+		let toSendId = message.localId;
+		message = this.prepareOutgoingMessage(message);
+		let tmp = message.build();
+		message.versions = [tmp];
+		message.localId = localId;
+		let _gthis = this;
+		this.client.storeMessages([message.build()],function(corrected) {
+			let tmp = corrected[0].localId == localId ? corrected[0].versions : [message.build()];
+			message.versions = tmp;
+			message.localId = toSendId;
+			_gthis.client.sendStanza(message.build().asStanza());
+			_gthis.client.notifyMessageHandlers(corrected[0],1);
+			let tmp1 = _gthis.lastMessage;
+			if(localId == (tmp1 != null ? tmp1.localId : null)) {
+				_gthis.setLastMessage(corrected[0]);
+				_gthis.client.trigger("chats/update",[_gthis]);
+			}
+		});
+	}
+	sendMessage(message) {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.client.chatActivity(this);
+		message = this.prepareOutgoingMessage(message);
+		let stanza = message.build().asStanza();
+		stanza.attr["from"] = this.getFullJid().asString();
+		let fromStanza = snikket_Message.fromStanza(stanza,this.client.jid).parsed;
+		stanza.attr["from"] = this.client.jid.asString();
+		let _gthis = this;
+		switch(fromStanza._hx_index) {
+		case 1:
+			let _g = fromStanza.message;
+			if(this.isActive != null) {
+				this.isActive = true;
+				this.activeThread = message.threadId;
+				stanza.tag("active",{ xmlns : "http://jabber.org/protocol/chatstates"}).up();
+			}
+			this.client.storeMessages([message.build()],function(stored) {
+				_gthis.client.sendStanza(stanza);
+				_gthis.setLastMessage(stored[0]);
+				_gthis.client.notifyMessageHandlers(stored[0],stored[0].versions.length > 1 ? 1 : 0);
+				_gthis.client.trigger("chats/update",[_gthis]);
+			});
+			break;
+		case 3:
+			let update = fromStanza.update;
+			this.persistence.storeReaction(this.client.accountId(),update,function(stored) {
+				_gthis.client.sendStanza(stanza);
+				if(stored != null) {
+					_gthis.client.notifyMessageHandlers(stored,2);
+				}
+			});
+			break;
+		default:
+			haxe_Log.trace("Invalid message",{ fileName : "snikket/Chat.hx", lineNumber : 1314, className : "snikket.Channel", methodName : "sendMessage", customParams : [fromStanza]});
+			throw haxe_Exception.thrown("Trying to send invalid message.");
+		}
+	}
+	removeReaction(m,reaction) {
+		if(((reaction) instanceof snikket_CustomEmojiReaction)) {
+			if(reaction.envelopeId == null) {
+				throw haxe_Exception.thrown("Cannot remove custom emoji reaction without envelopeId");
+			}
+			let correct = m.reply();
+			correct.localId = snikket_ID.long();
+			correct.setHtml("");
+			correct.text = null;
+			this.correctMessage(reaction.envelopeId,correct);
+			return;
+		}
+		let reactions = [];
+		let _gthis = this;
+		let jsIterator = m.reactions.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let areaction = _g_key;
+			let reacts = _g_value;
+			if(areaction != reaction.key) {
+				let react = Lambda.find(reacts,function(r) {
+					return r.senderId == _gthis.getFullJid().asString();
+				});
+				if(react != null && !((react) instanceof snikket_CustomEmojiReaction)) {
+					reactions.push(react);
+				}
+			}
+		}
+		let update = new snikket_ReactionUpdate(snikket_ID.long(),m.serverId,m.chatId(),null,m.chatId(),this.getFullJid().asString(),snikket_Date.format(new Date()),reactions,0);
+		this.persistence.storeReaction(this.client.accountId(),update,function(stored) {
+			let stanza = update.asStanza();
+			stanza.attr["to"] = _gthis.chatId;
+			_gthis.client.sendStanza(stanza);
+			if(stored != null) {
+				_gthis.client.notifyMessageHandlers(stored,2);
+			}
+		});
+	}
+	lastMessageId() {
+		let tmp = this.lastMessage;
+		if(tmp != null) {
+			return tmp.serverId;
+		} else {
+			return null;
+		}
+	}
+	markReadUpTo(message) {
+		let _gthis = this;
+		this.markReadUpToMessage(message,function() {
+			let stanza = new snikket_Stanza("message",{ to : _gthis.chatId, id : snikket_ID.long(), type : "groupchat"}).tag("displayed",{ xmlns : "urn:xmpp:chat-markers:0", id : message.serverId}).up();
+			if(message.threadId != null) {
+				stanza.textTag("thread",message.threadId);
+			}
+			_gthis.client.sendStanza(stanza);
+			_gthis.publishMds();
+			_gthis.client.trigger("chats/update",[_gthis]);
+		});
+	}
+	bookmark() {
+		let _gthis = this;
+		this.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub"}).tag("publish",{ node : "urn:xmpp:bookmarks:1"}).tag("item",{ id : this.chatId}).tag("conference",{ xmlns : "urn:xmpp:bookmarks:1", name : this.getDisplayName(), autojoin : this.uiState == 2 ? "false" : "true"}).textTag("nick",this.client.displayName()).addChild(this.extensions).up().up().tag("publish-options").tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value","http://jabber.org/protocol/pubsub#publish-options").up().tag("field",{ "var" : "pubsub#persist_items"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#max_items"}).textTag("value","max").up().tag("field",{ "var" : "pubsub#send_last_published_item"}).textTag("value","never").up().tag("field",{ "var" : "pubsub#access_model"}).textTag("value","whitelist").up().tag("field",{ "var" : "pubsub#notify_delete"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#notify_retract"}).textTag("value","true").up().up().up().up().up(),function(response) {
+			if(response.attr["type"] == "error") {
+				let tmp = response.getChild("error");
+				let preconditionError = tmp != null ? tmp.getChild("precondition-not-met","http://jabber.org/protocol/pubsub#errors") : null;
+				if(preconditionError != null) {
+					_gthis.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub#owner"}).tag("configure",{ node : "urn:xmpp:bookmarks:1"}).tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value","http://jabber.org/protocol/pubsub#publish-options").up().tag("field",{ "var" : "pubsub#persist_items"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#max_items"}).textTag("value","max").up().tag("field",{ "var" : "pubsub#send_last_published_item"}).textTag("value","never").up().tag("field",{ "var" : "pubsub#access_model"}).textTag("value","whitelist").up().tag("field",{ "var" : "pubsub#notify_delete"}).textTag("value","true").up().tag("field",{ "var" : "pubsub#notify_retract"}).textTag("value","true").up().up().up().up(),function(response) {
+						if(response.attr["type"] == "result") {
+							_gthis.bookmark();
+						}
+					});
+				}
+			}
+		});
+	}
+	sendChatState(state,threadId) {
+		let stanza = new snikket_Stanza("message",{ id : snikket_ID.long(), type : "groupchat", from : this.client.jid.asString(), to : this.chatId}).tag(state,{ xmlns : "http://jabber.org/protocol/chatstates"}).up();
+		if(threadId != null) {
+			stanza.textTag("thread",threadId);
+		}
+		this.stream.sendStanza(stanza);
+	}
+	close() {
+		if(this.typingTimer != null) {
+			this.typingTimer.stop();
+		}
+		this.uiState = 2;
+		this.persistence.storeChats(this.client.accountId(),[this]);
+		this.selfPing(false);
+		this.bookmark();
+		this.sendChatState("gone",null);
+		this.client.trigger("chats/update",[this]);
+	}
+}
+$hx_exports["snikket"]["Channel"] = snikket_Channel;
+snikket_Channel.__name__ = "snikket.Channel";
+snikket_Channel.__super__ = snikket_Chat;
+Object.assign(snikket_Channel.prototype, {
+	__class__: snikket_Channel
+});
+class snikket_AvailableChat {
+	constructor(chatId,displayName,note,caps) {
+		this.chatId = chatId;
+		this.displayName = displayName;
+		this.note = note;
+		this.caps = caps;
+	}
+	isChannel() {
+		return this.caps.isChannel(this.chatId);
+	}
+}
+$hx_exports["snikket"]["AvailableChat"] = snikket_AvailableChat;
+snikket_AvailableChat.__name__ = "snikket.AvailableChat";
+Object.assign(snikket_AvailableChat.prototype, {
+	__class__: snikket_AvailableChat
+});
+class snikket_SerializedChat {
+	constructor(chatId,trusted,avatarSha1,presence,displayName,uiState,isBlocked,extensions,readUpToId,readUpToBy,disco,klass) {
+		this.chatId = chatId;
+		this.trusted = trusted;
+		this.avatarSha1 = avatarSha1;
+		this.presence = presence;
+		this.displayName = displayName;
+		let tmp = uiState;
+		this.uiState = tmp != null ? tmp : 1;
+		let tmp1 = isBlocked;
+		this.isBlocked = tmp1 != null && tmp1;
+		let tmp2 = extensions;
+		this.extensions = tmp2 != null ? tmp2 : "<extensions xmlns='urn:app:bookmarks:1' />";
+		this.readUpToId = readUpToId;
+		this.readUpToBy = readUpToBy;
+		this.disco = disco;
+		this.klass = klass;
+	}
+	toChat(client,stream,persistence) {
+		let extensionsStanza = snikket_Stanza.fromXml(Xml.parse(this.extensions));
+		let chat;
+		if(this.klass == "DirectChat") {
+			chat = new snikket_DirectChat(client,stream,persistence,this.chatId,this.uiState,this.isBlocked,extensionsStanza,this.readUpToId,this.readUpToBy);
+		} else if(this.klass == "Channel") {
+			let channel = new snikket_Channel(client,stream,persistence,this.chatId,this.uiState,this.isBlocked,extensionsStanza,this.readUpToId,this.readUpToBy);
+			let tmp = this.disco;
+			channel.disco = tmp != null ? tmp : new snikket_Caps("",[],["http://jabber.org/protocol/muc"]);
+			chat = channel;
+		} else {
+			throw haxe_Exception.thrown("Unknown class of " + this.chatId + ": " + this.klass);
+		}
+		if(this.displayName != null) {
+			chat.displayName = this.displayName;
+		}
+		if(this.avatarSha1 != null) {
+			chat.setAvatarSha1(this.avatarSha1);
+		}
+		chat.setTrusted(this.trusted);
+		let jsIterator = this.presence.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let _g_key = v[0];
+			let _g_value = v[1];
+			let resource = _g_key;
+			let p = _g_value;
+			chat.setPresence(resource,p);
+		}
+		return chat;
+	}
+}
+$hx_exports["snikket"]["SerializedChat"] = snikket_SerializedChat;
+snikket_SerializedChat.__name__ = "snikket.SerializedChat";
+Object.assign(snikket_SerializedChat.prototype, {
+	__class__: snikket_SerializedChat
+});
+class snikket_ChatAttachment {
+	constructor(name,mime,size,uris,hashes) {
+		this.name = name;
+		this.mime = mime;
+		this.size = size;
+		this.uris = uris;
+		this.hashes = hashes;
+	}
+}
+$hx_exports["snikket"]["ChatAttachment"] = snikket_ChatAttachment;
+snikket_ChatAttachment.__name__ = "snikket.ChatAttachment";
+Object.assign(snikket_ChatAttachment.prototype, {
+	__class__: snikket_ChatAttachment
+});
+class snikket_ChatMessage {
+	constructor(params) {
+		this.localId = params.localId;
+		this.serverId = params.serverId;
+		this.serverIdBy = params.serverIdBy;
+		let tmp = params.type;
+		this.type = tmp != null ? tmp : 0;
+		let tmp1 = params.syncPoint;
+		this.syncPoint = tmp1 != null && tmp1;
+		this.replyId = params.replyId;
+		this.timestamp = params.timestamp;
+		this.to = params.to;
+		this.from = params.from;
+		this.senderId = params.senderId;
+		let tmp2 = params.recipients;
+		this.recipients = tmp2 != null ? tmp2 : [];
+		let tmp3 = params.replyTo;
+		this.replyTo = tmp3 != null ? tmp3 : [];
+		this.replyToMessage = params.replyToMessage;
+		this.threadId = params.threadId;
+		let tmp4 = params.attachments;
+		this.attachments = tmp4 != null ? tmp4 : [];
+		let tmp5 = params.reactions;
+		this.reactions = tmp5 != null ? tmp5 : new Map([]);
+		this.text = params.text;
+		this.lang = params.lang;
+		let tmp6 = params.direction;
+		this.direction = tmp6 != null ? tmp6 : 1;
+		let tmp7 = params.status;
+		this.status = tmp7 != null ? tmp7 : 0;
+		let tmp8 = params.versions;
+		this.versions = tmp8 != null ? tmp8 : [];
+		let tmp9 = params.payloads;
+		this.payloads = tmp9 != null ? tmp9 : [];
+		this.stanza = params.stanza;
+	}
+	reply() {
+		let m = new snikket_ChatMessageBuilder();
+		m.type = this.type;
+		let tmp = this.threadId;
+		m.threadId = tmp != null ? tmp : snikket_ID.long();
+		m.replyToMessage = this;
+		return m;
+	}
+	getReplyId() {
+		if(this.replyId != null) {
+			return this.replyId;
+		}
+		if(this.type == 2 || this.type == 3) {
+			return this.serverId;
+		} else {
+			return this.localId;
+		}
+	}
+	set_replyToMessage(m) {
+		let rtm = this.replyToMessage;
+		if(rtm == null) {
+			throw haxe_Exception.thrown("Cannot hydrate null replyToMessage");
+		}
+		if(rtm.serverId != null && rtm.serverId != m.serverId) {
+			throw haxe_Exception.thrown("Hydrate serverId mismatch");
+		}
+		if(rtm.localId != null && rtm.localId != m.localId) {
+			throw haxe_Exception.thrown("Hydrate localId mismatch");
+		}
+		return this.replyToMessage = m;
+	}
+	set_reactions(r) {
+		let _gthis = this;
+		if(this.reactions != null && !Lambda.empty({ iterator : function() {
+			return new js_lib_HaxeIterator(_gthis.reactions.keys());
+		}})) {
+			throw haxe_Exception.thrown("Reactions already hydrated");
+		}
+		return this.reactions = r;
+	}
+	inlineHashReferences() {
+		let result = [];
+		let tmp = Lambda.find(this.payloads,function(p) {
+			if(p.attr["xmlns"] == "http://jabber.org/protocol/xhtml-im") {
+				return p.name == "html";
+			} else {
+				return false;
+			}
+		});
+		let htmlBody = tmp != null ? tmp.getChild("body","http://www.w3.org/1999/xhtml") : null;
+		if(htmlBody != null) {
+			htmlBody.traverse(function(child) {
+				if(child.name == "img") {
+					let src = child.attr["src"];
+					if(src != null) {
+						let hash = snikket_Hash.fromUri(src);
+						if(hash != null) {
+							let x = hash;
+							result.push(x);
+						}
+					}
+					return true;
+				}
+				return false;
+			});
+		}
+		return result;
+	}
+	html() {
+		let tmp = Lambda.find(this.payloads,function(p) {
+			if(p.attr["xmlns"] == "http://jabber.org/protocol/xhtml-im") {
+				return p.name == "html";
+			} else {
+				return false;
+			}
+		});
+		let htmlBody = tmp != null ? tmp.getChild("body","http://www.w3.org/1999/xhtml") : null;
+		if(htmlBody != null) {
+			let _this = htmlBody.getChildren();
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].traverse(function(child) {
+					if(child.name == "img") {
+						let src = child.attr["src"];
+						if(src != null) {
+							let hash = snikket_Hash.fromUri(src);
+							if(hash != null) {
+								child.attr["src"] = hash.toUri();
+							}
+						}
+						return true;
+					}
+					return false;
+				}).serialize();
+			}
+			return result.join("");
+		}
+		let tmp1 = this.text;
+		let codepoints = snikket_StringUtil.codepointArray(tmp1 != null ? tmp1 : "");
+		let _gthis = this;
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.payloads;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.attr["xmlns"] == "urn:xmpp:fallback:0" && ((v.attr["for"] == "jabber:x:oob" || v.attr["for"] == "urn:xmpp:sims:1") && _gthis.attachments.length > 0 || _gthis.replyToMessage != null && v.attr["for"] == "urn:xmpp:reply:0" || v.attr["for"] == "http://jabber.org/protocol/address")) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			result[i] = _this[i].getChild("body");
+		}
+		let _this1 = result;
+		let result1 = new Array(_this1.length);
+		let _g5 = 0;
+		let _g6 = _this1.length;
+		while(_g5 < _g6) {
+			let i = _g5++;
+			let b = _this1[i];
+			let fallbacks;
+			if(b == null) {
+				fallbacks = null;
+			} else {
+				let tmp = b.attr["start"];
+				let tmp1 = Std.parseInt(tmp != null ? tmp : "0");
+				let tmp2 = b.attr["end"];
+				let tmp3 = Std.parseInt(tmp2 != null ? tmp2 : codepoints.length == null ? "null" : "" + codepoints.length);
+				fallbacks = { start : tmp1 != null ? tmp1 : 0, end : tmp3 != null ? tmp3 : codepoints.length};
+			}
+			result1[i] = fallbacks;
+		}
+		let _g7 = [];
+		let _g8 = 0;
+		let _g9 = result1;
+		while(_g8 < _g9.length) {
+			let v = _g9[_g8];
+			++_g8;
+			if(v != null) {
+				_g7.push(v);
+			}
+		}
+		let fallbacks = _g7;
+		fallbacks.sort(function(x,y) {
+			return y.start - x.start;
+		});
+		let _g10 = 0;
+		while(_g10 < fallbacks.length) {
+			let fallback = fallbacks[_g10];
+			++_g10;
+			codepoints.splice(fallback.start,fallback.end - fallback.start);
+		}
+		let body = codepoints.join("");
+		if(Lambda.find(this.payloads,function(p) {
+			if(p.attr["xmlns"] == "urn:xmpp:styling:0") {
+				return p.name == "unstyled";
+			} else {
+				return false;
+			}
+		}) == null) {
+			let _g = [];
+			let x = $getIterator(snikket_XEP0393.parse(body));
+			while(x.hasNext()) {
+				let x1 = x.next();
+				_g.push(x1.toString());
+			}
+			return _g.join("");
+		} else {
+			return StringTools.htmlEscape(body);
+		}
+	}
+	chatId() {
+		if(this.isIncoming()) {
+			let _this = this.replyTo;
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].asBare().asString();
+			}
+			return result.join("\n");
+		} else {
+			let _this = this.recipients;
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].asString();
+			}
+			return result.join("\n");
+		}
+	}
+	account() {
+		let tmp;
+		if(!this.isIncoming()) {
+			let tmp1 = this.from;
+			let tmp2 = tmp1 != null ? tmp1.asBare() : null;
+			tmp = tmp2 != null ? tmp2.asString() : null;
+		} else {
+			let tmp1 = this.to;
+			let tmp2 = tmp1 != null ? tmp1.asBare() : null;
+			tmp = tmp2 != null ? tmp2.asString() : null;
+		}
+		if(tmp != null) {
+			return tmp;
+		} else {
+			throw haxe_Exception.thrown("from or to is null");
+		}
+	}
+	isIncoming() {
+		return this.direction == 0;
+	}
+	threadIcon() {
+		if(this.threadId == null) {
+			return null;
+		} else {
+			return snikket_Identicon.svg(this.threadId);
+		}
+	}
+	callStatus() {
+		let tmp = Lambda.find(this.payloads,function(el) {
+			return el.attr["xmlns"] == "urn:xmpp:jingle-message:0";
+		});
+		if(tmp != null) {
+			return tmp.name;
+		} else {
+			return null;
+		}
+	}
+	callSid() {
+		let tmp = Lambda.find(this.payloads,function(el) {
+			return el.attr["xmlns"] == "urn:xmpp:jingle-message:0";
+		});
+		let tmp1 = tmp != null ? tmp.attr : null;
+		if(tmp1 != null) {
+			return tmp1["id"];
+		} else {
+			return null;
+		}
+	}
+	callDuration() {
+		if(this.versions.length < 2) {
+			return null;
+		}
+		let startedStr = this.versions[this.versions.length - 1].timestamp;
+		let _g = this.callStatus();
+		if(_g == null) {
+			return null;
+		} else {
+			switch(_g) {
+			case "finish":
+				let endedStr = this.versions[0].timestamp;
+				if(startedStr == null || endedStr == null) {
+					return null;
+				}
+				let started = datetime_utils_DateTimeUtils.fromString(startedStr);
+				let ended = datetime_utils_DateTimeUtils.fromString(endedStr);
+				let duration = datetime_DateTimeInterval.create(started,ended - 62135596800.0 + 62135596800.0);
+				return datetime_utils_DateTimeIntervalUtils.strftime(duration,"%I:%S");
+			case "proceed":
+				if(startedStr == null) {
+					return null;
+				}
+				let started1 = datetime_utils_DateTimeUtils.fromString(startedStr);
+				let ended1 = Math.floor(new Date().getTime() / 1000) + 62135596800.0;
+				let duration1 = datetime_DateTimeInterval.create(started1,ended1 - 62135596800.0 + 62135596800.0);
+				return datetime_utils_DateTimeIntervalUtils.strftime(duration1,"%I:%S");
+			default:
+				return null;
+			}
+		}
+	}
+	asStanza() {
+		if(this.stanza != null) {
+			return this.stanza;
+		}
+		let body = this.text;
+		let attrs = { type : this.type == 2 ? "groupchat" : "chat"};
+		if(this.from != null) {
+			attrs["from"] = this.from.asString();
+		}
+		if(this.to != null) {
+			attrs["to"] = this.to.asString();
+		}
+		if(this.localId != null) {
+			attrs["id"] = this.localId;
+		}
+		let stanza = new snikket_Stanza("message",attrs);
+		if(this.versions.length > 0 && this.versions[this.versions.length - 1].localId != null) {
+			stanza.tag("replace",{ xmlns : "urn:xmpp:message-correct:0", id : this.versions[this.versions.length - 1].localId}).up();
+		}
+		if(this.threadId != null) {
+			stanza.textTag("thread",this.threadId);
+		}
+		if(this.recipients.length > 1) {
+			let addresses = stanza.tag("addresses",{ xmlns : "http://jabber.org/protocol/address"});
+			let _g = 0;
+			let _g1 = this.recipients;
+			while(_g < _g1.length) {
+				let recipient = _g1[_g];
+				++_g;
+				addresses.tag("address",{ type : "to", jid : recipient.asString(), delivered : "true"}).up();
+			}
+			addresses.up();
+		} else if(this.recipients.length == 1 && this.to == null) {
+			attrs["to"] = this.recipients[0].asString();
+		}
+		let replyToM = this.replyToMessage;
+		let _gthis = this;
+		if(replyToM != null) {
+			let replyId = replyToM.getReplyId();
+			if(body != null) {
+				let tmp = replyToM.text;
+				let tmp1 = tmp != null ? tmp.split("\n") : null;
+				let lines = tmp1 != null ? tmp1 : [];
+				let quoteText = "";
+				let _g = 0;
+				while(_g < lines.length) {
+					let line = lines[_g];
+					++_g;
+					if(!new EReg("^(?:> ?){3,}","").match(line)) {
+						if(line.charAt(0) == ">") {
+							quoteText += ">" + line + "\n";
+						} else {
+							quoteText += "> " + line + "\n";
+						}
+					}
+				}
+				let reaction = snikket_EmojiUtil.isEmoji(StringTools.trim(body)) ? StringTools.trim(body) : null;
+				body = quoteText + body;
+				if(replyId != null) {
+					let codepoints = snikket_StringUtil.codepointArray(quoteText);
+					if(reaction != null) {
+						let addedReactions = new Map([]);
+						stanza.tag("reactions",{ xmlns : "urn:xmpp:reactions:0", id : replyId});
+						stanza.textTag("reaction",reaction);
+						addedReactions.set(reaction,true);
+						let jsIterator = replyToM.reactions.entries();
+						let _g_jsIterator = jsIterator;
+						let _g_lastStep = jsIterator.next();
+						while(!_g_lastStep.done) {
+							let v = _g_lastStep.value;
+							_g_lastStep = _g_jsIterator.next();
+							let _g_key = v[0];
+							let _g_value = v[1];
+							let areaction = _g_key;
+							let reactions = _g_value;
+							let tmp = addedReactions.get(areaction);
+							if(!(tmp != null && tmp) && Lambda.find(reactions,function(r) {
+								return r.senderId == _gthis.senderId;
+							}) != null) {
+								addedReactions.set(areaction,true);
+								stanza.textTag("reaction",areaction);
+							}
+						}
+						stanza.up();
+						stanza.tag("fallback",{ xmlns : "urn:xmpp:fallback:0", "for" : "urn:xmpp:reactions:0"}).tag("body").up().up();
+					}
+					let tmp = codepoints.length == null ? "null" : "" + codepoints.length;
+					stanza.tag("fallback",{ xmlns : "urn:xmpp:fallback:0", "for" : "urn:xmpp:reply:0"}).tag("body",{ start : "0", end : tmp}).up().up();
+				}
+			}
+			if(replyId != null) {
+				let tmp = replyToM.from;
+				stanza.tag("reply",{ xmlns : "urn:xmpp:reply:0", to : tmp != null ? tmp.asString() : null, id : replyId}).up();
+			}
+		}
+		let _g = 0;
+		let _g1 = this.attachments;
+		while(_g < _g1.length) {
+			let attachment = _g1[_g];
+			++_g;
+			stanza.tag("reference",{ xmlns : "urn:xmpp:reference:0", type : "data"}).tag("media-sharing",{ xmlns : "urn:xmpp:sims:1"});
+			stanza.tag("file",{ xmlns : "urn:xmpp:jingle:apps:file-transfer:5"});
+			if(attachment.name != null) {
+				stanza.textTag("name",attachment.name);
+			}
+			stanza.textTag("media-type",attachment.mime);
+			if(attachment.size != null) {
+				stanza.textTag("size",attachment.size == null ? "null" : "" + attachment.size);
+			}
+			let _g2 = 0;
+			let _g3 = attachment.hashes;
+			while(_g2 < _g3.length) {
+				let hash = _g3[_g2];
+				++_g2;
+				stanza.textTag("hash",haxe_crypto_Base64.encode(haxe_io_Bytes.ofData(hash.hash)),{ xmlns : "urn:xmpp:hashes:2", algo : hash.algorithm});
+			}
+			stanza.up();
+			stanza.tag("sources");
+			let _g4 = 0;
+			let _g5 = attachment.uris;
+			while(_g4 < _g5.length) {
+				let uri = _g5[_g4];
+				++_g4;
+				stanza.tag("reference",{ xmlns : "urn:xmpp:reference:0", type : "data", uri : uri}).up();
+			}
+			stanza.up().up().up();
+			if(attachment.uris.length > 0) {
+				stanza.tag("x",{ xmlns : "jabber:x:oob"}).textTag("url",attachment.uris[0]).up();
+				if(body == null) {
+					body = "";
+				}
+				let codepoints = snikket_StringUtil.codepointArray(body);
+				let start = codepoints.length;
+				let end = start + attachment.uris[0].length;
+				if(body != "") {
+					body += "\n";
+					++end;
+				}
+				body += attachment.uris[0];
+				stanza.tag("fallback",{ xmlns : "urn:xmpp:fallback:0", "for" : "jabber:x:oob"}).tag("body",{ start : start == null ? "null" : "" + start, end : end == null ? "null" : "" + end}).up().up();
+			}
+		}
+		if(body != null) {
+			stanza.textTag("body",body);
+		}
+		let _g2 = 0;
+		let _g3 = this.payloads;
+		while(_g2 < _g3.length) {
+			let payload = _g3[_g2];
+			++_g2;
+			stanza.addDirectChild(snikket_Node.Element(payload));
+		}
+		return stanza;
+	}
+	static fromStanza(stanza,localJid,addContext) {
+		let _g = snikket_Message.fromStanza(stanza,localJid,addContext).parsed;
+		if(_g._hx_index == 1) {
+			let message = _g.message;
+			return message;
+		} else {
+			return null;
+		}
+	}
+}
+$hx_exports["snikket"]["ChatMessage"] = snikket_ChatMessage;
+snikket_ChatMessage.__name__ = "snikket.ChatMessage";
+Object.assign(snikket_ChatMessage.prototype, {
+	__class__: snikket_ChatMessage
+});
+class snikket_ChatMessageBuilder {
+	constructor(params) {
+		this.stanza = null;
+		this.payloads = [];
+		this.versions = [];
+		this.status = 0;
+		this.direction = 0;
+		this.lang = null;
+		this.text = null;
+		this.reactions = new Map([]);
+		this.attachments = [];
+		this.threadId = null;
+		this.replyToMessage = null;
+		this.senderId = null;
+		this.replyTo = [];
+		this.recipients = [];
+		this.sender = null;
+		this.from = null;
+		this.to = null;
+		this.timestamp = null;
+		this.replyId = null;
+		this.syncPoint = false;
+		this.type = 0;
+		this.serverIdBy = null;
+		this.serverId = null;
+		this.localId = null;
+		this.localId = params != null ? params.localId : null;
+		this.serverId = params != null ? params.serverId : null;
+		this.serverIdBy = params != null ? params.serverIdBy : null;
+		let tmp = params != null ? params.type : null;
+		this.type = tmp != null ? tmp : 0;
+		let tmp1 = params != null ? params.syncPoint : null;
+		this.syncPoint = tmp1 != null && tmp1;
+		this.replyId = params != null ? params.replyId : null;
+		this.timestamp = params != null ? params.timestamp : null;
+		this.senderId = params != null ? params.senderId : null;
+		this.replyToMessage = params != null ? params.replyToMessage : null;
+		this.threadId = params != null ? params.threadId : null;
+		let tmp2 = params != null ? params.attachments : null;
+		this.attachments = tmp2 != null ? tmp2 : [];
+		let tmp3 = params != null ? params.reactions : null;
+		this.reactions = tmp3 != null ? tmp3 : new Map([]);
+		this.text = params != null ? params.text : null;
+		this.lang = params != null ? params.lang : null;
+		let tmp4 = params != null ? params.direction : null;
+		this.direction = tmp4 != null ? tmp4 : 1;
+		let tmp5 = params != null ? params.status : null;
+		this.status = tmp5 != null ? tmp5 : 0;
+		let tmp6 = params != null ? params.versions : null;
+		this.versions = tmp6 != null ? tmp6 : [];
+		let tmp7 = params != null ? params.payloads : null;
+		this.payloads = tmp7 != null ? tmp7 : [];
+		let html = params != null ? params.html : null;
+		if(html != null) {
+			this.setHtml(html);
+		}
+	}
+	attachSims(sims) {
+		let mime = sims.findText("{urn:xmpp:jingle:apps:file-transfer:5}/media-type#");
+		if(mime == null) {
+			mime = sims.findText("{urn:xmpp:jingle:apps:file-transfer:3}/media-type#");
+		}
+		if(mime == null) {
+			mime = "application/octet-stream";
+		}
+		let name = sims.findText("{urn:xmpp:jingle:apps:file-transfer:5}/name#");
+		if(name == null) {
+			name = sims.findText("{urn:xmpp:jingle:apps:file-transfer:3}/name#");
+		}
+		let size = sims.findText("{urn:xmpp:jingle:apps:file-transfer:5}/size#");
+		if(size == null) {
+			size = sims.findText("{urn:xmpp:jingle:apps:file-transfer:3}/size#");
+		}
+		let tmp = sims.getChild("file","urn:xmpp:jingle:apps:file-transfer:5");
+		let tmp1 = tmp != null ? tmp : sims.getChild("file","urn:xmpp:jingle:apps:file-transfer:3");
+		let tmp2 = tmp1 != null ? tmp1.allTags("hash","urn:xmpp:hashes:2") : null;
+		let _this = tmp2 != null ? tmp2 : [];
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let hash = _this[i];
+			let tmp = hash.attr["algo"];
+			result[i] = new snikket_Hash(tmp != null ? tmp : "",haxe_crypto_Base64.decode(hash.getText()).b.bufferValue);
+		}
+		let hashes = result;
+		let sources = sims.getChild("sources");
+		let tmp3 = sources != null ? sources.allTags("reference","urn:xmpp:reference:0") : null;
+		let _this1 = tmp3 != null ? tmp3 : [];
+		let result1 = new Array(_this1.length);
+		let _g2 = 0;
+		let _g3 = _this1.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			let tmp = _this1[i].attr["uri"];
+			result1[i] = tmp != null ? tmp : "";
+		}
+		let _g4 = [];
+		let _g5 = 0;
+		let _g6 = result1;
+		while(_g5 < _g6.length) {
+			let v = _g6[_g5];
+			++_g5;
+			if(v != "") {
+				_g4.push(v);
+			}
+		}
+		let uris = _g4;
+		if(uris.length > 0) {
+			this.attachments.push(new snikket_ChatAttachment(name,mime,size == null ? null : Std.parseInt(size),uris,hashes));
+		}
+	}
+	addAttachment(attachment) {
+		this.attachments.push(attachment);
+	}
+	setHtml(html) {
+		let htmlEl = new snikket_Stanza("html",{ xmlns : "http://jabber.org/protocol/xhtml-im"});
+		let body = new snikket_Stanza("body",{ xmlns : "http://www.w3.org/1999/xhtml"});
+		htmlEl.addChild(body);
+		let nodes = htmlparser_HtmlParser.run(html,true);
+		let _g = 0;
+		while(_g < nodes.length) {
+			let node = nodes[_g];
+			++_g;
+			let el = snikket_Util_downcast(node,htmlparser_HtmlNodeElement);
+			if(el != null && (el.name == "html" || el.name == "body")) {
+				let _g = 0;
+				let _g1 = el.nodes;
+				while(_g < _g1.length) {
+					let inner = _g1[_g];
+					++_g;
+					body.addDirectChild(this.htmlToNode(inner));
+				}
+			} else {
+				body.addDirectChild(this.htmlToNode(node));
+			}
+		}
+		let htmlIdx = Lambda.findIndex(this.payloads,function(p) {
+			if(p.attr["xmlns"] == "http://jabber.org/protocol/xhtml-im") {
+				return p.name == "html";
+			} else {
+				return false;
+			}
+		});
+		if(htmlIdx >= 0) {
+			this.payloads.splice(htmlIdx,1);
+		}
+		this.payloads.push(htmlEl);
+		this.text = snikket_XEP0393.render(body);
+	}
+	htmlToNode(node) {
+		let txt = snikket_Util_downcast(node,htmlparser_HtmlNodeText);
+		if(txt != null) {
+			return snikket_Node.CData(new snikket_TextNode(txt.toText()));
+		}
+		let el = snikket_Util_downcast(node,htmlparser_HtmlNodeElement);
+		if(el != null) {
+			let s = new snikket_Stanza(el.name,{ });
+			let _g = 0;
+			let _g1 = el.attributes;
+			while(_g < _g1.length) {
+				let attr = _g1[_g];
+				++_g;
+				s.attr[attr.name] = attr.value;
+			}
+			let _g2 = 0;
+			let _g3 = el.nodes;
+			while(_g2 < _g3.length) {
+				let child = _g3[_g2];
+				++_g2;
+				s.addDirectChild(this.htmlToNode(child));
+			}
+			return snikket_Node.Element(s);
+		}
+		throw haxe_Exception.thrown("node was neither text nor element?");
+	}
+	chatId() {
+		if(this.isIncoming()) {
+			let _this = this.replyTo;
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].asBare().asString();
+			}
+			return result.join("\n");
+		} else {
+			let _this = this.recipients;
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].asString();
+			}
+			return result.join("\n");
+		}
+	}
+	get_senderId() {
+		let tmp = this.senderId;
+		let tmp1;
+		if(tmp != null) {
+			tmp1 = tmp;
+		} else {
+			let tmp = this.sender;
+			tmp1 = tmp != null ? tmp.asString() : null;
+		}
+		if(tmp1 != null) {
+			return tmp1;
+		} else {
+			throw haxe_Exception.thrown("sender is null");
+		}
+	}
+	isIncoming() {
+		return this.direction == 0;
+	}
+	build() {
+		if(this.serverId == null && this.localId == null) {
+			throw haxe_Exception.thrown("Cannot build a ChatMessage with no id");
+		}
+		let to = this.to;
+		if(to == null) {
+			throw haxe_Exception.thrown("Cannot build a ChatMessage with no to");
+		}
+		let from = this.from;
+		if(from == null) {
+			throw haxe_Exception.thrown("Cannot build a ChatMessage with no from");
+		}
+		let tmp = this.sender;
+		let sender = tmp != null ? tmp : from.asBare();
+		let tmp1 = this.timestamp;
+		return new snikket_ChatMessage({ localId : this.localId, serverId : this.serverId, serverIdBy : this.serverIdBy, type : this.type, syncPoint : this.syncPoint, replyId : this.replyId, timestamp : tmp1 != null ? tmp1 : snikket_Date.format(new Date()), to : to, from : from, senderId : this.get_senderId(), recipients : this.recipients, replyTo : this.replyTo, replyToMessage : this.replyToMessage, threadId : this.threadId, attachments : this.attachments, reactions : this.reactions, text : this.text, lang : this.lang, direction : this.direction, status : this.status, versions : this.versions, payloads : this.payloads, stanza : this.stanza});
+	}
+	static makeModerated(m,timestamp,moderatorId,reason) {
+		let builder = new snikket_ChatMessageBuilder();
+		builder.localId = m.localId;
+		builder.serverId = m.serverId;
+		builder.serverIdBy = m.serverIdBy;
+		builder.type = m.type;
+		builder.syncPoint = m.syncPoint;
+		builder.replyId = m.replyId;
+		builder.timestamp = m.timestamp;
+		builder.to = m.to;
+		builder.from = m.from;
+		builder.senderId = m.senderId;
+		builder.recipients = Lambda.array(m.recipients);
+		builder.replyTo = Lambda.array(m.replyTo);
+		builder.replyToMessage = m.replyToMessage;
+		builder.threadId = m.threadId;
+		builder.reactions = m.reactions;
+		builder.direction = m.direction;
+		builder.status = m.status;
+		let cleanedStub = builder.build();
+		let payload = new snikket_Stanza("retracted",{ xmlns : "urn:xmpp:message-retract:1", stamp : timestamp});
+		if(reason != null) {
+			payload.textTag("reason",reason);
+		}
+		payload.tag("moderated",{ by : moderatorId, xmlns : "urn:xmpp:message-moderate:1"}).up();
+		builder.payloads.push(payload);
+		builder.timestamp = timestamp;
+		builder.versions = [builder.build(),cleanedStub];
+		builder.timestamp = m.timestamp;
+		return builder.build();
+	}
+}
+$hx_exports["snikket"]["ChatMessageBuilder"] = snikket_ChatMessageBuilder;
+snikket_ChatMessageBuilder.__name__ = "snikket.ChatMessageBuilder";
+Object.assign(snikket_ChatMessageBuilder.prototype, {
+	__class__: snikket_ChatMessageBuilder
+});
+class snikket_EventEmitter {
+	constructor() {
+		if(snikket_EventEmitter._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.eventHandlers = new Map([]);
+	}
+	on(eventName,callback) {
+		let handlers = this.eventHandlers.get(eventName);
+		if(handlers == null) {
+			handlers = [];
+			this.eventHandlers.set(eventName,handlers);
+		}
+		let newHandler = new snikket_EventHandler(handlers,callback);
+		handlers.push(newHandler);
+		return newHandler;
+	}
+	once(eventName,callback) {
+		return this.on(eventName,callback).once();
+	}
+	trigger(eventName,eventData) {
+		let handlers = this.eventHandlers.get(eventName);
+		if(handlers == null || handlers.length == 0) {
+			haxe_Log.trace("no event handlers for " + eventName,{ fileName : "snikket/EventEmitter.hx", lineNumber : 29, className : "snikket.EventEmitter", methodName : "trigger"});
+			return snikket_EventResult.EventUnhandled;
+		}
+		haxe_Log.trace("firing event: " + eventName,{ fileName : "snikket/EventEmitter.hx", lineNumber : 32, className : "snikket.EventEmitter", methodName : "trigger"});
+		let handled = false;
+		let _g = 0;
+		while(_g < handlers.length) {
+			let handler = handlers[_g];
+			++_g;
+			let ret = handler.call(eventData);
+			switch(ret._hx_index) {
+			case 0:
+				handled = true;
+				break;
+			case 1:
+				continue;
+			case 2:
+				return ret;
+			case 3:
+				let _g1 = ret.result;
+				return ret;
+			}
+		}
+		if(handled) {
+			return snikket_EventResult.EventHandled;
+		} else {
+			return snikket_EventResult.EventUnhandled;
+		}
+	}
+}
+snikket_EventEmitter.__name__ = "snikket.EventEmitter";
+Object.assign(snikket_EventEmitter.prototype, {
+	__class__: snikket_EventEmitter
+});
+class snikket_Client extends snikket_EventEmitter {
+	constructor(address,persistence) {
+		snikket_EventEmitter._hx_skip_constructor = true;
+		super();
+		snikket_EventEmitter._hx_skip_constructor = false;
+		this._hx_constructor(address,persistence);
+	}
+	_hx_constructor(address,persistence) {
+		this.inSync = false;
+		this.pendingCaps = new Map([]);
+		this.token = null;
+		this.fastMechanism = null;
+		this.caps = new snikket_Caps("https://sdk.snikket.org",[],["http://jabber.org/protocol/disco#info","http://jabber.org/protocol/caps","urn:xmpp:avatar:metadata+notify","http://jabber.org/protocol/nick+notify","urn:xmpp:bookmarks:1+notify","urn:xmpp:mds:displayed:0+notify","urn:xmpp:jingle-message:0","urn:xmpp:jingle:1","urn:xmpp:jingle:apps:dtls:0","urn:xmpp:jingle:apps:rtp:1","urn:xmpp:jingle:apps:rtp:audio","urn:xmpp:jingle:apps:rtp:video","urn:xmpp:jingle:transports:ice-udp:1"]);
+		this.chats = [];
+		this.chatStateHandlers = [];
+		this.syncMessageHandlers = [];
+		this.chatMessageHandlers = [];
+		this.sendAvailable = true;
+		snikket_Util_setupTrace();
+		super._hx_constructor();
+		this.jid = snikket_JID.parse(address);
+		this._displayName = this.jid.node;
+		this.persistence = persistence;
+		this.stream = new snikket_streams_XmppJsStream();
+		this.stream.on("status/online",$bind(this,this.onConnected));
+		let _gthis = this;
+		this.stream.on("status/offline",function(data) {
+			return _gthis.trigger("status/offline",{ });
+		});
+		this.stream.on("fast-token",function(data) {
+			_gthis.token = data.token;
+			let persistence1 = persistence;
+			let tmp = _gthis.jid.asBare().asString();
+			let tmp1 = _gthis.stream.clientId;
+			persistence1.storeLogin(tmp,tmp1 != null ? tmp1 : _gthis.jid.resource,_gthis.displayName(),_gthis.token);
+			return snikket_EventResult.EventHandled;
+		});
+		this.stream.on("sm/update",function(data) {
+			let anySyncHappening = Lambda.exists(_gthis.chats,function(chat) {
+				if(chat.uiState != 2) {
+					return chat.syncing();
+				} else {
+					return false;
+				}
+			});
+			persistence.storeStreamManagement(_gthis.accountId(),anySyncHappening ? null : data.sm);
+			return snikket_EventResult.EventHandled;
+		});
+		this.stream.on("sm/ack",function(data) {
+			persistence.updateMessageStatus(_gthis.accountId(),data.id,1,function(m) {
+				_gthis.notifyMessageHandlers(m,3);
+			});
+			return snikket_EventResult.EventHandled;
+		});
+		this.stream.on("sm/fail",function(data) {
+			persistence.updateMessageStatus(_gthis.accountId(),data.id,3,function(m) {
+				_gthis.notifyMessageHandlers(m,3);
+			});
+			return snikket_EventResult.EventHandled;
+		});
+		this.stream.on("message",function(event) {
+			let stanza = event.stanza;
+			if(stanza.getChild("result","urn:xmpp:mam:2") != null) {
+				return snikket_EventResult.EventUnhandled;
+			}
+			let from = stanza.attr["from"] == null ? null : snikket_JID.parse(stanza.attr["from"]);
+			if(stanza.attr["type"] == "error" && from != null) {
+				let chat = _gthis.getChat(from.asBare().asString());
+				let channel = ((chat) instanceof snikket_Channel) ? chat : null;
+				if(channel != null) {
+					channel.selfPing(true);
+				}
+			}
+			let fwd = null;
+			if(from != null && from.asBare().asString() == _gthis.accountId()) {
+				let carbon = stanza.getChild("received","urn:xmpp:carbons:2");
+				if(carbon == null) {
+					carbon = stanza.getChild("sent","urn:xmpp:carbons:2");
+				}
+				if(carbon != null) {
+					let tmp = carbon.getChild("forwarded","urn:xmpp:forward:0");
+					fwd = tmp != null ? tmp.getFirstChild() : null;
+				}
+			}
+			let message = snikket_Message.fromStanza(stanza,_gthis.jid,function(builder,stanza) {
+				let chat = _gthis.getChat(builder.chatId());
+				if(chat == null && stanza.attr["type"] != "groupchat") {
+					chat = _gthis.getDirectChat(builder.chatId());
+				}
+				if(chat == null) {
+					return builder;
+				}
+				return chat.prepareIncomingMessage(builder,stanza);
+			});
+			let _g = message.parsed;
+			switch(_g._hx_index) {
+			case 1:
+				let chatMessage = _g.message;
+				let _g1 = 0;
+				let _g2 = chatMessage.inlineHashReferences();
+				while(_g1 < _g2.length) {
+					let hash = _g2[_g1];
+					++_g1;
+					_gthis.fetchMediaByHash([hash],[chatMessage.from]);
+				}
+				let chat = _gthis.getChat(chatMessage.chatId());
+				if(chat != null) {
+					let updateChat = function(chatMessage) {
+						_gthis.notifyMessageHandlers(chatMessage,chatMessage.versions.length > 1 ? 1 : 0);
+						if(chatMessage.versions.length < 1 || chat.lastMessageId() == chatMessage.serverId || chat.lastMessageId() == chatMessage.localId) {
+							chat.setLastMessage(chatMessage);
+							if(chatMessage.versions.length < 1) {
+								chat.setUnreadCount(chatMessage.isIncoming() ? chat.unreadCount() + 1 : 0);
+							}
+							_gthis.chatActivity(chat);
+						}
+					};
+					if(chatMessage.serverId == null) {
+						updateChat(chatMessage);
+					} else {
+						_gthis.storeMessages([chatMessage],function(stored) {
+							updateChat(stored[0]);
+						});
+					}
+				}
+				break;
+			case 2:
+				let action = _g.action;
+				_gthis.moderateMessage(action).then(function(stored) {
+					if(stored != null) {
+						_gthis.notifyMessageHandlers(stored,1);
+					}
+				});
+				break;
+			case 3:
+				let update = _g.update;
+				let _g3 = 0;
+				let _g4 = update.inlineHashReferences();
+				while(_g3 < _g4.length) {
+					let hash = _g4[_g3];
+					++_g3;
+					_gthis.fetchMediaByHash([hash],[from]);
+				}
+				persistence.storeReaction(_gthis.accountId(),update,function(stored) {
+					if(stored != null) {
+						_gthis.notifyMessageHandlers(stored,2);
+					}
+				});
+				break;
+			default:
+			}
+			let jmiP = stanza.getChild("propose","urn:xmpp:jingle-message:0");
+			if(jmiP != null && jmiP.attr["id"] != null) {
+				let session = new snikket_jingle_IncomingProposedSession(_gthis,from,jmiP.attr["id"]);
+				let chat = _gthis.getDirectChat(from.asBare().asString());
+				if(!chat.jingleSessions.has(session.get_sid())) {
+					chat.jingleSessions.set(session.get_sid(),session);
+					_gthis.chatActivity(chat);
+					session.ring();
+				}
+			}
+			let jmiR = stanza.getChild("retract","urn:xmpp:jingle-message:0");
+			if(jmiR != null && jmiR.attr["id"] != null) {
+				let chat = _gthis.getDirectChat(from.asBare().asString());
+				let session = chat.jingleSessions.get(jmiR.attr["id"]);
+				if(session != null) {
+					session.retract();
+					chat.jingleSessions.delete(session.get_sid());
+				}
+			}
+			let jmiProFwd = fwd != null ? fwd.getChild("proceed","urn:xmpp:jingle-message:0") : null;
+			if(jmiProFwd != null && jmiProFwd.attr["id"] != null) {
+				let chat = _gthis.getDirectChat(snikket_JID.parse(fwd.attr["to"]).asBare().asString());
+				let session = chat.jingleSessions.get(jmiProFwd.attr["id"]);
+				if(session != null) {
+					session.retract();
+					chat.jingleSessions.delete(session.get_sid());
+				}
+			}
+			let jmiPro = stanza.getChild("proceed","urn:xmpp:jingle-message:0");
+			if(jmiPro != null && jmiPro.attr["id"] != null) {
+				let chat = _gthis.getDirectChat(from.asBare().asString());
+				let session = chat.jingleSessions.get(jmiPro.attr["id"]);
+				if(session != null) {
+					try {
+						chat.jingleSessions.set(session.get_sid(),session.initiate(stanza));
+					} catch( _g ) {
+						let e = haxe_Exception.caught(_g);
+						haxe_Log.trace("JMI proceed failed",{ fileName : "snikket/Client.hx", lineNumber : 243, className : "snikket.Client", methodName : "new", customParams : [e]});
+					}
+				}
+			}
+			let jmiRej = stanza.getChild("reject","urn:xmpp:jingle-message:0");
+			if(jmiRej != null && jmiRej.attr["id"] != null) {
+				let chat = _gthis.getDirectChat(from.asBare().asString());
+				let session = chat.jingleSessions.get(jmiRej.attr["id"]);
+				if(session != null) {
+					session.retract();
+					chat.jingleSessions.delete(session.get_sid());
+				}
+			}
+			if(stanza.attr["type"] != "error") {
+				let chatState = stanza.getChild(null,"http://jabber.org/protocol/chatstates");
+				let userState;
+				let _g = chatState != null ? chatState.name : null;
+				if(_g == null) {
+					userState = null;
+				} else {
+					switch(_g) {
+					case "active":
+						userState = 2;
+						break;
+					case "composing":
+						userState = 3;
+						break;
+					case "gone":
+						userState = 0;
+						break;
+					case "inactive":
+						userState = 1;
+						break;
+					case "paused":
+						userState = 4;
+						break;
+					default:
+						userState = null;
+					}
+				}
+				if(userState != null) {
+					let chat = _gthis.getChat(from.asBare().asString());
+					if(chat == null || !chat.getParticipantDetails(message.senderId).isSelf) {
+						let _g = 0;
+						let _g1 = _gthis.chatStateHandlers;
+						while(_g < _g1.length) {
+							let handler = _g1[_g];
+							++_g;
+							handler(message.senderId,message.chatId,message.threadId,userState);
+						}
+					}
+				}
+			}
+			let pubsubEvent = snikket_PubsubEvent.fromStanza(stanza);
+			if(pubsubEvent != null && pubsubEvent.getFrom() != null && pubsubEvent.getNode() == "urn:xmpp:avatar:metadata" && pubsubEvent.getItems().length > 0) {
+				let item = pubsubEvent.getItems()[0];
+				let avatarSha1Hex = pubsubEvent.getItems()[0].attr["id"];
+				let tmp = snikket_Hash.fromHex("sha-1",avatarSha1Hex);
+				let avatarSha1 = tmp != null ? tmp.hash : null;
+				let metadata = item.getChild("metadata","urn:xmpp:avatar:metadata");
+				let mime = "image/png";
+				if(metadata != null) {
+					let info = metadata.getChild("info");
+					if(info != null && info.attr["type"] != null) {
+						mime = info.attr["type"];
+					}
+				}
+				if(avatarSha1 != null) {
+					let chat = _gthis.getDirectChat(snikket_JID.parse(pubsubEvent.getFrom()).asBare().asString(),false);
+					chat.setAvatarSha1(avatarSha1);
+					persistence.storeChats(_gthis.accountId(),[chat]);
+					persistence.hasMedia("sha-1",avatarSha1,function(has) {
+						if(has) {
+							_gthis.trigger("chats/update",[chat]);
+						} else {
+							let pubsubGet = new snikket_queries_PubsubGet(pubsubEvent.getFrom(),"urn:xmpp:avatar:data",avatarSha1Hex);
+							pubsubGet.onFinished(function() {
+								let item = pubsubGet.getResult()[0];
+								if(item == null) {
+									return;
+								}
+								let dataNode = item.getChild("data","urn:xmpp:avatar:data");
+								if(dataNode == null) {
+									return;
+								}
+								persistence.storeMedia(mime,haxe_crypto_Base64.decode(StringTools.replace(dataNode.getText(),"\n","")).b.bufferValue,function() {
+									_gthis.trigger("chats/update",[chat]);
+								});
+							});
+							_gthis.sendQuery(pubsubGet);
+						}
+					});
+				}
+			}
+			if(pubsubEvent != null && pubsubEvent.getFrom() != null && snikket_JID.parse(pubsubEvent.getFrom()).asBare().asString() == _gthis.accountId() && pubsubEvent.getNode() == "http://jabber.org/protocol/nick" && pubsubEvent.getItems().length > 0) {
+				_gthis.updateDisplayName(pubsubEvent.getItems()[0].getChildText("nick","http://jabber.org/protocol/nick"));
+			}
+			if(pubsubEvent != null && pubsubEvent.getFrom() != null && snikket_JID.parse(pubsubEvent.getFrom()).asBare().asString() == _gthis.accountId() && pubsubEvent.getNode() == "urn:xmpp:mds:displayed:0" && pubsubEvent.getItems().length > 0) {
+				let _g = 0;
+				let _g1 = pubsubEvent.getItems();
+				while(_g < _g1.length) {
+					let item = _g1[_g];
+					++_g;
+					if(item.attr["id"] != null) {
+						let tmp = item.getChild("displayed","urn:xmpp:mds:displayed:0");
+						let upTo = tmp != null ? tmp.getChild("stanza-id","urn:xmpp:sid:0") : null;
+						let chat = _gthis.getChat(item.attr["id"]);
+						if(chat == null) {
+							_gthis.startChatWith(item.attr["id"],function(caps) {
+								return 2;
+							},function(chat) {
+								chat.markReadUpToId(upTo.attr["id"],upTo.attr["by"]);
+							});
+						} else {
+							chat.markReadUpToId(upTo.attr["id"],upTo.attr["by"],function() {
+								persistence.storeChats(_gthis.accountId(),[chat]);
+								_gthis.trigger("chats/update",[chat]);
+							});
+						}
+					}
+				}
+			}
+			return snikket_EventResult.EventUnhandled;
+		});
+		this.stream.onIq(snikket_IqRequestType.Set,"jingle","urn:xmpp:jingle:1",function(stanza) {
+			let from = stanza.attr["from"] == null ? null : snikket_JID.parse(stanza.attr["from"]);
+			let jingle = stanza.getChild("jingle","urn:xmpp:jingle:1");
+			let chat = _gthis.getDirectChat(from.asBare().asString());
+			let session = chat.jingleSessions.get(jingle.attr["sid"]);
+			if(jingle.attr["action"] == "session-initiate") {
+				if(session != null) {
+					try {
+						chat.jingleSessions.set(session.get_sid(),session.initiate(stanza));
+					} catch( _g ) {
+						let e = haxe_Exception.caught(_g);
+						haxe_Log.trace("Bad session-inititate",{ fileName : "snikket/Client.hx", lineNumber : 350, className : "snikket.Client", methodName : "new", customParams : [e]});
+						chat.jingleSessions.delete(session.get_sid());
+					}
+				} else {
+					let newSession = snikket_jingle_InitiatedSession.fromSessionInitiate(_gthis,stanza);
+					chat.jingleSessions.set(newSession.get_sid(),newSession);
+					_gthis.chatActivity(chat);
+					newSession.ring();
+				}
+			}
+			if(session != null && jingle.attr["action"] == "session-accept") {
+				try {
+					chat.jingleSessions.set(session.get_sid(),session.initiate(stanza));
+				} catch( _g ) {
+					let e = haxe_Exception.caught(_g);
+					haxe_Log.trace("session-accept failed",{ fileName : "snikket/Client.hx", lineNumber : 365, className : "snikket.Client", methodName : "new", customParams : [e]});
+				}
+			}
+			if(session != null && jingle.attr["action"] == "session-terminate") {
+				session.terminate();
+				chat.jingleSessions.delete(jingle.attr["sid"]);
+			}
+			if(session != null && jingle.attr["action"] == "content-add") {
+				session.contentAdd(stanza);
+			}
+			if(session != null && jingle.attr["action"] == "content-accept") {
+				session.contentAccept(stanza);
+			}
+			if(session != null && jingle.attr["action"] == "transport-info") {
+				session.transportInfo(stanza);
+			}
+			return snikket_IqResult.IqResult;
+		});
+		this.stream.onIq(snikket_IqRequestType.Get,"query","http://jabber.org/protocol/disco#info",function(stanza) {
+			return snikket_IqResult.IqResultElement(_gthis.caps.discoReply());
+		});
+		this.stream.onIq(snikket_IqRequestType.Set,"query","jabber:iq:roster",function(stanza) {
+			if(stanza.attr["from"] != null && stanza.attr["from"] != _gthis.jid.domain) {
+				return snikket_IqResult.IqNoResult;
+			}
+			let roster = new snikket_queries_RosterGet();
+			roster.handleResponse(stanza);
+			let items = roster.getResult();
+			if(items.length == 0) {
+				return snikket_IqResult.IqNoResult;
+			}
+			let chatsToUpdate = [];
+			let _g = 0;
+			while(_g < items.length) {
+				let item = items[_g];
+				++_g;
+				if(item.subscription != "remove") {
+					let chat = _gthis.getDirectChat(item.jid,false);
+					chat.updateFromRoster(item);
+					chatsToUpdate.push(js_Boot.__cast(chat , snikket_Chat));
+				}
+			}
+			persistence.storeChats(_gthis.accountId(),chatsToUpdate);
+			_gthis.trigger("chats/update",chatsToUpdate);
+			return snikket_IqResult.IqResult;
+		});
+		this.stream.onIq(snikket_IqRequestType.Set,"block","urn:xmpp:blocking",function(stanza) {
+			if(stanza.attr["from"] != null && stanza.attr["from"] != _gthis.jid.domain) {
+				return snikket_IqResult.IqNoResult;
+			}
+			let _g = 0;
+			let tmp = stanza.getChild("block","urn:xmpp:blocking");
+			let tmp1 = tmp != null ? tmp.allTags("item") : null;
+			let _g1 = tmp1 != null ? tmp1 : [];
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				if(item.attr["jid"] != null) {
+					_gthis.serverBlocked(item.attr["jid"]);
+				}
+			}
+			return snikket_IqResult.IqResult;
+		});
+		this.stream.onIq(snikket_IqRequestType.Set,"unblock","urn:xmpp:blocking",function(stanza) {
+			if(stanza.attr["from"] != null && stanza.attr["from"] != _gthis.jid.domain) {
+				return snikket_IqResult.IqNoResult;
+			}
+			let tmp = stanza.getChild("unblock","urn:xmpp:blocking");
+			let unblocks = tmp != null ? tmp.allTags("item") : null;
+			if(unblocks == null) {
+				let _g = 0;
+				let _g1 = _gthis.chats;
+				while(_g < _g1.length) {
+					let chat = _g1[_g];
+					++_g;
+					if(chat.isBlocked) {
+						chat.unblock(false);
+					}
+				}
+			} else {
+				let _g = 0;
+				while(_g < unblocks.length) {
+					let item = unblocks[_g];
+					++_g;
+					if(item.attr["jid"] != null) {
+						let tmp = _gthis.getChat(item.attr["jid"]);
+						if(tmp != null) {
+							tmp.unblock(false);
+						}
+					}
+				}
+			}
+			return snikket_IqResult.IqResult;
+		});
+		this.stream.on("presence",function(event) {
+			let stanza = event.stanza;
+			let c = stanza.getChild("c","http://jabber.org/protocol/caps");
+			let mucUser = stanza.getChild("x","http://jabber.org/protocol/muc#user");
+			if(stanza.attr["from"] != null && stanza.attr["type"] == null) {
+				let from = snikket_JID.parse(stanza.attr["from"]);
+				let chat = _gthis.getChat(from.asBare().asString());
+				if(chat == null) {
+					haxe_Log.trace("Presence for unknown JID: " + stanza.attr["from"],{ fileName : "snikket/Client.hx", lineNumber : 467, className : "snikket.Client", methodName : "new"});
+					return snikket_EventResult.EventUnhandled;
+				}
+				if(c == null) {
+					chat.setPresence(snikket_JID.parse(stanza.attr["from"]).resource,new snikket_Presence(null,mucUser));
+					persistence.storeChats(_gthis.accountId(),[chat]);
+					if(chat.livePresence()) {
+						_gthis.trigger("chats/update",[chat]);
+					}
+				} else {
+					let handleCaps = function(caps) {
+						chat.setPresence(snikket_JID.parse(stanza.attr["from"]).resource,new snikket_Presence(caps,mucUser));
+						if(mucUser == null || chat.livePresence()) {
+							persistence.storeChats(_gthis.accountId(),[chat]);
+						}
+						return chat;
+					};
+					persistence.getCaps(c.attr["ver"],function(caps) {
+						if(caps == null) {
+							let pending = _gthis.pendingCaps.get(c.attr["ver"]);
+							if(pending == null) {
+								_gthis.pendingCaps.set(c.attr["ver"],[handleCaps]);
+								let discoGet = new snikket_queries_DiscoInfoGet(stanza.attr["from"],c.attr["node"] + "#" + c.attr["ver"]);
+								discoGet.onFinished(function() {
+									let chatsToUpdate = new Map([]);
+									let tmp = _gthis.pendingCaps.get(c.attr["ver"]);
+									let handlers = tmp != null ? tmp : [];
+									_gthis.pendingCaps.delete(c.attr["ver"]);
+									if(discoGet.getResult() != null) {
+										persistence.storeCaps(discoGet.getResult());
+									}
+									let _g = 0;
+									while(_g < handlers.length) {
+										let handler = handlers[_g];
+										++_g;
+										let c = handler(discoGet.getResult());
+										if(c.livePresence()) {
+											chatsToUpdate.set(c.chatId,c);
+										}
+									}
+									_gthis.trigger("chats/update",Lambda.array({ iterator : function() {
+										return new js_lib_HaxeIterator(chatsToUpdate.values());
+									}}));
+								});
+								_gthis.sendQuery(discoGet);
+							} else {
+								pending.push(handleCaps);
+							}
+						} else {
+							handleCaps(caps);
+						}
+					});
+				}
+				if(from.isBare()) {
+					let avatarSha1Hex = stanza.findText("{vcard-temp:x:update}x/photo#");
+					if(avatarSha1Hex != null) {
+						let tmp = snikket_Hash.fromHex("sha-1",avatarSha1Hex);
+						let avatarSha1 = tmp != null ? tmp.hash : null;
+						chat.setAvatarSha1(avatarSha1);
+						persistence.storeChats(_gthis.accountId(),[chat]);
+						persistence.hasMedia("sha-1",avatarSha1,function(has) {
+							if(has) {
+								if(chat.livePresence()) {
+									_gthis.trigger("chats/update",[chat]);
+								}
+							} else {
+								let vcardGet = new snikket_queries_VcardTempGet(from);
+								vcardGet.onFinished(function() {
+									let vcard = vcardGet.getResult();
+									if(vcard.photo == null) {
+										return;
+									}
+									persistence.storeMedia(vcard.photo.mime,vcard.photo.data.b.bufferValue,function() {
+										_gthis.trigger("chats/update",[chat]);
+									});
+								});
+								_gthis.sendQuery(vcardGet);
+							}
+						});
+					}
+				}
+				return snikket_EventResult.EventHandled;
+			}
+			if(stanza.attr["from"] != null && stanza.attr["type"] == "unavailable") {
+				let chat = _gthis.getChat(snikket_JID.parse(stanza.attr["from"]).asBare().asString());
+				if(chat == null) {
+					haxe_Log.trace("Presence for unknown JID: " + stanza.attr["from"],{ fileName : "snikket/Client.hx", lineNumber : 536, className : "snikket.Client", methodName : "new"});
+					return snikket_EventResult.EventUnhandled;
+				}
+				chat.removePresence(snikket_JID.parse(stanza.attr["from"]).resource);
+				persistence.storeChats(_gthis.accountId(),[chat]);
+				_gthis.trigger("chats/update",[chat]);
+			}
+			return snikket_EventResult.EventUnhandled;
+		});
+	}
+	start() {
+		let _gthis = this;
+		this.persistence.getLogin(this.accountId(),function(clientId,loadedToken,fastCount,displayName) {
+			_gthis.token = loadedToken;
+			_gthis.persistence.getStreamManagement(_gthis.accountId(),function(sm) {
+				let tmp = clientId;
+				let tmp1 = tmp != null ? tmp : snikket_ID.long();
+				_gthis.stream.clientId = tmp1;
+				_gthis.jid = _gthis.jid.withResource(_gthis.stream.clientId);
+				if(!_gthis.updateDisplayName(displayName) && clientId == null) {
+					_gthis.persistence.storeLogin(_gthis.jid.asBare().asString(),_gthis.stream.clientId,_gthis.displayName(),null);
+				}
+				_gthis.persistence.getChats(_gthis.accountId(),function(protoChats) {
+					let _g = 0;
+					while(_g < protoChats.length) {
+						let protoChat = protoChats[_g];
+						++_g;
+						_gthis.chats.push(protoChat.toChat(_gthis,_gthis.stream,_gthis.persistence));
+					}
+					_gthis.persistence.getChatsUnreadDetails(_gthis.accountId(),_gthis.chats,function(details) {
+						let _g = 0;
+						while(_g < details.length) {
+							let detail = details[_g];
+							++_g;
+							let chat = _gthis.getChat(detail.chatId);
+							if(chat != null) {
+								chat.setLastMessage(detail.message);
+								chat.setUnreadCount(detail.unreadCount);
+							}
+						}
+						_gthis.sortChats();
+						_gthis.trigger("chats/update",_gthis.chats);
+						_gthis.stream.on("auth/password-needed",function(data) {
+							let tmp = data.mechanisms;
+							let tmp1 = tmp != null ? tmp.find(function(mech) {
+								return mech.canFast;
+							}) : null;
+							_gthis.fastMechanism = tmp1 != null ? tmp1.name : null;
+							if(_gthis.token == null || _gthis.fastMechanism == null && data.mechanimsms != null) {
+								return _gthis.trigger("auth/password-needed",{ accountId : _gthis.accountId()});
+							} else {
+								return _gthis.stream.trigger("auth/password",{ password : _gthis.token, mechanism : _gthis.fastMechanism, fastCount : fastCount});
+							}
+						});
+						_gthis.stream.on("auth/fail",function(data) {
+							if(_gthis.token != null) {
+								_gthis.token = null;
+								_gthis.stream.connect(_gthis.jid.asString(),sm);
+							} else {
+								_gthis.stream.connect(_gthis.jid.asString(),sm);
+							}
+							return snikket_EventResult.EventHandled;
+						});
+						_gthis.stream.connect(_gthis.jid.asString(),sm);
+					});
+				});
+			});
+		});
+	}
+	logout(completely) {
+		this.persistence.removeAccount(this.accountId(),completely);
+		let disable = new snikket_queries_Push2Disable(this.jid.asBare().asString());
+		let _gthis = this;
+		disable.onFinished(function() {
+			_gthis.stream.disconnect();
+		});
+		this.sendQuery(disable);
+	}
+	usePassword(password) {
+		this.stream.trigger("auth/password",{ password : password, requestToken : this.fastMechanism});
+	}
+	accountId() {
+		return this.jid.asBare().asString();
+	}
+	displayName() {
+		return this._displayName;
+	}
+	setDisplayName(displayName) {
+		if(displayName == null || displayName == "" || displayName == this.displayName()) {
+			return;
+		}
+		this.stream.sendIq(new snikket_Stanza("iq",{ type : "set"}).tag("pubsub",{ xmlns : "http://jabber.org/protocol/pubsub"}).tag("publish",{ node : "http://jabber.org/protocol/nick"}).tag("item").textTag("nick",displayName,{ xmlns : "http://jabber.org/protocol/nick"}).up().up().up(),function(response) {
+		});
+	}
+	updateDisplayName(fn) {
+		if(fn == null || fn == "" || fn == this.displayName()) {
+			return false;
+		}
+		this._displayName = fn;
+		let tmp = this.persistence;
+		let tmp1 = this.jid.asBare().asString();
+		let tmp2 = this.stream.clientId;
+		tmp.storeLogin(tmp1,tmp2 != null ? tmp2 : this.jid.resource,fn,null);
+		this.pingAllChannels(false);
+		return true;
+	}
+	onConnected(data) {
+		if(data != null && data.jid != null) {
+			this.jid = snikket_JID.parse(data.jid);
+			if(this.stream.clientId == null && !this.jid.isBare()) {
+				this.persistence.storeLogin(this.jid.asBare().asString(),this.jid.resource,this.displayName(),null);
+			}
+		}
+		if(data.resumed) {
+			this.inSync = true;
+			this.trigger("status/online",{ });
+			return snikket_EventResult.EventHandled;
+		}
+		let _gthis = this;
+		this.discoverServices(new snikket_JID(null,this.jid.domain),null,function(service,caps) {
+			_gthis.persistence.storeService(_gthis.accountId(),service.jid.asString(),service.name,service.node,caps);
+		});
+		this.rosterGet();
+		haxe_Log.trace("SYNC: bookmarks",{ fileName : "snikket/Client.hx", lineNumber : 687, className : "snikket.Client", methodName : "onConnected"});
+		this.bookmarksGet(function() {
+			haxe_Log.trace("SYNC: MAM",{ fileName : "snikket/Client.hx", lineNumber : 689, className : "snikket.Client", methodName : "onConnected"});
+			_gthis.sync(function(syncFinished) {
+				if(!syncFinished) {
+					haxe_Log.trace("SYNC: failed",{ fileName : "snikket/Client.hx", lineNumber : 692, className : "snikket.Client", methodName : "onConnected"});
+					_gthis.inSync = false;
+					_gthis.stream.disconnect();
+					return;
+				}
+				haxe_Log.trace("SYNC: details",{ fileName : "snikket/Client.hx", lineNumber : 699, className : "snikket.Client", methodName : "onConnected"});
+				_gthis.inSync = true;
+				_gthis.persistence.getChatsUnreadDetails(_gthis.accountId(),_gthis.chats,function(details) {
+					let _g = 0;
+					while(_g < details.length) {
+						let detail = details[_g];
+						++_g;
+						let tmp = _gthis.getChat(detail.chatId);
+						let chat = tmp != null ? tmp : _gthis.getDirectChat(detail.chatId,false);
+						let initialLastId = chat.lastMessageId();
+						chat.setLastMessage(detail.message);
+						chat.setUnreadCount(detail.unreadCount);
+						if(detail.unreadCount > 0 && initialLastId != chat.lastMessageId()) {
+							_gthis.chatActivity(chat,false);
+						}
+					}
+					_gthis.sortChats();
+					_gthis.trigger("chats/update",_gthis.chats);
+					if(_gthis.sendAvailable) {
+						_gthis.sendStanza(new snikket_Stanza("iq",{ type : "set", id : snikket_ID.short()}).tag("enable",{ xmlns : "urn:xmpp:carbons:2"}).up());
+						_gthis.sendPresence();
+						_gthis.pingAllChannels(true);
+					}
+					_gthis.trigger("status/online",{ });
+					haxe_Log.trace("SYNC: done",{ fileName : "snikket/Client.hx", lineNumber : 725, className : "snikket.Client", methodName : "onConnected"});
+				});
+			});
+		});
+		this.trigger("session-started",{ });
+		return snikket_EventResult.EventHandled;
+	}
+	prepareAttachment(source,callback) {
+		let _gthis = this;
+		this.persistence.findServicesWithFeature(this.accountId(),"urn:xmpp:http:upload:0",function(services) {
+			let sha256 = new sha_SHA256();
+			let options = null;
+			let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+			tink_io_Source.chunked(new tink_io_js_BlobSource(source.name,source,0,chunkSize)).forEach(tink_streams_Handler.ofSafeSync(function(chunk) {
+				sha256.update(chunk.toBytes());
+				return tink_streams_Handled.Resume;
+			})).handle(function(o) {
+				if(o._hx_index == 3) {
+					_gthis.prepareAttachmentFor(source,services,[new snikket_Hash("sha-256",sha256.digest().b.bufferValue)],callback);
+				} else {
+					haxe_Log.trace("Error computing attachment hash",{ fileName : "snikket/Client.hx", lineNumber : 748, className : "snikket.Client", methodName : "prepareAttachment", customParams : [o]});
+					callback(null);
+				}
+			});
+		});
+	}
+	prepareAttachmentFor(source,services,hashes,callback) {
+		if(services.length < 1) {
+			callback(null);
+			return;
+		}
+		let httpUploadSlot = new snikket_queries_HttpUploadSlot(services[0].serviceId,source.name,source.size,source.type,hashes);
+		let _gthis = this;
+		httpUploadSlot.onFinished(function() {
+			let slot = httpUploadSlot.getResult();
+			if(slot == null) {
+				_gthis.prepareAttachmentFor(source,services.slice(1),hashes,callback);
+			} else {
+				let url = tink_Url.fromString(slot.put);
+				let options = null;
+				let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+				tink_http_FetchResponse.all(tink_http_Fetch.fetch(url,{ method : "PUT", headers : slot.putHeaders, body : tink_io_RealSourceTools.idealize(new tink_io_js_BlobSource(source.name,source,0,chunkSize),function(e) {
+					throw haxe_Exception.thrown(e);
+				})})).handle(function(o) {
+					if(o._hx_index == 0) {
+						let res = o.data;
+						if(res.header.statusCode == 201) {
+							callback(new snikket_ChatAttachment(source.name,source.type,source.size,[slot.get],hashes));
+						} else {
+							_gthis.prepareAttachmentFor(source,services.slice(1),hashes,callback);
+						}
+					} else {
+						_gthis.prepareAttachmentFor(source,services.slice(1),hashes,callback);
+					}
+				});
+			}
+		});
+		this.sendQuery(httpUploadSlot);
+	}
+	getChats() {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.chats;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.uiState != 2) {
+				_g.push(v);
+			}
+		}
+		return _g;
+	}
+	findAvailableChats(q,callback) {
+		let results = [];
+		let query = StringTools.trim(q);
+		let _gthis = this;
+		let checkAndAdd = function(jid,prepend) {
+			if(prepend == null) {
+				prepend = false;
+			}
+			let add = function(item) {
+				if(prepend) {
+					results.unshift(item);
+				} else {
+					results.push(item);
+				}
+			};
+			let discoGet = new snikket_queries_DiscoInfoGet(jid.asString());
+			discoGet.onFinished(function() {
+				let resultCaps = discoGet.getResult();
+				if(resultCaps == null) {
+					let tmp = discoGet.responseStanza;
+					let tmp1 = tmp != null ? tmp.getChild("error") : null;
+					let err = tmp1 != null ? tmp1.getChild(null,"urn:ietf:params:xml:ns:xmpp-stanzas") : null;
+					if(err == null || (err != null ? err.name : null) == "service-unavailable" || (err != null ? err.name : null) == "feature-not-implemented") {
+						add(new snikket_AvailableChat(jid.asString(),query,jid.asString(),new snikket_Caps("",[],[])));
+					}
+				} else {
+					_gthis.persistence.storeCaps(resultCaps);
+					let identity = resultCaps.identities[0];
+					let tmp = identity != null ? identity.name : null;
+					let displayName = tmp != null ? tmp : query;
+					let note = jid.asString() + (identity == null ? "" : " (" + identity.type + ")");
+					add(new snikket_AvailableChat(jid.asString(),displayName,note,resultCaps));
+				}
+				callback(q,results);
+			});
+			_gthis.sendQuery(discoGet);
+		};
+		let jid = query.startsWith("xmpp:") ? snikket_JID.parse(HxOverrides.substr(query,5,null)) : snikket_JID.parse(query);
+		if(jid.isValid()) {
+			checkAndAdd(jid,true);
+		}
+		let _g = 0;
+		let _g1 = this.chats;
+		while(_g < _g1.length) {
+			let chat = _g1[_g];
+			++_g;
+			if(chat.chatId != jid.asBare().asString()) {
+				if(chat.chatId.includes(query.toLowerCase()) || chat.getDisplayName().toLowerCase().includes(query.toLowerCase())) {
+					let channel = snikket_Util_downcast(chat,snikket_Channel);
+					results.push(new snikket_AvailableChat(chat.chatId,chat.getDisplayName(),chat.chatId,channel == null || channel.disco == null ? new snikket_Caps("",[],[]) : channel.disco));
+				}
+			}
+			if(chat.isTrusted()) {
+				let resources = new Map([]);
+				let _g = 0;
+				let _g1 = snikket_Caps.withIdentity(chat.getCaps(),"gateway",null);
+				while(_g < _g1.length) {
+					let resource = _g1[_g];
+					++_g;
+					resources.set(resource,true);
+				}
+				let _g2 = 0;
+				let _g3 = snikket_Caps.withFeature(chat.getCaps(),"jabber:iq:gateway");
+				while(_g2 < _g3.length) {
+					let resource = _g3[_g2];
+					++_g2;
+					resources.set(resource,true);
+				}
+				if(!this.sendAvailable && snikket_JID.parse(chat.chatId).isDomain()) {
+					resources.set(null,true);
+				}
+				let jsIterator = resources.keys();
+				let _g_jsIterator = jsIterator;
+				let _g_lastStep = jsIterator.next();
+				while(!_g_lastStep.done) {
+					let v = _g_lastStep.value;
+					_g_lastStep = _g_jsIterator.next();
+					let resource = v;
+					let bareJid = snikket_JID.parse(chat.chatId);
+					let fullJid = new snikket_JID(bareJid.node,bareJid.domain,resource);
+					let jigGet = new snikket_queries_JabberIqGatewayGet(fullJid.asString(),query);
+					jigGet.onFinished(function() {
+						if(jigGet.getResult() == null) {
+							let caps = chat.getResourceCaps(resource);
+							if(bareJid.isDomain() && caps.features.includes("jid\\20escaping")) {
+								checkAndAdd(new snikket_JID(query,bareJid.domain));
+							} else if(bareJid.isDomain()) {
+								checkAndAdd(new snikket_JID(StringTools.replace(query,"@","%"),bareJid.domain));
+							}
+						} else {
+							let _g = jigGet.getResult();
+							switch(_g._hx_index) {
+							case 0:
+								let error = _g.v;
+								return;
+							case 1:
+								let result = _g.v;
+								checkAndAdd(snikket_JID.parse(result));
+								break;
+							}
+						}
+					});
+					this.sendQuery(jigGet);
+				}
+			}
+		}
+		if(!jid.isValid() && results.length > 0) {
+			callback(q,results);
+		}
+	}
+	startChat(availableChat) {
+		let existingChat = this.getChat(availableChat.chatId);
+		if(existingChat != null) {
+			let channel = ((existingChat) instanceof snikket_Channel) ? existingChat : null;
+			if(channel == null && availableChat.isChannel() || channel != null && !availableChat.isChannel()) {
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = this.chats;
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(v.chatId != availableChat.chatId) {
+						_g.push(v);
+					}
+				}
+				this.chats = _g;
+			} else {
+				if(existingChat.uiState == 2) {
+					existingChat.uiState = 1;
+				}
+				if(channel != null) {
+					channel.selfPing(true);
+				}
+				this.persistence.storeChats(this.accountId(),[existingChat]);
+				this.trigger("chats/update",[existingChat]);
+				return existingChat;
+			}
+		}
+		let chat;
+		if(availableChat.isChannel()) {
+			let channel = new snikket_Channel(this,this.stream,this.persistence,availableChat.chatId,1,false,null,null,null,availableChat.caps);
+			this.chats.unshift(channel);
+			channel.selfPing(false);
+			chat = channel;
+		} else {
+			chat = this.getDirectChat(availableChat.chatId,false);
+		}
+		this.persistence.storeChats(this.accountId(),[chat]);
+		this.trigger("chats/update",[chat]);
+		return chat;
+	}
+	getChat(chatId) {
+		return Lambda.find(this.chats,function(chat) {
+			return chat.chatId == chatId;
+		});
+	}
+	moderateMessage(action) {
+		let _gthis = this;
+		return thenshim_Promise._new(function(resolve,reject) {
+			_gthis.persistence.getMessage(_gthis.accountId(),action.chatId,action.moderateServerId,null,function(moderateMessage) {
+				if(moderateMessage == null) {
+					resolve(null);
+					return;
+				}
+				let _g = 0;
+				let _g1 = moderateMessage.attachments;
+				while(_g < _g1.length) {
+					let attachment = _g1[_g];
+					++_g;
+					let _g2 = 0;
+					let _g3 = attachment.hashes;
+					while(_g2 < _g3.length) {
+						let hash = _g3[_g2];
+						++_g2;
+						_gthis.persistence.removeMedia(hash.algorithm,hash.hash);
+					}
+				}
+				moderateMessage = snikket_ChatMessageBuilder.makeModerated(moderateMessage,action.timestamp,action.moderatorId,action.reason);
+				_gthis.persistence.updateMessage(_gthis.accountId(),moderateMessage);
+				resolve(moderateMessage);
+			});
+		});
+	}
+	getDirectChat(chatId,triggerIfNew) {
+		if(triggerIfNew == null) {
+			triggerIfNew = true;
+		}
+		let _g = 0;
+		let _g1 = this.chats;
+		while(_g < _g1.length) {
+			let chat = _g1[_g];
+			++_g;
+			if(((chat) instanceof snikket_DirectChat) && chat.chatId == chatId) {
+				if(((chat) instanceof snikket_DirectChat)) {
+					return chat;
+				} else {
+					return null;
+				}
+			}
+		}
+		let chat = new snikket_DirectChat(this,this.stream,this.persistence,chatId);
+		this.persistence.storeChats(this.accountId(),[chat]);
+		this.chats.unshift(chat);
+		if(triggerIfNew) {
+			this.trigger("chats/update",[chat]);
+		}
+		return chat;
+	}
+	subscribePush(reg,push_service,vapid_key) {
+		let _gthis = this;
+		window.crypto.subtle.exportKey("raw",vapid_key.publicKey).then(function(vapid_public_raw) {
+			return reg.pushManager.subscribe({ userVisibleOnly : true, applicationServerKey : vapid_public_raw}).then(function(pushSubscription) {
+				if(pushSubscription == null) {
+					haxe_Log.trace("WebPush subscription failed",{ fileName : "snikket/Client.hx", lineNumber : 950, className : "snikket.Client", methodName : "subscribePush"});
+					return;
+				}
+				_gthis.enablePush(push_service,vapid_key.privateKey,pushSubscription.endpoint,pushSubscription.getKey("p256dh"),pushSubscription.getKey("auth"));
+			});
+		});
+	}
+	enablePush(push_service,vapid_private_key,endpoint,p256dh,auth) {
+		let _gthis = this;
+		window.crypto.subtle.exportKey("pkcs8",vapid_private_key).then(function(vapid_private_pkcs8) {
+			let _gthis1 = _gthis;
+			let tmp = _gthis.jid.asBare().asString();
+			let push_service1 = push_service;
+			let endpoint1 = endpoint;
+			let tmp1 = haxe_io_Bytes.ofData(p256dh);
+			let tmp2 = haxe_io_Bytes.ofData(auth);
+			let tmp3 = haxe_io_Bytes.ofData(vapid_private_pkcs8);
+			let _g = new haxe_ds_StringMap();
+			let value = new URL(endpoint).origin;
+			_g.h["aud"] = value;
+			_gthis1.sendQuery(new snikket_queries_Push2Enable(tmp,push_service1,endpoint1,tmp1,tmp2,"ES256",tmp3,snikket_Map.fromMap(_g)));
+		});
+	}
+	addPasswordNeededListener(handler) {
+		let _gthis = this;
+		this.on("auth/password-needed",function(data) {
+			handler(_gthis);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addStatusOnlineListener(handler) {
+		this.on("status/online",function(data) {
+			handler();
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addStatusOfflineListener(handler) {
+		this.on("status/offline",function(data) {
+			handler();
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addConnectionFailedListener(handler) {
+		this.stream.on("status/error",function(data) {
+			handler();
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addUserStateListener(handler) {
+		this.chatStateHandlers.push(handler);
+	}
+	addChatMessageListener(handler) {
+		this.chatMessageHandlers.push(handler);
+	}
+	addSyncMessageListener(handler) {
+		this.syncMessageHandlers.push(handler);
+	}
+	addChatsUpdatedListener(handler) {
+		this.on("chats/update",function(data) {
+			handler(data);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallRingListener(handler) {
+		this.on("call/ring",function(data) {
+			handler(data.session,data.chatId);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallRetractListener(handler) {
+		this.on("call/retract",function(data) {
+			handler(data.chatId);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallRingingListener(handler) {
+		this.on("call/ringing",function(data) {
+			handler(data.chatId);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallMediaListener(handler) {
+		this.on("call/media",function(data) {
+			handler(data.session,data.audio,data.video);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	addCallTrackListener(handler) {
+		this.on("call/track",function(data) {
+			handler(data.chatId,data.track,data.streams);
+			return snikket_EventResult.EventHandled;
+		});
+	}
+	setInForeground() {
+		if(!this.stream.csi) {
+			return;
+		}
+		this.stream.sendStanza(new snikket_Stanza("active",{ xmlns : "urn:xmpp:csi:0"}));
+	}
+	setNotInForeground() {
+		if(!this.stream.csi) {
+			return;
+		}
+		this.stream.sendStanza(new snikket_Stanza("inactive",{ xmlns : "urn:xmpp:csi:0"}));
+	}
+	fetchMediaByHash(hashes,counterparts) {
+		if(hashes.length < 1 || counterparts.length < 1) {
+			return thenshim_Promise.reject("no counterparts left");
+		}
+		let _gthis = this;
+		return thenshim_Promise.then(this.fetchMediaByHashOneCounterpart(hashes,counterparts[0]),function(x) {
+			return x;
+		},function(_) {
+			return _gthis.fetchMediaByHash(hashes,counterparts.slice(1));
+		});
+	}
+	fetchMediaByHashOneCounterpart(hashes,counterpart) {
+		if(hashes.length < 1) {
+			return thenshim_Promise.reject("no hashes left");
+		}
+		let _gthis = this;
+		return thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+			_gthis.persistence.hasMedia(hashes[0].algorithm,hashes[0].hash,resolve);
+		}),function(has) {
+			if(has) {
+				return thenshim_Promise.resolve(null);
+			}
+			return thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+				let q = snikket_queries_BoB.forHash(counterpart.asString(),hashes[0]);
+				q.onFinished(function() {
+					let r = q.getResult();
+					if(r == null) {
+						reject("bad or no result from BoB query");
+					} else {
+						_gthis.persistence.storeMedia(r.type,r.bytes.b.bufferValue,function() {
+							resolve(null);
+						});
+					}
+				});
+				_gthis.sendQuery(q);
+			}),function(x) {
+				return x;
+			},function(_) {
+				return _gthis.fetchMediaByHashOneCounterpart(hashes.slice(1),counterpart);
+			});
+		});
+	}
+	chatActivity(chat,trigger) {
+		if(trigger == null) {
+			trigger = true;
+		}
+		if(chat.isBlocked) {
+			return;
+		}
+		if(chat.uiState == 2) {
+			chat.uiState = 1;
+			this.persistence.storeChats(this.accountId(),[chat]);
+		}
+		let pinnedCount = chat.uiState == 0 ? 0 : Lambda.fold(this.chats,function(item,result) {
+			return result + (item.uiState == 0 ? 1 : 0);
+		},0);
+		let idx = this.chats.indexOf(chat);
+		if(idx > pinnedCount) {
+			this.chats.splice(idx,1);
+			this.chats.splice(pinnedCount,0,chat);
+		}
+		if(trigger) {
+			this.trigger("chats/update",[chat]);
+		}
+	}
+	sortChats() {
+		this.chats.sort(function(a,b) {
+			if(a.uiState == 0 && b.uiState != 0) {
+				return -1;
+			}
+			if(b.uiState == 0 && a.uiState != 0) {
+				return 1;
+			}
+			let tmp = a.lastMessageTimestamp();
+			let tmp1 = b.lastMessageTimestamp();
+			return -Reflect.compare(tmp != null ? tmp : "0",tmp1 != null ? tmp1 : "0");
+		});
+	}
+	storeMessages(messages,callback) {
+		let tmp = callback;
+		this.persistence.storeMessages(this.accountId(),messages,tmp != null ? tmp : function(_) {
+		});
+	}
+	sendQuery(query) {
+		this.stream.sendIq(query.getQueryStanza(),$bind(query,query.handleResponse));
+	}
+	sendStanza(stanza) {
+		if(stanza.attr["id"] == null) {
+			stanza.attr["id"] = snikket_ID.long();
+		}
+		this.stream.sendStanza(stanza);
+	}
+	sendPresence(to,augment) {
+		let tmp = augment;
+		this.sendStanza((tmp != null ? tmp : function(s) {
+			return s;
+		})(this.caps.addC(new snikket_Stanza("presence",to == null ? { } : { to : to})).textTag("nick",this.displayName(),{ xmlns : "http://jabber.org/protocol/nick"})));
+	}
+	getIceServers(callback) {
+		let extDiscoGet = new snikket_queries_ExtDiscoGet(this.jid.domain);
+		extDiscoGet.onFinished(function() {
+			let didUrl = new Map([]);
+			let servers = [];
+			let _g = 0;
+			let tmp = extDiscoGet.getResult();
+			let _g1 = tmp != null ? tmp : [];
+			while(_g < _g1.length) {
+				let service = _g1[_g];
+				++_g;
+				if(!["stun","stuns","turn","turns"].includes(service.attr["type"])) {
+					continue;
+				}
+				let host = service.attr["host"];
+				if(host == null || host == "") {
+					continue;
+				}
+				let port = Std.parseInt(service.attr["port"]);
+				if(port == null || port < 1 || port > 65535) {
+					continue;
+				}
+				let isTurn = ["turn","turns"].includes(service.attr["type"]);
+				let url = service.attr["type"] + ":" + (host.indexOf(":") >= 0 ? "[" + host + "]" : host) + ":" + port + (isTurn ? "?transport=" + service.attr["transport"] : "");
+				if(!didUrl.has(url)) {
+					servers.push({ username : service.attr["username"], credential : service.attr["password"], urls : [url]});
+					didUrl.set(url,true);
+				}
+			}
+			callback(servers);
+		});
+		this.sendQuery(extDiscoGet);
+	}
+	discoverServices(target,node,callback) {
+		let itemsGet = new snikket_queries_DiscoItemsGet(target.asString(),node);
+		let _gthis = this;
+		itemsGet.onFinished(function() {
+			let _g = 0;
+			let tmp = itemsGet.getResult();
+			let _g1 = tmp != null ? tmp : [];
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				let infoGet = new snikket_queries_DiscoInfoGet(item.jid.asString(),item.node);
+				infoGet.onFinished(function() {
+					callback(item,infoGet.getResult());
+				});
+				_gthis.sendQuery(infoGet);
+			}
+		});
+		this.sendQuery(itemsGet);
+	}
+	notifyMessageHandlers(message,event) {
+		let chat = this.getChat(message.chatId());
+		if(chat != null && chat.isBlocked) {
+			return;
+		}
+		let _g = 0;
+		let _g1 = this.chatMessageHandlers;
+		while(_g < _g1.length) {
+			let handler = _g1[_g];
+			++_g;
+			handler(message,event);
+		}
+	}
+	notifySyncMessageHandlers(message) {
+		if(message == null || message.versions.length > 1) {
+			return;
+		}
+		let chat = this.getChat(message.chatId());
+		if(chat != null && chat.isBlocked) {
+			return;
+		}
+		let _g = 0;
+		let _g1 = this.syncMessageHandlers;
+		while(_g < _g1.length) {
+			let handler = _g1[_g];
+			++_g;
+			handler(message);
+		}
+	}
+	rosterGet() {
+		let rosterGet = new snikket_queries_RosterGet();
+		let _gthis = this;
+		rosterGet.onFinished(function() {
+			let chatsToUpdate = [];
+			let _g = 0;
+			let _g1 = rosterGet.getResult();
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				let chat = _gthis.getDirectChat(item.jid,false);
+				chat.updateFromRoster(item);
+				chatsToUpdate.push(js_Boot.__cast(chat , snikket_Chat));
+			}
+			_gthis.persistence.storeChats(_gthis.accountId(),chatsToUpdate);
+			_gthis.trigger("chats/update",chatsToUpdate);
+		});
+		this.sendQuery(rosterGet);
+	}
+	startChatWith(jid,handleCaps,handleChat) {
+		let discoGet = new snikket_queries_DiscoInfoGet(jid);
+		let _gthis = this;
+		discoGet.onFinished(function() {
+			let resultCaps = discoGet.getResult();
+			if(resultCaps == null) {
+				let tmp = discoGet.responseStanza;
+				let tmp1 = tmp != null ? tmp.getChild("error") : null;
+				let err = tmp1 != null ? tmp1.getChild(null,"urn:ietf:params:xml:ns:xmpp-stanzas") : null;
+				if(err == null || (err != null ? err.name : null) == "service-unavailable" || (err != null ? err.name : null) == "feature-not-implemented") {
+					let chat = _gthis.getDirectChat(jid,false);
+					handleChat(chat);
+					_gthis.persistence.storeChats(_gthis.accountId(),[chat]);
+				}
+			} else {
+				_gthis.persistence.storeCaps(resultCaps);
+				let uiState = handleCaps(resultCaps);
+				if(resultCaps.isChannel(jid)) {
+					let chat = new snikket_Channel(_gthis,_gthis.stream,_gthis.persistence,jid,uiState,false,null,null,null,resultCaps);
+					handleChat(chat);
+					_gthis.chats.unshift(chat);
+					_gthis.persistence.storeChats(_gthis.accountId(),[chat]);
+				} else {
+					let chat = _gthis.getDirectChat(jid,false);
+					handleChat(chat);
+					_gthis.persistence.storeChats(_gthis.accountId(),[chat]);
+				}
+			}
+		});
+		this.sendQuery(discoGet);
+	}
+	serverBlocked(blocked) {
+		let tmp = this.getChat(blocked);
+		let chat = tmp != null ? tmp : this.getDirectChat(blocked,false);
+		chat.block(null,false);
+	}
+	bookmarksGet(callback) {
+		let blockingGet = new snikket_queries_BlocklistGet();
+		let _gthis = this;
+		blockingGet.onFinished(function() {
+			let _g = 0;
+			let _g1 = blockingGet.getResult();
+			while(_g < _g1.length) {
+				let blocked = _g1[_g];
+				++_g;
+				_gthis.serverBlocked(blocked);
+			}
+		});
+		this.sendQuery(blockingGet);
+		let mdsGet = new snikket_queries_PubsubGet(null,"urn:xmpp:mds:displayed:0");
+		mdsGet.onFinished(function() {
+			let chatsToUpdate = [];
+			let _g = 0;
+			let _g1 = mdsGet.getResult();
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				if(item.attr["id"] != null) {
+					let tmp = item.getChild("displayed","urn:xmpp:mds:displayed:0");
+					let upTo = tmp != null ? tmp.getChild("stanza-id","urn:xmpp:sid:0") : null;
+					let chat = _gthis.getChat(item.attr["id"]);
+					if(chat == null) {
+						_gthis.startChatWith(item.attr["id"],function(caps) {
+							return 2;
+						},function(chat) {
+							chat.markReadUpToId(upTo.attr["id"],upTo.attr["by"]);
+						});
+					} else {
+						chat.markReadUpToId(upTo.attr["id"],upTo.attr["by"]);
+						chatsToUpdate.push(chat);
+					}
+				}
+			}
+			_gthis.persistence.storeChats(_gthis.accountId(),chatsToUpdate);
+		});
+		this.sendQuery(mdsGet);
+		let pubsubGet = new snikket_queries_PubsubGet(null,"urn:xmpp:bookmarks:1");
+		pubsubGet.onFinished(function() {
+			let chatsToUpdate = [];
+			let _g = 0;
+			let _g1 = pubsubGet.getResult();
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				if(item.attr["id"] != null) {
+					let chat = _gthis.getChat(item.attr["id"]);
+					if(chat == null) {
+						_gthis.startChatWith(item.attr["id"],function(caps) {
+							let identity = caps.identities[0];
+							let conf = item.getChild("conference","urn:xmpp:bookmarks:1");
+							if(conf.attr["name"] == null) {
+								conf.attr["name"] = identity != null ? identity.name : null;
+							}
+							if(conf.attr["autojoin"] == "1" || conf.attr["autojoin"] == "true" || !caps.isChannel(item.attr["id"])) {
+								return 1;
+							} else {
+								return 2;
+							}
+						},function(chat) {
+							chat.updateFromBookmark(item);
+						});
+					} else {
+						chat.updateFromBookmark(item);
+						chatsToUpdate.push(chat);
+					}
+				}
+			}
+			_gthis.persistence.storeChats(_gthis.accountId(),chatsToUpdate);
+			callback();
+		});
+		this.sendQuery(pubsubGet);
+	}
+	sync(callback) {
+		let _gthis = this;
+		if(((this.persistence) instanceof snikket_persistence_Dummy)) {
+			callback(true);
+		} else {
+			this.persistence.lastId(this.accountId(),null,function(lastId) {
+				_gthis.doSync(callback,lastId);
+			});
+		}
+	}
+	onMAMJMI(sid,stanza) {
+		if(stanza.attr["from"] == null) {
+			return;
+		}
+		let from = snikket_JID.parse(stanza.attr["from"]);
+		let chat = this.getDirectChat(from.asBare().asString());
+		if(chat.jingleSessions.has(sid)) {
+			return;
+		}
+		let jmiP = stanza.getChild("propose","urn:xmpp:jingle-message:0");
+		if(jmiP == null) {
+			return;
+		}
+		let session = new snikket_jingle_IncomingProposedSession(this,from,sid);
+		chat.jingleSessions.set(session.get_sid(),session);
+		this.chatActivity(chat);
+		session.ring();
+	}
+	doSync(callback,lastId) {
+		let thirtyDaysAgo = snikket_Date.format(new Date(new Date().getTime() + (-2592000000.)));
+		let sync = new snikket_MessageSync(this,this.stream,lastId == null ? { startTime : thirtyDaysAgo} : { page : { after : lastId}});
+		sync.setNewestPageFirst(false);
+		sync.addContext(function(builder,stanza) {
+			builder.syncPoint = true;
+			return builder;
+		});
+		let _gthis = this;
+		sync.onMessages(function(messageList) {
+			let promises = [];
+			let chatMessages = [];
+			let _g = 0;
+			let _g1 = messageList.messages;
+			while(_g < _g1.length) {
+				let m = _g1[_g];
+				++_g;
+				switch(m._hx_index) {
+				case 1:
+					let message = m.message;
+					chatMessages.push(message);
+					break;
+				case 2:
+					let action = m.action;
+					promises.push(thenshim_Promise._new(function(resolve,reject) {
+						_gthis.moderateMessage(action).then(function(_) {
+							resolve(null);
+						});
+					}));
+					break;
+				case 3:
+					let update = m.update;
+					promises.push(thenshim_Promise._new(function(resolve,reject) {
+						_gthis.persistence.storeReaction(_gthis.accountId(),update,function(_) {
+							resolve(null);
+						});
+					}));
+					break;
+				default:
+				}
+			}
+			promises.push(thenshim_Promise._new(function(resolve,reject) {
+				_gthis.persistence.storeMessages(_gthis.accountId(),chatMessages,resolve);
+			}));
+			haxe_Log.trace("SYNC: MAM page wait for writes",{ fileName : "snikket/Client.hx", lineNumber : 1467, className : "snikket.Client", methodName : "doSync"});
+			thenshim_Promise.then(thenshim_PromiseTools.all(promises),function(results) {
+				if(_gthis.syncMessageHandlers.length > 0) {
+					let _g = 0;
+					while(_g < results.length) {
+						let messages = results[_g];
+						++_g;
+						if(messages != null) {
+							let _g = 0;
+							while(_g < messages.length) {
+								let message = messages[_g];
+								++_g;
+								_gthis.notifySyncMessageHandlers(message);
+							}
+						}
+					}
+				}
+				if(sync.hasMore()) {
+					sync.fetchNext();
+				} else {
+					let jsIterator = sync.jmi.entries();
+					let _g_jsIterator = jsIterator;
+					let _g_lastStep = jsIterator.next();
+					while(!_g_lastStep.done) {
+						let v = _g_lastStep.value;
+						_g_lastStep = _g_jsIterator.next();
+						let _g_key = v[0];
+						let _g_value = v[1];
+						let sid = _g_key;
+						let stanza = _g_value;
+						_gthis.onMAMJMI(sid,stanza);
+					}
+					if(callback != null) {
+						callback(true);
+					}
+				}
+			},function(e) {
+				haxe_Log.trace("SYNC: error",{ fileName : "snikket/Client.hx", lineNumber : 1489, className : "snikket.Client", methodName : "doSync", customParams : [e == null ? "null" : Std.string(e)]});
+				callback(false);
+			});
+		});
+		sync.onError(function(stanza) {
+			if(lastId != null) {
+				_gthis.doSync(callback,null);
+			} else {
+				haxe_Log.trace("SYNC: error",{ fileName : "snikket/Client.hx", lineNumber : 1498, className : "snikket.Client", methodName : "doSync", customParams : [stanza]});
+				if(callback != null) {
+					callback(false);
+				}
+			}
+		});
+		sync.fetchNext();
+	}
+	pingAllChannels(refresh) {
+		let _g = 0;
+		let _g1 = this.getChats();
+		while(_g < _g1.length) {
+			let chat = _g1[_g];
+			++_g;
+			let channel = ((chat) instanceof snikket_Channel) ? chat : null;
+			if(channel != null) {
+				channel.selfPing(refresh || (channel != null ? channel.disco : null) == null);
+			}
+		}
+	}
+}
+$hx_exports["snikket"]["Client"] = snikket_Client;
+snikket_Client.__name__ = "snikket.Client";
+snikket_Client.__super__ = snikket_EventEmitter;
+Object.assign(snikket_Client.prototype, {
+	__class__: snikket_Client
+});
+class snikket_Color {
+	static forString(s) {
+		let hash = haxe_crypto_Sha1.make(haxe_io_Bytes.ofString(s));
+		let hue = hash.getUInt16(0) / 65536.0 * 360;
+		let color = new hsluv_Hsluv();
+		color.hsluv_h = hue;
+		color.hsluv_s = 100;
+		color.hsluv_l = 50;
+		color.hsluvToHex();
+		return color.hex;
+	}
+	static defaultPhoto(input,letter) {
+		let hex = HxOverrides.substr(snikket_Color.forString(input),1,null);
+		return "data:image/svg+xml,<svg%20xmlns=\"http://www.w3.org/2000/svg\"%20version=\"1.1\"%20width=\"15\"%20height=\"15\"%20viewBox=\"0%200%2015%2015\">" + "<rect%20style=\"fill:%23" + hex + ";\"%20width=\"15\"%20height=\"15\"%20x=\"0\"%20y=\"0\"%20/>" + "<text%20style=\"fill:%23ffffff;font-size:8px;font-family:sans-serif;\"%20text-anchor=\"middle\"%20dominant-baseline=\"central\"%20x=\"50%25\"%20y=\"50%25\">" + encodeURIComponent(letter) + "</text>" + "</svg>";
+	}
+}
+snikket_Color.__name__ = "snikket.Color";
+class snikket_Config {
+}
+$hx_exports["snikket"]["Config"] = snikket_Config;
+snikket_Config.__name__ = "snikket.Config";
+class snikket_Date {
+	static format(d) {
+		let millis = d.getTime();
+		let frac = millis - (millis / 1000 | 0) * 1000.0 | 0;
+		return Std.string(d.getUTCFullYear()) + "-" + StringTools.lpad(Std.string(d.getUTCMonth() + 1),"0",2) + "-" + StringTools.lpad(Std.string(d.getUTCDate()),"0",2) + "T" + StringTools.lpad(Std.string(d.getUTCHours()),"0",2) + ":" + StringTools.lpad(Std.string(d.getUTCMinutes()),"0",2) + ":" + StringTools.lpad(Std.string(d.getUTCSeconds()),"0",2) + "." + StringTools.lpad(frac == null ? "null" : "" + frac,"0",3) + "Z";
+	}
+}
+snikket_Date.__name__ = "snikket.Date";
+class snikket_UnicodeSet {
+}
+snikket_UnicodeSet.__name__ = "snikket.UnicodeSet";
+snikket_UnicodeSet.__isInterface__ = true;
+Object.assign(snikket_UnicodeSet.prototype, {
+	__class__: snikket_UnicodeSet
+});
+class snikket_UnicodeList {
+	constructor(...codes) {
+		this.list = codes.slice();
+	}
+	contains(codepoint) {
+		return this.list.includes(codepoint);
+	}
+}
+snikket_UnicodeList.__name__ = "snikket.UnicodeList";
+snikket_UnicodeList.__interfaces__ = [snikket_UnicodeSet];
+Object.assign(snikket_UnicodeList.prototype, {
+	__class__: snikket_UnicodeList
+});
+class snikket_UnicodeRange {
+	constructor(lower,upper) {
+		this.lower = lower;
+		this.upper = upper;
+	}
+	contains(codePoint) {
+		if(codePoint >= this.lower) {
+			return codePoint <= this.upper;
+		} else {
+			return false;
+		}
+	}
+}
+snikket_UnicodeRange.__name__ = "snikket.UnicodeRange";
+snikket_UnicodeRange.__interfaces__ = [snikket_UnicodeSet];
+Object.assign(snikket_UnicodeRange.prototype, {
+	__class__: snikket_UnicodeRange
+});
+class snikket_UnicodeBlocks {
+	constructor(...sets) {
+		this.unicodeSets = sets.slice();
+	}
+	contains(codepoint) {
+		let _g = 0;
+		let _g1 = this.unicodeSets;
+		while(_g < _g1.length) {
+			let unicodeSet = _g1[_g];
+			++_g;
+			if(unicodeSet.contains(codepoint)) {
+				return true;
+			}
+		}
+		return false;
+	}
+}
+snikket_UnicodeBlocks.__name__ = "snikket.UnicodeBlocks";
+snikket_UnicodeBlocks.__interfaces__ = [snikket_UnicodeSet];
+Object.assign(snikket_UnicodeBlocks.prototype, {
+	__class__: snikket_UnicodeBlocks
+});
+class snikket_EmojiUtil {
+	static parse(str) {
+		let symbols = [];
+		let builder = new snikket_Builder();
+		let needsFinalBuild = false;
+		let input = snikket_StringUtil.rawCodepointArray(str);
+		let _g = 0;
+		let _g1 = input.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let cp = input[i];
+			if(builder.offer(cp)) {
+				needsFinalBuild = true;
+			} else {
+				symbols.push(builder.build());
+				builder = new snikket_Builder();
+				if(builder.offer(cp)) {
+					needsFinalBuild = true;
+				}
+			}
+		}
+		if(needsFinalBuild) {
+			symbols.push(builder.build());
+		}
+		return symbols;
+	}
+	static isEmoji(input) {
+		let symbols = snikket_EmojiUtil.parse(input);
+		if(symbols.length == 1) {
+			return symbols[0].isEmoji();
+		} else {
+			return false;
+		}
+	}
+	static isOnlyEmoji(input) {
+		let symbols = snikket_EmojiUtil.parse(input);
+		let _g = 0;
+		while(_g < symbols.length) {
+			let symbol = symbols[_g];
+			++_g;
+			if(!symbol.isEmoji()) {
+				return false;
+			}
+		}
+		return symbols.length > 0;
+	}
+}
+snikket_EmojiUtil.__name__ = "snikket.EmojiUtil";
+class snikket_Symbol {
+	constructor(codepoints) {
+		let builder_b = "";
+		let _g = 0;
+		while(_g < codepoints.length) {
+			let codepoint = codepoints[_g];
+			++_g;
+			builder_b += String.fromCodePoint(codepoint);
+		}
+		this.value = builder_b;
+	}
+	toString() {
+		return this.value;
+	}
+}
+snikket_Symbol.__name__ = "snikket.Symbol";
+Object.assign(snikket_Symbol.prototype, {
+	__class__: snikket_Symbol
+});
+class snikket_Emoji extends snikket_Symbol {
+	constructor(codepoints) {
+		super(codepoints);
+	}
+	isEmoji() {
+		return true;
+	}
+}
+snikket_Emoji.__name__ = "snikket.Emoji";
+snikket_Emoji.__super__ = snikket_Symbol;
+Object.assign(snikket_Emoji.prototype, {
+	__class__: snikket_Emoji
+});
+class snikket_Other extends snikket_Symbol {
+	constructor(codepoints) {
+		super(codepoints);
+	}
+	isEmoji() {
+		return false;
+	}
+}
+snikket_Other.__name__ = "snikket.Other";
+snikket_Other.__super__ = snikket_Symbol;
+Object.assign(snikket_Other.prototype, {
+	__class__: snikket_Other
+});
+class snikket_Builder {
+	constructor() {
+		this.codepoints = [];
+	}
+	offer(codepoint) {
+		let add = false;
+		if(this.codepoints.length == 0) {
+			if(snikket_EmojiUtil.SYMBOLIZE.contains(codepoint)) {
+				add = true;
+			} else if(snikket_EmojiUtil.REGIONAL_INDICATORS.contains(codepoint)) {
+				add = true;
+			} else if(snikket_EmojiUtil.EMOJIS.contains(codepoint) && !snikket_EmojiUtil.FITZPATRICK.contains(codepoint) && codepoint != snikket_EmojiUtil.ZWJ) {
+				add = true;
+			}
+		} else {
+			let previous = this.codepoints[this.codepoints.length - 1];
+			if(this.codepoints[0] == snikket_EmojiUtil.BLACK_FLAG) {
+				add = snikket_EmojiUtil.TAGS.contains(codepoint);
+			} else if(snikket_EmojiUtil.COMBINING_ENCLOSING_KEYCAP == codepoint) {
+				add = snikket_EmojiUtil.KEYCAP_COMBINEABLE.contains(previous) || previous == snikket_EmojiUtil.VARIATION_16;
+			} else if(snikket_EmojiUtil.SYMBOLIZE.contains(previous)) {
+				add = codepoint == snikket_EmojiUtil.VARIATION_16;
+			} else if(snikket_EmojiUtil.REGIONAL_INDICATORS.contains(previous) && snikket_EmojiUtil.REGIONAL_INDICATORS.contains(codepoint)) {
+				add = this.codepoints.length == 1;
+			} else if(previous == snikket_EmojiUtil.VARIATION_16) {
+				add = snikket_Builder.isMerger(codepoint) || codepoint == snikket_EmojiUtil.VARIATION_16;
+			} else if(snikket_EmojiUtil.FITZPATRICK.contains(previous)) {
+				add = codepoint == snikket_EmojiUtil.ZWJ;
+			} else if(snikket_EmojiUtil.ZWJ == previous) {
+				add = snikket_EmojiUtil.EMOJIS.contains(codepoint);
+			} else if(snikket_Builder.isMerger(codepoint)) {
+				add = true;
+			} else if(codepoint == snikket_EmojiUtil.VARIATION_16 && snikket_EmojiUtil.EMOJIS.contains(previous)) {
+				add = true;
+			}
+		}
+		if(add) {
+			this.codepoints.push(codepoint);
+			return true;
+		} else {
+			return false;
+		}
+	}
+	build() {
+		if(this.codepoints.length > 0 && snikket_EmojiUtil.SYMBOLIZE.contains(this.codepoints[this.codepoints.length - 1])) {
+			return new snikket_Other(this.codepoints);
+		} else if(this.codepoints.length > 1 && snikket_EmojiUtil.KEYCAP_COMBINEABLE.contains(this.codepoints[0]) && this.codepoints[this.codepoints.length - 1] != snikket_EmojiUtil.COMBINING_ENCLOSING_KEYCAP) {
+			return new snikket_Other(this.codepoints);
+		}
+		if(this.codepoints.length == 0) {
+			return new snikket_Other(this.codepoints);
+		} else {
+			return new snikket_Emoji(this.codepoints);
+		}
+	}
+	static isMerger(codepoint) {
+		if(codepoint != snikket_EmojiUtil.ZWJ) {
+			return snikket_EmojiUtil.FITZPATRICK.contains(codepoint);
+		} else {
+			return true;
+		}
+	}
+}
+snikket_Builder.__name__ = "snikket.Builder";
+Object.assign(snikket_Builder.prototype, {
+	__class__: snikket_Builder
+});
+var snikket_EventResult = $hxEnums["snikket.EventResult"] = { __ename__:true,__constructs__:null
+	,EventHandled: {_hx_name:"EventHandled",_hx_index:0,__enum__:"snikket.EventResult",toString:$estr}
+	,EventUnhandled: {_hx_name:"EventUnhandled",_hx_index:1,__enum__:"snikket.EventResult",toString:$estr}
+	,EventStop: {_hx_name:"EventStop",_hx_index:2,__enum__:"snikket.EventResult",toString:$estr}
+	,EventValue: ($_=function(result) { return {_hx_index:3,result:result,__enum__:"snikket.EventResult",toString:$estr}; },$_._hx_name="EventValue",$_.__params__ = ["result"],$_)
+};
+snikket_EventResult.__constructs__ = [snikket_EventResult.EventHandled,snikket_EventResult.EventUnhandled,snikket_EventResult.EventStop,snikket_EventResult.EventValue];
+class snikket_EventHandler {
+	constructor(handlers,callback,onlyOnce) {
+		this.onlyOnce = false;
+		this.callback = null;
+		this.handlers = null;
+		this.handlers = handlers;
+		this.callback = callback;
+		if(onlyOnce != null) {
+			this.onlyOnce = onlyOnce;
+		}
+	}
+	call(data) {
+		if(this.onlyOnce) {
+			this.unsubscribe();
+		}
+		return this.callback(data);
+	}
+	once() {
+		this.onlyOnce = true;
+		return this;
+	}
+	unsubscribe() {
+		HxOverrides.remove(this.handlers,this);
+	}
+}
+snikket_EventHandler.__name__ = "snikket.EventHandler";
+Object.assign(snikket_EventHandler.prototype, {
+	__class__: snikket_EventHandler
+});
+class snikket_FSM extends snikket_EventEmitter {
+	constructor(desc,initialState,initialAttr) {
+		snikket_EventEmitter._hx_skip_constructor = true;
+		super();
+		snikket_EventEmitter._hx_skip_constructor = false;
+		this._hx_constructor(desc,initialState,initialAttr);
+	}
+	_hx_constructor(desc,initialState,initialAttr) {
+		this.currentStateAttributes = null;
+		this.currentState = null;
+		this.states = new Map([]);
+		super._hx_constructor();
+		let _g = 0;
+		let _g1 = desc.transitions;
+		while(_g < _g1.length) {
+			let transition = _g1[_g];
+			++_g;
+			let from_states = transition.from;
+			let _g2 = 0;
+			while(_g2 < from_states.length) {
+				let from_state = from_states[_g2];
+				++_g2;
+				let from_state_def = this.states.get(from_state);
+				if(from_state_def == null) {
+					from_state_def = new Map([]);
+					this.states.set(from_state,from_state_def);
+				}
+				let to_state_def = this.states.get(transition.to);
+				if(to_state_def == null) {
+					to_state_def = new Map([]);
+					this.states.set(transition.to,to_state_def);
+				}
+				if(this.states.get(from_state).get(transition.name) != null) {
+					throw new haxe_Exception("Duplicate transition in FSM specification: " + transition.name + " from " + from_state);
+				}
+				this.states.get(from_state).set(transition.name,transition.to);
+			}
+		}
+		if(desc.state_handlers != null) {
+			let jsIterator = desc.state_handlers.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let state = _g_key;
+				let handler = _g_value;
+				this.on("enter/" + state,function(data) {
+					handler(data);
+					return snikket_EventResult.EventHandled;
+				});
+			}
+		}
+		if(desc.transition_handlers != null) {
+			let jsIterator = desc.transition_handlers.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let transition = _g_key;
+				let handler = _g_value;
+				this.on("transition/" + transition,function(data) {
+					if(handler(data) == false) {
+						return snikket_EventResult.EventStop;
+					}
+					return snikket_EventResult.EventHandled;
+				});
+			}
+		}
+		this.currentState = initialState;
+		this.currentStateAttributes = initialAttr;
+		let initialEvent = { fsm : this, to : initialState, toAttr : initialAttr};
+		this.notifyTransitioned(initialEvent,true);
+	}
+	can(name) {
+		return this.states.get(this.currentState).get(name) != null;
+	}
+	getState() {
+		return this.currentState;
+	}
+	event(name,attr) {
+		let newState = this.states.get(this.currentState).get(name);
+		if(newState == null) {
+			throw new haxe_Exception("Invalid state transition: " + this.currentState + " cannot " + name);
+		}
+		let event = { fsm : this, name : name, to : newState, toAttr : attr, from : this.currentState, fromAttr : this.currentStateAttributes};
+		if(this.notifyTransition(event) == false) {
+			return false;
+		}
+		this.currentState = newState;
+		this.currentStateAttributes = attr;
+		this.notifyTransitioned(event,false);
+		return true;
+	}
+	notifyTransition(event) {
+		let ret = this.trigger("transition",event);
+		if(ret == snikket_EventResult.EventStop) {
+			return false;
+		}
+		if(event.to != event.from) {
+			ret = this.trigger("leave/" + event.from,event);
+			if(ret == snikket_EventResult.EventStop) {
+				return false;
+			}
+		}
+		ret = this.trigger("transition/" + event.name,event);
+		if(ret == snikket_EventResult.EventStop) {
+			return false;
+		}
+		return true;
+	}
+	notifyTransitioned(event,isInitial) {
+		if(event.to != event.from) {
+			this.trigger("enter/" + event.to,event);
+		}
+		if(isInitial == false) {
+			if(event.name != null) {
+				this.trigger("transitioned/" + event.name,event);
+			}
+			this.trigger("transitioned",event);
+		}
+	}
+}
+snikket_FSM.__name__ = "snikket.FSM";
+snikket_FSM.__super__ = snikket_EventEmitter;
+Object.assign(snikket_FSM.prototype, {
+	__class__: snikket_FSM
+});
+var snikket_IqResult = $hxEnums["snikket.IqResult"] = { __ename__:true,__constructs__:null
+	,IqResultElement: ($_=function(element) { return {_hx_index:0,element:element,__enum__:"snikket.IqResult",toString:$estr}; },$_._hx_name="IqResultElement",$_.__params__ = ["element"],$_)
+	,IqResult: {_hx_name:"IqResult",_hx_index:1,__enum__:"snikket.IqResult",toString:$estr}
+	,IqNoResult: {_hx_name:"IqNoResult",_hx_index:2,__enum__:"snikket.IqResult",toString:$estr}
+};
+snikket_IqResult.__constructs__ = [snikket_IqResult.IqResultElement,snikket_IqResult.IqResult,snikket_IqResult.IqNoResult];
+class snikket_GenericStream extends snikket_EventEmitter {
+	constructor() {
+		if(snikket_EventEmitter._hx_skip_constructor) {
+			super();
+			return;
+		}
+		snikket_EventEmitter._hx_skip_constructor = true;
+		super();
+		snikket_EventEmitter._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.csi = false;
+		this.clientId = null;
+		super._hx_constructor();
+	}
+	sendIq(stanza,callback) {
+		let id = this.newId();
+		stanza.attr["id"] = id;
+		this.once("iq-response/" + id,function(event) {
+			callback(event.stanza);
+			return snikket_EventResult.EventHandled;
+		});
+		this.sendStanza(stanza);
+	}
+	onStanza(stanza) {
+		haxe_Log.trace("stanza received!",{ fileName : "snikket/GenericStream.hx", lineNumber : 40, className : "snikket.GenericStream", methodName : "onStanza"});
+		let xmlns = stanza.attr["xmlns"];
+		if(xmlns == "jabber:client") {
+			let name = stanza.name;
+			if(name == "iq") {
+				let type = stanza.attr["type"];
+				haxe_Log.trace("type: " + type,{ fileName : "snikket/GenericStream.hx", lineNumber : 46, className : "snikket.GenericStream", methodName : "onStanza"});
+				if(type == "result" || type == "error") {
+					let id = stanza.attr["id"];
+					this.trigger("iq-response/" + id,{ stanza : stanza});
+				}
+			} else if(name == "message" || name == "presence") {
+				this.trigger(name,{ stanza : stanza});
+			}
+		}
+	}
+}
+snikket_GenericStream.__name__ = "snikket.GenericStream";
+snikket_GenericStream.__super__ = snikket_EventEmitter;
+Object.assign(snikket_GenericStream.prototype, {
+	__class__: snikket_GenericStream
+});
+class snikket_Hash {
+	constructor(algorithm,hash) {
+		this.algorithm = algorithm;
+		this.hash = hash;
+	}
+	toUri() {
+		if(snikket_Config.relativeHashUri) {
+			let s = this.algorithm;
+			return "/.well-known/ni/" + encodeURIComponent(s) + "/" + this.toBase64Url();
+		} else {
+			return this.serializeUri();
+		}
+	}
+	bobUri() {
+		let tmp;
+		if(this.algorithm == "sha-1") {
+			tmp = "sha1";
+		} else {
+			let s = this.algorithm;
+			tmp = encodeURIComponent(s);
+		}
+		return "cid:" + tmp + "+" + this.toHex() + "@bob.xmpp.org";
+	}
+	serializeUri() {
+		let s = this.algorithm;
+		return "ni:///" + encodeURIComponent(s) + ";" + this.toBase64Url();
+	}
+	toHex() {
+		return haxe_io_Bytes.ofData(this.hash).toHex();
+	}
+	toBase64() {
+		return haxe_crypto_Base64.encode(haxe_io_Bytes.ofData(this.hash),true);
+	}
+	toBase64Url() {
+		return haxe_crypto_Base64.urlEncode(haxe_io_Bytes.ofData(this.hash));
+	}
+	static fromHex(algorithm,hash) {
+		try {
+			return new snikket_Hash(algorithm,haxe_io_Bytes.ofHex(hash).b.bufferValue);
+		} catch( _g ) {
+			return null;
+		}
+	}
+	static fromUri(uri) {
+		if(uri.startsWith("cid:") && uri.endsWith("@bob.xmpp.org") && uri.includes("+")) {
+			let parts = HxOverrides.substr(uri,4,null).split("@")[0].split("+");
+			let algo = parts[0] == "sha1" ? "sha-1" : parts[0];
+			return snikket_Hash.fromHex(algo,parts[1]);
+		}
+		if(uri.startsWith("ni:///") && uri.includes(";")) {
+			let parts = uri.substring(6).split(";");
+			return new snikket_Hash(parts[0],haxe_crypto_Base64.urlDecode(parts[1]).b.bufferValue);
+		} else if(uri.startsWith("/.well-known/ni/")) {
+			let parts = uri.substring(16).split("/");
+			return new snikket_Hash(parts[0],haxe_crypto_Base64.urlDecode(parts[1]).b.bufferValue);
+		}
+		return null;
+	}
+	static sha1(bytes) {
+		return new snikket_Hash("sha-1",haxe_crypto_Sha1.make(bytes).b.bufferValue);
+	}
+	static sha256(bytes) {
+		return new snikket_Hash("sha-256",haxe_crypto_Sha256.make(bytes).b.bufferValue);
+	}
+}
+$hx_exports["snikket"]["Hash"] = snikket_Hash;
+snikket_Hash.__name__ = "snikket.Hash";
+Object.assign(snikket_Hash.prototype, {
+	__class__: snikket_Hash
+});
+class snikket_ID {
+	static tiny() {
+		return hx_strings_RandomStrings.random(6,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC));
+	}
+	static short() {
+		return hx_strings_RandomStrings.random(18,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC));
+	}
+	static medium() {
+		return hx_strings_RandomStrings.random(32,hx_strings_internal__$Either2__$Either2.b(hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC));
+	}
+	static long() {
+		return hx_strings_RandomStrings.randomUUIDv4();
+	}
+}
+snikket_ID.__name__ = "snikket.ID";
+class snikket_Identicon {
+	static svg(source) {
+		let sha = haxe_crypto_Sha1.make(haxe_io_Bytes.ofString(source));
+		let input = new haxe_io_BytesInput(sha);
+		input.set_bigEndian(true);
+		let hash = input.readInt32();
+		let uri = "data:image/svg+xml,<svg%20xmlns=\"http://www.w3.org/2000/svg\"%20version=\"1.1\"%20width=\"5\"%20height=\"5\"%20viewBox=\"0%200%205%205\">";
+		uri += "<style>rect{fill:%23" + HxOverrides.substr(snikket_Color.forString(source),1,null) + ";}</style>";
+		let i = 0;
+		let value = hash >> i++;
+		if(value % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 0 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 0 + "\"/>";
+		}
+		let value1 = hash >> i++;
+		if(value1 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 1 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 1 + "\"/>";
+		}
+		let value2 = hash >> i++;
+		if(value2 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 2 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 2 + "\"/>";
+		}
+		let value3 = hash >> i++;
+		if(value3 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 3 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 3 + "\"/>";
+		}
+		let value4 = hash >> i++;
+		if(value4 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 0 + "\"%20y=\"" + 4 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 4 + "\"%20y=\"" + 4 + "\"/>";
+		}
+		let value5 = hash >> i++;
+		if(value5 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 0 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 0 + "\"/>";
+		}
+		let value6 = hash >> i++;
+		if(value6 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 1 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 1 + "\"/>";
+		}
+		let value7 = hash >> i++;
+		if(value7 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 2 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 2 + "\"/>";
+		}
+		let value8 = hash >> i++;
+		if(value8 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 3 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 3 + "\"/>";
+		}
+		let value9 = hash >> i++;
+		if(value9 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 1 + "\"%20y=\"" + 4 + "\"/>";
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 3 + "\"%20y=\"" + 4 + "\"/>";
+		}
+		let value10 = hash >> i++;
+		if(value10 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 0 + "\"/>";
+		}
+		let value11 = hash >> i++;
+		if(value11 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 1 + "\"/>";
+		}
+		let value12 = hash >> i++;
+		if(value12 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 2 + "\"/>";
+		}
+		let value13 = hash >> i++;
+		if(value13 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 3 + "\"/>";
+		}
+		let value14 = hash >> i++;
+		if(value14 % 2 == 0) {
+			uri += "<rect%20width=\"1\"%20height=\"1\"%20x=\"" + 2 + "\"%20y=\"" + 4 + "\"/>";
+		}
+		return uri + "</svg>";
+	}
+}
+$hx_exports["snikket"]["Identicon"] = snikket_Identicon;
+snikket_Identicon.__name__ = "snikket.Identicon";
+class snikket_JID {
+	constructor(node,domain,resource) {
+		this.node = node == null ? null : StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.replace(StringTools.trim(node),"\\5c","\\5c5c"),"\\20","\\5c20"),"\\22","\\5c22"),"\\26","\\5c26"),"\\27","\\5c27"),"\\2f","\\5c2f"),"\\3a","\\5c3a"),"\\3c","\\5c3c"),"\\3e","\\5c3e"),"\\40","\\5c40")," ","\\20"),"\"","\\22"),"&","\\26"),"'","\\27"),"/","\\2f"),":","\\3a"),"<","\\3c"),">","\\3e"),"@","\\40");
+		this.domain = domain;
+		this.resource = resource;
+	}
+	asBare() {
+		return new snikket_JID(this.node,this.domain);
+	}
+	withResource(resource) {
+		return new snikket_JID(this.node,this.domain,resource);
+	}
+	isValid() {
+		return this.domain.indexOf(".") >= 0;
+	}
+	isDomain() {
+		return this.node == null;
+	}
+	isBare() {
+		return this.resource == null;
+	}
+	equals(rhs) {
+		if(this.node == rhs.node && this.domain == rhs.domain) {
+			return this.resource == rhs.resource;
+		} else {
+			return false;
+		}
+	}
+	asString() {
+		return (this.node != null ? this.node + "@" : "") + this.domain + (this.resource != null ? "/" + this.resource : "");
+	}
+	static parse(jid) {
+		let resourceDelimiter = jid.indexOf("/");
+		let nodeDelimiter = jid.indexOf("@");
+		if(resourceDelimiter > 0 && nodeDelimiter >= resourceDelimiter) {
+			nodeDelimiter = -1;
+		}
+		return new snikket_JID(nodeDelimiter > 0 ? HxOverrides.substr(jid,0,nodeDelimiter) : null,jid.substring(nodeDelimiter == -1 ? 0 : nodeDelimiter + 1,resourceDelimiter == -1 ? jid.length + 1 : resourceDelimiter),resourceDelimiter == -1 ? null : jid.substring(resourceDelimiter + 1));
+	}
+}
+$hx_exports["snikket"]["JID"] = snikket_JID;
+snikket_JID.__name__ = "snikket.JID";
+Object.assign(snikket_JID.prototype, {
+	__class__: snikket_JID
+});
+class snikket_Map {
+	static set(this1,k,v) {
+		this1.set(k,v);
+	}
+	static get(this1,k) {
+		return this1.get(k);
+	}
+	static exists(this1,k) {
+		return this1.has(k);
+	}
+	static remove(this1,k) {
+		return this1.delete(k);
+	}
+	static keys(this1) {
+		return new js_lib_HaxeIterator(this1.keys());
+	}
+	static iterator(this1) {
+		return new js_lib_HaxeIterator(this1.values());
+	}
+	static keyValueIterator(this1) {
+		return new snikket_HaxeKVIterator(this1.entries());
+	}
+	static flatMap(this1,f) {
+		let _g = [];
+		let x = $getIterator({ iterator : function() {
+			return new js_lib_HaxeIterator(this1.values());
+		}});
+		while(x.hasNext()) {
+			let x1 = x.next();
+			_g.push(f(x1));
+		}
+		let _g1 = [];
+		let e = $getIterator(_g);
+		while(e.hasNext()) {
+			let e1 = e.next();
+			let x = $getIterator(e1);
+			while(x.hasNext()) {
+				let x1 = x.next();
+				_g1.push(x1);
+			}
+		}
+		return _g1;
+	}
+	static arrayRead(this1,k) {
+		return this1.get(k);
+	}
+	static arrayWrite(this1,k,v) {
+		this1.set(k,v);
+		return v;
+	}
+	static fromMap(map) {
+		let result = new Map();
+		let _g = map.keyValueIterator();
+		while(_g.hasNext()) {
+			let _g1 = _g.next();
+			let k = _g1.key;
+			let v = _g1.value;
+			result.set(k,v);
+		}
+		return result;
+	}
+	static fromArray(iterable) {
+		return new Map(iterable);
+	}
+}
+class snikket_HaxeKVIterator {
+	constructor(jsIterator) {
+		this.jsIterator = jsIterator;
+		this.lastStep = jsIterator.next();
+	}
+	hasNext() {
+		return !this.lastStep.done;
+	}
+	next() {
+		let v = this.lastStep.value;
+		this.lastStep = this.jsIterator.next();
+		return { key : v[0], value : v[1]};
+	}
+}
+snikket_HaxeKVIterator.__name__ = "snikket.HaxeKVIterator";
+Object.assign(snikket_HaxeKVIterator.prototype, {
+	__class__: snikket_HaxeKVIterator
+});
+var snikket_MessageStanza = $hxEnums["snikket.MessageStanza"] = { __ename__:true,__constructs__:null
+	,ErrorMessageStanza: ($_=function(stanza) { return {_hx_index:0,stanza:stanza,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="ErrorMessageStanza",$_.__params__ = ["stanza"],$_)
+	,ChatMessageStanza: ($_=function(message) { return {_hx_index:1,message:message,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="ChatMessageStanza",$_.__params__ = ["message"],$_)
+	,ModerateMessageStanza: ($_=function(action) { return {_hx_index:2,action:action,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="ModerateMessageStanza",$_.__params__ = ["action"],$_)
+	,ReactionUpdateStanza: ($_=function(update) { return {_hx_index:3,update:update,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="ReactionUpdateStanza",$_.__params__ = ["update"],$_)
+	,UnknownMessageStanza: ($_=function(stanza) { return {_hx_index:4,stanza:stanza,__enum__:"snikket.MessageStanza",toString:$estr}; },$_._hx_name="UnknownMessageStanza",$_.__params__ = ["stanza"],$_)
+};
+snikket_MessageStanza.__constructs__ = [snikket_MessageStanza.ErrorMessageStanza,snikket_MessageStanza.ChatMessageStanza,snikket_MessageStanza.ModerateMessageStanza,snikket_MessageStanza.ReactionUpdateStanza,snikket_MessageStanza.UnknownMessageStanza];
+class snikket_Message {
+	constructor(chatId,senderId,threadId,parsed) {
+		this.chatId = chatId;
+		this.senderId = senderId;
+		this.threadId = threadId;
+		this.parsed = parsed;
+	}
+	static fromStanza(stanza,localJid,addContext) {
+		let fromAttr = stanza.attr["from"];
+		let from = fromAttr == null ? localJid.domain : fromAttr;
+		if(stanza.attr["type"] == "error") {
+			return new snikket_Message(from,from,null,snikket_MessageStanza.ErrorMessageStanza(stanza));
+		}
+		let msg = new snikket_ChatMessageBuilder();
+		msg.stanza = stanza;
+		msg.timestamp = stanza.findText("{urn:xmpp:delay}delay@stamp");
+		msg.threadId = stanza.getChildText("thread");
+		msg.lang = stanza.attr["xml:lang"];
+		msg.text = stanza.getChildText("body");
+		if(msg.text != null && (msg.lang == null || msg.lang == "")) {
+			let tmp = stanza.getChild("body");
+			msg.lang = tmp != null ? tmp.attr["xml:lang"] : null;
+		}
+		msg.from = snikket_JID.parse(from);
+		let isGroupchat = stanza.attr["type"] == "groupchat";
+		msg.type = isGroupchat ? 2 : 0;
+		let tmp;
+		if(isGroupchat) {
+			tmp = msg.from;
+		} else {
+			let tmp1 = msg.from;
+			tmp = tmp1 != null ? tmp1.asBare() : null;
+		}
+		msg.senderId = tmp != null ? tmp.asString() : null;
+		let localJidBare = localJid.asBare();
+		let domain = localJid.domain;
+		let to = stanza.attr["to"];
+		msg.to = to == null ? localJid : snikket_JID.parse(to);
+		if(msg.from != null && msg.from.equals(localJidBare)) {
+			let carbon = stanza.getChild("received","urn:xmpp:carbons:2");
+			if(carbon == null) {
+				carbon = stanza.getChild("sent","urn:xmpp:carbons:2");
+			}
+			if(carbon != null) {
+				let fwd = carbon.getChild("forwarded","urn:xmpp:forward:0");
+				if(fwd != null) {
+					return snikket_Message.fromStanza(fwd.getFirstChild(),localJid);
+				}
+			}
+		}
+		let localId = stanza.attr["id"];
+		if(localId != null) {
+			msg.localId = localId;
+		}
+		let altServerId = null;
+		let _g = 0;
+		let _g1 = stanza.allTags("stanza-id","urn:xmpp:sid:0");
+		while(_g < _g1.length) {
+			let stanzaId = _g1[_g];
+			++_g;
+			let id = stanzaId.attr["id"];
+			if((stanzaId.attr["by"] == domain || stanzaId.attr["by"] == localJidBare.asString()) && id != null) {
+				msg.serverIdBy = localJidBare.asString();
+				msg.serverId = id;
+				break;
+			}
+			altServerId = stanzaId;
+		}
+		if(msg.serverId == null && altServerId != null && stanza.attr["type"] != "error") {
+			let id = altServerId.attr["id"];
+			if(id != null) {
+				msg.serverId = id;
+				msg.serverIdBy = altServerId.attr["by"];
+			}
+		}
+		if(msg.serverIdBy != null && msg.serverIdBy != localJid.asBare().asString()) {
+			msg.replyId = msg.serverId;
+		} else if(msg.serverIdBy == localJid.asBare().asString()) {
+			msg.replyId = msg.localId;
+		}
+		msg.direction = msg.to == null || msg.to.asBare().equals(localJidBare) ? 0 : 1;
+		if(msg.from != null && msg.from.asBare().equals(localJidBare)) {
+			msg.direction = 1;
+		}
+		msg.status = msg.direction == 0 ? 2 : 1;
+		let recipients = new Map([]);
+		let replyTo = new Map([]);
+		if(msg.to != null) {
+			let k = msg.to.asBare().asString();
+			recipients.set(k,true);
+		}
+		let from1 = msg.from;
+		if(msg.direction == 0 && from1 != null) {
+			let k = isGroupchat ? from1.asBare().asString() : from1.asString();
+			replyTo.set(k,true);
+		} else if(msg.to != null) {
+			let k = msg.to.asString();
+			replyTo.set(k,true);
+		}
+		let addresses = stanza.getChild("addresses","http://jabber.org/protocol/address");
+		let anyExtendedReplyTo = false;
+		if(addresses != null) {
+			let _g = 0;
+			let _g1 = addresses.allTags("address");
+			while(_g < _g1.length) {
+				let address = _g1[_g];
+				++_g;
+				let jid = address.attr["jid"];
+				if(address.attr["type"] == "noreply") {
+					replyTo.clear();
+				} else if(jid == null) {
+					haxe_Log.trace("No support for addressing to non-jid",{ fileName : "snikket/Message.hx", lineNumber : 128, className : "snikket.Message", methodName : "fromStanza", customParams : [address]});
+					return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.UnknownMessageStanza(stanza));
+				} else if(address.attr["type"] == "to" || address.attr["type"] == "cc") {
+					let k = snikket_JID.parse(jid).asBare().asString();
+					recipients.set(k,true);
+					if(!anyExtendedReplyTo) {
+						let k = snikket_JID.parse(jid).asString();
+						replyTo.set(k,true);
+					}
+				} else if(address.attr["type"] == "replyto" || address.attr["type"] == "replyroom") {
+					if(!anyExtendedReplyTo) {
+						replyTo.clear();
+						anyExtendedReplyTo = true;
+					}
+					let k = snikket_JID.parse(jid).asString();
+					replyTo.set(k,true);
+				} else if(address.attr["type"] == "ofrom") {
+					let tmp = msg.from;
+					let tmp1 = tmp != null ? tmp.domain : null;
+					if(snikket_JID.parse(jid).domain == tmp1) {
+						msg.senderId = snikket_JID.parse(jid).asBare().asString();
+					}
+				}
+			}
+		}
+		let _g2 = [];
+		let inlobj_iterator = function() {
+			return new js_lib_HaxeIterator(recipients.keys());
+		};
+		let x = inlobj_iterator();
+		while(x.hasNext()) {
+			let x1 = x.next();
+			_g2.push(snikket_JID.parse(x1));
+		}
+		msg.recipients = _g2;
+		msg.recipients.sort(function(x,y) {
+			return Reflect.compare(x.asString(),y.asString());
+		});
+		let _g3 = [];
+		let inlobj_iterator1 = function() {
+			return new js_lib_HaxeIterator(replyTo.keys());
+		};
+		let x1 = inlobj_iterator1();
+		while(x1.hasNext()) {
+			let x = x1.next();
+			_g3.push(snikket_JID.parse(x));
+		}
+		msg.replyTo = _g3;
+		msg.replyTo.sort(function(x,y) {
+			return Reflect.compare(x.asString(),y.asString());
+		});
+		let msgFrom = msg.from;
+		if(msg.direction == 0 && msgFrom != null && Lambda.find(msg.replyTo,function(r) {
+			return r.asBare().equals(msgFrom.asBare());
+		}) == null) {
+			haxe_Log.trace("Don't know what chat message without from in replyTo belongs in",{ fileName : "snikket/Message.hx", lineNumber : 155, className : "snikket.Message", methodName : "fromStanza", customParams : [stanza]});
+			return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.UnknownMessageStanza(stanza));
+		}
+		if(addContext != null) {
+			msg = addContext(msg,stanza);
+		}
+		let tmp1 = msg.timestamp;
+		let timestamp = tmp1 != null ? tmp1 : snikket_Date.format(new Date());
+		msg.timestamp = timestamp;
+		let reactionsEl = stanza.getChild("reactions","urn:xmpp:reactions:0");
+		if(reactionsEl != null) {
+			let _this = reactionsEl.allTags("reaction");
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].getText();
+			}
+			let reactions = result;
+			let reactionId = reactionsEl.attr["id"];
+			if(reactionId != null) {
+				let tmp = msg.chatId();
+				let tmp1 = msg.get_senderId();
+				let msg1 = msg.threadId;
+				let tmp2 = stanza.attr["id"];
+				let tmp3 = tmp2 != null ? tmp2 : snikket_ID.long();
+				let tmp4 = isGroupchat ? reactionId : null;
+				let tmp5 = isGroupchat ? msg.chatId() : null;
+				let tmp6 = isGroupchat ? null : reactionId;
+				let tmp7 = msg.chatId();
+				let tmp8 = msg.get_senderId();
+				let result = new Array(reactions.length);
+				let _g = 0;
+				let _g1 = reactions.length;
+				while(_g < _g1) {
+					let i = _g++;
+					result[i] = new snikket_Reaction(msg.get_senderId(),timestamp,reactions[i],msg.localId);
+				}
+				return new snikket_Message(tmp,tmp1,msg1,snikket_MessageStanza.ReactionUpdateStanza(new snikket_ReactionUpdate(tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,timestamp,result,0)));
+			}
+		}
+		let _g4 = 0;
+		let _g5 = stanza.allTags("reference","urn:xmpp:reference:0");
+		while(_g4 < _g5.length) {
+			let ref = _g5[_g4];
+			++_g4;
+			if(ref.attr["begin"] == null && ref.attr["end"] == null) {
+				let sims = ref.getChild("media-sharing","urn:xmpp:sims:1");
+				if(sims != null) {
+					msg.attachSims(sims);
+				}
+			}
+		}
+		let _g6 = 0;
+		let _g7 = stanza.allTags("media-sharing","urn:xmpp:sims:1");
+		while(_g6 < _g7.length) {
+			let sims = _g7[_g6];
+			++_g6;
+			msg.attachSims(sims);
+		}
+		let jmi = stanza.getChild(null,"urn:xmpp:jingle-message:0");
+		if(jmi != null) {
+			msg.type = 1;
+			msg.payloads.push(jmi);
+			if(msg.text == null) {
+				msg.text = "call " + jmi.name;
+			}
+			if(jmi.name != "propose") {
+				msg.versions = [msg.build()];
+			}
+			msg.localId = jmi.attr["id"];
+		}
+		let retract = stanza.getChild("replace","urn:xmpp:message-retract:1");
+		let fasten = stanza.getChild("apply-to","urn:xmpp:fasten:0");
+		let tmp2 = retract != null ? retract.getChild("moderated","urn:xmpp:message-retract:1") : null;
+		let moderated = tmp2 != null ? tmp2 : fasten != null ? fasten.getChild("moderated","urn:xmpp:message-moderate:0") : null;
+		let moderateServerId;
+		let tmp3 = retract != null ? retract.attr : null;
+		let tmp4 = tmp3 != null ? tmp3["id"] : null;
+		if(tmp4 != null) {
+			moderateServerId = tmp4;
+		} else {
+			let tmp = fasten != null ? fasten.attr : null;
+			moderateServerId = tmp != null ? tmp["id"] : null;
+		}
+		if(moderated != null && moderateServerId != null && isGroupchat && msg.from != null && msg.from.isBare() && msg.from.asString() == msg.chatId()) {
+			let tmp = retract != null ? retract.getChildText("reason") : null;
+			let reason = tmp != null ? tmp : moderated != null ? moderated.getChildText("reason") : null;
+			let by = moderated.attr["by"];
+			return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.ModerateMessageStanza(new snikket_ModerationAction(msg.chatId(),moderateServerId,timestamp,by,reason)));
+		}
+		let replace = stanza.getChild("replace","urn:xmpp:message-correct:0");
+		let tmp5 = replace != null ? replace.attr : null;
+		let replaceId = tmp5 != null ? tmp5["id"] : null;
+		if(msg.text == null && msg.attachments.length < 1 && replaceId == null) {
+			return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.UnknownMessageStanza(stanza));
+		}
+		let _g8 = 0;
+		let _g9 = stanza.allTags("fallback","urn:xmpp:fallback:0");
+		while(_g8 < _g9.length) {
+			let fallback = _g9[_g8];
+			++_g8;
+			msg.payloads.push(fallback);
+		}
+		let unstyled = stanza.getChild("unstyled","urn:xmpp:styling:0");
+		if(unstyled != null) {
+			msg.payloads.push(unstyled);
+		}
+		let html = stanza.getChild("html","http://jabber.org/protocol/xhtml-im");
+		if(html != null) {
+			msg.payloads.push(html);
+		}
+		let reply = stanza.getChild("reply","urn:xmpp:reply:0");
+		if(reply != null) {
+			let replyToJid = reply.attr["to"];
+			let replyToID = reply.attr["id"];
+			let text = msg.text;
+			if(text != null && snikket_EmojiUtil.isOnlyEmoji(StringTools.trim(text))) {
+				let tmp = msg.chatId();
+				let tmp1 = msg.get_senderId();
+				let msg1 = msg.threadId;
+				let tmp2 = stanza.attr["id"];
+				let tmp3 = tmp2 != null ? tmp2 : snikket_ID.long();
+				let tmp4 = isGroupchat ? msg.chatId() : null;
+				let tmp5 = msg.chatId();
+				let tmp6 = msg.get_senderId();
+				return new snikket_Message(tmp,tmp1,msg1,snikket_MessageStanza.ReactionUpdateStanza(new snikket_ReactionUpdate(tmp3,isGroupchat ? replyToID : null,tmp4,isGroupchat ? null : replyToID,tmp5,tmp6,timestamp,[new snikket_Reaction(msg.get_senderId(),timestamp,StringTools.trim(text),msg.localId)],1)));
+			}
+			if(html != null) {
+				let body = html.getChild("body","http://www.w3.org/1999/xhtml");
+				if(body != null) {
+					let els = body.allTags();
+					if(els.length == 1 && els[0].name == "img") {
+						let tmp = els[0].attr["src"];
+						let hash = snikket_Hash.fromUri(tmp != null ? tmp : "");
+						if(hash != null) {
+							let tmp = msg.chatId();
+							let tmp1 = msg.get_senderId();
+							let msg1 = msg.threadId;
+							let tmp2 = stanza.attr["id"];
+							let tmp3 = tmp2 != null ? tmp2 : snikket_ID.long();
+							let tmp4 = isGroupchat ? msg.chatId() : null;
+							let tmp5 = msg.chatId();
+							let tmp6 = msg.get_senderId();
+							let tmp7 = msg.get_senderId();
+							let tmp8 = els[0].attr["alt"];
+							return new snikket_Message(tmp,tmp1,msg1,snikket_MessageStanza.ReactionUpdateStanza(new snikket_ReactionUpdate(tmp3,isGroupchat ? replyToID : null,tmp4,isGroupchat ? null : replyToID,tmp5,tmp6,timestamp,[new snikket_CustomEmojiReaction(tmp7,timestamp,tmp8 != null ? tmp8 : "",hash.serializeUri(),msg.localId)],1)));
+						}
+					}
+				}
+			}
+			if(replyToID != null) {
+				let replyToMessage = new snikket_ChatMessageBuilder();
+				replyToMessage.to = replyToJid == msg.get_senderId() ? msg.to : msg.from;
+				replyToMessage.from = replyToJid == null ? null : snikket_JID.parse(replyToJid);
+				let tmp = replyToMessage.from;
+				replyToMessage.senderId = tmp != null ? tmp.asString() : null;
+				replyToMessage.replyId = replyToID;
+				if(msg.serverIdBy != null && msg.serverIdBy != localJid.asBare().asString()) {
+					replyToMessage.serverId = replyToID;
+				} else {
+					replyToMessage.localId = replyToID;
+				}
+				msg.replyToMessage = replyToMessage.build();
+			}
+		}
+		if(replaceId != null) {
+			msg.versions = [msg.build()];
+			msg.localId = replaceId;
+		}
+		return new snikket_Message(msg.chatId(),msg.get_senderId(),msg.threadId,snikket_MessageStanza.ChatMessageStanza(msg.build()));
+	}
+}
+snikket_Message.__name__ = "snikket.Message";
+Object.assign(snikket_Message.prototype, {
+	__class__: snikket_Message
+});
+class snikket_MessageSync {
+	constructor(client,stream,filter,serviceJID) {
+		this.jmi = new Map([]);
+		this.newestPageFirst = true;
+		this.complete = false;
+		this.progress = 0;
+		this.contextHandler = function(b,_) {
+			return b;
+		};
+		this.client = client;
+		this.stream = stream;
+		this.filter = Reflect.copy(filter);
+		this.serviceJID = serviceJID != null ? serviceJID : client.accountId();
+	}
+	fetchNext() {
+		if(this.handler == null) {
+			throw new haxe_Exception("Attempt to fetch messages, but no handler has been set");
+		}
+		if(this.complete) {
+			throw new haxe_Exception("Attempt to fetch messages, but already complete");
+		}
+		let messages = [];
+		if(this.lastPage == null) {
+			if(this.newestPageFirst == true && (this.filter.page == null || this.filter.page.before == null && this.filter.page.after == null)) {
+				if(this.filter.page == null) {
+					this.filter.page = { };
+				}
+				this.filter.page.before = "";
+			}
+		} else {
+			if(this.filter.page == null) {
+				this.filter.page = { };
+			}
+			if(this.newestPageFirst == true) {
+				this.filter.page.before = this.lastPage.first;
+			} else {
+				this.filter.page.after = this.lastPage.last;
+			}
+		}
+		let query = new snikket_queries_MAMQuery(this.filter,this.serviceJID);
+		let _gthis = this;
+		let resultHandler = this.stream.on("message",function(event) {
+			_gthis.progress++;
+			let message = event.stanza;
+			let from = Object.prototype.hasOwnProperty.call(message.attr,"from") ? message.attr["from"] : _gthis.client.accountId();
+			if(from != _gthis.serviceJID) {
+				return snikket_EventResult.EventUnhandled;
+			}
+			let result = message.getChild("result",query.xmlns);
+			if(result == null || result.attr["queryid"] != query.queryId) {
+				return snikket_EventResult.EventUnhandled;
+			}
+			let originalMessage = result.findChild("{urn:xmpp:forward:0}forwarded/{jabber:client}message");
+			if(originalMessage == null) {
+				return snikket_EventResult.EventHandled;
+			}
+			let timestamp = result.findText("{urn:xmpp:forward:0}forwarded/{urn:xmpp:delay}delay@stamp");
+			let jmiChildren = originalMessage.allTags(null,"urn:xmpp:jingle-message:0");
+			if(jmiChildren.length > 0) {
+				_gthis.jmi.set(jmiChildren[0].attr["id"],originalMessage);
+			}
+			let msg = snikket_Message.fromStanza(originalMessage,_gthis.client.jid,function(builder,stanza) {
+				builder.serverId = result.attr["id"];
+				builder.serverIdBy = _gthis.serviceJID;
+				if(timestamp != null && builder.timestamp == null) {
+					builder.timestamp = timestamp;
+				}
+				return _gthis.contextHandler(builder,stanza);
+			}).parsed;
+			messages.push(msg);
+			return snikket_EventResult.EventHandled;
+		});
+		query.onFinished(function() {
+			resultHandler.unsubscribe();
+			let result = query.getResult();
+			if(result == null) {
+				haxe_Log.trace("Error from MAM, stopping sync",{ fileName : "snikket/MessageSync.hx", lineNumber : 101, className : "snikket.MessageSync", methodName : "fetchNext"});
+				_gthis.complete = true;
+				if(_gthis.errorHandler != null) {
+					_gthis.errorHandler(query.responseStanza);
+				}
+			} else {
+				_gthis.complete = result.complete;
+				_gthis.lastPage = result.page;
+			}
+			if(result != null || _gthis.errorHandler == null) {
+				_gthis.handler({ sync : _gthis, messages : messages});
+			}
+		});
+		this.client.sendQuery(query);
+	}
+	hasMore() {
+		return !this.complete;
+	}
+	addContext(handler) {
+		this.contextHandler = handler;
+	}
+	onMessages(handler) {
+		this.handler = handler;
+	}
+	onError(handler) {
+		this.errorHandler = handler;
+	}
+	setNewestPageFirst(newestPageFirst) {
+		this.newestPageFirst = newestPageFirst;
+	}
+}
+snikket_MessageSync.__name__ = "snikket.MessageSync";
+Object.assign(snikket_MessageSync.prototype, {
+	__class__: snikket_MessageSync
+});
+class snikket_ModerationAction {
+	constructor(chatId,moderateServerId,timestamp,moderatorId,reason) {
+		this.chatId = chatId;
+		this.moderateServerId = moderateServerId;
+		this.timestamp = timestamp;
+		this.moderatorId = moderatorId;
+		this.reason = reason;
+	}
+}
+snikket_ModerationAction.__name__ = "snikket.ModerationAction";
+Object.assign(snikket_ModerationAction.prototype, {
+	__class__: snikket_ModerationAction
+});
+class snikket_Notification {
+	constructor(title,body,accountId,chatId,messageId,type,callStatus,callSid,imageUri,lang,timestamp) {
+		this.title = title;
+		this.body = body;
+		this.accountId = accountId;
+		this.chatId = chatId;
+		this.messageId = messageId;
+		this.type = type;
+		this.callStatus = callStatus;
+		this.callSid = callSid;
+		this.imageUri = imageUri;
+		this.lang = lang;
+		this.timestamp = timestamp;
+	}
+	static fromChatMessage(m) {
+		let imageUri = null;
+		let attachment = m.attachments[0];
+		if(attachment != null) {
+			imageUri = attachment.uris[0];
+		}
+		return new snikket_Notification(m.type == 1 ? "Incoming Call" : "New Message",m.text,m.account(),m.chatId(),m.serverId,m.type,m.callStatus(),m.callSid(),imageUri,m.lang,m.timestamp);
+	}
+	static fromThinStanza(stanza) {
+		return new snikket_Notification("New Message","",snikket_JID.parse(stanza.attr["to"]).asBare().asString(),snikket_JID.parse(stanza.attr["from"]).asBare().asString(),stanza.getChildText("stanza-id","urn:xmpp:sid:0"),0,null,null,null,null,null);
+	}
+}
+$hx_exports["snikket"]["Notification"] = snikket_Notification;
+snikket_Notification.__name__ = "snikket.Notification";
+Object.assign(snikket_Notification.prototype, {
+	__class__: snikket_Notification
+});
+class snikket_Participant {
+	constructor(displayName,photoUri,placeholderUri,isSelf) {
+		this.displayName = displayName;
+		this.photoUri = photoUri;
+		this.placeholderUri = placeholderUri;
+		this.isSelf = isSelf;
+	}
+}
+$hx_exports["snikket"]["Participant"] = snikket_Participant;
+snikket_Participant.__name__ = "snikket.Participant";
+Object.assign(snikket_Participant.prototype, {
+	__class__: snikket_Participant
+});
+class snikket_Persistence {
+}
+snikket_Persistence.__name__ = "snikket.Persistence";
+snikket_Persistence.__isInterface__ = true;
+Object.assign(snikket_Persistence.prototype, {
+	__class__: snikket_Persistence
+});
+class snikket_Presence {
+	constructor(caps,mucUser) {
+		this.caps = caps;
+		this.mucUser = mucUser;
+	}
+}
+$hx_exports["snikket"]["Presence"] = snikket_Presence;
+snikket_Presence.__name__ = "snikket.Presence";
+Object.assign(snikket_Presence.prototype, {
+	__class__: snikket_Presence
+});
+class snikket_PubsubEvent {
+	constructor(from,to,node,items) {
+		this.from = from;
+		this.to = to;
+		this.node = node;
+		this.items = items;
+	}
+	getFrom() {
+		return this.from;
+	}
+	getNode() {
+		return this.node;
+	}
+	getItems() {
+		return this.items;
+	}
+	static fromStanza(stanza) {
+		let event = stanza.getChild("event","http://jabber.org/protocol/pubsub#event");
+		if(event == null) {
+			return null;
+		}
+		let items = event.getChild("items");
+		if(items == null) {
+			return null;
+		}
+		return new snikket_PubsubEvent(stanza.attr["from"],stanza.attr["to"],items.attr["node"],items.allTags("item"));
+	}
+}
+snikket_PubsubEvent.__name__ = "snikket.PubsubEvent";
+Object.assign(snikket_PubsubEvent.prototype, {
+	__class__: snikket_PubsubEvent
+});
+function snikket_Push_receive(data,persistence) {
+	let stanza = snikket_Stanza.parse(data);
+	if(stanza == null) {
+		return null;
+	}
+	if(stanza.name == "envelope" && stanza.attr["xmlns"] == "urn:xmpp:sce:1") {
+		stanza = stanza.getChild("content").getFirstChild();
+	}
+	if(stanza.name == "forwarded" && stanza.attr["xmlns"] == "urn:xmpp:forward:0") {
+		stanza = stanza.getChild("message","jabber:client");
+	}
+	if(stanza.attr["to"] == null) {
+		return null;
+	}
+	let message = snikket_ChatMessage.fromStanza(stanza,snikket_JID.parse(stanza.attr["to"]).asBare());
+	if(message != null) {
+		return snikket_Notification.fromChatMessage(message);
+	} else {
+		return snikket_Notification.fromThinStanza(stanza);
+	}
+}
+$hx_exports["snikket"]["Push"]["receive"] = snikket_Push_receive;
+class snikket_Reaction {
+	constructor(senderId,timestamp,text,envelopeId,key) {
+		this.senderId = senderId;
+		this.timestamp = timestamp;
+		this.text = StringTools.replace(text,"️","");
+		this.envelopeId = envelopeId;
+		let tmp = key;
+		this.key = tmp != null ? tmp : this.text;
+	}
+	render(forText,forImage) {
+		return forText(this.text + "️");
+	}
+}
+$hx_exports["snikket"]["Reaction"] = snikket_Reaction;
+snikket_Reaction.__name__ = "snikket.Reaction";
+Object.assign(snikket_Reaction.prototype, {
+	__class__: snikket_Reaction
+});
+class snikket_CustomEmojiReaction extends snikket_Reaction {
+	constructor(senderId,timestamp,text,uri,envelopeId) {
+		super(senderId,timestamp,text,envelopeId,uri);
+		this.uri = uri;
+	}
+	render(forText,forImage) {
+		let hash = snikket_Hash.fromUri(this.uri);
+		let tmp = this.text;
+		let tmp1 = hash != null ? hash.toUri() : null;
+		return forImage(tmp,tmp1 != null ? tmp1 : this.uri);
+	}
+}
+$hx_exports["snikket"]["CustomEmojiReaction"] = snikket_CustomEmojiReaction;
+snikket_CustomEmojiReaction.__name__ = "snikket.CustomEmojiReaction";
+snikket_CustomEmojiReaction.__super__ = snikket_Reaction;
+Object.assign(snikket_CustomEmojiReaction.prototype, {
+	__class__: snikket_CustomEmojiReaction
+});
+class snikket_ReactionUpdate {
+	constructor(updateId,serverId,serverIdBy,localId,chatId,senderId,timestamp,reactions,kind) {
+		if(serverId == null && localId == null) {
+			throw haxe_Exception.thrown("ReactionUpdate serverId and localId cannot both be null");
+		}
+		if(serverId != null && serverIdBy == null) {
+			throw haxe_Exception.thrown("serverId requires serverIdBy");
+		}
+		this.updateId = updateId;
+		this.serverId = serverId;
+		this.serverIdBy = serverIdBy;
+		this.localId = localId;
+		this.chatId = chatId;
+		this.senderId = senderId;
+		this.timestamp = timestamp;
+		this.reactions = reactions;
+		this.kind = kind;
+	}
+	getReactions(existingReactions) {
+		if(this.kind == 1) {
+			let set = new Map([]);
+			let list = [];
+			let _g = 0;
+			let tmp = existingReactions;
+			let _g1 = tmp != null ? tmp : [];
+			while(_g < _g1.length) {
+				let r = _g1[_g];
+				++_g;
+				if(!set.has(r.key)) {
+					list.push(r);
+				}
+				set.set(r.key,true);
+			}
+			let _g2 = 0;
+			let _g3 = this.reactions;
+			while(_g2 < _g3.length) {
+				let r = _g3[_g2];
+				++_g2;
+				if(!set.has(r.key)) {
+					list.push(r);
+				}
+				set.set(r.key,true);
+			}
+			return list;
+		} else if(this.kind == 0) {
+			let list = Lambda.array(this.reactions);
+			let _g = 0;
+			let tmp = existingReactions;
+			let _g1 = tmp != null ? tmp : [];
+			while(_g < _g1.length) {
+				let r = _g1[_g];
+				++_g;
+				let custom = snikket_Util_downcast(r,snikket_CustomEmojiReaction);
+				if(custom != null) {
+					list.push(custom);
+				}
+			}
+			return list;
+		} else if(this.kind == 2) {
+			return this.reactions;
+		}
+		throw haxe_Exception.thrown("Unknown kind of reaction update");
+	}
+	inlineHashReferences() {
+		let hashes = [];
+		let _g = 0;
+		let _g1 = this.reactions;
+		while(_g < _g1.length) {
+			let r = _g1[_g];
+			++_g;
+			let custom = snikket_Util_downcast(r,snikket_CustomEmojiReaction);
+			if(custom != null) {
+				let hash = snikket_Hash.fromUri(custom.uri);
+				if(hash != null) {
+					hashes.push(hash);
+				}
+			}
+		}
+		return hashes;
+	}
+	asStanza() {
+		if(this.kind != 0) {
+			throw haxe_Exception.thrown("Cannot make a reaction XEP stanza for this kind");
+		}
+		let attrs = { type : this.serverId == null ? "chat" : "groupchat", id : this.updateId};
+		let stanza = new snikket_Stanza("message",attrs);
+		let tmp = this.localId;
+		stanza.tag("reactions",{ xmlns : "urn:xmpp:reactions:0", id : tmp != null ? tmp : this.serverId});
+		let _g = 0;
+		let _g1 = this.reactions;
+		while(_g < _g1.length) {
+			let reaction = _g1[_g];
+			++_g;
+			if(!((reaction) instanceof snikket_CustomEmojiReaction)) {
+				stanza.textTag("reaction",reaction.text);
+			}
+		}
+		stanza.up();
+		return stanza;
+	}
+}
+$hx_exports["snikket"]["ReactionUpdate"] = snikket_ReactionUpdate;
+snikket_ReactionUpdate.__name__ = "snikket.ReactionUpdate";
+Object.assign(snikket_ReactionUpdate.prototype, {
+	__class__: snikket_ReactionUpdate
+});
+var snikket_Node = $hxEnums["snikket.Node"] = { __ename__:true,__constructs__:null
+	,Element: ($_=function(stanza) { return {_hx_index:0,stanza:stanza,__enum__:"snikket.Node",toString:$estr}; },$_._hx_name="Element",$_.__params__ = ["stanza"],$_)
+	,CData: ($_=function(textNode) { return {_hx_index:1,textNode:textNode,__enum__:"snikket.Node",toString:$estr}; },$_._hx_name="CData",$_.__params__ = ["textNode"],$_)
+};
+snikket_Node.__constructs__ = [snikket_Node.Element,snikket_Node.CData];
+class snikket__$Stanza_NodeInterface {
+}
+snikket__$Stanza_NodeInterface.__name__ = "snikket._Stanza.NodeInterface";
+snikket__$Stanza_NodeInterface.__isInterface__ = true;
+Object.assign(snikket__$Stanza_NodeInterface.prototype, {
+	__class__: snikket__$Stanza_NodeInterface
+});
+class snikket_TextNode {
+	constructor(content) {
+		this.content = "";
+		this.content = content;
+	}
+	serialize() {
+		return snikket_Util_xmlEscape(this.content);
+	}
+	clone() {
+		return new snikket_TextNode(this.content);
+	}
+	traverse(f) {
+		return this;
+	}
+}
+snikket_TextNode.__name__ = "snikket.TextNode";
+snikket_TextNode.__interfaces__ = [snikket__$Stanza_NodeInterface];
+Object.assign(snikket_TextNode.prototype, {
+	__class__: snikket_TextNode
+});
+class snikket_StanzaError {
+	constructor(type_,condition_,text_) {
+		this.type = type_;
+		this.condition = condition_;
+		this.text = text_;
+	}
+}
+snikket_StanzaError.__name__ = "snikket.StanzaError";
+Object.assign(snikket_StanzaError.prototype, {
+	__class__: snikket_StanzaError
+});
+class snikket_Stanza {
+	constructor(name,attr) {
+		this.last_added_stack = [];
+		this.children = [];
+		this.attr = { };
+		this.name = null;
+		this.name = name;
+		if(attr != null) {
+			this.attr = attr;
+		}
+		this.last_added = this;
+	}
+	serialize() {
+		let el = Xml.createElement(this.name);
+		let _g = 0;
+		let _g1 = Reflect.fields(this.attr);
+		while(_g < _g1.length) {
+			let attr_k = _g1[_g];
+			++_g;
+			el.set(attr_k,this.attr[attr_k]);
+		}
+		if(this.children.length == 0) {
+			return haxe_xml_Printer.print(el);
+		}
+		let serialized = haxe_xml_Printer.print(el);
+		let buffer = [serialized.substring(0,serialized.length - 2) + ">"];
+		let _g2 = 0;
+		let _g3 = this.children;
+		while(_g2 < _g3.length) {
+			let child = _g3[_g2];
+			++_g2;
+			let tmp;
+			switch(child._hx_index) {
+			case 0:
+				let c = child.stanza;
+				tmp = c.serialize();
+				break;
+			case 1:
+				let c1 = child.textNode;
+				tmp = c1.serialize();
+				break;
+			}
+			buffer.push(tmp);
+		}
+		buffer.push("</" + this.name + ">");
+		return buffer.join("");
+	}
+	toString() {
+		return this.serialize();
+	}
+	tag(name,attr) {
+		let child = new snikket_Stanza(name,attr);
+		this.last_added.addDirectChild(snikket_Node.Element(child));
+		this.last_added_stack.push(this.last_added);
+		this.last_added = child;
+		return this;
+	}
+	text(content) {
+		this.last_added.addDirectChild(snikket_Node.CData(new snikket_TextNode(content)));
+		return this;
+	}
+	textTag(tagName,textContent,attr) {
+		let tmp = attr;
+		this.last_added.addDirectChild(snikket_Node.Element(new snikket_Stanza(tagName,tmp != null ? tmp : { }).text(textContent)));
+		return this;
+	}
+	up() {
+		if(this.last_added != this) {
+			this.last_added = this.last_added_stack.pop();
+		}
+		return this;
+	}
+	reset() {
+		this.last_added = this;
+		return this;
+	}
+	addChildren(children) {
+		let child = $getIterator(children);
+		while(child.hasNext()) {
+			let child1 = child.next();
+			this.addChild(child1);
+		}
+		return this;
+	}
+	addChildNodes(children) {
+		let child = $getIterator(children);
+		while(child.hasNext()) {
+			let child1 = child.next();
+			this.addDirectChild(child1);
+		}
+		return this;
+	}
+	addChild(stanza) {
+		this.last_added.children.push(snikket_Node.Element(stanza));
+		return this;
+	}
+	addDirectChild(child) {
+		this.children.push(child);
+		return this;
+	}
+	clone() {
+		let clone = new snikket_Stanza(this.name,this.attr);
+		let _g = 0;
+		let _g1 = this.children;
+		while(_g < _g1.length) {
+			let child = _g1[_g];
+			++_g;
+			let tmp;
+			switch(child._hx_index) {
+			case 0:
+				let c = child.stanza;
+				tmp = snikket_Node.Element(c.clone());
+				break;
+			case 1:
+				let c1 = child.textNode;
+				tmp = snikket_Node.CData(c1.clone());
+				break;
+			}
+			clone.addDirectChild(tmp);
+		}
+		return clone;
+	}
+	allTags(name,xmlns) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.children;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			let tmp;
+			if(v._hx_index == 0) {
+				let _g = v.stanza;
+				tmp = true;
+			} else {
+				tmp = false;
+			}
+			if(tmp) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			let child = _this[i];
+			let tmp;
+			if(child._hx_index == 0) {
+				let c = child.stanza;
+				tmp = c;
+			} else {
+				tmp = null;
+			}
+			result[i] = tmp;
+		}
+		let tags = result;
+		if(name != null || xmlns != null) {
+			let ourXmlns = this.attr["xmlns"];
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = tags;
+			while(_g1 < _g2.length) {
+				let v = _g2[_g1];
+				++_g1;
+				let childXmlns = v.attr["xmlns"];
+				if((name == null || v.name == name) && (xmlns == null && (ourXmlns == childXmlns || childXmlns == null) || childXmlns == xmlns)) {
+					_g.push(v);
+				}
+			}
+			tags = _g;
+		}
+		return tags;
+	}
+	allText() {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.children;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			let tmp;
+			if(v._hx_index == 1) {
+				let _g = v.textNode;
+				tmp = true;
+			} else {
+				tmp = false;
+			}
+			if(tmp) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			let child = _this[i];
+			let tmp;
+			if(child._hx_index == 1) {
+				let c = child.textNode;
+				tmp = c.content;
+			} else {
+				tmp = null;
+			}
+			result[i] = tmp;
+		}
+		return result;
+	}
+	getFirstChild() {
+		return this.allTags()[0];
+	}
+	getChildren() {
+		let _this = this.children;
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let child = _this[i];
+			let tmp;
+			switch(child._hx_index) {
+			case 0:
+				let el = child.stanza;
+				tmp = el;
+				break;
+			case 1:
+				let text = child.textNode;
+				tmp = text;
+				break;
+			}
+			result[i] = tmp;
+		}
+		return result;
+	}
+	getChild(name,xmlns) {
+		let ourXmlns = this.attr["xmlns"];
+		let tags = this.allTags(name,xmlns);
+		if(tags.length == 0) {
+			return null;
+		}
+		return tags[0];
+	}
+	getChildText(name,xmlns) {
+		let child = this.getChild(name,xmlns);
+		if(child == null) {
+			return null;
+		}
+		return child.getText();
+	}
+	getText() {
+		return this.allText().join("");
+	}
+	find(path) {
+		let pos = 0;
+		let len = path.length;
+		let cursor = this;
+		do {
+			let xmlns = null;
+			let name = null;
+			let text = null;
+			let char = path.charAt(pos);
+			if(char == "@") {
+				return snikket_Node.CData(new snikket_TextNode(cursor.attr[HxOverrides.substr(path,pos + 1,null)]));
+			} else if(char == "{") {
+				xmlns = path.substring(pos + 1,path.indexOf("}",pos + 1));
+				pos += xmlns.length + 2;
+			}
+			let reName = new EReg("([^@/#]*)([/#]?)","");
+			if(!reName.matchSub(path,pos)) {
+				throw new haxe_Exception("Invalid path to Stanza.find(): " + path);
+			}
+			let name1 = reName.matched(1);
+			let text1 = reName.matched(2);
+			pos = reName.matchedPos().pos + reName.matchedPos().len;
+			if(name1 == "") {
+				name1 = null;
+			}
+			if(pos == len) {
+				if(text1 == "#") {
+					let text = cursor.getChildText(name1,xmlns);
+					if(text == null) {
+						return null;
+					}
+					return snikket_Node.CData(new snikket_TextNode(text));
+				}
+				return snikket_Node.Element(cursor.getChild(name1,xmlns));
+			}
+			cursor = cursor.getChild(name1,xmlns);
+		} while(cursor != null);
+		return null;
+	}
+	findChild(path) {
+		let result = this.find(path);
+		if(result == null) {
+			return null;
+		}
+		if(result == null) {
+			return null;
+		} else if(result._hx_index == 0) {
+			let stanza = result.stanza;
+			return stanza;
+		} else {
+			return null;
+		}
+	}
+	findText(path) {
+		let result = this.find(path);
+		if(result == null) {
+			return null;
+		}
+		if(result == null) {
+			return null;
+		} else if(result._hx_index == 1) {
+			let textNode = result.textNode;
+			return textNode.content;
+		} else {
+			return null;
+		}
+	}
+	traverse(f) {
+		if(!f(this)) {
+			let _g = 0;
+			let _g1 = this.allTags();
+			while(_g < _g1.length) {
+				let child = _g1[_g];
+				++_g;
+				child.traverse(f);
+			}
+		}
+		return this;
+	}
+	getError() {
+		let errorTag = this.getChild("error");
+		if(errorTag == null) {
+			return null;
+		}
+		let errorTag1 = errorTag.attr["type"];
+		let tmp = errorTag.getChild(null,"urn:ietf:params:xml:ns:xmpp-stanzas");
+		return new snikket_StanzaError(errorTag1,tmp != null ? tmp.name : null,errorTag.getChildText("text","urn:ietf:params:xml:ns:xmpp-stanzas"));
+	}
+	removeChildren(name,xmlns_) {
+		let tmp = xmlns_;
+		let xmlns = tmp != null ? tmp : this.attr["xmlns"];
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.children;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			let tmp;
+			if(v._hx_index == 0) {
+				let c = v.stanza;
+				let tmp1;
+				if(name == null || c.name == name) {
+					let tmp = c.attr["xmlns"];
+					tmp1 = (tmp != null ? tmp : xmlns) == xmlns;
+				} else {
+					tmp1 = false;
+				}
+				tmp = !tmp1;
+			} else {
+				tmp = true;
+			}
+			if(tmp) {
+				_g.push(v);
+			}
+		}
+		this.children = _g;
+	}
+	static parse(s) {
+		return snikket_Stanza.fromXml(Xml.parse(s));
+	}
+	static fromXml(el) {
+		if(el.nodeType == 6) {
+			return snikket_Stanza.fromXml(el.firstElement());
+		}
+		let attrs = { };
+		let a = el.attributes();
+		while(a.hasNext()) {
+			let a1 = a.next();
+			attrs[a1] = el.get(a1);
+		}
+		if(el.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element but found " + (el.nodeType == null ? "null" : XmlType.toString(el.nodeType)));
+		}
+		let stanza = new snikket_Stanza(el.nodeName,attrs);
+		if(el.nodeType != Xml.Document && el.nodeType != Xml.Element) {
+			throw haxe_Exception.thrown("Bad node type, expected Element or Document but found " + (el.nodeType == null ? "null" : XmlType.toString(el.nodeType)));
+		}
+		let _g_current = 0;
+		let _g_array = el.children;
+		while(_g_current < _g_array.length) {
+			let child = _g_array[_g_current++];
+			if(child.nodeType == 0) {
+				stanza.addChild(snikket_Stanza.fromXml(child));
+			} else if(!(child.nodeType == 5 || child.nodeType == 4 || child.nodeType == 3)) {
+				if(child.nodeType == Xml.Document || child.nodeType == Xml.Element) {
+					throw haxe_Exception.thrown("Bad node type, unexpected " + (child.nodeType == null ? "null" : XmlType.toString(child.nodeType)));
+				}
+				stanza.text(child.nodeValue);
+			}
+		}
+		return stanza;
+	}
+	static parseXmlBool(x) {
+		if(x != "true") {
+			return x == "1";
+		} else {
+			return true;
+		}
+	}
+}
+$hx_exports["snikket"]["Stanza"] = snikket_Stanza;
+snikket_Stanza.__name__ = "snikket.Stanza";
+snikket_Stanza.__interfaces__ = [snikket__$Stanza_NodeInterface];
+Object.assign(snikket_Stanza.prototype, {
+	__class__: snikket_Stanza
+});
+var snikket_IqRequestType = $hxEnums["snikket.IqRequestType"] = { __ename__:true,__constructs__:null
+	,Get: {_hx_name:"Get",_hx_index:0,__enum__:"snikket.IqRequestType",toString:$estr}
+	,Set: {_hx_name:"Set",_hx_index:1,__enum__:"snikket.IqRequestType",toString:$estr}
+};
+snikket_IqRequestType.__constructs__ = [snikket_IqRequestType.Get,snikket_IqRequestType.Set];
+class snikket_StringUtil {
+	static codepointArray(s) {
+		let result = [];
+		let offset = 0;
+		while(offset < s.length) {
+			let c = s.charCodeAt(offset);
+			if(c >= 55296 && c <= 56319) {
+				c = c - 55232 << 10 | s.charCodeAt(offset + 1) & 1023;
+			}
+			let c1 = c;
+			if(c1 >= 65536) {
+				result.push(HxOverrides.substr(s,offset,2));
+				++offset;
+			} else {
+				result.push(HxOverrides.substr(s,offset,1));
+			}
+			++offset;
+		}
+		return result;
+	}
+	static rawCodepointArray(s) {
+		let result = [];
+		let offset = 0;
+		while(offset < s.length) {
+			let c = s.charCodeAt(offset);
+			if(c >= 55296 && c <= 56319) {
+				c = c - 55232 << 10 | s.charCodeAt(offset + 1) & 1023;
+			}
+			let c1 = c;
+			if(c1 >= 65536) {
+				result.push(c1);
+				++offset;
+			} else {
+				result.push(c1);
+			}
+			++offset;
+		}
+		return result;
+	}
+}
+snikket_StringUtil.__name__ = "snikket.StringUtil";
+function snikket_Util_setupTrace() {
+	haxe_Log.trace = function(v,infos) {
+		if(typeof(console) != "undefined" && console.debug != null) {
+			let tmp = infos.customParams;
+			let params = tmp != null ? tmp : [];
+			infos.customParams = [];
+			let str = haxe_Log.formatOutput(v,infos);
+			let tmp1 = [str].concat(params);
+			console.debug.apply(null,tmp1);
+		} else if(typeof(console) != "undefined" && console.log != null) {
+			let str = haxe_Log.formatOutput(v,infos);
+			console.log(str);
+		}
+	};
+}
+function snikket_Util_downcast(value,c) {
+	let value1 = value;
+	return js_Boot.__downcastCheck(value1,c) ? value1 : null;
+}
+function snikket_Util_xmlEscape(s) {
+	return StringTools.replace(StringTools.replace(StringTools.replace(s,"&","&amp;"),"<","&lt;"),">","&gt;");
+}
+class snikket_Version {
+}
+$hx_exports["snikket"]["Version"] = snikket_Version;
+snikket_Version.__name__ = "snikket.Version";
+class snikket_XEP0393 {
+	static parse(styled) {
+		let blocks = [];
+		while(styled.length > 0) {
+			let result = snikket_XEP0393.parseBlock(styled);
+			styled = result.rest;
+			blocks.push(result.block);
+		}
+		return blocks;
+	}
+	static render(xhtml) {
+		if(xhtml.name == "br") {
+			return "\n";
+		}
+		if(xhtml.name == "img") {
+			let tmp = xhtml.attr["alt"];
+			if(tmp != null) {
+				return tmp;
+			} else {
+				return "";
+			}
+		}
+		let s_b = "";
+		if(xhtml.name == "pre") {
+			s_b += "\n```\n";
+		}
+		if(xhtml.name == "b" || xhtml.name == "strong") {
+			s_b += "*";
+		}
+		if(xhtml.name == "i" || xhtml.name == "em") {
+			s_b += "_";
+		}
+		if(xhtml.name == "s" || xhtml.name == "del") {
+			s_b += "~";
+		}
+		if(xhtml.name == "tt") {
+			s_b += "`";
+		}
+		let _g = 0;
+		let _g1 = xhtml.children;
+		while(_g < _g1.length) {
+			let child = _g1[_g];
+			++_g;
+			s_b += Std.string(snikket_XEP0393.renderNode(child));
+		}
+		if(xhtml.name == "b" || xhtml.name == "strong") {
+			s_b += "*";
+		}
+		if(xhtml.name == "i" || xhtml.name == "em") {
+			s_b += "_";
+		}
+		if(xhtml.name == "s" || xhtml.name == "del") {
+			s_b += "~";
+		}
+		if(xhtml.name == "tt") {
+			s_b += "`";
+		}
+		if(xhtml.name == "blockquote" || xhtml.name == "p" || xhtml.name == "div" || xhtml.name == "pre") {
+			s_b += "\n";
+		}
+		if(xhtml.name == "pre") {
+			s_b += "```\n";
+		}
+		if(xhtml.name == "blockquote") {
+			let _this_r = new RegExp("^","gm".split("u").join(""));
+			return s_b.replace(_this_r,"> ");
+		}
+		return s_b;
+	}
+	static renderNode(xhtml) {
+		switch(xhtml._hx_index) {
+		case 0:
+			let c = xhtml.stanza;
+			return snikket_XEP0393.render(c);
+		case 1:
+			let c1 = xhtml.textNode;
+			return c1.content;
+		}
+	}
+	static parseSpans(styled) {
+		let spans = [];
+		let start = 0;
+		let nextLink = null;
+		while(start < styled.length) if(StringTools.isSpace(styled,start + 1)) {
+			spans.push(snikket_Node.CData(new snikket_TextNode(HxOverrides.substr(styled,start,2))));
+			start += 2;
+		} else if(start != 0 && !StringTools.isSpace(styled,start - 1)) {
+			spans.push(snikket_Node.CData(new snikket_TextNode(styled.charAt(start))));
+			++start;
+		} else if(styled.charAt(start) == "*") {
+			let parsed = snikket_XEP0393.parseSpan("strong","*",styled,start);
+			spans.push(parsed.span);
+			start = parsed.end;
+		} else if(styled.charAt(start) == "_") {
+			let parsed = snikket_XEP0393.parseSpan("em","_",styled,start);
+			spans.push(parsed.span);
+			start = parsed.end;
+		} else if(styled.charAt(start) == "~") {
+			let parsed = snikket_XEP0393.parseSpan("s","~",styled,start);
+			spans.push(parsed.span);
+			start = parsed.end;
+		} else if(styled.charAt(start) == "`") {
+			let parsed = snikket_XEP0393.parseSpan("tt","`",styled,start);
+			spans.push(parsed.span);
+			start = parsed.end;
+		} else {
+			if(nextLink == null || start > nextLink.start) {
+				nextLink = snikket_Autolink.one(styled,start);
+			}
+			if(nextLink != null && nextLink.start == start && nextLink.span != null) {
+				spans.push(nextLink.span);
+				start = nextLink.end;
+			} else {
+				spans.push(snikket_Node.CData(new snikket_TextNode(styled.charAt(start))));
+				++start;
+			}
+		}
+		return spans;
+	}
+	static parseSpan(tagName,marker,styled,start) {
+		let end = start + 1;
+		while(end < styled.length && styled.charAt(end) != marker) {
+			if(StringTools.isSpace(styled,end)) {
+				++end;
+			}
+			++end;
+		}
+		if(end == start + 1) {
+			return { span : snikket_Node.CData(new snikket_TextNode(HxOverrides.substr(styled,start,2))), end : end + 1};
+		} else if(styled.charAt(end) != marker) {
+			return { span : snikket_Node.CData(new snikket_TextNode(HxOverrides.substr(styled,start,end - start))), end : end};
+		} else if(marker == "`") {
+			return { span : snikket_Node.Element(new snikket_Stanza(tagName).text(HxOverrides.substr(styled,start + 1,end - start - 1))), end : end + 1};
+		} else {
+			return { span : snikket_Node.Element(new snikket_Stanza(tagName).addChildNodes(snikket_XEP0393.parseSpans(HxOverrides.substr(styled,start + 1,end - start - 1)))), end : end + 1};
+		}
+	}
+	static parseBlock(styled) {
+		if(styled.charAt(0) == ">") {
+			return snikket_XEP0393.parseQuote(styled);
+		} else if(HxOverrides.substr(styled,0,3) == "```") {
+			return snikket_XEP0393.parsePreformatted(styled);
+		} else {
+			let end = 0;
+			while(end < styled.length && styled.charAt(end) != "\n") ++end;
+			if(end < styled.length && styled.charAt(end) == "\n") {
+				++end;
+			}
+			return { block : new snikket_Stanza("div").addChildNodes(snikket_XEP0393.parseSpans(HxOverrides.substr(styled,0,end))), rest : HxOverrides.substr(styled,end,null)};
+		}
+	}
+	static parseQuote(styled) {
+		let lines = [];
+		let line = "";
+		let end = 1;
+		let spaceAfter = 0;
+		while(end < styled.length) {
+			if(styled.charAt(end) != "\n" && StringTools.isSpace(styled,end)) {
+				++end;
+			}
+			while(end < styled.length && styled.charAt(end) != "\n") {
+				line += styled.charAt(end);
+				++end;
+			}
+			if(end < styled.length && styled.charAt(end) == "\n") {
+				++end;
+			}
+			lines.push(line + "\n");
+			line = "";
+			if(styled.charAt(end) == ">") {
+				++end;
+			} else {
+				break;
+			}
+		}
+		return { block : new snikket_Stanza("blockquote").addChildren(snikket_XEP0393.parse(lines.join(""))), rest : HxOverrides.substr(styled,end,null)};
+	}
+	static parsePreformatted(styled) {
+		let lines = [];
+		let line = null;
+		let end = 0;
+		while(end < styled.length) {
+			while(end < styled.length && styled.charAt(end) != "\n") {
+				if(line != null) {
+					line += styled.charAt(end);
+				}
+				++end;
+			}
+			if(end < styled.length && styled.charAt(end) == "\n") {
+				++end;
+			}
+			if(line != null) {
+				lines.push(line + "\n");
+			}
+			line = "";
+			if(HxOverrides.substr(styled,end,4) == "```\n" || HxOverrides.substr(styled,end,null) == "```") {
+				end += 4;
+				break;
+			}
+		}
+		return { block : new snikket_Stanza("pre").text(lines.join("")), rest : HxOverrides.substr(styled,end,null)};
+	}
+}
+snikket_XEP0393.__name__ = "snikket.XEP0393";
+class snikket_jingle_Group {
+	constructor(semantics,identificationTags) {
+		this.semantics = semantics;
+		this.identificationTags = identificationTags;
+	}
+	toSdp() {
+		if(this.semantics.indexOf(" ") >= 0) {
+			throw haxe_Exception.thrown("Group semantics cannot contain a space in SDP");
+		}
+		return this.semantics + " " + this.identificationTags.join(" ");
+	}
+	toElement() {
+		let group = new snikket_Stanza("group",{ xmlns : "urn:xmpp:jingle:apps:grouping:0", semantics : this.semantics});
+		let _g = 0;
+		let _g1 = this.identificationTags;
+		while(_g < _g1.length) {
+			let tag = _g1[_g];
+			++_g;
+			group.tag("content",{ name : tag}).up();
+		}
+		return group;
+	}
+	static parse(input) {
+		let segments = input.split(" ");
+		if(segments.length < 2) {
+			return null;
+		}
+		return new snikket_jingle_Group(segments[0],segments.slice(1));
+	}
+	static fromElement(el) {
+		let idTags = [];
+		let _g = 0;
+		let _g1 = el.allTags("content");
+		while(_g < _g1.length) {
+			let content = _g1[_g];
+			++_g;
+			if(content.attr["name"] != null) {
+				idTags.push(content.attr["name"]);
+			}
+		}
+		return new snikket_jingle_Group(el.attr["semantics"],idTags);
+	}
+}
+snikket_jingle_Group.__name__ = "snikket.jingle.Group";
+Object.assign(snikket_jingle_Group.prototype, {
+	__class__: snikket_jingle_Group
+});
+class snikket_jingle_Session {
+}
+snikket_jingle_Session.__name__ = "snikket.jingle.Session";
+snikket_jingle_Session.__isInterface__ = true;
+Object.assign(snikket_jingle_Session.prototype, {
+	__class__: snikket_jingle_Session
+});
+class snikket_jingle_IncomingProposedSession {
+	constructor(client,from,sid) {
+		this.accepted = false;
+		this.client = client;
+		this.from = from;
+		this._sid = sid;
+	}
+	ring() {
+		let event = new snikket_Stanza("ringing",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.from,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+		});
+		this.client.trigger("call/ring",{ chatId : this.from.asBare().asString(), session : this});
+	}
+	hangup() {
+		let event = new snikket_Stanza("reject",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.from,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+		});
+		this.client.getDirectChat(this.from.asBare().asString(),false).jingleSessions.delete(this.get_sid());
+	}
+	retract() {
+		this.client.trigger("call/retract",{ chatId : this.from.asBare().asString()});
+	}
+	terminate() {
+		haxe_Log.trace("Tried to terminate before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 102, className : "snikket.jingle.IncomingProposedSession", methodName : "terminate", customParams : [this]});
+	}
+	contentAdd(_) {
+		haxe_Log.trace("Got content-add before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 106, className : "snikket.jingle.IncomingProposedSession", methodName : "contentAdd", customParams : [this]});
+	}
+	contentAccept(_) {
+		haxe_Log.trace("Got content-accept before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 110, className : "snikket.jingle.IncomingProposedSession", methodName : "contentAccept", customParams : [this]});
+	}
+	transportInfo(_) {
+		haxe_Log.trace("Got transport-info before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 114, className : "snikket.jingle.IncomingProposedSession", methodName : "transportInfo", customParams : [this]});
+		return Promise.resolve(null);
+	}
+	accept() {
+		if(this.accepted) {
+			return;
+		}
+		this.accepted = true;
+		this.client.sendPresence(this.from.asString());
+		let event = new snikket_Stanza("proceed",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.from,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+			_gthis.client.sendStanza(new snikket_Stanza("message",{ to : _gthis.from.asString(), type : "chat", id : msg.versions[0].localId}).addChild(event).tag("store",{ xmlns : "urn:xmpp:hints"}));
+		});
+	}
+	initiate(stanza) {
+		let session = snikket_jingle_InitiatedSession.fromSessionInitiate(this.client,stanza);
+		if(session.get_sid() != this.get_sid()) {
+			throw haxe_Exception.thrown("id mismatch");
+		}
+		if(!this.accepted) {
+			throw haxe_Exception.thrown("trying to initiate unaccepted session");
+		}
+		session.accept();
+		return session;
+	}
+	addMedia(_) {
+		throw haxe_Exception.thrown("Cannot add media before call starts");
+	}
+	callStatus() {
+		return "incoming";
+	}
+	videoTracks() {
+		return [];
+	}
+	dtmf() {
+		return null;
+	}
+	get_sid() {
+		return this._sid;
+	}
+}
+snikket_jingle_IncomingProposedSession.__name__ = "snikket.jingle.IncomingProposedSession";
+snikket_jingle_IncomingProposedSession.__interfaces__ = [snikket_jingle_Session];
+Object.assign(snikket_jingle_IncomingProposedSession.prototype, {
+	__class__: snikket_jingle_IncomingProposedSession
+});
+class snikket_jingle_OutgoingProposedSession {
+	constructor(client,to) {
+		this.video = false;
+		this.audio = false;
+		this.client = client;
+		this.to = to;
+		this._sid = snikket_ID.long();
+	}
+	propose(audio,video) {
+		this.audio = audio;
+		this.video = video;
+		let event = new snikket_Stanza("propose",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		if(audio) {
+			event.tag("description",{ xmlns : "urn:xmpp:jingle:apps:rtp:1", media : "audio"}).up();
+		}
+		if(video) {
+			event.tag("description",{ xmlns : "urn:xmpp:jingle:apps:rtp:1", media : "video"}).up();
+		}
+		let msg = snikket_jingle_Session_mkCallMessage(this.to,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			let stanza = new snikket_Stanza("message",{ to : _gthis.to.asString(), type : "chat", id : msg.localId}).addChild(event).tag("store",{ xmlns : "urn:xmpp:hints"});
+			_gthis.client.sendStanza(stanza);
+			_gthis.client.notifyMessageHandlers(stored[0],0);
+			_gthis.client.trigger("call/ringing",{ chatId : _gthis.to.asBare().asString()});
+		});
+	}
+	ring() {
+		haxe_Log.trace("Tried to accept before initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 200, className : "snikket.jingle.OutgoingProposedSession", methodName : "ring", customParams : [this]});
+	}
+	hangup() {
+		let event = new snikket_Stanza("retract",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.to,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.sendStanza(new snikket_Stanza("message",{ to : _gthis.to.asString(), type : "chat", id : msg.versions[0].localId}).addChild(event).tag("store",{ xmlns : "urn:xmpp:hints"}));
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+		});
+		this.client.getDirectChat(this.to.asBare().asString(),false).jingleSessions.delete(this.get_sid());
+	}
+	retract() {
+		this.client.trigger("call/retract",{ chatId : this.to.asBare().asString()});
+	}
+	terminate() {
+		haxe_Log.trace("Tried to terminate before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 223, className : "snikket.jingle.OutgoingProposedSession", methodName : "terminate", customParams : [this]});
+	}
+	contentAdd(_) {
+		haxe_Log.trace("Got content-add before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 227, className : "snikket.jingle.OutgoingProposedSession", methodName : "contentAdd", customParams : [this]});
+	}
+	contentAccept(_) {
+		haxe_Log.trace("Got content-accept before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 231, className : "snikket.jingle.OutgoingProposedSession", methodName : "contentAccept", customParams : [this]});
+	}
+	transportInfo(_) {
+		haxe_Log.trace("Got transport-info before session-initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 235, className : "snikket.jingle.OutgoingProposedSession", methodName : "transportInfo", customParams : [this]});
+		return Promise.resolve(null);
+	}
+	accept() {
+		haxe_Log.trace("Tried to accept before initiate: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 240, className : "snikket.jingle.OutgoingProposedSession", methodName : "accept", customParams : [this]});
+	}
+	initiate(stanza) {
+		let jmi = stanza.getChild("proceed","urn:xmpp:jingle-message:0");
+		if(jmi == null) {
+			throw haxe_Exception.thrown("no jmi: " + Std.string(stanza));
+		}
+		if(jmi.attr["id"] != this.get_sid()) {
+			throw haxe_Exception.thrown("sid doesn't match: " + jmi.attr["id"] + " vs " + this.get_sid());
+		}
+		this.client.sendPresence(this.to.asString());
+		let session = new snikket_jingle_OutgoingSession(this.client,snikket_JID.parse(stanza.attr["from"]),this.get_sid());
+		this.client.trigger("call/media",{ session : session, audio : this.audio, video : this.video});
+		return session;
+	}
+	addMedia(_) {
+		throw haxe_Exception.thrown("Cannot add media before call starts");
+	}
+	callStatus() {
+		return "outgoing";
+	}
+	videoTracks() {
+		return [];
+	}
+	dtmf() {
+		return null;
+	}
+	get_sid() {
+		return this._sid;
+	}
+}
+snikket_jingle_OutgoingProposedSession.__name__ = "snikket.jingle.OutgoingProposedSession";
+snikket_jingle_OutgoingProposedSession.__interfaces__ = [snikket_jingle_Session];
+Object.assign(snikket_jingle_OutgoingProposedSession.prototype, {
+	__class__: snikket_jingle_OutgoingProposedSession
+});
+class snikket_jingle_InitiatedSession {
+	constructor(client,counterpart,sid,remoteDescription) {
+		this.candidatesDone = null;
+		this.afterMedia = null;
+		this.accepted = false;
+		this.queuedOutboundCandidate = [];
+		this.queuedInboundTransportInfo = [];
+		this.peerDtlsSetup = "actpass";
+		this.pc = null;
+		this.localDescription = null;
+		this.remoteDescription = null;
+		this.client = client;
+		this.counterpart = counterpart;
+		this._sid = sid;
+		this.remoteDescription = remoteDescription;
+		this.initiator = remoteDescription == null;
+	}
+	get_sid() {
+		return this._sid;
+	}
+	ring() {
+		this.client.trigger("call/ring",{ chatId : this.counterpart.asBare().asString(), session : this});
+	}
+	retract() {
+		haxe_Log.trace("Tried to retract session in wrong state: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 327, className : "snikket.jingle.InitiatedSession", methodName : "retract", customParams : [this]});
+	}
+	accept() {
+		if(this.accepted || this.remoteDescription == null) {
+			return;
+		}
+		this.accepted = true;
+		let audio = Lambda.find(this.remoteDescription.media,function(m) {
+			return m.media == "audio";
+		}) != null;
+		let video = Lambda.find(this.remoteDescription.media,function(m) {
+			return m.media == "video";
+		}) != null;
+		this.client.trigger("call/media",{ session : this, audio : audio, video : video});
+	}
+	hangup() {
+		this.client.sendStanza(new snikket_Stanza("iq",{ to : this.counterpart.asString(), type : "set", id : snikket_ID.medium()}).tag("jingle",{ xmlns : "urn:xmpp:jingle:1", action : "session-terminate", sid : this.get_sid()}).tag("reason").tag("success").up().up().up());
+		this.terminate();
+	}
+	initiate(stanza) {
+		haxe_Log.trace("Trying to initiate already initiated session: " + this.get_sid(),{ fileName : "snikket/jingle/Session.hx", lineNumber : 350, className : "snikket.jingle.InitiatedSession", methodName : "initiate"});
+		throw haxe_Exception.thrown("already initiated");
+	}
+	terminate() {
+		if(this.pc == null) {
+			return;
+		}
+		this.pc.close();
+		let _g = 0;
+		let _g1 = this.pc.getTransceivers();
+		while(_g < _g1.length) {
+			let tranceiver = _g1[_g];
+			++_g;
+			if(tranceiver.sender != null && tranceiver.sender.track != null) {
+				tranceiver.sender.track.stop();
+			}
+		}
+		this.pc = null;
+		this.client.trigger("call/retract",{ chatId : this.counterpart.asBare().asString()});
+		let event = new snikket_Stanza("finish",{ xmlns : "urn:xmpp:jingle-message:0", id : this.get_sid()});
+		let msg = snikket_jingle_Session_mkCallMessage(this.counterpart,this.client.jid,event);
+		let _gthis = this;
+		this.client.storeMessages([msg],function(stored) {
+			_gthis.client.notifyMessageHandlers(stored[0],1);
+			_gthis.client.sendStanza(new snikket_Stanza("message",{ to : _gthis.counterpart.asString(), type : "chat", id : msg.versions[0].localId}).addChild(event).tag("store",{ xmlns : "urn:xmpp:hints"}));
+		});
+	}
+	contentAdd(stanza) {
+		if(this.remoteDescription == null) {
+			throw haxe_Exception.thrown("Got content-add before session-accept");
+		}
+		let addThis = snikket_jingle_SessionDescription.fromStanza(stanza,this.initiator,this.remoteDescription);
+		let video = false;
+		let audio = false;
+		let _g = 0;
+		let _g1 = addThis.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			if(Lambda.exists(m.attributes,function(attr) {
+				if(attr.key != "sendrecv") {
+					return attr.key == "sendonly";
+				} else {
+					return true;
+				}
+			})) {
+				if(m.media == "video") {
+					video = true;
+				}
+				if(m.media == "audio") {
+					audio = true;
+				}
+			}
+			m.attributes.push(new snikket_jingle_Attribute("setup",this.peerDtlsSetup));
+		}
+		this.remoteDescription = this.remoteDescription.addContent(addThis);
+		let _gthis = this;
+		this.pc.setRemoteDescription({ type : "offer", sdp : this.remoteDescription.toSdp()}).then(function(_) {
+			_gthis.afterMedia = function() {
+				let _gthis1 = _gthis;
+				let _this = addThis.media;
+				let result = new Array(_this.length);
+				let _g = 0;
+				let _g1 = _this.length;
+				while(_g < _g1) {
+					let i = _g++;
+					result[i] = _this[i].mid;
+				}
+				_gthis1.setupLocalDescription("content-accept",result,false,function(gonnaAccept) {
+					if(Lambda.find(gonnaAccept.media,function(m) {
+						return m.contentElement(false).attr["senders"] != Lambda.find(addThis.media,function(addM) {
+							return addM.mid == m.mid;
+						}).contentElement(false).attr["senders"];
+					}) != null) {
+						let modify = gonnaAccept.toStanza("content-modify",_gthis.get_sid(),_gthis.initiator);
+						modify.attr["to"] = _gthis.counterpart.asString();
+						modify.attr["id"] = snikket_ID.medium();
+						_gthis.client.sendStanza(modify);
+					}
+				});
+				_gthis.afterMedia = null;
+			};
+			return _gthis.client.trigger("call/media",{ session : _gthis, audio : audio, video : video});
+		});
+	}
+	contentAccept(stanza) {
+		if(this.remoteDescription == null) {
+			throw haxe_Exception.thrown("Got content-accept before session-accept");
+		}
+		let addThis = snikket_jingle_SessionDescription.fromStanza(stanza,!this.initiator,this.remoteDescription);
+		let _g = 0;
+		let _g1 = addThis.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			m.attributes.push(new snikket_jingle_Attribute("setup",this.peerDtlsSetup));
+		}
+		this.remoteDescription = this.remoteDescription.addContent(addThis);
+		this.pc.setRemoteDescription({ type : "answer", sdp : this.remoteDescription.toSdp()});
+	}
+	transportInfo(stanza) {
+		if(this.pc == null || this.remoteDescription == null) {
+			this.queuedInboundTransportInfo.push(stanza);
+			return Promise.resolve(null);
+		}
+		let _gthis = this;
+		let _this = snikket_jingle_IceCandidate.fromStanza(stanza);
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let candidate = _this[i];
+			let index = _gthis.remoteDescription.identificationTags.indexOf(candidate.sdpMid);
+			result[i] = _gthis.pc.addIceCandidate({ candidate : candidate.toSdp(), sdpMid : candidate.sdpMid, sdpMLineIndex : index < 0 ? null : index, usernameFragment : candidate.ufrag});
+		}
+		return thenshim_Promise.then(thenshim_PromiseTools.all(result),function(_) {
+			return;
+		});
+	}
+	addMedia(streams) {
+		if(this.pc == null) {
+			throw haxe_Exception.thrown("tried to add media before PeerConnection exists");
+		}
+		let _this = this.localDescription.media;
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = _this[i].mid;
+		}
+		let oldMids = result;
+		let _g2 = 0;
+		while(_g2 < streams.length) {
+			let stream = streams[_g2];
+			++_g2;
+			let _g = 0;
+			let _g1 = stream.getTracks();
+			while(_g < _g1.length) {
+				let track = _g1[_g];
+				++_g;
+				this.pc.addTrack(track,stream);
+			}
+		}
+		this.setupLocalDescription("content-add",oldMids,true);
+	}
+	callStatus() {
+		return "ongoing";
+	}
+	videoTracks() {
+		if(this.pc == null) {
+			return [];
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.pc.getTransceivers();
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.receiver != null && v.receiver.track != null && v.receiver.track.kind == "video" && !v.receiver.track.muted) {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			result[i] = _this[i].receiver.track;
+		}
+		return result;
+	}
+	dtmf() {
+		if(this.pc == null) {
+			return null;
+		}
+		let transceiver = Lambda.find(this.pc.getTransceivers(),function(t) {
+			if(t.sender != null && t.sender.track != null && t.sender.track.kind == "audio") {
+				return !t.sender.track.muted;
+			} else {
+				return false;
+			}
+		});
+		if(transceiver == null) {
+			return null;
+		}
+		return transceiver.sender.dtmf;
+	}
+	sendIceCandidate(candidate) {
+		if(candidate == null || candidate.candidate == "") {
+			if(this.candidatesDone != null) {
+				this.candidatesDone();
+			}
+			return;
+		}
+		if(this.candidatesDone != null) {
+			return;
+		}
+		if(this.localDescription == null) {
+			this.queuedOutboundCandidate.push(candidate);
+			return;
+		}
+		let media = Lambda.find(this.localDescription.media,function(media) {
+			return media.mid == candidate.sdpMid;
+		});
+		if(media == null) {
+			throw haxe_Exception.thrown("Unknown media: " + candidate.sdpMid);
+		}
+		let media1 = media.mid;
+		let media2 = media.media;
+		let media3 = media.connectionData;
+		let media4 = media.port;
+		let media5 = media.protocol;
+		let transportInfo = snikket_jingle_Attribute.parse(candidate.candidate);
+		let transportInfo1 = new snikket_jingle_Attribute("ice-ufrag",candidate.usernameFragment);
+		let tmp = Lambda.find(media.attributes,function(attr) {
+			return attr.key == "ice-pwd";
+		});
+		let transportInfo2 = new snikket_jingle_TransportInfo(new snikket_jingle_Media(media1,media2,media3,media4,media5,[transportInfo,transportInfo1,tmp != null ? tmp : Lambda.find(this.localDescription.attributes,function(attr) {
+			return attr.key == "ice-pwd";
+		})],media.formats),this.get_sid()).toStanza(this.initiator);
+		transportInfo2.attr["to"] = this.counterpart.asString();
+		transportInfo2.attr["id"] = snikket_ID.medium();
+		this.client.sendStanza(transportInfo2);
+	}
+	supplyMedia(streams) {
+		let _gthis = this;
+		this.setupPeerConnection(function() {
+			let _g = 0;
+			while(_g < streams.length) {
+				let stream = streams[_g];
+				++_g;
+				let _g1 = 0;
+				let _g2 = stream.getTracks();
+				while(_g1 < _g2.length) {
+					let track = _g2[_g1];
+					++_g1;
+					_gthis.pc.addTrack(track,stream);
+				}
+			}
+			if(_gthis.afterMedia == null) {
+				_gthis.onPeerConnection().catch(function(e) {
+					haxe_Log.trace("supplyMedia error",{ fileName : "snikket/jingle/Session.hx", lineNumber : 523, className : "snikket.jingle.InitiatedSession", methodName : "supplyMedia", customParams : [e]});
+					_gthis.pc.close();
+				});
+			} else {
+				_gthis.afterMedia();
+			}
+		});
+	}
+	setupPeerConnection(callback) {
+		if(this.pc != null) {
+			callback();
+			return;
+		}
+		let _gthis = this;
+		this.client.getIceServers(function(servers) {
+			_gthis.pc = new RTCPeerConnection({ iceServers : servers},null);
+			_gthis.pc.addEventListener("track",function(event) {
+				return _gthis.client.trigger("call/track",{ chatId : _gthis.counterpart.asBare().asString(), track : event.track, streams : event.streams});
+			});
+			_gthis.pc.addEventListener("negotiationneeded",function(event) {
+				haxe_Log.trace("renegotiate",{ fileName : "snikket/jingle/Session.hx", lineNumber : 542, className : "snikket.jingle.InitiatedSession", methodName : "setupPeerConnection", customParams : [event]});
+			});
+			_gthis.pc.addEventListener("icecandidate",function(event) {
+				_gthis.sendIceCandidate(event.candidate);
+			});
+			_gthis.pc.addEventListener("connectionstatechange",function(event) {
+				if(_gthis.pc != null && (_gthis.pc.connectionState == "closed" || _gthis.pc.connectionState == "failed")) {
+					_gthis.terminate();
+				}
+			});
+			callback();
+		});
+	}
+	setupLocalDescription(type,filterMedia,filterOut,beforeSend) {
+		if(filterOut == null) {
+			filterOut = false;
+		}
+		let _gthis = this;
+		return this.pc.setLocalDescription(null).then(function(_) {
+			let caps = _gthis.client.getDirectChat(_gthis.counterpart.asBare().asString()).getResourceCaps(_gthis.counterpart.resource);
+			if((type == "session-initiate" || type == "session-accept") && caps.features.includes("urn:ietf:rfc:3264")) {
+				return new Promise(function(resolve,reject) {
+					let timeout = haxe_Timer.delay(function() {
+						_gthis.candidatesDone = function() {
+						};
+						resolve(false);
+					},3000);
+					_gthis.candidatesDone = function() {
+						timeout.stop();
+						resolve(true);
+					};
+				});
+			} else {
+				return null;
+			}
+		}).then(function(_) {
+			_gthis.localDescription = snikket_jingle_SessionDescription.parse(_gthis.pc.localDescription.sdp);
+			let descriptionToSend = _gthis.localDescription;
+			if(filterMedia != null) {
+				let descriptionToSend1 = descriptionToSend.version;
+				let descriptionToSend2 = descriptionToSend.name;
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = descriptionToSend.media;
+				while(_g1 < _g2.length) {
+					let v = _g2[_g1];
+					++_g1;
+					if(filterOut ? !filterMedia.includes(v.mid) : filterMedia.includes(v.mid)) {
+						_g.push(v);
+					}
+				}
+				descriptionToSend = new snikket_jingle_SessionDescription(descriptionToSend1,descriptionToSend2,_g,descriptionToSend.attributes,descriptionToSend.identificationTags);
+			}
+			if(beforeSend != null) {
+				beforeSend(descriptionToSend);
+			}
+			let sessionAccept = descriptionToSend.toStanza(type,_gthis.get_sid(),_gthis.initiator);
+			sessionAccept.attr["to"] = _gthis.counterpart.asString();
+			sessionAccept.attr["id"] = snikket_ID.medium();
+			_gthis.client.sendStanza(sessionAccept);
+			let outboundCandidate = _gthis.queuedOutboundCandidate.slice();
+			_gthis.queuedOutboundCandidate.length = 0;
+			let _g = 0;
+			while(_g < outboundCandidate.length) {
+				let candidate = outboundCandidate[_g];
+				++_g;
+				_gthis.sendIceCandidate(candidate);
+			}
+		});
+	}
+	onPeerConnection() {
+		let _gthis = this;
+		return this.pc.setRemoteDescription({ type : "offer", sdp : this.remoteDescription.toSdp()}).then(function(_) {
+			let inboundTransportInfo = _gthis.queuedInboundTransportInfo.slice();
+			_gthis.queuedInboundTransportInfo.length = 0;
+			let f = $bind(_gthis,_gthis.transportInfo);
+			let result = new Array(inboundTransportInfo.length);
+			let _g = 0;
+			let _g1 = inboundTransportInfo.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = f(inboundTransportInfo[i]);
+			}
+			return result;
+		}).then(function(_) {
+			return _gthis.setupLocalDescription("session-accept");
+		}).then(function(_) {
+			let tmp = _gthis.localDescription.getDtlsSetup() == "active" ? "passive" : "active";
+			return _gthis.peerDtlsSetup = tmp;
+		});
+	}
+	static fromSessionInitiate(client,stanza) {
+		let jingle = stanza.getChild("jingle","urn:xmpp:jingle:1");
+		let session = new snikket_jingle_InitiatedSession(client,snikket_JID.parse(stanza.attr["from"]),jingle.attr["sid"],snikket_jingle_SessionDescription.fromStanza(stanza,false));
+		session.transportInfo(stanza);
+		return session;
+	}
+}
+snikket_jingle_InitiatedSession.__name__ = "snikket.jingle.InitiatedSession";
+snikket_jingle_InitiatedSession.__interfaces__ = [snikket_jingle_Session];
+Object.assign(snikket_jingle_InitiatedSession.prototype, {
+	__class__: snikket_jingle_InitiatedSession
+});
+class snikket_jingle_OutgoingSession extends snikket_jingle_InitiatedSession {
+	constructor(client,counterpart,sid) {
+		super(client,counterpart,sid,null);
+	}
+	onPeerConnection() {
+		return this.setupLocalDescription("session-initiate");
+	}
+	initiate(stanza) {
+		this.remoteDescription = snikket_jingle_SessionDescription.fromStanza(stanza,true);
+		this.peerDtlsSetup = this.remoteDescription.getDtlsSetup();
+		let _gthis = this;
+		this.pc.setRemoteDescription({ type : "answer", sdp : this.remoteDescription.toSdp()}).then(function(_) {
+			return _gthis.transportInfo(stanza);
+		});
+		return this;
+	}
+}
+snikket_jingle_OutgoingSession.__name__ = "snikket.jingle.OutgoingSession";
+snikket_jingle_OutgoingSession.__super__ = snikket_jingle_InitiatedSession;
+Object.assign(snikket_jingle_OutgoingSession.prototype, {
+	__class__: snikket_jingle_OutgoingSession
+});
+function snikket_jingle_Session_mkCallMessage(to,from,event) {
+	let m = new snikket_ChatMessageBuilder();
+	m.type = 1;
+	m.to = to;
+	m.recipients = [to.asBare()];
+	m.from = from;
+	m.sender = m.from.asBare();
+	m.replyTo = [m.sender];
+	m.direction = 1;
+	m.text = "call " + event.name;
+	m.timestamp = snikket_Date.format(new Date());
+	m.payloads.push(event);
+	m.localId = snikket_ID.long();
+	if(event.name != "propose") {
+		m.versions = [m.build()];
+	}
+	m.localId = event.attr["id"];
+	return m.build();
+}
+class snikket_jingle_SessionDescription {
+	constructor(version,name,media,attributes,identificationTags) {
+		this.version = version;
+		this.name = name;
+		this.media = media;
+		this.attributes = attributes;
+		this.identificationTags = identificationTags;
+	}
+	getUfragPwd() {
+		let ufragPwd = null;
+		let _g = 0;
+		let _g1 = this.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			let mUfragPwd = m.getUfragPwd();
+			if(ufragPwd != null && mUfragPwd.ufrag != ufragPwd.ufrag) {
+				throw haxe_Exception.thrown("ufrag not unique");
+			}
+			if(ufragPwd != null && mUfragPwd.pwd != ufragPwd.pwd) {
+				throw haxe_Exception.thrown("pwd not unique");
+			}
+			ufragPwd = mUfragPwd;
+		}
+		if(ufragPwd == null) {
+			throw haxe_Exception.thrown("no ufrag or pwd found");
+		}
+		return ufragPwd;
+	}
+	getFingerprint() {
+		let fingerprint = Lambda.find(this.attributes,function(attr) {
+			return attr.key == "fingerprint";
+		});
+		if(fingerprint != null) {
+			return fingerprint;
+		}
+		let _g = 0;
+		let _g1 = this.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			let mFingerprint = Lambda.find(m.attributes,function(attr) {
+				return attr.key == "fingerprint";
+			});
+			if(fingerprint != null && mFingerprint != null && fingerprint.value != mFingerprint.value) {
+				throw haxe_Exception.thrown("fingerprint not unique");
+			}
+			fingerprint = mFingerprint;
+		}
+		if(fingerprint == null) {
+			throw haxe_Exception.thrown("no fingerprint found");
+		}
+		return fingerprint;
+	}
+	getDtlsSetup() {
+		let setup = Lambda.find(this.attributes,function(attr) {
+			return attr.key == "setup";
+		});
+		if(setup != null) {
+			return setup.value;
+		}
+		let _g = 0;
+		let _g1 = this.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			let mSetup = Lambda.find(m.attributes,function(attr) {
+				return attr.key == "setup";
+			});
+			if(setup != null && mSetup != null && setup.value != mSetup.value) {
+				throw haxe_Exception.thrown("setup not unique");
+			}
+			setup = mSetup;
+		}
+		if(setup == null) {
+			throw haxe_Exception.thrown("no setup found");
+		}
+		return setup.value;
+	}
+	addContent(newDescription) {
+		let _g = 0;
+		let _g1 = newDescription.media;
+		while(_g < _g1.length) {
+			let newM = _g1[_g];
+			++_g;
+			if(Lambda.find(this.media,function(m) {
+				return m.mid == newM.mid;
+			}) != null) {
+				throw haxe_Exception.thrown("Media with id " + newM.mid + " already exists!");
+			}
+		}
+		let tmp = this.version;
+		let tmp1 = this.name;
+		let tmp2 = this.media.concat(newDescription.media);
+		let _g2 = [];
+		let _g3 = 0;
+		let _g4 = this.attributes;
+		while(_g3 < _g4.length) {
+			let v = _g4[_g3];
+			++_g3;
+			if(v.key != "group") {
+				_g2.push(v);
+			}
+		}
+		let tmp3 = _g2;
+		let _g5 = [];
+		let _g6 = 0;
+		let _g7 = newDescription.attributes;
+		while(_g6 < _g7.length) {
+			let v = _g7[_g6];
+			++_g6;
+			if(v.key == "group") {
+				_g5.push(v);
+			}
+		}
+		return new snikket_jingle_SessionDescription(tmp,tmp1,tmp2,tmp3.concat(_g5),newDescription.identificationTags);
+	}
+	toSdp() {
+		let tmp = "v=" + this.version + "\r\n" + "o=- 8770656990916039506 2 IN IP4 127.0.0.1\r\n" + "s=" + this.name + "\r\n" + "t=0 0\r\n";
+		let _this = this.attributes;
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = _this[i].toSdp();
+		}
+		let tmp1 = tmp + result.join("");
+		let _this1 = this.media;
+		let result1 = new Array(_this1.length);
+		let _g2 = 0;
+		let _g3 = _this1.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			result1[i] = _this1[i].toSdp();
+		}
+		return tmp1 + result1.join("");
+	}
+	toStanza(action,sid,initiator) {
+		let iq = new snikket_Stanza("iq",{ type : "set"});
+		let jingle = iq.tag("jingle",{ xmlns : "urn:xmpp:jingle:1", action : action, sid : sid});
+		let group = Lambda.find(this.attributes,function(attr) {
+			return attr.key == "group";
+		});
+		if(group != null) {
+			jingle.addChild(snikket_jingle_Group.parse(group.value).toElement());
+		}
+		let _g = 0;
+		let _g1 = this.media;
+		while(_g < _g1.length) {
+			let m = _g1[_g];
+			++_g;
+			jingle.addChild(m.toElement(this.attributes,initiator));
+		}
+		jingle.up();
+		return iq;
+	}
+	static parse(input) {
+		let version = 0;
+		let name = "-";
+		let attributes = [];
+		let media = [];
+		let currentAttributes = [];
+		let currentMedia = null;
+		let _g = 0;
+		let _g1 = input.split("\r\n");
+		while(_g < _g1.length) {
+			let line = _g1[_g];
+			++_g;
+			if(line.indexOf("=") != 1) {
+				continue;
+			}
+			let value = HxOverrides.substr(line,2,null);
+			switch(line.charAt(0)) {
+			case "a":
+				currentAttributes.push(snikket_jingle_Attribute.parse(value));
+				break;
+			case "c":
+				if(currentMedia != null) {
+					currentMedia.connectionData = value;
+				}
+				break;
+			case "m":
+				if(currentMedia == null) {
+					attributes = currentAttributes;
+				} else {
+					let mid = Lambda.find(currentAttributes,function(attr) {
+						return attr.key == "mid";
+					});
+					media.push(new snikket_jingle_Media(mid == null ? null : mid.value,currentMedia.media,currentMedia.connectionData,currentMedia.port,currentMedia.protocol,currentAttributes,currentMedia.formats));
+				}
+				currentAttributes = [];
+				let segments = value.split(" ");
+				if(segments.length >= 3) {
+					let segments1 = segments[0];
+					let segments2 = segments[1];
+					let segments3 = segments[2];
+					let _this = segments.slice(3);
+					let result = new Array(_this.length);
+					let _g = 0;
+					let _g1 = _this.length;
+					while(_g < _g1) {
+						let i = _g++;
+						result[i] = Std.parseInt(_this[i]);
+					}
+					currentMedia = { media : segments1, port : segments2, protocol : segments3, formats : result};
+				} else {
+					currentMedia = { };
+				}
+				break;
+			case "s":
+				name = value;
+				break;
+			case "v":
+				version = Std.parseInt(value);
+				break;
+			}
+		}
+		if(currentMedia != null) {
+			let mid = Lambda.find(currentAttributes,function(attr) {
+				return attr.key == "mid";
+			});
+			media.push(new snikket_jingle_Media(mid == null ? null : mid.value,currentMedia.media,currentMedia.connectionData,currentMedia.port,currentMedia.protocol,currentAttributes,currentMedia.formats));
+		} else {
+			attributes = currentAttributes;
+		}
+		let tags;
+		let group = Lambda.find(attributes,function(attr) {
+			return attr.key == "group";
+		});
+		if(group != null) {
+			tags = snikket_jingle_Group.parse(group.value).identificationTags;
+		} else {
+			let result = new Array(media.length);
+			let _g = 0;
+			let _g1 = media.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = media[i].mid;
+			}
+			tags = result;
+		}
+		return new snikket_jingle_SessionDescription(version,name,media,attributes,tags);
+	}
+	static fromStanza(iq,initiator,existingDescription) {
+		let attributes = [];
+		let jingle = iq.getChild("jingle","urn:xmpp:jingle:1");
+		let group = jingle.getChild("group","urn:xmpp:jingle:apps:grouping:0");
+		let _this = jingle.allTags("content");
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = snikket_jingle_Media.fromElement(_this[i],initiator,group != null,existingDescription);
+		}
+		let media = result;
+		let tags;
+		if(group != null) {
+			let group1 = snikket_jingle_Group.fromElement(group);
+			attributes.push(new snikket_jingle_Attribute("group",group1.toSdp()));
+			tags = group1.identificationTags;
+		} else {
+			let result = new Array(media.length);
+			let _g = 0;
+			let _g1 = media.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = media[i].mid;
+			}
+			tags = result;
+		}
+		attributes.push(new snikket_jingle_Attribute("msid-semantic","WMS my-media-stream"));
+		return new snikket_jingle_SessionDescription(0,"-",media,attributes,tags);
+	}
+}
+snikket_jingle_SessionDescription.__name__ = "snikket.jingle.SessionDescription";
+Object.assign(snikket_jingle_SessionDescription.prototype, {
+	__class__: snikket_jingle_SessionDescription
+});
+class snikket_jingle_TransportInfo {
+	constructor(media,sid) {
+		this.media = media;
+		this.sid = sid;
+	}
+	toStanza(initiator) {
+		let iq = new snikket_Stanza("iq",{ type : "set"});
+		let jingle = iq.tag("jingle",{ xmlns : "urn:xmpp:jingle:1", action : "transport-info", sid : this.sid});
+		jingle.addChild(this.media.contentElement(initiator).addChild(this.media.toTransportElement([])).up());
+		jingle.up();
+		return iq;
+	}
+}
+snikket_jingle_TransportInfo.__name__ = "snikket.jingle.TransportInfo";
+Object.assign(snikket_jingle_TransportInfo.prototype, {
+	__class__: snikket_jingle_TransportInfo
+});
+class snikket_jingle_Media {
+	constructor(mid,media,connectionData,port,protocol,attributes,formats) {
+		this.mid = mid;
+		this.media = media;
+		this.connectionData = connectionData;
+		this.port = port;
+		this.protocol = protocol;
+		this.attributes = attributes;
+		this.formats = formats;
+	}
+	toSdp() {
+		let tmp = "m=" + this.media + " " + this.port + " " + this.protocol + " " + this.formats.join(" ") + "\r\n" + "c=" + this.connectionData + "\r\n";
+		let _this = this.attributes;
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = _this[i].toSdp();
+		}
+		return tmp + result.join("");
+	}
+	contentElement(initiator) {
+		let attrs = { xmlns : "urn:xmpp:jingle:1", creator : "initiator", name : this.mid};
+		if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "inactive";
+		})) {
+			attrs["senders"] = "none";
+		} else if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "sendonly";
+		})) {
+			attrs["senders"] = initiator ? "initiator" : "responder";
+		} else if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "recvonly";
+		})) {
+			attrs["senders"] = initiator ? "responder" : "initiator";
+		}
+		return new snikket_Stanza("content",attrs);
+	}
+	toElement(sessionAttributes,initiator) {
+		let content = this.contentElement(initiator);
+		let description = content.tag("description",{ xmlns : "urn:xmpp:jingle:apps:rtp:1", media : this.media});
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.attributes;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.key == "rtcp-fb") {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			let segments = _this[i].value.split(" ");
+			let segments1 = segments[0];
+			let tmp;
+			if(segments[1] == "trr-int") {
+				tmp = new snikket_Stanza("rtcp-fb-trr-int",{ xmlns : "urn:xmpp:jingle:apps:rtp:rtcp-fb:0", value : segments[2]});
+			} else {
+				let fbattrs = { xmlns : "urn:xmpp:jingle:apps:rtp:rtcp-fb:0", type : segments[1]};
+				if(segments.length >= 3) {
+					fbattrs["subtype"] = segments[2];
+				}
+				tmp = new snikket_Stanza("rtcp-fb",fbattrs);
+			}
+			result[i] = { id : segments1, el : tmp};
+		}
+		let fbs = result;
+		let ssrc = new Map([]);
+		let fmtp = new Map([]);
+		let _g5 = 0;
+		let _g6 = this.attributes;
+		while(_g5 < _g6.length) {
+			let attr = _g6[_g5];
+			++_g5;
+			if(attr.key == "fmtp") {
+				let pos = attr.value.indexOf(" ");
+				if(pos < 0) {
+					continue;
+				}
+				let k = HxOverrides.substr(attr.value,0,pos);
+				let _this = HxOverrides.substr(attr.value,pos + 1,null).split(";");
+				let result = new Array(_this.length);
+				let _g = 0;
+				let _g1 = _this.length;
+				while(_g < _g1) {
+					let i = _g++;
+					let param = _this[i];
+					let eqPos = param.indexOf("=");
+					let attrs = { value : eqPos > 0 ? HxOverrides.substr(param,eqPos + 1,null) : param};
+					if(eqPos > 0) {
+						attrs["name"] = HxOverrides.substr(param,0,eqPos);
+					}
+					result[i] = new snikket_Stanza("parameter",attrs);
+				}
+				fmtp.set(k,result);
+			} else if(attr.key == "ssrc") {
+				let pos = attr.value.indexOf(" ");
+				if(pos < 0) {
+					continue;
+				}
+				let id = HxOverrides.substr(attr.value,0,pos);
+				if(ssrc.get(id) == null) {
+					ssrc.set(id,[]);
+				}
+				let param = HxOverrides.substr(attr.value,pos + 1,null);
+				let colonPos = param.indexOf(":");
+				let attrs = { name : colonPos > 0 ? HxOverrides.substr(param,0,colonPos) : param};
+				if(colonPos > 0) {
+					attrs["value"] = HxOverrides.substr(param,colonPos + 1,null);
+				}
+				ssrc.get(id).push(new snikket_Stanza("parameter",attrs));
+			} else if(attr.key == "extmap") {
+				let pos = attr.value.indexOf(" ");
+				if(pos < 0) {
+					continue;
+				}
+				description.tag("rtp-hdrext",{ xmlns : "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0", id : HxOverrides.substr(attr.value,0,pos), uri : HxOverrides.substr(attr.value,pos + 1,null)}).up();
+			} else if(attr.key == "ssrc-group") {
+				let segments = attr.value.split(" ");
+				if(segments.length < 2) {
+					continue;
+				}
+				let group = description.tag("ssrc-group",{ xmlns : "urn:xmpp:jingle:apps:rtp:ssma:0", semantics : segments[0]});
+				let _g = 0;
+				let _g1 = segments.slice(1);
+				while(_g < _g1.length) {
+					let seg = _g1[_g];
+					++_g;
+					group.tag("source",{ ssrc : seg}).up();
+				}
+				group.up();
+			}
+		}
+		let _g7 = [];
+		let _g8 = 0;
+		let _g9 = fbs;
+		while(_g8 < _g9.length) {
+			let v = _g9[_g8];
+			++_g8;
+			if(v.id == "*") {
+				_g7.push(v);
+			}
+		}
+		let _this1 = _g7;
+		let result1 = new Array(_this1.length);
+		let _g10 = 0;
+		let _g11 = _this1.length;
+		while(_g10 < _g11) {
+			let i = _g10++;
+			result1[i] = _this1[i].el;
+		}
+		description.addChildren(result1);
+		let _g12 = [];
+		let _g13 = 0;
+		let _g14 = this.attributes;
+		while(_g13 < _g14.length) {
+			let v = _g14[_g13];
+			++_g13;
+			if(v.key == "rtpmap") {
+				_g12.push(v);
+			}
+		}
+		let _this2 = _g12;
+		let result2 = new Array(_this2.length);
+		let _g15 = 0;
+		let _g16 = _this2.length;
+		while(_g15 < _g16) {
+			let i = _g15++;
+			let rtpmap = _this2[i];
+			let pos = rtpmap.value.indexOf(" ");
+			if(pos < 0) {
+				throw haxe_Exception.thrown("invalid rtpmap");
+			}
+			let id = HxOverrides.substr(rtpmap.value,0,pos);
+			let segments = HxOverrides.substr(rtpmap.value,pos + 1,null).split("/");
+			let attrs = { id : id};
+			if(segments.length > 0) {
+				attrs["name"] = segments[0];
+			}
+			if(segments.length > 1) {
+				attrs["clockrate"] = segments[1];
+			}
+			if(segments.length > 2 && segments[2] != "" && segments[2] != "1") {
+				attrs["channels"] = segments[2];
+			}
+			let tmp = new snikket_Stanza("payload-type",attrs);
+			let _g = [];
+			let _g1 = 0;
+			let _g2 = fbs;
+			while(_g1 < _g2.length) {
+				let v = _g2[_g1];
+				++_g1;
+				if(v.id == id) {
+					_g.push(v);
+				}
+			}
+			let _this = _g;
+			let result = new Array(_this.length);
+			let _g3 = 0;
+			let _g4 = _this.length;
+			while(_g3 < _g4) {
+				let i = _g3++;
+				result[i] = _this[i].el;
+			}
+			let tmp1 = fmtp.get(id) == null ? [] : fmtp.get(id);
+			result2[i] = tmp.addChildren(result).addChildren(tmp1);
+		}
+		description.addChildren(result2);
+		if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "extmap-allow-mixed";
+		}) || Lambda.exists(sessionAttributes,function(attr) {
+			return attr.key == "extmap-allow-mixed";
+		})) {
+			description.tag("extmap-allow-mixed",{ xmlns : "urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"}).up();
+		}
+		let jsIterator = ssrc.entries();
+		let _g_jsIterator = jsIterator;
+		let _g_lastStep = jsIterator.next();
+		while(!_g_lastStep.done) {
+			let v = _g_lastStep.value;
+			_g_lastStep = _g_jsIterator.next();
+			let entry_key = v[0];
+			let entry_value = v[1];
+			let msid = Lambda.find(this.attributes,function(attr) {
+				return attr.key == "msid";
+			});
+			if(msid != null && !Lambda.exists(entry_value,function(param) {
+				return param.attr["name"] == "msid";
+			})) {
+				entry_value.push(new snikket_Stanza("parameter",{ name : "msid", value : msid.value}));
+			}
+			description.tag("source",{ xmlns : "urn:xmpp:jingle:apps:rtp:ssma:0", ssrc : entry_key}).addChildren(entry_value).up();
+		}
+		if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "rtcp-mux";
+		})) {
+			description.tag("rtcp-mux").up();
+		}
+		if(Lambda.exists(this.attributes,function(attr) {
+			return attr.key == "ice-lite";
+		})) {
+			description.tag("ice-lite").up();
+		}
+		description.up();
+		content.addChild(this.toTransportElement(sessionAttributes)).up();
+		return content;
+	}
+	getUfragPwd(sessionAttributes) {
+		let tmp = sessionAttributes;
+		let allAttributes = this.attributes.concat(tmp != null ? tmp : []);
+		let ufrag = Lambda.find(allAttributes,function(attr) {
+			return attr.key == "ice-ufrag";
+		});
+		let pwd = Lambda.find(allAttributes,function(attr) {
+			return attr.key == "ice-pwd";
+		});
+		if(ufrag == null || pwd == null) {
+			throw haxe_Exception.thrown("transport is missing ufrag or pwd");
+		}
+		return { ufrag : ufrag.value, pwd : pwd.value};
+	}
+	toTransportElement(sessionAttributes) {
+		let transportAttr = { xmlns : "urn:xmpp:jingle:transports:ice-udp:1"};
+		let ufragPwd = this.getUfragPwd(sessionAttributes);
+		transportAttr["ufrag"] = ufragPwd.ufrag;
+		transportAttr["pwd"] = ufragPwd.pwd;
+		let transport = new snikket_Stanza("transport",transportAttr);
+		let fingerprint = Lambda.find(this.attributes.concat(sessionAttributes),function(attr) {
+			return attr.key == "fingerprint";
+		});
+		let setup = Lambda.find(this.attributes.concat(sessionAttributes),function(attr) {
+			return attr.key == "setup";
+		});
+		if(fingerprint != null && setup != null && fingerprint.value.indexOf(" ") > 0) {
+			let pos = fingerprint.value.indexOf(" ");
+			transport.textTag("fingerprint",HxOverrides.substr(fingerprint.value,pos + 1,null),{ xmlns : "urn:xmpp:jingle:apps:dtls:0", hash : HxOverrides.substr(fingerprint.value,0,pos), setup : setup.value});
+		}
+		let _gthis = this;
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.attributes;
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			if(v.key == "candidate") {
+				_g.push(v);
+			}
+		}
+		let _this = _g;
+		let result = new Array(_this.length);
+		let _g3 = 0;
+		let _g4 = _this.length;
+		while(_g3 < _g4) {
+			let i = _g3++;
+			result[i] = snikket_jingle_IceCandidate.parse(_this[i].value,_gthis.mid,ufragPwd.ufrag).toElement();
+		}
+		transport.addChildren(result);
+		transport.up();
+		return transport;
+	}
+	static fromElement(content,initiator,hasGroup,existingDescription) {
+		let mediaAttributes = [];
+		let mediaFormats = [];
+		let mid = content.attr["name"];
+		let transport = content.getChild("transport","urn:xmpp:jingle:transports:ice-udp:1");
+		if(transport == null) {
+			throw haxe_Exception.thrown("ice-udp transport is missing");
+		}
+		let ufrag = transport.attr["ufrag"];
+		let pwd = transport.attr["pwd"];
+		if((ufrag == null || pwd == null) && existingDescription != null) {
+			let ufragPwd = existingDescription.getUfragPwd();
+			ufrag = ufragPwd.ufrag;
+			pwd = ufragPwd.pwd;
+		}
+		if(ufrag == null) {
+			throw haxe_Exception.thrown("transport is missing ufrag");
+		}
+		mediaAttributes.push(new snikket_jingle_Attribute("ice-ufrag",ufrag));
+		if(pwd == null) {
+			throw haxe_Exception.thrown("transport is missing pwd");
+		}
+		mediaAttributes.push(new snikket_jingle_Attribute("ice-pwd",pwd));
+		mediaAttributes.push(new snikket_jingle_Attribute("ice-options","trickle"));
+		let fingerprint = transport.getChild("fingerprint","urn:xmpp:jingle:apps:dtls:0");
+		if(fingerprint == null) {
+			if(existingDescription != null) {
+				mediaAttributes.push(existingDescription.getFingerprint());
+			}
+		} else {
+			mediaAttributes.push(new snikket_jingle_Attribute("fingerprint",fingerprint.attr["hash"] + " " + fingerprint.getText()));
+			if(fingerprint.attr["setup"] != null) {
+				mediaAttributes.push(new snikket_jingle_Attribute("setup",fingerprint.attr["setup"]));
+			}
+		}
+		let description = content.getChild("description","urn:xmpp:jingle:apps:rtp:1");
+		let _g = 0;
+		let _g1 = description.allTags("payload-type");
+		while(_g < _g1.length) {
+			let payloadType = _g1[_g];
+			++_g;
+			let id = Std.parseInt(payloadType.attr["id"]);
+			if(payloadType.attr["id"] == null) {
+				throw haxe_Exception.thrown("payload-type missing or invalid id");
+			}
+			mediaFormats.push(id);
+			let clockRate = Std.parseInt(payloadType.attr["clockrate"]);
+			let channels = Std.parseInt(payloadType.attr["channels"]);
+			mediaAttributes.push(new snikket_jingle_Attribute("rtpmap",id + " " + payloadType.attr["name"] + "/" + (clockRate == null ? 0 : clockRate) + (channels == null || channels == 1 ? "" : "/" + channels)));
+			let _this = payloadType.allTags("parameter");
+			let result = new Array(_this.length);
+			let _g2 = 0;
+			let _g3 = _this.length;
+			while(_g2 < _g3) {
+				let i = _g2++;
+				let el = _this[i];
+				result[i] = (el.attr["name"] == null ? "" : el.attr["name"] + "=") + el.attr["value"];
+			}
+			let parameters = result;
+			if(parameters.length > 0) {
+				mediaAttributes.push(new snikket_jingle_Attribute("fmtp",id + " " + parameters.join(";")));
+			}
+			let _g4 = 0;
+			let _g5 = payloadType.allTags("rtcp-fb","urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
+			while(_g4 < _g5.length) {
+				let feedbackNegotiation = _g5[_g4];
+				++_g4;
+				let subtype = feedbackNegotiation.attr["subtype"];
+				mediaAttributes.push(new snikket_jingle_Attribute("rtcp-fb",id + " " + feedbackNegotiation.attr["type"] + (subtype == null || subtype == "" ? "" : " " + subtype)));
+			}
+			let _g6 = 0;
+			let _g7 = payloadType.allTags("rtcp-fb-trr-int","urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
+			while(_g6 < _g7.length) {
+				let trrInt = _g7[_g6];
+				++_g6;
+				mediaAttributes.push(new snikket_jingle_Attribute("rtcp-fb",id + " trr-int " + trrInt.attr["value"]));
+			}
+		}
+		let _g2 = 0;
+		let _g3 = description.allTags("rtcp-fb","urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
+		while(_g2 < _g3.length) {
+			let feedbackNegotiation = _g3[_g2];
+			++_g2;
+			let subtype = feedbackNegotiation.attr["subtype"];
+			mediaAttributes.push(new snikket_jingle_Attribute("rtcp-fb","* " + feedbackNegotiation.attr["type"] + (subtype == null || subtype == "" ? "" : " " + subtype)));
+		}
+		let _g4 = 0;
+		let _g5 = description.allTags("rtcp-fb-trr-int","urn:xmpp:jingle:apps:rtp:rtcp-fb:0");
+		while(_g4 < _g5.length) {
+			let trrInt = _g5[_g4];
+			++_g4;
+			mediaAttributes.push(new snikket_jingle_Attribute("rtcp-fb","* trr-int " + trrInt.attr["value"]));
+		}
+		let _g6 = 0;
+		let _g7 = description.allTags("rtp-hdrext","urn:xmpp:jingle:apps:rtp:rtp-hdrext:0");
+		while(_g6 < _g7.length) {
+			let headerExtension = _g7[_g6];
+			++_g6;
+			mediaAttributes.push(new snikket_jingle_Attribute("extmap",headerExtension.attr["id"] + " " + headerExtension.attr["uri"]));
+		}
+		if(description.getChild("extmap-allow-mixed","urn:xmpp:jingle:apps:rtp:rtp-hdrext:0") != null) {
+			mediaAttributes.push(new snikket_jingle_Attribute("extmap-allow-mixed",""));
+		}
+		let _g8 = 0;
+		let _g9 = description.allTags("ssrc-group","urn:xmpp:jingle:apps:rtp:ssma:0");
+		while(_g8 < _g9.length) {
+			let sourceGroup = _g9[_g8];
+			++_g8;
+			let tmp = sourceGroup.attr["semantics"] + " ";
+			let _this = sourceGroup.allTags("source");
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].attr["ssrc"];
+			}
+			mediaAttributes.push(new snikket_jingle_Attribute("ssrc-group",tmp + result.join(" ")));
+		}
+		let _g10 = 0;
+		let _g11 = description.allTags("source","urn:xmpp:jingle:apps:rtp:ssma:0");
+		while(_g10 < _g11.length) {
+			let source = _g11[_g10];
+			++_g10;
+			let _g = 0;
+			let _g1 = source.allTags("parameter");
+			while(_g < _g1.length) {
+				let parameter = _g1[_g];
+				++_g;
+				mediaAttributes.push(new snikket_jingle_Attribute("ssrc",source.attr["ssrc"] + " " + parameter.attr["name"] + ":" + parameter.attr["value"]));
+			}
+		}
+		mediaAttributes.push(new snikket_jingle_Attribute("mid",mid));
+		let _g12 = content.attr["senders"];
+		if(_g12 == null) {
+			mediaAttributes.push(new snikket_jingle_Attribute("sendrecv",""));
+		} else {
+			switch(_g12) {
+			case "initiator":
+				if(initiator) {
+					mediaAttributes.push(new snikket_jingle_Attribute("sendonly",""));
+				} else {
+					mediaAttributes.push(new snikket_jingle_Attribute("recvonly",""));
+				}
+				break;
+			case "none":
+				mediaAttributes.push(new snikket_jingle_Attribute("inactive",""));
+				break;
+			case "responder":
+				if(initiator) {
+					mediaAttributes.push(new snikket_jingle_Attribute("recvonly",""));
+				} else {
+					mediaAttributes.push(new snikket_jingle_Attribute("sendonly",""));
+				}
+				break;
+			default:
+				mediaAttributes.push(new snikket_jingle_Attribute("sendrecv",""));
+			}
+		}
+		if(hasGroup || description.getChild("rtcp-mux") != null) {
+			mediaAttributes.push(new snikket_jingle_Attribute("rtcp-mux",""));
+		}
+		if(description.getChild("ice-lite") != null) {
+			mediaAttributes.push(new snikket_jingle_Attribute("ice-lite",""));
+		}
+		mediaAttributes.push(new snikket_jingle_Attribute("rtcp","9 IN IP4 0.0.0.0"));
+		return new snikket_jingle_Media(mid,description == null ? "" : description.attr["media"],"IN IP4 0.0.0.0","9","UDP/TLS/RTP/SAVPF",mediaAttributes,mediaFormats);
+	}
+}
+snikket_jingle_Media.__name__ = "snikket.jingle.Media";
+Object.assign(snikket_jingle_Media.prototype, {
+	__class__: snikket_jingle_Media
+});
+class snikket_jingle_IceCandidate {
+	constructor(sdpMid,ufrag,foundation,component,transport,priority,connectionAddress,port,parameters) {
+		this.sdpMid = sdpMid;
+		this.ufrag = ufrag;
+		this.foundation = foundation;
+		this.component = component;
+		this.transport = transport;
+		this.priority = priority;
+		this.connectionAddress = connectionAddress;
+		this.port = port;
+		this.parameters = parameters;
+	}
+	toElement() {
+		let tmp = this.parameters.get("generation");
+		let attrs = { xmlns : this.parameters.get("tcptype") == null ? "urn:xmpp:jingle:transports:ice-udp:1" : "urn:xmpp:jingle:transports:ice:0", foundation : this.foundation, component : this.component, protocol : this.transport.toLowerCase(), priority : this.priority, ip : this.connectionAddress, port : this.port, generation : tmp != null ? tmp : "0"};
+		if(this.parameters.get("typ") != null) {
+			attrs["type"] = this.parameters.get("typ");
+		}
+		if(this.parameters.get("raddr") != null) {
+			attrs["rel-addr"] = this.parameters.get("raddr");
+		}
+		if(this.parameters.get("rport") != null) {
+			attrs["rel-port"] = this.parameters.get("rport");
+		}
+		if(this.parameters.get("tcptype") != null) {
+			attrs["tcptype"] = this.parameters.get("tcptype");
+		}
+		return new snikket_Stanza("candidate",attrs);
+	}
+	toSdp() {
+		let result = "candidate:" + this.foundation + " " + this.component + " " + this.transport + " " + this.priority + " " + this.connectionAddress + " " + this.port;
+		if(this.parameters.has("typ")) {
+			result += " typ " + this.parameters.get("typ");
+		}
+		if(this.parameters.has("raddr")) {
+			result += " raddr " + this.parameters.get("raddr");
+		}
+		if(this.parameters.has("rport")) {
+			result += " rport " + this.parameters.get("rport");
+		}
+		let jsIterator = this.parameters.entries();
+		let entry_jsIterator = jsIterator;
+		let entry_lastStep = jsIterator.next();
+		while(!entry_lastStep.done) {
+			let v = entry_lastStep.value;
+			entry_lastStep = entry_jsIterator.next();
+			let entry_key = v[0];
+			let entry_value = v[1];
+			if(entry_key != "typ" && entry_key != "raddr" && entry_key != "rport") {
+				result += " " + entry_key + " " + entry_value;
+			}
+		}
+		return result;
+	}
+	static fromElement(candidate,sdpMid,ufrag) {
+		let parameters = new Map([]);
+		if(candidate.attr["type"] != null) {
+			parameters.set("typ",candidate.attr["type"]);
+		}
+		if(candidate.attr["rel-addr"] != null) {
+			parameters.set("raddr",candidate.attr["rel-addr"]);
+		}
+		if(candidate.attr["rel-port"] != null) {
+			parameters.set("rport",candidate.attr["rel-port"]);
+		}
+		if(candidate.attr["generation"] != null) {
+			parameters.set("generation",candidate.attr["generation"]);
+		}
+		if(candidate.attr["tcptype"] != null) {
+			parameters.set("tcptype",candidate.attr["tcptype"]);
+		}
+		if(ufrag != null) {
+			parameters.set("ufrag",ufrag);
+		}
+		return new snikket_jingle_IceCandidate(sdpMid,ufrag,candidate.attr["foundation"],candidate.attr["component"],candidate.attr["protocol"].toLowerCase(),candidate.attr["priority"],candidate.attr["ip"],candidate.attr["port"],parameters);
+	}
+	static fromTransport(transport,sdpMid) {
+		let _this = transport.allTags("candidate");
+		let result = new Array(_this.length);
+		let _g = 0;
+		let _g1 = _this.length;
+		while(_g < _g1) {
+			let i = _g++;
+			result[i] = snikket_jingle_IceCandidate.fromElement(_this[i],sdpMid,transport.attr["ufrag"]);
+		}
+		return result;
+	}
+	static fromStanza(iq) {
+		let jingle = iq.getChild("jingle","urn:xmpp:jingle:1");
+		let _g = [];
+		let x = $getIterator(jingle.allTags("content"));
+		while(x.hasNext()) {
+			let x1 = x.next();
+			let transport = x1.getChild("transport","urn:xmpp:jingle:transports:ice-udp:1");
+			_g.push(snikket_jingle_IceCandidate.fromTransport(transport,x1.attr["name"]));
+		}
+		let _g1 = [];
+		let e = $getIterator(_g);
+		while(e.hasNext()) {
+			let e1 = e.next();
+			let x = $getIterator(e1);
+			while(x.hasNext()) {
+				let x1 = x.next();
+				_g1.push(x1);
+			}
+		}
+		return _g1;
+	}
+	static parse(input,sdpMid,ufrag) {
+		if(HxOverrides.substr(input,0,10) == "candidate:") {
+			input = HxOverrides.substr(input,11,null);
+		}
+		let segments = input.split(" ");
+		let paramSegs = segments.slice(6);
+		let paramLength = paramSegs.length / 2 | 0;
+		let parameters = new Map([]);
+		let _g = 0;
+		let _g1 = paramLength;
+		while(_g < _g1) {
+			let i = _g++;
+			parameters.set(paramSegs[i * 2],paramSegs[i * 2 + 1]);
+		}
+		if(ufrag != null) {
+			parameters.set("ufrag",ufrag);
+		}
+		return new snikket_jingle_IceCandidate(sdpMid,ufrag,segments[0],segments[1],segments[2],segments[3],segments[4],segments[5],parameters);
+	}
+}
+snikket_jingle_IceCandidate.__name__ = "snikket.jingle.IceCandidate";
+Object.assign(snikket_jingle_IceCandidate.prototype, {
+	__class__: snikket_jingle_IceCandidate
+});
+class snikket_jingle_Attribute {
+	constructor(key,value) {
+		this.key = key;
+		this.value = value;
+	}
+	toSdp() {
+		return "a=" + this.key + (this.value == null || this.value == "" ? "" : ":" + this.value) + "\r\n";
+	}
+	toString() {
+		return this.toSdp();
+	}
+	static parse(input) {
+		let pos = input.indexOf(":");
+		if(pos < 0) {
+			return new snikket_jingle_Attribute(input,"");
+		} else {
+			return new snikket_jingle_Attribute(HxOverrides.substr(input,0,pos),HxOverrides.substr(input,pos + 1,null));
+		}
+	}
+}
+snikket_jingle_Attribute.__name__ = "snikket.jingle.Attribute";
+Object.assign(snikket_jingle_Attribute.prototype, {
+	__class__: snikket_jingle_Attribute
+});
+class snikket_persistence_Dummy {
+	constructor() {
+	}
+	lastId(accountId,chatId,callback) {
+		callback(null);
+	}
+	storeChats(accountId,chat) {
+	}
+	getChats(accountId,callback) {
+		callback([]);
+	}
+	storeMessages(accountId,messages,callback) {
+		callback(messages);
+	}
+	updateMessage(accountId,message) {
+	}
+	getMessage(accountId,chatId,serverId,localId,callback) {
+		callback(null);
+	}
+	getMessagesBefore(accountId,chatId,beforeId,beforeTime,callback) {
+		callback([]);
+	}
+	getMessagesAfter(accountId,chatId,afterId,afterTime,callback) {
+		callback([]);
+	}
+	getMessagesAround(accountId,chatId,aroundId,aroundTime,callback) {
+		callback([]);
+	}
+	getChatsUnreadDetails(accountId,chats,callback) {
+		callback([]);
+	}
+	storeReaction(accountId,update,callback) {
+		callback(null);
+	}
+	updateMessageStatus(accountId,localId,status,callback) {
+		callback(null);
+	}
+	getMediaUri(hashAlgorithm,hash,callback) {
+		callback(null);
+	}
+	hasMedia(hashAlgorithm,hash,callback) {
+		callback(false);
+	}
+	storeMedia(mime,bd,callback) {
+		callback();
+	}
+	removeMedia(hashAlgorithm,hash) {
+	}
+	storeCaps(caps) {
+	}
+	getCaps(ver,callback) {
+		callback(null);
+	}
+	storeLogin(login,clientId,displayName,token) {
+	}
+	getLogin(login,callback) {
+		callback(null,null,0,null);
+	}
+	removeAccount(accountId,completely) {
+	}
+	storeStreamManagement(accountId,sm) {
+	}
+	getStreamManagement(accountId,callback) {
+		callback(null);
+	}
+	storeService(accountId,serviceId,name,node,caps) {
+	}
+	findServicesWithFeature(accountId,feature,callback) {
+		callback([]);
+	}
+}
+$hx_exports["snikket"]["persistence"]["Dummy"] = snikket_persistence_Dummy;
+snikket_persistence_Dummy.__name__ = "snikket.persistence.Dummy";
+snikket_persistence_Dummy.__interfaces__ = [snikket_Persistence];
+Object.assign(snikket_persistence_Dummy.prototype, {
+	__class__: snikket_persistence_Dummy
+});
+class snikket_persistence_KeyValueStore {
+}
+snikket_persistence_KeyValueStore.__name__ = "snikket.persistence.KeyValueStore";
+snikket_persistence_KeyValueStore.__isInterface__ = true;
+Object.assign(snikket_persistence_KeyValueStore.prototype, {
+	__class__: snikket_persistence_KeyValueStore
+});
+class snikket_persistence_MediaStore {
+}
+snikket_persistence_MediaStore.__name__ = "snikket.persistence.MediaStore";
+snikket_persistence_MediaStore.__isInterface__ = true;
+Object.assign(snikket_persistence_MediaStore.prototype, {
+	__class__: snikket_persistence_MediaStore
+});
+class snikket_persistence_Sqlite {
+	constructor(dbfile,media) {
+		this.smStoreNext = null;
+		this.smStoreInProgress = false;
+		this.storeChatTimer = null;
+		this.storeChatBuffer = new Map([]);
+		this.media = media;
+		media.setKV(this);
+		this.db = new snikket_persistence_SqliteDriver(dbfile);
+		let _gthis = this;
+		let version = thenshim_Promise.then(this.db.exec("PRAGMA user_version;"),function(iter) {
+			let tmp = iter.array[iter.current++];
+			let tmp1 = Std.parseInt(tmp != null ? tmp.user_version : null);
+			let version = tmp1 != null ? tmp1 : 0;
+			if(version < 1) {
+				_gthis.db.exec("CREATE TABLE messages (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tmam_id TEXT,\n\t\t\t\t\tmam_by TEXT,\n\t\t\t\t\tstanza_id TEXT,\n\t\t\t\t\tcorrection_id TEXT NOT NULL,\n\t\t\t\t\tsync_point INTEGER NOT NULL,\n\t\t\t\t\tchat_id TEXT NOT NULL,\n\t\t\t\t\tsender_id TEXT NOT NULL,\n\t\t\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\t\t\tstatus INTEGER NOT NULL,\n\t\t\t\t\tdirection INTEGER NOT NULL,\n\t\t\t\t\ttype INTEGER NOT NULL,\n\t\t\t\t\tstanza TEXT NOT NULL,\n\t\t\t\t\tPRIMARY KEY (account_id, mam_id, mam_by, stanza_id)\n\t\t\t\t);\n\t\t\t\tCREATE INDEX messages_created_at ON messages (account_id, chat_id, created_at);\n\t\t\t\tCREATE INDEX messages_correction_id ON messages (correction_id);\n\t\t\t\tCREATE TABLE chats (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tchat_id TEXT NOT NULL,\n\t\t\t\t\ttrusted INTEGER NOT NULL,\n\t\t\t\t\tavatar_sha1 BLOB,\n\t\t\t\t\tfn TEXT,\n\t\t\t\t\tui_state INTEGER NOT NULL,\n\t\t\t\t\tblocked INTEGER NOT NULL,\n\t\t\t\t\textensions TEXT,\n\t\t\t\t\tread_up_to_id TEXT,\n\t\t\t\t\tread_up_to_by TEXT,\n\t\t\t\t\tcaps_ver BLOB,\n\t\t\t\t\tpresence BLOB NOT NULL,\n\t\t\t\t\tclass TEXT NOT NULL,\n\t\t\t\t\tPRIMARY KEY (account_id, chat_id)\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE keyvaluepairs (\n\t\t\t\t\tk TEXT NOT NULL PRIMARY KEY,\n\t\t\t\t\tv TEXT NOT NULL\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE caps (\n\t\t\t\t\tsha1 BLOB NOT NULL PRIMARY KEY,\n\t\t\t\t\tcaps BLOB NOT NULL\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE services (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tservice_id TEXT NOT NULL,\n\t\t\t\t\tname TEXT,\n\t\t\t\t\tnode TEXT,\n\t\t\t\t\tcaps BLOB NOT NULL,\n\t\t\t\t\tPRIMARY KEY (account_id, service_id)\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE accounts (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tclient_id TEXT NOT NULL,\n\t\t\t\t\tdisplay_name TEXT,\n\t\t\t\t\ttoken TEXT,\n\t\t\t\t\tfast_count INTEGER NOT NULL DEFAULT 0,\n\t\t\t\t\tsm_state BLOB,\n\t\t\t\t\tPRIMARY KEY (account_id)\n\t\t\t\t) STRICT;\n\t\t\t\tCREATE TABLE reactions (\n\t\t\t\t\taccount_id TEXT NOT NULL,\n\t\t\t\t\tupdate_id TEXT NOT NULL,\n\t\t\t\t\tmam_id TEXT,\n\t\t\t\t\tmam_by TEXT,\n\t\t\t\t\tstanza_id TEXT,\n\t\t\t\t\tchat_id TEXT NOT NULL,\n\t\t\t\t\tsender_id TEXT NOT NULL,\n\t\t\t\t\tcreated_at INTEGER NOT NULL,\n\t\t\t\t\treactions BLOB NOT NULL,\n\t\t\t\t\tkind INTEGER NOT NULL,\n\t\t\t\t\tPRIMARY KEY (account_id, chat_id, sender_id, update_id)\n\t\t\t\t) STRICT;\n\t\t\t\tPRAGMA user_version = 1;");
+			}
+		});
+	}
+	get(k,callback) {
+		thenshim_Promise.then(this.db.exec("SELECT v FROM keyvaluepairs WHERE k=? LIMIT 1",[k]),function(iter) {
+			let _g = iter;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				callback(row.v);
+				return;
+			}
+			callback(null);
+		});
+	}
+	set(k,v,callback) {
+		if(v == null) {
+			thenshim_Promise.then(this.db.exec("DELETE FROM keyvaluepairs WHERE k=?",[k]),function(_) {
+				callback();
+			});
+		} else {
+			thenshim_Promise.then(this.db.exec("INSERT OR REPLACE INTO keyvaluepairs VALUES (?,?)",[k,v]),function(_) {
+				callback();
+			});
+		}
+	}
+	lastId(accountId,chatId,callback) {
+		let params = [accountId];
+		let q = "SELECT mam_id FROM messages WHERE mam_id IS NOT NULL AND sync_point AND account_id=?";
+		if(chatId == null) {
+			q += " AND mam_by=?";
+			params.push(accountId);
+		} else {
+			q += " AND chat_id=?";
+			params.push(chatId);
+		}
+		q += " ORDER BY ROWID DESC LIMIT 1";
+		thenshim_Promise.then(this.db.exec(q,params),function(iter) {
+			let callback1 = callback;
+			let tmp = iter.array[iter.current++];
+			callback1(tmp != null ? tmp.mam_id : null);
+		},function(_) {
+			callback(null);
+		});
+	}
+	storeChats(accountId,chats) {
+		if(this.storeChatTimer != null) {
+			this.storeChatTimer.stop();
+		}
+		let _g = 0;
+		while(_g < chats.length) {
+			let chat = chats[_g];
+			++_g;
+			this.storeChatBuffer.set(accountId + "\n" + chat.chatId,chat);
+		}
+		let _gthis = this;
+		this.storeChatTimer = haxe_Timer.delay(function() {
+			let mapPresence = function(chat) {
+				let storePresence = { };
+				let jsIterator = chat.presence.entries();
+				let _g_jsIterator = jsIterator;
+				let _g_lastStep = jsIterator.next();
+				while(!_g_lastStep.done) {
+					let v = _g_lastStep.value;
+					_g_lastStep = _g_jsIterator.next();
+					let _g_key = v[0];
+					let _g_value = v[1];
+					let resource = _g_key;
+					let presence = _g_value;
+					storePresence[resource] = { };
+					if(presence.caps != null) {
+						_gthis.storeCaps(presence.caps);
+						storePresence[resource].caps = presence.caps.ver();
+					}
+					if(presence.mucUser != null) {
+						storePresence[resource].mucUser = presence.mucUser.toString();
+					}
+				}
+				return storePresence;
+			};
+			let q_b = "";
+			q_b += "INSERT OR REPLACE INTO chats VALUES ";
+			let first = true;
+			let jsIterator = _gthis.storeChatBuffer.values();
+			let __jsIterator = jsIterator;
+			let __lastStep = jsIterator.next();
+			while(!__lastStep.done) {
+				let v = __lastStep.value;
+				__lastStep = __jsIterator.next();
+				let _ = v;
+				if(!first) {
+					q_b += ",";
+				}
+				first = false;
+				q_b += "(?,?,?,?,?,?,?,?,?,?,?,jsonb(?),?)";
+			}
+			let _gthis1 = _gthis.db;
+			let this1 = _gthis.storeChatBuffer;
+			let _g = [];
+			let x = $getIterator({ iterator : function() {
+				return new js_lib_HaxeIterator(this1.values());
+			}});
+			while(x.hasNext()) {
+				let x1 = x.next();
+				let channel = ((x1) instanceof snikket_Channel) ? x1 : null;
+				if(channel != null) {
+					_gthis.storeCaps(channel.disco);
+				}
+				let accountId1 = accountId;
+				let x2 = x1.chatId;
+				let row = x1.isTrusted();
+				let x3 = x1.avatarSha1;
+				let row1 = x1.getDisplayName();
+				let x4 = x1.uiState;
+				let x5 = x1.isBlocked;
+				let row2 = x1.extensions.toString();
+				let row3 = x1.readUpTo();
+				let x6 = x1.readUpToBy;
+				let tmp = channel != null ? channel.disco : null;
+				let row4 = tmp != null ? tmp.verRaw().hash : null;
+				let row5 = JSON.stringify(mapPresence(x1));
+				let c = js_Boot.getClass(x1);
+				let row6 = [accountId1,x2,row,x3,row1,x4,x5,row2,row3,x6,row4,row5,c.__name__.split(".").pop()];
+				_g.push(row6);
+			}
+			let _g1 = [];
+			let e = $getIterator(_g);
+			while(e.hasNext()) {
+				let e1 = e.next();
+				let x = $getIterator(e1);
+				while(x.hasNext()) {
+					let x1 = x.next();
+					_g1.push(x1);
+				}
+			}
+			_gthis1.exec(q_b,_g1);
+			_gthis.storeChatTimer = null;
+			_gthis.storeChatBuffer.clear();
+		},100);
+	}
+	getChats(accountId,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(this.db.exec("SELECT chat_id, trusted, avatar_sha1, fn, ui_state, blocked, extensions, read_up_to_id, read_up_to_by, json(caps) AS caps, json(presence) AS presence, class FROM chats LEFT JOIN caps ON chats.caps_ver=caps.sha1 WHERE account_id=?",[accountId]),function(result) {
+			let fetchCaps = new Map([]);
+			let chats = [];
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let capsJson = row.caps == null ? null : JSON.parse(row.caps);
+				row.capsObj = capsJson == null ? null : new snikket_Caps(capsJson.node,capsJson.identities.map(function(i) {
+					return new snikket_Identity(i.category,i.type,i.name);
+				}),capsJson.features);
+				let presenceJson = JSON.parse(row.presence);
+				row.presenceJson = presenceJson;
+				let access = presenceJson;
+				let _g_access = access;
+				let _g_keys = Reflect.fields(access);
+				let _g_index = 0;
+				while(_g_index < _g_keys.length) {
+					let key = _g_keys[_g_index++];
+					let _g_value = _g_access[key];
+					let _g_key = key;
+					let resource = _g_key;
+					let presence = _g_value;
+					if(presence.caps) {
+						let k = haxe_crypto_Base64.decode(presence.caps).b.bufferValue;
+						fetchCaps.set(k,true);
+					}
+				}
+				chats.push(row);
+			}
+			let fetchCapsSha1s = Lambda.array({ iterator : function() {
+				return new js_lib_HaxeIterator(fetchCaps.keys());
+			}});
+			let _gthis1 = _gthis.db;
+			let result1 = new Array(fetchCapsSha1s.length);
+			let _g1 = 0;
+			let _g2 = fetchCapsSha1s.length;
+			while(_g1 < _g2) {
+				let i = _g1++;
+				result1[i] = "?";
+			}
+			return thenshim_Promise.then(_gthis1.exec("SELECT sha1, json(caps) AS caps FROM caps WHERE sha1 IN (" + result1.join(",") + ")",fetchCapsSha1s),function(capsResult) {
+				return { chats : chats, caps : capsResult};
+			});
+		}),function(result) {
+			let capsMap = new Map([]);
+			let _g = result.caps;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let json = JSON.parse(row.caps);
+				let k = haxe_crypto_Base64.encode(haxe_io_Bytes.ofData(row.sha1));
+				let v = new snikket_Caps(json.node,json.identities.map(function(i) {
+					return new snikket_Identity(i.category,i.type,i.name);
+				}),json.features);
+				capsMap.set(k,v);
+			}
+			let chats = [];
+			let _g1 = 0;
+			let _g2 = result.chats;
+			while(_g1 < _g2.length) {
+				let row = _g2[_g1];
+				++_g1;
+				let presenceMap = new Map([]);
+				let presenceJson = row.presenceJson;
+				let access = presenceJson;
+				let _g_access = access;
+				let _g_keys = Reflect.fields(access);
+				let _g_index = 0;
+				while(_g_index < _g_keys.length) {
+					let key = _g_keys[_g_index++];
+					let _g_value = _g_access[key];
+					let _g_key = key;
+					let resource = _g_key;
+					let presence = _g_value;
+					let v = new snikket_Presence(presence.caps == null ? null : capsMap.get(presence.caps),presence.mucUser == null ? null : snikket_Stanza.parse(presence.mucUser));
+					presenceMap.set(resource,v);
+				}
+				chats.push(new snikket_SerializedChat(row.chat_id,row.trusted,row.avatar_sha1,presenceMap,row.fn,row.ui_state,row.blocked,row.extensions,row.read_up_to_id,row.read_up_to_by,row.capsObj,Reflect.field(row,"class")));
+			}
+			callback(chats);
+		});
+	}
+	storeMessages(accountId,messages,callback) {
+		if(messages.length < 1) {
+			callback(messages);
+			return;
+		}
+		let chatIds = [];
+		let localIds = [];
+		let replyTos = [];
+		let _g = 0;
+		while(_g < messages.length) {
+			let message = messages[_g];
+			++_g;
+			if(message.serverId == null && message.localId == null) {
+				throw haxe_Exception.thrown("Cannot store a message with no id");
+			}
+			if(message.serverId == null && message.isIncoming()) {
+				throw haxe_Exception.thrown("Cannot store an incoming message with no server id");
+			}
+			if(message.serverId != null && message.serverIdBy == null) {
+				throw haxe_Exception.thrown("Cannot store a message with a server id and no by");
+			}
+			if(!message.isIncoming() && message.versions.length < 1) {
+				chatIds.push(message.chatId());
+				localIds.push(message.localId);
+			}
+			if(message.replyToMessage != null && message.replyToMessage.serverIdBy == null) {
+				replyTos.push({ chatId : message.chatId(), serverId : message.replyToMessage.serverId, localId : message.replyToMessage.localId});
+			}
+		}
+		let _gthis = this;
+		let tmp;
+		if(chatIds.length > 0 && localIds.length > 0) {
+			let q_b = "";
+			q_b += "DELETE FROM messages WHERE account_id=? AND direction=? AND chat_id IN (";
+			let result = new Array(chatIds.length);
+			let _g = 0;
+			let _g1 = chatIds.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = "?";
+			}
+			q_b += Std.string(result.join(","));
+			q_b += ") AND stanza_id IN (";
+			let result1 = new Array(localIds.length);
+			let _g2 = 0;
+			let _g3 = localIds.length;
+			while(_g2 < _g3) {
+				let i = _g2++;
+				result1[i] = "?";
+			}
+			q_b += Std.string(result1.join(","));
+			q_b += ")";
+			tmp = this.db.exec(q_b,[accountId,1].concat(chatIds).concat(localIds));
+		} else {
+			tmp = thenshim_Promise.resolve(null);
+		}
+		thenshim_Promise.then(thenshim_Promise.then(tmp,function(_) {
+			let _gthis1 = _gthis.db;
+			let result = new Array(messages.length);
+			let _g = 0;
+			let _g1 = messages.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = "(?,?,?,?,?,?,?,?,CAST(unixepoch(?, 'subsec') * 1000 AS INTEGER),?,?,?,?)";
+			}
+			let tmp = "INSERT OR REPLACE INTO messages VALUES " + result.join(",");
+			let _g2 = [];
+			let _g_current = 0;
+			let _g_array = messages;
+			while(_g_current < _g_array.length) {
+				let x = _g_array[_g_current++];
+				let correctable = x;
+				let message = x.versions.length == 1 ? x.versions[0] : x;
+				let tmp = correctable.localId;
+				_g2.push([accountId,message.serverId,message.serverIdBy,message.localId,tmp != null ? tmp : correctable.serverId,correctable.syncPoint,correctable.chatId(),correctable.senderId,message.timestamp,message.status,message.direction,message.type,message.asStanza().toString()]);
+			}
+			let _g3 = [];
+			let e = $getIterator(_g2);
+			while(e.hasNext()) {
+				let e1 = e.next();
+				let x = $getIterator(e1);
+				while(x.hasNext()) {
+					let x1 = x.next();
+					_g3.push(x1);
+				}
+			}
+			return _gthis1.exec(tmp,_g3);
+		}),function(_) {
+			return thenshim_Promise.then(thenshim_Promise.then(_gthis.hydrateReplyTo(accountId,messages,replyTos),function(ms) {
+				return _gthis.hydrateReactions(accountId,ms);
+			}),callback);
+		});
+	}
+	updateMessage(accountId,message) {
+		this.storeMessages(accountId,[message],function(_) {
+		});
+	}
+	getMessage(accountId,chatId,serverId,localId,callback) {
+		let q = "SELECT stanza, direction, type, strftime('%FT%H:%M:%fZ', created_at / 1000.0, 'unixepoch') AS timestamp, sender_id, mam_id, mam_by, sync_point FROM messages WHERE account_id=? AND chat_id=?";
+		let params = [accountId,chatId];
+		if(serverId != null) {
+			q += " AND mam_id=?";
+			params.push(serverId);
+		} else if(localId != null) {
+			q += " AND stanza_id=?";
+			params.push(localId);
+		}
+		q += "LIMIT 1";
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(this.db.exec(q,params),function(result) {
+			return _gthis.hydrateMessages(accountId,result);
+		}),function(messages) {
+			let _g = 0;
+			while(_g < messages.length) {
+				let message = messages[_g];
+				++_g;
+				thenshim_Promise.then(thenshim_Promise.then(message.replyToMessage != null ? _gthis.hydrateReplyTo(accountId,[message],[{ chatId : chatId, serverId : message.replyToMessage.serverId, localId : message.replyToMessage.localId}]) : thenshim_Promise.resolve([message]),function(messages) {
+					return _gthis.hydrateReactions(accountId,messages);
+				}),function(hydrated) {
+					callback(hydrated[0]);
+				});
+				return;
+			}
+			callback(null);
+		});
+	}
+	getMessages(accountId,chatId,time,op) {
+		let q = "SELECT\n\t\t\tcorrection_id AS stanza_id,\n\t\t\tversions.stanza,\n\t\t\tjson_group_object(COALESCE(versions.mam_id, versions.stanza_id), strftime('%FT%H:%M:%fZ', versions.created_at / 1000.0, 'unixepoch')) AS version_times,\n\t\t\tjson_group_object(COALESCE(versions.mam_id, versions.stanza_id), versions.stanza) AS versions,\n\t\t\tmessages.direction,\n\t\t\tmessages.type,\n\t\t\tstrftime('%FT%H:%M:%fZ', messages.created_at / 1000.0, 'unixepoch') AS timestamp,\n\t\t\tmessages.sender_id,\n\t\t\tmessages.mam_id,\n\t\t\tmessages.mam_by,\n\t\t\tmessages.sync_point,\n\t\t\tMAX(versions.created_at)\n\t\t\tFROM messages INNER JOIN messages versions USING (correction_id) WHERE messages.stanza_id=correction_id AND messages.account_id=? AND messages.chat_id=?";
+		let params = [accountId,chatId];
+		if(time != null) {
+			q += " AND messages.created_at " + op + "CAST(unixepoch(?, 'subsec') * 1000 AS INTEGER)";
+			params.push(time);
+		}
+		q += " GROUP BY correction_id ORDER BY messages.created_at";
+		if(op == "<" || op == "<=") {
+			q += " DESC";
+		}
+		q += ", messages.ROWID";
+		if(op == "<" || op == "<=") {
+			q += " DESC";
+		}
+		q += " LIMIT 50";
+		let _gthis = this;
+		return thenshim_Promise.then(thenshim_Promise.then(thenshim_Promise.then(this.db.exec(q,params),function(result) {
+			return _gthis.hydrateMessages(accountId,result);
+		}),function(iter) {
+			let arr = [];
+			let replyTos = [];
+			let _g = 0;
+			while(_g < iter.length) {
+				let message = iter[_g];
+				++_g;
+				arr.push(message);
+				if(message.replyToMessage != null && message.replyToMessage.serverIdBy == null) {
+					replyTos.push({ chatId : message.chatId(), serverId : message.replyToMessage.serverId, localId : message.replyToMessage.localId});
+				}
+			}
+			if(op == "<" || op == "<=") {
+				arr.reverse();
+			}
+			return _gthis.hydrateReplyTo(accountId,arr,replyTos);
+		}),function(messages) {
+			return _gthis.hydrateReactions(accountId,messages);
+		});
+	}
+	getMessagesBefore(accountId,chatId,beforeId,beforeTime,callback) {
+		thenshim_Promise.then(this.getMessages(accountId,chatId,beforeTime,"<"),callback);
+	}
+	getMessagesAfter(accountId,chatId,afterId,afterTime,callback) {
+		thenshim_Promise.then(this.getMessages(accountId,chatId,afterTime,">"),callback);
+	}
+	getMessagesAround(accountId,chatId,aroundId,aroundTime,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(aroundTime == null ? thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+			_gthis.getMessage(accountId,chatId,aroundId,null,resolve);
+		}),function(m) {
+			if(m != null) {
+				return thenshim_Promise.resolve(m.timestamp);
+			} else {
+				return thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+					_gthis.getMessage(accountId,chatId,null,aroundId,resolve);
+				}),function(m) {
+					if(m != null) {
+						return m.timestamp;
+					} else {
+						return null;
+					}
+				});
+			}
+		}) : thenshim_Promise.resolve(aroundTime),function(aroundTime) {
+			return thenshim_PromiseTools.all([_gthis.getMessages(accountId,chatId,aroundTime,"<"),_gthis.getMessages(accountId,chatId,aroundTime,">=")]);
+		}),function(results) {
+			let callback1 = callback;
+			let _g = [];
+			let _g_current = 0;
+			let _g_array = results;
+			while(_g_current < _g_array.length) {
+				let x = _g_array[_g_current++];
+				_g.push(x);
+			}
+			let _g1 = [];
+			let e = $getIterator(_g);
+			while(e.hasNext()) {
+				let e1 = e.next();
+				let x = $getIterator(e1);
+				while(x.hasNext()) {
+					let x1 = x.next();
+					_g1.push(x1);
+				}
+			}
+			callback1(_g1);
+		});
+	}
+	getChatsUnreadDetails(accountId,chats,callback) {
+		if(chats == null || chats.length < 1) {
+			callback([]);
+			return;
+		}
+		let params = [accountId];
+		let subq_b = "";
+		subq_b += "SELECT chat_id, MAX(created_at) AS created_at FROM messages WHERE account_id=?";
+		subq_b += " AND chat_id IN (";
+		let _g_current = 0;
+		let _g_array = chats;
+		while(_g_current < _g_array.length) {
+			let _g_value = _g_array[_g_current];
+			let _g_key = _g_current++;
+			let i = _g_key;
+			let chat = _g_value;
+			if(i != 0) {
+				subq_b += ",";
+			}
+			subq_b += "?";
+			params.push(chat.chatId);
+		}
+		subq_b += ") AND (mam_id IN (";
+		let didOne = false;
+		let _g = 0;
+		while(_g < chats.length) {
+			let chat = chats[_g];
+			++_g;
+			if(chat.readUpTo() != null) {
+				if(didOne) {
+					subq_b += ",";
+				}
+				subq_b += "?";
+				params.push(chat.readUpTo());
+				didOne = true;
+			}
+		}
+		subq_b += ") OR direction=?) GROUP BY chat_id";
+		params.push(1);
+		let q_b = "";
+		q_b += "SELECT chat_id AS chatId, stanza, direction, type, sender_id, mam_id, mam_by, sync_point, CASE WHEN subq.created_at IS NULL THEN COUNT(*) ELSE COUNT(*) - 1 END AS unreadCount, strftime('%FT%H:%M:%fZ', MAX(messages.created_at) / 1000.0, 'unixepoch') AS timestamp FROM messages LEFT JOIN (";
+		q_b += Std.string(subq_b);
+		q_b += ") subq USING (chat_id) WHERE account_id=? AND chat_id IN (";
+		params.push(accountId);
+		let _g_current1 = 0;
+		let _g_array1 = chats;
+		while(_g_current1 < _g_array1.length) {
+			let _g_value = _g_array1[_g_current1];
+			let _g_key = _g_current1++;
+			let i = _g_key;
+			let chat = _g_value;
+			if(i != 0) {
+				q_b += ",";
+			}
+			q_b += "?";
+			params.push(chat.chatId);
+		}
+		q_b += ") AND (subq.created_at IS NULL OR messages.created_at >= subq.created_at) GROUP BY chat_id;";
+		let _gthis = this;
+		thenshim_Promise.then(this.db.exec(q_b,params),function(result) {
+			let details = [];
+			let rows = Lambda.array({ iterator : function() {
+				return result;
+			}});
+			return thenshim_Promise.then(thenshim_Promise.resolve(_gthis.hydrateMessages(accountId,new haxe_iterators_ArrayIterator(rows))),function(messages) {
+				let _g_current = 0;
+				let _g_array = messages;
+				while(_g_current < _g_array.length) {
+					let _g_value = _g_array[_g_current];
+					let _g_key = _g_current++;
+					let i = _g_key;
+					let m = _g_value;
+					details.push({ unreadCount : rows[i].unreadCount, chatId : rows[i].chatId, message : m});
+				}
+				callback(details);
+			});
+		});
+	}
+	storeReaction(accountId,update,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(this.db.exec("INSERT OR REPLACE INTO reactions VALUES (?,?,?,?,?,?,?,CAST(unixepoch(?, 'subsec') * 1000 AS INTEGER),jsonb(?),?)",[accountId,update.updateId,update.serverId,update.serverIdBy,update.localId,update.chatId,update.senderId,update.timestamp,JSON.stringify(update.reactions),update.kind]),function(_) {
+			_gthis.getMessage(accountId,update.chatId,update.serverId,update.localId,callback);
+		});
+	}
+	updateMessageStatus(accountId,localId,status,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(thenshim_Promise.then(this.db.exec("UPDATE messages SET status=? WHERE account_id=? AND stanza_id=? AND direction=? AND status <> ?",[status,accountId,localId,1,2]),function(_) {
+			return _gthis.db.exec("SELECT stanza, direction, type, strftime('%FT%H:%M:%fZ', created_at / 1000.0, 'unixepoch') AS timestamp, sender_id, mam_id, mam_by, sync_point FROM messages WHERE account_id=? AND stanza_id=? AND direction=?",[accountId,localId,1]);
+		}),function(result) {
+			return _gthis.hydrateMessages(accountId,result);
+		}),function(messages) {
+			let _g = 0;
+			while(_g < messages.length) {
+				let message = messages[_g];
+				++_g;
+				thenshim_Promise.then(thenshim_Promise.then(message.replyToMessage != null ? _gthis.hydrateReplyTo(accountId,[message],[{ chatId : message.chatId(), serverId : message.replyToMessage.serverId, localId : message.replyToMessage.localId}]) : thenshim_Promise.resolve([message]),function(messages) {
+					return _gthis.hydrateReactions(accountId,messages);
+				}),function(hydrated) {
+					callback(hydrated[0]);
+				});
+				return;
+			}
+		});
+	}
+	hasMedia(hashAlgorithm,hash,callback) {
+		this.media.hasMedia(hashAlgorithm,hash,callback);
+	}
+	removeMedia(hashAlgorithm,hash) {
+		this.media.removeMedia(hashAlgorithm,hash);
+	}
+	storeMedia(mime,bd,callback) {
+		this.media.storeMedia(mime,bd,callback);
+	}
+	storeCaps(caps) {
+		this.db.exec("INSERT OR IGNORE INTO caps VALUES (?,jsonb(?))",[caps.verRaw().hash,JSON.stringify({ node : caps.node, identities : caps.identities, features : caps.features})]);
+	}
+	getCaps(ver,callback) {
+		let verData;
+		try {
+			verData = haxe_crypto_Base64.decode(ver).b.bufferValue;
+		} catch( _g ) {
+			callback(null);
+			return;
+		}
+		thenshim_Promise.then(this.db.exec("SELECT json(caps) AS caps FROM caps WHERE sha1=? LIMIT 1",[verData]),function(result) {
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let json = JSON.parse(row.caps);
+				callback(new snikket_Caps(json.node,json.identities.map(function(i) {
+					return new snikket_Identity(i.category,i.type,i.name);
+				}),json.features));
+				return;
+			}
+			callback(null);
+		});
+	}
+	storeLogin(accountId,clientId,displayName,token) {
+		let params = [accountId,clientId,displayName];
+		let q_b = "";
+		q_b += "INSERT INTO accounts (account_id, client_id, display_name";
+		if(token != null) {
+			q_b += ", token, fast_count";
+		}
+		q_b += ") VALUES (?,?,?";
+		if(token != null) {
+			q_b += ",?";
+			params.push(token);
+			q_b += ",0";
+		}
+		q_b += ") ON CONFLICT DO UPDATE SET client_id=?";
+		params.push(clientId);
+		q_b += ", display_name=?";
+		params.push(displayName);
+		if(token != null) {
+			q_b += ", token=?";
+			params.push(token);
+			q_b += ", fast_count=0";
+		}
+		this.db.exec(q_b,params);
+	}
+	getLogin(accountId,callback) {
+		let _gthis = this;
+		thenshim_Promise.then(this.db.exec("SELECT client_id, display_name, token, fast_count FROM accounts WHERE account_id=? LIMIT 1",[accountId]),function(result) {
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				if(row.token != null) {
+					_gthis.db.exec("UPDATE accounts SET fast_count=fast_count+1 WHERE account_id=?",[accountId]);
+				}
+				let tmp = row.fast_count;
+				callback(row.client_id,row.token,tmp != null ? tmp : 0,row.display_name);
+				return;
+			}
+			callback(null,null,0,null);
+		});
+	}
+	removeAccount(accountId,completely) {
+		this.db.exec("DELETE FROM accounts WHERE account_id=?",[accountId]);
+		if(!completely) {
+			return;
+		}
+		this.db.exec("DELETE FROM messages WHERE account_id=?",[accountId]);
+		this.db.exec("DELETE FROM chats WHERE account_id=?",[accountId]);
+		this.db.exec("DELETE FROM services WHERE account_id=?",[accountId]);
+	}
+	storeStreamManagement(accountId,sm) {
+		this.smStoreNext = sm;
+		let _gthis = this;
+		if(!this.smStoreInProgress) {
+			this.smStoreInProgress = true;
+			thenshim_Promise.then(this.db.exec("UPDATE accounts SET sm_state=? WHERE account_id=?",[sm,accountId]),function(_) {
+				_gthis.smStoreInProgress = false;
+				if(_gthis.smStoreNext != sm) {
+					_gthis.storeStreamManagement(accountId,sm);
+				}
+			});
+		}
+	}
+	getStreamManagement(accountId,callback) {
+		thenshim_Promise.then(this.db.exec("SELECT sm_state FROM accounts  WHERE account_id=?",[accountId]),function(result) {
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				callback(row.sm_state);
+				return;
+			}
+			callback(null);
+		});
+	}
+	storeService(accountId,serviceId,name,node,caps) {
+		this.storeCaps(caps);
+		this.db.exec("INSERT OR REPLACE INTO services VALUES (?,?,?,?,?)",[accountId,serviceId,name,node,caps.verRaw().hash]);
+	}
+	findServicesWithFeature(accountId,feature,callback) {
+		thenshim_Promise.then(this.db.exec("SELECT service_id, name, node, json(caps.caps) AS caps FROM services INNER JOIN caps ON services.caps=caps.sha1 WHERE account_id=?",[accountId]),function(result) {
+			let services = [];
+			let _g = result;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let json = JSON.parse(row.caps);
+				let features = json.features;
+				if(features.contains(feature)) {
+					let json1 = json.node;
+					let tmp = json.identities.map(function(i) {
+						return new snikket_Identity(i.category,i.type,i.name);
+					});
+					let tmp1 = features.array();
+					row.set("caps",new snikket_Caps(json1,tmp,tmp1));
+					services.push(row);
+				}
+			}
+			callback(services);
+		});
+	}
+	hydrateReactions(accountId,messages) {
+		let result = new Array(messages.length);
+		let _g = 0;
+		let _g1 = messages.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let m = messages[i];
+			result[i] = { chatId : m.chatId(), serverId : m.serverId, serverIdBy : m.serverIdBy, localId : m.localId};
+		}
+		return thenshim_Promise.then(this.fetchReactions(accountId,result),function(result) {
+			let jsIterator = result.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let id = _g_key;
+				let reactions = _g_value;
+				let m = Lambda.find(messages,function(m) {
+					return (m.serverId == null ? m.localId : m.serverId + "\n" + m.serverIdBy) + "\n" + m.chatId() == id;
+				});
+				if(m != null) {
+					m.set_reactions(reactions);
+				}
+			}
+			return messages;
+		});
+	}
+	fetchReactions(accountId,ids) {
+		let q_b = "";
+		q_b += "SELECT kind, chat_id, mam_id, mam_by, stanza_id, sender_id, json(reactions) AS reactions FROM reactions WHERE 1=0";
+		let params = [];
+		let _g = 0;
+		while(_g < ids.length) {
+			let item = ids[_g];
+			++_g;
+			if(item.serverId != null) {
+				q_b += " OR (mam_id=? AND mam_by=?)";
+				params.push(item.serverId);
+				params.push(item.serverIdBy);
+			} else {
+				q_b += " OR stanza_id=?";
+				params.push(item.localId);
+			}
+		}
+		q_b += " ORDER BY created_at, ROWID";
+		return thenshim_Promise.then(this.db.exec(q_b,params),function(rows) {
+			let agg = new Map([]);
+			let _g = rows;
+			while(_g.current < _g.array.length) {
+				let row = _g.array[_g.current++];
+				let reactions = JSON.parse(row.reactions);
+				let mapId = (row.mam_id == null ? row.stanza_id : row.mam_id + "\n" + row.mam_by) + "\n" + row.chat_id;
+				if(!agg.has(mapId)) {
+					agg.set(mapId,new Map([]));
+				}
+				let map = agg.get(mapId);
+				if(!map.has(row.sender_id)) {
+					let v = [];
+					map.set(row.sender_id,v);
+				}
+				if(row.kind == 1) {
+					let _g = 0;
+					while(_g < reactions.length) {
+						let reaction = reactions[_g];
+						++_g;
+						map.get(row.sender_id).push(reaction);
+					}
+				} else if(row.kind == 0) {
+					let k = row.sender_id;
+					let _g = [];
+					let _g1 = 0;
+					let _g2 = map.get(row.sender_id);
+					while(_g1 < _g2.length) {
+						let v = _g2[_g1];
+						++_g1;
+						if(v.uri != null) {
+							_g.push(v);
+						}
+					}
+					let v = reactions.concat(_g);
+					map.set(k,v);
+				} else if(row.kind == 2) {
+					map.set(row.sender_id,reactions);
+				}
+			}
+			let result = new Map([]);
+			let jsIterator = agg.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let id = _g_key;
+				let reactions = _g_value;
+				let map = new Map([]);
+				let jsIterator = reactions.values();
+				let _g_jsIterator1 = jsIterator;
+				let _g_lastStep1 = jsIterator.next();
+				while(!_g_lastStep1.done) {
+					let v = _g_lastStep1.value;
+					_g_lastStep1 = _g_jsIterator1.next();
+					let reactionsBySender = v;
+					let _g = 0;
+					while(_g < reactionsBySender.length) {
+						let reactionD = reactionsBySender[_g];
+						++_g;
+						let reaction = reactionD.uri == null ? new snikket_Reaction(reactionD.senderId,reactionD.timestamp,reactionD.text,reactionD.envelopeId,reactionD.key) : new snikket_CustomEmojiReaction(reactionD.senderId,reactionD.timestamp,reactionD.text,reactionD.uri,reactionD.envelopeId);
+						if(!map.has(reaction.key)) {
+							let v = [];
+							map.set(reaction.key,v);
+						}
+						map.get(reaction.key).push(reaction);
+					}
+				}
+				result.set(id,map);
+			}
+			return result;
+		});
+	}
+	hydrateReplyTo(accountId,messages,replyTos) {
+		let _gthis = this;
+		let tmp;
+		if(replyTos.length < 1) {
+			tmp = thenshim_Promise.resolve(null);
+		} else {
+			let params = [accountId];
+			let q_b = "";
+			q_b += "SELECT chat_id, stanza_id, stanza, direction, type, strftime('%FT%H:%M:%fZ', created_at / 1000.0, 'unixepoch') AS timestamp, sender_id, mam_id, mam_by, sync_point FROM messages WHERE account_id=? AND (";
+			let result = new Array(replyTos.length);
+			let _g = 0;
+			let _g1 = replyTos.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let parent = replyTos[i];
+				let x;
+				if(parent.serverId != null) {
+					params.push(parent.chatId);
+					params.push(parent.serverId);
+					x = " (chat_id=? AND mam_id=?)";
+				} else {
+					params.push(parent.chatId);
+					params.push(parent.localId);
+					x = " (chat_id=? AND stanza_id=?)";
+				}
+				result[i] = x;
+			}
+			q_b += Std.string(result.join(" OR "));
+			q_b += ")";
+			tmp = this.db.exec(q_b,params);
+		}
+		return thenshim_Promise.then(tmp,function(iter) {
+			if(iter != null) {
+				let parents = Lambda.array({ iterator : function() {
+					return iter;
+				}});
+				let _g = 0;
+				while(_g < messages.length) {
+					let message = messages[_g];
+					++_g;
+					if(message.replyToMessage != null) {
+						let found = Lambda.find(parents,function(p) {
+							if(p.chat_id == message.chatId() && (message.replyToMessage.serverId == null || p.mam_id == message.replyToMessage.serverId)) {
+								if(message.replyToMessage.localId != null) {
+									return p.stanza_id == message.replyToMessage.localId;
+								} else {
+									return true;
+								}
+							} else {
+								return false;
+							}
+						});
+						if(found != null) {
+							message.set_replyToMessage(_gthis.hydrateMessages(accountId,new haxe_iterators_ArrayIterator([found]))[0]);
+						}
+					}
+				}
+			}
+			return messages;
+		});
+	}
+	hydrateMessages(accountId,rows) {
+		let accountJid = snikket_JID.parse(accountId);
+		let _g = [];
+		let inlobj_iterator = function() {
+			return rows;
+		};
+		let x = inlobj_iterator();
+		while(x.hasNext()) {
+			let x1 = x.next();
+			let row = x1;
+			_g.push(snikket_ChatMessage.fromStanza(snikket_Stanza.parse(row.stanza),accountJid,function(builder,_) {
+				builder.syncPoint = row.sync_point;
+				builder.timestamp = row.timestamp;
+				builder.direction = row.direction;
+				builder.type = row.type;
+				builder.senderId = row.sender_id;
+				builder.serverId = row.mam_id;
+				builder.serverIdBy = row.mam_by;
+				if(row.stanza_id != null) {
+					builder.localId = row.stanza_id;
+				}
+				if(row.versions != null) {
+					let versionTimes = JSON.parse(row.version_times);
+					let versions = JSON.parse(row.versions);
+					if(Reflect.fields(versions).length > 1) {
+						let access = versions;
+						let _g_access = access;
+						let _g_keys = Reflect.fields(access);
+						let _g_index = 0;
+						while(_g_index < _g_keys.length) {
+							let version = _g_access[_g_keys[_g_index++]];
+							let versionM = snikket_ChatMessage.fromStanza(snikket_Stanza.parse(version),accountJid,function(toPushB,_) {
+								let tmp = toPushB.serverId;
+								toPushB.timestamp = versionTimes[tmp != null ? tmp : toPushB.localId];
+								return toPushB;
+							});
+							let toPush = versionM == null || versionM.versions.length < 1 ? versionM : versionM.versions[0];
+							if(toPush != null) {
+								builder.versions.push(toPush);
+							}
+						}
+						builder.versions.sort(function(a,b) {
+							return Reflect.compare(b.timestamp,a.timestamp);
+						});
+					}
+				}
+				return builder;
+			}));
+		}
+		return _g;
+	}
+}
+$hx_exports["snikket"]["persistence"]["Sqlite"] = snikket_persistence_Sqlite;
+snikket_persistence_Sqlite.__name__ = "snikket.persistence.Sqlite";
+snikket_persistence_Sqlite.__interfaces__ = [snikket_persistence_KeyValueStore,snikket_Persistence];
+Object.assign(snikket_persistence_Sqlite.prototype, {
+	__class__: snikket_persistence_Sqlite
+});
+class snikket_persistence_SqliteDriver {
+	constructor(dbfile) {
+		let _gthis = this;
+		thenshim_Promise.then(thenshim_Promise.then(snikket_persistence_Worker1.v2({ worker : function() {
+			return new Worker(new URL("sqlite-worker1.mjs",import.meta.url),{ type : "module"});
+		}}),function(promiser) {
+			_gthis.sqlite = promiser;
+			return _gthis.sqlite("open",{ filename : dbfile, vfs : "opfs-sahpool"});
+		}),function(openResult) {
+			return _gthis.dbId = openResult.dbId;
+		});
+	}
+	exec(sql,params) {
+		let _gthis = this;
+		if(this.sqlite == null || this.dbId == null) {
+			return thenshim_Promise.then(thenshim_Promise._new(function(resolve,reject) {
+				haxe_Timer.delay(function() {
+					resolve(null);
+				},100);
+			}),function(_) {
+				return _gthis.exec(sql,params);
+			});
+		}
+		let items = [];
+		let signalAllDone;
+		let allDone = thenshim_Promise._new(function(resolve,reject) {
+			signalAllDone = resolve;
+		});
+		return thenshim_Promise.then(thenshim_Promise.then(this.sqlite("exec",{ dbId : this.dbId, sql : sql, bind : params, rowMode : "object", callback : function(r) {
+			if(r.rowNumber == null) {
+				signalAllDone(null);
+			} else {
+				items.push(r.row);
+			}
+			return null;
+		}}),function(_) {
+			return allDone;
+		}),function(_) {
+			return new haxe_iterators_ArrayIterator(items);
+		});
+	}
+}
+snikket_persistence_SqliteDriver.__name__ = "snikket.persistence.SqliteDriver";
+Object.assign(snikket_persistence_SqliteDriver.prototype, {
+	__class__: snikket_persistence_SqliteDriver
+});
+class snikket_queries_GenericQuery {
+	constructor() {
+		if(snikket_queries_GenericQuery._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.isFinished = false;
+	}
+	getQueryStanza() {
+		if(this.queryStanza == null) {
+			throw new haxe_Exception("Query has not been initialized");
+		}
+		return this.queryStanza;
+	}
+	finish() {
+		this.isFinished = true;
+		if(this.handleFinished != null) {
+			this.handleFinished();
+		}
+	}
+	onFinished(handler) {
+		this.handleFinished = handler;
+		if(this.isFinished) {
+			this.handleFinished();
+		}
+	}
+}
+snikket_queries_GenericQuery.__name__ = "snikket.queries.GenericQuery";
+Object.assign(snikket_queries_GenericQuery.prototype, {
+	__class__: snikket_queries_GenericQuery
+});
+class snikket_queries_BlocklistGet extends snikket_queries_GenericQuery {
+	constructor() {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:blocking";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ type : "get", id : this.queryId}).tag("blocklist",{ xmlns : this.xmlns}).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return [];
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("blocklist",this.xmlns);
+			if(q == null) {
+				return [];
+			}
+			let _this = q.allTags("item");
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = _this[i].attr["jid"];
+			}
+			this.result = result;
+		}
+		return this.result;
+	}
+}
+snikket_queries_BlocklistGet.__name__ = "snikket.queries.BlocklistGet";
+snikket_queries_BlocklistGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_BlocklistGet.prototype, {
+	__class__: snikket_queries_BlocklistGet
+});
+class snikket_queries_BoB extends snikket_queries_GenericQuery {
+	constructor(to,uri) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,uri);
+	}
+	_hx_constructor(to,uri) {
+		this.xmlns = "urn:xmpp:bob";
+		super._hx_constructor();
+		if(!uri.startsWith("cid:") || !uri.endsWith("@bob.xmpp.org") || !uri.includes("+")) {
+			throw haxe_Exception.thrown("invalid BoB URI");
+		}
+		this.queryId = snikket_ID.short();
+		let tmp = HxOverrides.substr(uri,4,null);
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("data",{ xmlns : this.xmlns, cid : tmp}).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let data = this.responseStanza.getChild("data",this.xmlns);
+			if(data == null) {
+				return null;
+			}
+			let maxAge = data.attr["max-age"];
+			this.result = { bytes : haxe_crypto_Base64.decode(StringTools.replace(data.getText(),"\n","")), type : data.attr["type"], maxAge : maxAge == null ? null : Std.parseInt(maxAge)};
+		}
+		return this.result;
+	}
+	static uri(hash) {
+		let algo = hash.algorithm == "sha-1" ? "sha1" : hash.algorithm;
+		return "cid:" + encodeURIComponent(algo) + "+" + hash.toHex() + "@bob.xmpp.org";
+	}
+	static forHash(to,hash) {
+		let algo = hash.algorithm == "sha-1" ? "sha1" : hash.algorithm;
+		return new snikket_queries_BoB(to,"cid:" + encodeURIComponent(algo) + "+" + hash.toHex() + "@bob.xmpp.org");
+	}
+}
+snikket_queries_BoB.__name__ = "snikket.queries.BoB";
+snikket_queries_BoB.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_BoB.prototype, {
+	__class__: snikket_queries_BoB
+});
+class snikket_queries_DiscoInfoGet extends snikket_queries_GenericQuery {
+	constructor(to,node) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,node);
+	}
+	_hx_constructor(to,node) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "http://jabber.org/protocol/disco#info";
+		super._hx_constructor();
+		let attr = { xmlns : this.xmlns};
+		if(node != null) {
+			attr["node"] = node;
+		}
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("query",attr).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("query",this.xmlns);
+			if(q == null) {
+				return null;
+			}
+			let identities = q.allTags("identity");
+			let features = q.allTags("feature");
+			let q1 = q.attr["node"];
+			let result = new Array(identities.length);
+			let _g = 0;
+			let _g1 = identities.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let identity = identities[i];
+				result[i] = new snikket_Identity(identity.attr["category"],identity.attr["type"],identity.attr["name"]);
+			}
+			let tmp = result;
+			let result1 = new Array(features.length);
+			let _g2 = 0;
+			let _g3 = features.length;
+			while(_g2 < _g3) {
+				let i = _g2++;
+				result1[i] = features[i].attr["var"];
+			}
+			this.result = new snikket_Caps(q1,tmp,result1);
+		}
+		return this.result;
+	}
+}
+snikket_queries_DiscoInfoGet.__name__ = "snikket.queries.DiscoInfoGet";
+snikket_queries_DiscoInfoGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_DiscoInfoGet.prototype, {
+	__class__: snikket_queries_DiscoInfoGet
+});
+class snikket_queries_DiscoItemsGet extends snikket_queries_GenericQuery {
+	constructor(to,node) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,node);
+	}
+	_hx_constructor(to,node) {
+		this.queryId = null;
+		this.xmlns = "http://jabber.org/protocol/disco#items";
+		super._hx_constructor();
+		let attr = { xmlns : this.xmlns};
+		if(node != null) {
+			attr["node"] = node;
+		}
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("query",attr).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("query",this.xmlns);
+			if(q == null) {
+				return null;
+			}
+			this.result = [];
+			let _g = 0;
+			let _g1 = q.allTags("item");
+			while(_g < _g1.length) {
+				let item = _g1[_g];
+				++_g;
+				let jid = item.attr["jid"];
+				if(jid != null) {
+					this.result.push({ jid : snikket_JID.parse(jid), name : item.attr["name"], node : item.attr["node"]});
+				}
+			}
+		}
+		return this.result;
+	}
+}
+snikket_queries_DiscoItemsGet.__name__ = "snikket.queries.DiscoItemsGet";
+snikket_queries_DiscoItemsGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_DiscoItemsGet.prototype, {
+	__class__: snikket_queries_DiscoItemsGet
+});
+class snikket_queries_ExtDiscoGet extends snikket_queries_GenericQuery {
+	constructor(to) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to);
+	}
+	_hx_constructor(to) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:extdisco:2";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("services",{ xmlns : this.xmlns}).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("services",this.xmlns);
+			if(q == null) {
+				return null;
+			}
+			this.result = q.allTags("service");
+		}
+		return this.result;
+	}
+}
+snikket_queries_ExtDiscoGet.__name__ = "snikket.queries.ExtDiscoGet";
+snikket_queries_ExtDiscoGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_ExtDiscoGet.prototype, {
+	__class__: snikket_queries_ExtDiscoGet
+});
+class snikket_queries_HttpUploadSlot extends snikket_queries_GenericQuery {
+	constructor(to,filename,size,mime,hashes) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,filename,size,mime,hashes);
+	}
+	_hx_constructor(to,filename,size,mime,hashes) {
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:http:upload:0";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId}).tag("request",{ xmlns : this.xmlns, filename : filename, size : size == null ? "null" : "" + size, "content-type" : mime});
+		let _g = 0;
+		while(_g < hashes.length) {
+			let hash = hashes[_g];
+			++_g;
+			this.queryStanza.textTag("hash",haxe_crypto_Base64.encode(haxe_io_Bytes.ofData(hash.hash)),{ xmlns : "urn:xmpp:hashes:2", algo : hash.algorithm});
+		}
+		this.queryStanza.up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("slot",this.xmlns);
+			if(q == null) {
+				return null;
+			}
+			let get = q.findText("get@url");
+			if(get == null) {
+				return null;
+			}
+			let put = q.findText("put@url");
+			if(put == null) {
+				return null;
+			}
+			let headers = [];
+			let _g = 0;
+			let _g1 = q.getChild("put").allTags("header");
+			while(_g < _g1.length) {
+				let header = _g1[_g];
+				++_g;
+				headers.push(new tink_http_HeaderField(header.attr["name"].toLowerCase(),header.getText()));
+			}
+			this.result = { get : get, put : put, putHeaders : headers};
+		}
+		return this.result;
+	}
+}
+snikket_queries_HttpUploadSlot.__name__ = "snikket.queries.HttpUploadSlot";
+snikket_queries_HttpUploadSlot.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_HttpUploadSlot.prototype, {
+	__class__: snikket_queries_HttpUploadSlot
+});
+class snikket_queries_JabberIqGatewayGet extends snikket_queries_GenericQuery {
+	constructor(to,prompt) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,prompt);
+	}
+	_hx_constructor(to,prompt) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "jabber:iq:gateway";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : prompt == null ? "get" : "set", id : this.queryId});
+		let query = this.queryStanza.tag("query",{ xmlns : this.xmlns});
+		if(prompt != null) {
+			query.textTag("prompt",prompt,{ });
+		}
+		query.up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let error = this.responseStanza.getChild("error");
+			if(error == null) {
+				let q = this.responseStanza.getChild("query",this.xmlns);
+				if(q == null) {
+					return null;
+				}
+				let prompt = q.getChild("prompt");
+				if(prompt == null) {
+					let jid = q.getChild("jid");
+					if(jid == null) {
+						return null;
+					}
+					this.result = haxe_ds_Either.Right(jid.getText());
+				} else {
+					this.result = haxe_ds_Either.Right(prompt.getText());
+				}
+			} else {
+				if(error.getChild("service-unavailable","urn:ietf:params:xml:ns:xmpp-stanzas") != null) {
+					return null;
+				}
+				if(error.getChild("feature-not-implemented","urn:ietf:params:xml:ns:xmpp-stanzas") != null) {
+					return null;
+				}
+				this.result = haxe_ds_Either.Left(error.getText());
+			}
+		}
+		return this.result;
+	}
+}
+snikket_queries_JabberIqGatewayGet.__name__ = "snikket.queries.JabberIqGatewayGet";
+snikket_queries_JabberIqGatewayGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_JabberIqGatewayGet.prototype, {
+	__class__: snikket_queries_JabberIqGatewayGet
+});
+class snikket_queries_MAMQuery extends snikket_queries_GenericQuery {
+	constructor(params,jid) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(params,jid);
+	}
+	_hx_constructor(params,jid) {
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:mam:2";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ type : "set", to : jid}).tag("query",{ xmlns : this.xmlns, queryid : this.queryId}).tag("x",{ xmlns : "jabber:x:data", type : "submit"}).tag("field",{ "var" : "FORM_TYPE", type : "hidden"}).textTag("value",this.xmlns).up();
+		this.addStringField("start",params.startTime);
+		this.addStringField("end",params.endTime);
+		this.addStringField("with",params.with);
+		this.addStringField("before-id",params.beforeId);
+		this.addStringField("after-id",params.afterId);
+		this.addArrayField("ids",params.ids);
+		this.queryStanza.up();
+		if(params.page != null) {
+			let page = params.page;
+			this.queryStanza.tag("set",{ xmlns : "http://jabber.org/protocol/rsm"});
+			if(page.limit != null) {
+				this.queryStanza.textTag("max",page.limit == null ? "null" : "" + page.limit);
+			}
+			if(page.before != null && page.after != null) {
+				throw new haxe_Exception("It is not allowed to request a page before AND a page after");
+			}
+			if(page.before != null) {
+				this.queryStanza.textTag("before",page.before);
+			} else if(page.after != null) {
+				this.queryStanza.textTag("after",page.after);
+			}
+			this.queryStanza.up();
+		}
+	}
+	addStringField(name,value) {
+		if(value == null) {
+			return;
+		}
+		this.queryStanza.tag("field",{ "var" : name}).textTag("value",value).up();
+	}
+	addArrayField(name,values) {
+		if(values == null) {
+			return;
+		}
+		this.queryStanza.tag("field",{ "var" : name});
+		let _g = 0;
+		while(_g < values.length) {
+			let value = values[_g];
+			++_g;
+			this.queryStanza.textTag("value",value);
+		}
+		this.queryStanza.up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		if(this.result == null) {
+			let fin = this.responseStanza.getFirstChild();
+			if(fin == null || fin.name != "fin" || fin.attr["xmlns"] != this.xmlns) {
+				return null;
+			}
+			let rsmInfo = fin.getChild("set","http://jabber.org/protocol/rsm");
+			let count = rsmInfo.getChildText("count");
+			this.result = { complete : fin.attr["complete"] == "true" || fin.attr["complete"] == "1", page : { first : rsmInfo.getChildText("first"), last : rsmInfo.getChildText("last"), count : count == null ? null : Std.parseInt(count)}};
+		}
+		return this.result;
+	}
+}
+snikket_queries_MAMQuery.__name__ = "snikket.queries.MAMQuery";
+snikket_queries_MAMQuery.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_MAMQuery.prototype, {
+	__class__: snikket_queries_MAMQuery
+});
+class snikket_queries_PubsubGet extends snikket_queries_GenericQuery {
+	constructor(to,node,itemId) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,node,itemId);
+	}
+	_hx_constructor(to,node,itemId) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "http://jabber.org/protocol/pubsub";
+		super._hx_constructor();
+		let attr = { node : node};
+		if(this.ver != null) {
+			attr["ver"] = this.ver;
+		}
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "get", id : this.queryId});
+		let items = this.queryStanza.tag("pubsub",{ xmlns : this.xmlns}).tag("items",{ node : node});
+		if(itemId != null) {
+			items.tag("item",{ id : itemId}).up();
+		}
+		this.queryStanza.up().up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return [];
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("pubsub",this.xmlns);
+			if(q == null) {
+				return [];
+			}
+			let items = q.getChild("items");
+			if(items == null) {
+				return [];
+			}
+			if(items.attr["xmlns"] == null) {
+				items.attr["xmlns"] = this.xmlns;
+			}
+			this.result = items.allTags("item");
+		}
+		return this.result;
+	}
+}
+snikket_queries_PubsubGet.__name__ = "snikket.queries.PubsubGet";
+snikket_queries_PubsubGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_PubsubGet.prototype, {
+	__class__: snikket_queries_PubsubGet
+});
+class snikket_queries_Push2Disable extends snikket_queries_GenericQuery {
+	constructor(to) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to);
+	}
+	_hx_constructor(to) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:push2:0";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "set", id : this.queryId});
+		this.queryStanza.tag("disable",{ xmlns : this.xmlns});
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		return { type : this.responseStanza.attr["type"]};
+	}
+}
+snikket_queries_Push2Disable.__name__ = "snikket.queries.Push2Disable";
+snikket_queries_Push2Disable.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_Push2Disable.prototype, {
+	__class__: snikket_queries_Push2Disable
+});
+class snikket_queries_Push2Enable extends snikket_queries_GenericQuery {
+	constructor(to,service,client,ua_public,auth_secret,jwt_alg,jwt_key,jwt_claims) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to,service,client,ua_public,auth_secret,jwt_alg,jwt_key,jwt_claims);
+	}
+	_hx_constructor(to,service,client,ua_public,auth_secret,jwt_alg,jwt_key,jwt_claims) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "urn:xmpp:push2:0";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to, type : "set", id : this.queryId});
+		let enable = this.queryStanza.tag("enable",{ xmlns : this.xmlns});
+		enable.textTag("service",service);
+		enable.textTag("client",client);
+		let match = enable.tag("match",{ profile : "urn:xmpp:push2:match:important"});
+		let send = match.tag("send",{ xmlns : "urn:xmpp:push2:send:sce+rfc8291+rfc8292:0"});
+		send.textTag("ua-public",haxe_crypto_Base64.encode(ua_public));
+		send.textTag("auth-secret",haxe_crypto_Base64.encode(auth_secret));
+		if(jwt_alg != null) {
+			send.textTag("jwt-alg",jwt_alg);
+			send.textTag("jwt-key",haxe_crypto_Base64.encode(jwt_key));
+			let jsIterator = jwt_claims.entries();
+			let _g_jsIterator = jsIterator;
+			let _g_lastStep = jsIterator.next();
+			while(!_g_lastStep.done) {
+				let v = _g_lastStep.value;
+				_g_lastStep = _g_jsIterator.next();
+				let _g_key = v[0];
+				let _g_value = v[1];
+				let key = _g_key;
+				let value = _g_value;
+				send.textTag("jwt-claim",value,{ name : key});
+			}
+		}
+		enable.up().up().up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return null;
+		}
+		return { type : this.responseStanza.attr["type"]};
+	}
+}
+snikket_queries_Push2Enable.__name__ = "snikket.queries.Push2Enable";
+snikket_queries_Push2Enable.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_Push2Enable.prototype, {
+	__class__: snikket_queries_Push2Enable
+});
+class snikket_queries_RosterGet extends snikket_queries_GenericQuery {
+	constructor(ver) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(ver);
+	}
+	_hx_constructor(ver) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "jabber:iq:roster";
+		super._hx_constructor();
+		let attr = { xmlns : this.xmlns};
+		if(ver != null) {
+			attr["ver"] = ver;
+		}
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ type : "get"}).tag("query",attr).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return [];
+		}
+		if(this.result == null) {
+			let q = this.responseStanza.getChild("query","jabber:iq:roster");
+			if(q == null) {
+				return [];
+			}
+			this.ver = q.attr["ver"];
+			let _this = q.allTags("item");
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let item = _this[i];
+				result[i] = { jid : item.attr["jid"], fn : item.attr["name"], subscription : item.attr["subscription"]};
+			}
+			this.result = result;
+		}
+		return this.result;
+	}
+}
+snikket_queries_RosterGet.__name__ = "snikket.queries.RosterGet";
+snikket_queries_RosterGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_RosterGet.prototype, {
+	__class__: snikket_queries_RosterGet
+});
+class snikket_queries_VcardTempGet extends snikket_queries_GenericQuery {
+	constructor(to) {
+		snikket_queries_GenericQuery._hx_skip_constructor = true;
+		super();
+		snikket_queries_GenericQuery._hx_skip_constructor = false;
+		this._hx_constructor(to);
+	}
+	_hx_constructor(to) {
+		this.ver = null;
+		this.queryId = null;
+		this.xmlns = "vcard-temp";
+		super._hx_constructor();
+		this.queryId = snikket_ID.short();
+		this.queryStanza = new snikket_Stanza("iq",{ to : to.asString(), type : "get", id : this.queryId});
+		this.queryStanza.tag("vCard",{ xmlns : this.xmlns}).up();
+	}
+	handleResponse(stanza) {
+		this.responseStanza = stanza;
+		this.finish();
+	}
+	getResult() {
+		if(this.responseStanza == null) {
+			return { photo : null};
+		}
+		if(this.result == null) {
+			let vcard = this.responseStanza.getChild("vCard",this.xmlns);
+			if(vcard == null) {
+				return { photo : null};
+			}
+			let photoMime = vcard.findText("PHOTO/TYPE#");
+			let photoBinval = vcard.findText("PHOTO/BINVAL#");
+			if(photoMime != null && photoBinval != null) {
+				this.result = { photo : { mime : photoMime, data : haxe_crypto_Base64.decode(StringTools.replace(photoBinval,"\n",""))}};
+			} else {
+				this.result = { photo : null};
+			}
+		}
+		return this.result;
+	}
+}
+snikket_queries_VcardTempGet.__name__ = "snikket.queries.VcardTempGet";
+snikket_queries_VcardTempGet.__super__ = snikket_queries_GenericQuery;
+Object.assign(snikket_queries_VcardTempGet.prototype, {
+	__class__: snikket_queries_VcardTempGet
+});
+class snikket_streams_XmppJsStream extends snikket_GenericStream {
+	constructor() {
+		snikket_EventEmitter._hx_skip_constructor = true;
+		super();
+		snikket_EventEmitter._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.everConnected = false;
+		this.resumed = false;
+		this.initialSM = null;
+		this.pendingOnIq = [];
+		this.pending = [];
+		this.debug = true;
+		super._hx_constructor();
+		let _g = new haxe_ds_StringMap();
+		_g.h["online"] = $bind(this,this.onOnline);
+		_g.h["offline"] = $bind(this,this.onOffline);
+		let tmp = snikket_Map.fromMap(_g);
+		let _g1 = new haxe_ds_StringMap();
+		_g1.h["connection-error"] = $bind(this,this.onError);
+		this.state = new snikket_FSM({ transitions : [{ name : "connect-requested", from : ["offline"], to : "connecting"},{ name : "connection-success", from : ["connecting"], to : "online"},{ name : "connection-error", from : ["connecting"], to : "offline"},{ name : "connection-closed", from : ["connecting","online"], to : "offline"}], state_handlers : tmp, transition_handlers : snikket_Map.fromMap(_g1)},"offline");
+	}
+	connectWithURI(uri) {
+		haxe_Log.trace("Got connection URI: " + uri,{ fileName : "snikket/streams/XmppJsStream.hx", lineNumber : 165, className : "snikket.streams.XmppJsStream", methodName : "connectWithURI"});
+		if(uri == null) {
+			this.state.event("connection-error");
+			return;
+		}
+		this.connectionURI = uri;
+		let _gthis = this;
+		let waitForCreds = new Promise(function(resolve,reject) {
+			_gthis.on("auth/password",function(event) {
+				if(event.username == null) {
+					event.username = _gthis.jid.local;
+				}
+				resolve(event);
+				return snikket_EventResult.EventHandled;
+			});
+		});
+		let clientId = this.jid.resource;
+		let xmpp = new snikket_streams_XmppJsClient({ service : this.connectionURI, domain : this.jid.domain, resource : this.jid.resource, credentials : function(callback,mechanisms,fast) {
+			_gthis.everConnected = true;
+			_gthis.clientId = ((mechanisms) instanceof Array) ? clientId : null;
+			let mechs = fast == null ? [] : [{ name : fast.mechanism, canFast : true, canOther : false}];
+			let _this = ((mechanisms) instanceof Array) ? mechanisms : [mechanisms];
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				result[i] = { name : _this[i], canFast : false, canOther : true};
+			}
+			let mechs1 = mechs.concat(result);
+			let tmp = Lambda.find(mechs1,function(m) {
+				return m.canOther;
+			});
+			let mech = tmp != null ? tmp.name : null;
+			_gthis.trigger("auth/password-needed",{ mechanisms : mechs1});
+			return waitForCreds.then(function(creds) {
+				creds.username = _gthis.jid.local;
+				if(creds.fastCount != null) {
+					try {
+						creds = { username : _gthis.jid.local, token : JSON.parse(creds.password), mechanism : null};
+					} catch( _g ) {
+						creds = { password : null, fastCount : null, username : _gthis.jid.local, token : { token : "fail", mechanism : creds.mechanism}, mechanism : null};
+					}
+				}
+				let tmp = creds.mechanism;
+				return callback(creds,tmp != null ? tmp : mech,snikket_streams_XmppJsXml("user-agent",{ id : clientId}));
+			});
+		}});
+		snikket_streams_XmppJsScramSha1(xmpp.saslFactory);
+		xmpp.jid = this.jid;
+		xmpp.streamFeatures.use("csi","urn:xmpp:csi:0",function(ctx,next,feature) {
+			_gthis.csi = true;
+			next();
+		});
+		if(this.debug) {
+			snikket_streams_XmppJsDebug(xmpp,true);
+		}
+		if(this.initialSM != null) {
+			let parsedSM = JSON.parse(haxe_io_Bytes.ofData(this.initialSM).toString());
+			let parsedPending = parsedSM.pending;
+			if(parsedPending != null) {
+				let _g = 0;
+				while(_g < parsedPending.length) {
+					let item = parsedPending[_g];
+					++_g;
+					this.pending.push(snikket_streams_XmppJsLtx.parse(item));
+				}
+			}
+			xmpp.streamManagement.id = parsedSM.id;
+			xmpp.streamManagement.outbound = parsedSM.outbound;
+			xmpp.streamManagement.inbound = parsedSM.inbound;
+			let tmp = parsedSM.outbound_q;
+			let _this = tmp != null ? tmp : [];
+			let result = new Array(_this.length);
+			let _g = 0;
+			let _g1 = _this.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let item = _this[i];
+				result[i] = { stanza : snikket_streams_XmppJsLtx.parse(item.stanza), stamp : item.stamp};
+			}
+			xmpp.streamManagement.outbound_q = result;
+			this.initialSM = null;
+		}
+		this.client = xmpp;
+		this.processPendingOnIq();
+		xmpp.on("online",function(jid) {
+			_gthis.resumed = false;
+			_gthis.jid = jid;
+			_gthis.state.event("connection-success");
+		});
+		xmpp.on("offline",function(data) {
+			_gthis.state.event("connection-closed");
+		});
+		xmpp.streamManagement.on("resumed",function(_) {
+			_gthis.resumed = true;
+			if(xmpp.jid == null) {
+				xmpp.jid = _gthis.jid;
+			} else {
+				_gthis.jid = xmpp.jid;
+			}
+			_gthis.state.event("connection-success");
+		});
+		xmpp.on("stanza",function(stanza) {
+			_gthis.onStanza(snikket_streams_XmppJsStream.convertToStanza(stanza));
+			_gthis.triggerSMupdate();
+		});
+		xmpp.streamManagement.on("ack",function(stanza) {
+			let tmp;
+			if((stanza != null ? stanza.name : null) == "message") {
+				let tmp1 = stanza != null ? stanza.attrs : null;
+				tmp = (tmp1 != null ? tmp1.id : null) != null;
+			} else {
+				tmp = false;
+			}
+			if(tmp) {
+				_gthis.trigger("sm/ack",{ id : stanza.attrs.id});
+			}
+			_gthis.triggerSMupdate();
+		});
+		xmpp.streamManagement.on("fail",function(stanza) {
+			if(stanza.name == "message" && stanza.attrs.id != null) {
+				_gthis.trigger("sm/fail",{ id : stanza.attrs.id});
+			}
+			_gthis.triggerSMupdate();
+		});
+		xmpp.fast.saveToken = function(token) {
+			token.token = JSON.stringify(token);
+			_gthis.trigger("fast-token",token);
+			return Promise.resolve(null);
+		};
+		xmpp.on("status",function(status) {
+			if(status == "disconnect") {
+				if(_gthis.state.can("connection-closed")) {
+					_gthis.state.event("connection-closed");
+				}
+			} else if(status == "connecting") {
+				if(_gthis.state.can("connect-requested")) {
+					_gthis.state.event("connect-requested");
+				}
+			}
+		});
+		this.resumed = false;
+		xmpp.start().catch(function(err) {
+			if(_gthis.state.can("connection-error")) {
+				_gthis.state.event("connection-error");
+			}
+			let xmppError = ((err) instanceof snikket_streams_XmppJsError) ? err : null;
+			if((xmppError != null ? xmppError.name : null) == "SASLError") {
+				_gthis.trigger("auth/fail",xmppError);
+			} else {
+				haxe_Log.trace(err,{ fileName : "snikket/streams/XmppJsStream.hx", lineNumber : 298, className : "snikket.streams.XmppJsStream", methodName : "connectWithURI"});
+			}
+		});
+	}
+	connect(jid,sm) {
+		this.state.event("connect-requested");
+		this.jid = new snikket_streams_XmppJsJID(jid);
+		this.initialSM = sm;
+		snikket_streams_XmppJsStream.resolveConnectionURI(this.jid.domain,$bind(this,this.connectWithURI));
+	}
+	disconnect() {
+		if(this.client == null) {
+			return;
+		}
+		this.client.stop();
+	}
+	convertFromStanza(el) {
+		let xml = snikket_streams_XmppJsXml(el.name,el.attr);
+		if(el.children.length > 0) {
+			let _g = 0;
+			let _g1 = el.children;
+			while(_g < _g1.length) {
+				let child = _g1[_g];
+				++_g;
+				switch(child._hx_index) {
+				case 0:
+					let stanza = child.stanza;
+					xml.append(this.convertFromStanza(stanza));
+					break;
+				case 1:
+					let text = child.textNode;
+					xml.append(text.content);
+					break;
+				}
+			}
+		}
+		return xml;
+	}
+	sendStanza(stanza) {
+		if(this.client == null || this.client.status != "online") {
+			this.pending.push(this.convertFromStanza(stanza));
+		} else {
+			this.client.send(this.convertFromStanza(stanza));
+		}
+		this.triggerSMupdate();
+	}
+	newId() {
+		return snikket_streams_XmppJsId();
+	}
+	triggerSMupdate() {
+		if(this.client == null || !this.client.streamManagement.enabled) {
+			return;
+		}
+		let _this = this.client.streamManagement.id;
+		let _this1 = this.client.streamManagement.outbound;
+		let _this2 = this.client.streamManagement.inbound;
+		let tmp = this.client.streamManagement.outbound_q;
+		let _this3 = tmp != null ? tmp : [];
+		let result = new Array(_this3.length);
+		let _g = 0;
+		let _g1 = _this3.length;
+		while(_g < _g1) {
+			let i = _g++;
+			let item = _this3[i];
+			result[i] = { stanza : item.stanza.toString(), stamp : item.stamp};
+		}
+		let _this4 = result;
+		let _this5 = this.pending;
+		let result1 = new Array(_this5.length);
+		let _g2 = 0;
+		let _g3 = _this5.length;
+		while(_g2 < _g3) {
+			let i = _g2++;
+			result1[i] = _this5[i].toString();
+		}
+		this.trigger("sm/update",{ sm : haxe_io_Bytes.ofString(JSON.stringify({ id : _this, outbound : _this1, inbound : _this2, outbound_q : _this4, pending : result1})).b.bufferValue});
+	}
+	fromIqResult(result) {
+		switch(result._hx_index) {
+		case 0:
+			let el = result.element;
+			return this.convertFromStanza(el);
+		case 1:
+			return true;
+		case 2:
+			return false;
+		}
+	}
+	onIq(type,tag,xmlns,handler) {
+		let _gthis = this;
+		if(this.client == null) {
+			this.pendingOnIq.push({ type : type, tag : tag, xmlns : xmlns, handler : handler});
+		} else {
+			switch(type._hx_index) {
+			case 0:
+				this.client.iqCallee.get(xmlns,tag,function(el) {
+					return _gthis.fromIqResult(handler(snikket_streams_XmppJsStream.convertToStanza(el.stanza)));
+				});
+				break;
+			case 1:
+				this.client.iqCallee.set(xmlns,tag,function(el) {
+					return _gthis.fromIqResult(handler(snikket_streams_XmppJsStream.convertToStanza(el.stanza)));
+				});
+				break;
+			}
+		}
+	}
+	processPendingOnIq() {
+		let item;
+		while(true) {
+			item = this.pendingOnIq.shift();
+			if(!(item != null)) {
+				break;
+			}
+			this.onIq(item.type,item.tag,item.xmlns,item.handler);
+		}
+	}
+	onOnline(event) {
+		this.everConnected = true;
+		let item;
+		while(true) {
+			item = this.pending.shift();
+			if(!(item != null)) {
+				break;
+			}
+			this.client.send(item);
+		}
+		this.triggerSMupdate();
+		this.trigger("status/online",{ jid : this.jid.toString(), resumed : this.resumed});
+	}
+	onOffline(event) {
+		this.trigger("status/offline",{ });
+	}
+	onError(event) {
+		if(!this.everConnected) {
+			this.trigger("status/error",{ });
+		}
+		return true;
+	}
+	static resolveConnectionURI(domain,callback) {
+		callback("xmpp://" + domain);
+	}
+	static convertToStanza(el) {
+		let stanza = new snikket_Stanza(el.name,el.attrs);
+		let _g = 0;
+		let _g1 = el.children;
+		while(_g < _g1.length) {
+			let child = _g1[_g];
+			++_g;
+			if(snikket_streams_XmppJsLtx.isText(child)) {
+				stanza.text(js_Boot.__cast(child , String));
+			} else {
+				stanza.addChild(snikket_streams_XmppJsStream.convertToStanza(child));
+			}
+		}
+		return stanza;
+	}
+	static parse(input) {
+		return snikket_streams_XmppJsStream.convertToStanza(snikket_streams_XmppJsLtx.parse(input));
+	}
+}
+snikket_streams_XmppJsStream.__name__ = "snikket.streams.XmppJsStream";
+snikket_streams_XmppJsStream.__super__ = snikket_GenericStream;
+Object.assign(snikket_streams_XmppJsStream.prototype, {
+	__class__: snikket_streams_XmppJsStream
+});
+class thenshim_PromiseFactory {
+}
+thenshim_PromiseFactory.__name__ = "thenshim.PromiseFactory";
+thenshim_PromiseFactory.__isInterface__ = true;
+Object.assign(thenshim_PromiseFactory.prototype, {
+	__class__: thenshim_PromiseFactory
+});
+class thenshim_js_JSPromiseFactory {
+	constructor() {
+	}
+	make(executor) {
+		return new Promise(executor);
+	}
+	asResolved(object) {
+		return Promise.resolve(object);
+	}
+	asRejected(reason) {
+		return Promise.reject(reason);
+	}
+}
+thenshim_js_JSPromiseFactory.__name__ = "thenshim.js.JSPromiseFactory";
+thenshim_js_JSPromiseFactory.__interfaces__ = [thenshim_PromiseFactory];
+Object.assign(thenshim_js_JSPromiseFactory.prototype, {
+	__class__: thenshim_js_JSPromiseFactory
+});
+class thenshim_Promise {
+	static _new(executor) {
+		return thenshim_Promise.factory.make(executor);
+	}
+	static resolve(object) {
+		return thenshim_Promise.factory.asResolved(object);
+	}
+	static reject(reason) {
+		return thenshim_Promise.factory.asRejected(reason);
+	}
+	static then(this1,onFulfilled,onRejected) {
+		return this1.then(onFulfilled,onRejected);
+	}
+}
+class thenshim_PromiseTools {
+	static all(promises) {
+		return Promise.all(Lambda.array(promises));
+	}
+	static allSettled(promises) {
+		return Promise.allSettled(Lambda.array(promises));
+	}
+	static race(promises) {
+		return Promise.race(Lambda.array(promises));
+	}
+	static catch_(promise,onRejected) {
+		return promise.catch(onRejected);
+	}
+	static catchError(promise,onRejected) {
+		return thenshim_PromiseTools.catch_(promise,onRejected);
+	}
+	static finally(promise,onFinally) {
+		return promise.finally(onFinally);
+	}
+}
+thenshim_PromiseTools.__name__ = "thenshim.PromiseTools";
+class thenshim_Thenable {
+}
+thenshim_Thenable.__name__ = "thenshim.Thenable";
+thenshim_Thenable.__isInterface__ = true;
+Object.assign(thenshim_Thenable.prototype, {
+	__class__: thenshim_Thenable
+});
+class thenshim_ThenableCallback {
+	static toJSPromiseHandler(this1) {
+		return this1;
+	}
+}
+class tink_Anon {
+	static getExistentFields(o) {
+		let ret = { };
+		let _g = 0;
+		let _g1 = Reflect.fields(o);
+		while(_g < _g1.length) {
+			let f = _g1[_g];
+			++_g;
+			ret[f] = true;
+		}
+		return ret;
+	}
+}
+tink_Anon.__name__ = "tink.Anon";
+class tink_chunk_ChunkBase {
+	getCursor() {
+		if(this.flattened == null) {
+			this.flatten(this.flattened = []);
+		}
+		return tink_chunk_ChunkCursor.create(this.flattened.slice());
+	}
+	flatten(into) {
+	}
+}
+tink_chunk_ChunkBase.__name__ = "tink.chunk.ChunkBase";
+Object.assign(tink_chunk_ChunkBase.prototype, {
+	__class__: tink_chunk_ChunkBase
+});
+class tink_chunk_ChunkObject {
+}
+tink_chunk_ChunkObject.__name__ = "tink.chunk.ChunkObject";
+tink_chunk_ChunkObject.__isInterface__ = true;
+Object.assign(tink_chunk_ChunkObject.prototype, {
+	__class__: tink_chunk_ChunkObject
+});
+class tink__$Chunk_EmptyChunk extends tink_chunk_ChunkBase {
+	constructor() {
+		super();
+	}
+	getByte(i) {
+		return 0;
+	}
+	getLength() {
+		return 0;
+	}
+	slice(from,to) {
+		return this;
+	}
+	blitTo(target,offset) {
+	}
+	toString() {
+		return "";
+	}
+	toBytes() {
+		return tink__$Chunk_EmptyChunk.EMPTY;
+	}
+}
+tink__$Chunk_EmptyChunk.__name__ = "tink._Chunk.EmptyChunk";
+tink__$Chunk_EmptyChunk.__interfaces__ = [tink_chunk_ChunkObject];
+tink__$Chunk_EmptyChunk.__super__ = tink_chunk_ChunkBase;
+Object.assign(tink__$Chunk_EmptyChunk.prototype, {
+	__class__: tink__$Chunk_EmptyChunk
+});
+class tink_Chunk {
+	static get_length(this1) {
+		return this1.getLength();
+	}
+	static getByte(this1,i) {
+		return this1.getByte(i);
+	}
+	static concat(this1,that) {
+		return tink_chunk_CompoundChunk.cons(this1,that);
+	}
+	static cursor(this1) {
+		return this1.getCursor();
+	}
+	static iterator(this1) {
+		return new tink_chunk_ChunkIterator(this1.getCursor());
+	}
+	static sub(this1,pos,len) {
+		return this1.slice(pos,pos + len);
+	}
+	static slice(this1,from,to) {
+		return this1.slice(from,to);
+	}
+	static blitTo(this1,target,offset) {
+		this1.blitTo(target,offset);
+	}
+	static toHex(this1) {
+		return this1.toBytes().toHex();
+	}
+	static toString(this1) {
+		return this1.toString();
+	}
+	static toBytes(this1) {
+		return this1.toBytes();
+	}
+	static toBuffer(this1) {
+		let b = this1.toBytes();
+		let data = b.b;
+		return js_node_buffer_Buffer.from(data.buffer,data.byteOffset,b.length);
+	}
+	static join(chunks) {
+		if(chunks == null) {
+			return tink_Chunk.EMPTY;
+		} else {
+			switch(chunks.length) {
+			case 0:
+				return tink_Chunk.EMPTY;
+			case 1:
+				let v = chunks[0];
+				return v;
+			default:
+				let v1 = chunks;
+				let ret = tink_Chunk.concat(v1[0],v1[1]);
+				let _g = 2;
+				let _g1 = v1.length;
+				while(_g < _g1) {
+					let i = _g++;
+					ret = tink_Chunk.concat(ret,v1[i]);
+				}
+				return ret;
+			}
+		}
+	}
+	static ofBytes(b) {
+		return tink_chunk_ByteChunk.of(b);
+	}
+	static ofString(s) {
+		return tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(s));
+	}
+	static ofBuffer(b) {
+		return new tink_chunk_nodejs_BufferChunk(b);
+	}
+	static ofByte(byte) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(1));
+		bytes.b[0] = byte;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static ofHex(s) {
+		let length = s.length >> 1;
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(length));
+		let _g = 0;
+		let _g1 = length;
+		while(_g < _g1) {
+			let i = _g++;
+			bytes.b[i] = Std.parseInt("0x" + HxOverrides.substr(s,i * 2,2));
+		}
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static parseHex(v) {
+		return Std.parseInt("0x" + v);
+	}
+	static catChunk(a,b) {
+		return tink_Chunk.concat(a,b);
+	}
+	static rcatString(a,b) {
+		return tink_Chunk.concat(a,tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(b)));
+	}
+	static lcatString(a,b) {
+		return tink_Chunk.concat(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(a)),b);
+	}
+	static lcatBytes(a,b) {
+		return tink_Chunk.concat(tink_chunk_ByteChunk.of(a),b);
+	}
+	static rcatBytes(a,b) {
+		return tink_Chunk.concat(a,tink_chunk_ByteChunk.of(b));
+	}
+	static eqChunk(a,b) {
+		return a.toString() == b.toString();
+	}
+	static reqString(a,b) {
+		return a.toString() == b.toString();
+	}
+	static leqString(a,b) {
+		return a.toString() == b.toString();
+	}
+	static leqBytes(a,b) {
+		return a.toString() == b.toString();
+	}
+	static reqBytes(a,b) {
+		return a.toString() == b.toString();
+	}
+}
+class tink_Stringly {
+	static isNumber(s,allowFloat) {
+		if(s.length == 0) {
+			return false;
+		}
+		let pos = 0;
+		let max = s.length;
+		if(pos < max && s.charCodeAt(pos) == 45) {
+			++pos;
+		}
+		if(!allowFloat) {
+			if(pos < max && s.charCodeAt(pos) == 48 && pos++ > -1) {
+				if(pos < max && s.charCodeAt(pos) == 120) {
+					++pos;
+				}
+			}
+		}
+		while(pos < max && (s.charCodeAt(pos) ^ 48) < 10) ++pos;
+		if(allowFloat && pos < max) {
+			if(pos < max && s.charCodeAt(pos) == 46 && pos++ > -1) {
+				while(pos < max && (s.charCodeAt(pos) ^ 48) < 10) ++pos;
+			}
+			if(pos < max && s.charCodeAt(pos) == 101 && pos++ > -1 || pos < max && s.charCodeAt(pos) == 69 && pos++ > -1) {
+				if(!(pos < max && s.charCodeAt(pos) == 43 && pos++ > -1)) {
+					if(pos < max && s.charCodeAt(pos) == 45) {
+						++pos;
+					}
+				}
+				while(pos < max && (s.charCodeAt(pos) ^ 48) < 10) ++pos;
+			}
+		}
+		return pos == max;
+	}
+	static toBool(this1) {
+		if(this1 != null) {
+			switch(StringTools.trim(this1).toLowerCase()) {
+			case "0":case "false":case "no":
+				return false;
+			default:
+				return true;
+			}
+		} else {
+			return false;
+		}
+	}
+	static isFloat(this1) {
+		return tink_Stringly.isNumber(StringTools.trim(this1),true);
+	}
+	static parseFloat(this1) {
+		let _g = StringTools.trim(this1);
+		let v = _g;
+		if(tink_Stringly.isNumber(v,true)) {
+			return tink_core_Outcome.Success(parseFloat(v));
+		} else {
+			let v = _g;
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"" + v + " (encoded as " + this1 + ") is not a valid float",{ fileName : "tink/Stringly.hx", lineNumber : 65, className : "tink._Stringly.Stringly_Impl_", methodName : "parseFloat"}));
+		}
+	}
+	static toFloat(this1) {
+		return tink_core_OutcomeTools.sure(tink_Stringly.parseFloat(this1));
+	}
+	static isInt(this1) {
+		return tink_Stringly.isNumber(StringTools.trim(this1),false);
+	}
+	static parseInt(this1) {
+		let _g = StringTools.trim(this1);
+		let v = _g;
+		if(tink_Stringly.isNumber(v,false)) {
+			return tink_core_Outcome.Success(Std.parseInt(v));
+		} else {
+			let v = _g;
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"" + v + " (encoded as " + this1 + ") is not a valid integer",{ fileName : "tink/Stringly.hx", lineNumber : 80, className : "tink._Stringly.Stringly_Impl_", methodName : "parseInt"}));
+		}
+	}
+	static toInt(this1) {
+		return tink_core_OutcomeTools.sure(tink_Stringly.parseInt(this1));
+	}
+	static parseDate(this1) {
+		let _g = tink_Stringly.parseFloat(this1);
+		switch(_g._hx_index) {
+		case 0:
+			let f = _g.data;
+			return tink_core_Outcome.Success(new Date(f));
+		case 1:
+			let _g1 = _g.failure;
+			if(!tink_Stringly.SUPPORTED_DATE_REGEX.match(this1)) {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"" + this1 + " is not a valid date",{ fileName : "tink/Stringly.hx", lineNumber : 101, className : "tink._Stringly.Stringly_Impl_", methodName : "parseDate"}));
+			}
+			let date = new Date(this1);
+			let f1 = date.getTime();
+			if(isNaN(f1)) {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"" + this1 + " is not a valid date",{ fileName : "tink/Stringly.hx", lineNumber : 104, className : "tink._Stringly.Stringly_Impl_", methodName : "parseDate"}));
+			} else {
+				return tink_core_Outcome.Success(date);
+			}
+			break;
+		}
+	}
+	static toDate(this1) {
+		return tink_core_OutcomeTools.sure(tink_Stringly.parseDate(this1));
+	}
+	static parse(this1,f) {
+		let _g = f;
+		let a1 = this1;
+		return tink_core_TypedError.catchExceptions(function() {
+			return _g(a1);
+		},null,{ fileName : "tink/Stringly.hx", lineNumber : 171, className : "tink._Stringly.Stringly_Impl_", methodName : "parse"});
+	}
+	static ofBool(b) {
+		if(b) {
+			return "true";
+		} else {
+			return "false";
+		}
+	}
+	static ofInt(i) {
+		if(i == null) {
+			return "null";
+		} else {
+			return "" + i;
+		}
+	}
+	static ofFloat(f) {
+		if(f == null) {
+			return "null";
+		} else {
+			return "" + f;
+		}
+	}
+	static ofDate(d) {
+		let f = d.getTime();
+		if(f == null) {
+			return "null";
+		} else {
+			return "" + f;
+		}
+	}
+}
+class tink_Url {
+	static get_host(this1) {
+		return this1.hosts[0];
+	}
+	static get_hosts(this1) {
+		return this1.hosts;
+	}
+	static get_pathWithQuery(this1) {
+		if(this1.query == null) {
+			return this1.path;
+		} else {
+			return (this1.path == null ? "null" : this1.path) + "?" + (this1.query == null ? "null" : this1.query);
+		}
+	}
+	static _new(parts) {
+		return parts;
+	}
+	static resolve(this1,that) {
+		if(that.scheme != null) {
+			return that;
+		} else if(that.hosts[0] != null) {
+			if(that.scheme != null) {
+				return that;
+			} else {
+				let copy = Reflect.copy(that);
+				copy.scheme = this1.scheme;
+				return copy;
+			}
+		} else {
+			let parts = { path : tink_url_Path.join(this1.path,that.path), payload : "", scheme : this1.scheme, query : that.query, auth : this1.auth, hosts : this1.hosts, hash : that.hash};
+			tink_Url.makePayload(parts);
+			return parts;
+		}
+	}
+	static makePayload(parts) {
+		let payload = "";
+		let _g = parts.auth;
+		let _g1 = parts.hash;
+		let _g2 = parts.hosts;
+		let _g3 = parts.path;
+		let _g4 = parts.payload;
+		let _g5 = parts.query;
+		let _g6 = parts.scheme;
+		if(_g == null) {
+			if(_g2.length != 0) {
+				let v = _g2;
+				payload += "//" + v.join(",");
+			}
+		} else if(_g2.length == 0) {
+			let auth = _g;
+			payload += "//" + (auth == null ? "null" : auth == null ? "" : "" + auth + "@");
+		} else {
+			let auth = _g;
+			let v = _g2;
+			payload += "//" + (auth == null ? "null" : auth == null ? "" : "" + auth + "@") + v.join(",");
+		}
+		payload += parts.path == null ? "null" : parts.path;
+		let _g7 = parts.query;
+		if(_g7 != null) {
+			let v = _g7;
+			payload += "?" + (v == null ? "null" : v);
+		}
+		let _g8 = parts.hash;
+		if(_g8 != null) {
+			let v = _g8;
+			payload += "#" + v;
+		}
+		parts.payload = payload.toString();
+	}
+	static toString(this1) {
+		if(this1.scheme == null) {
+			return this1.payload;
+		} else {
+			return "" + this1.scheme + ":" + this1.payload;
+		}
+	}
+	static fromString(s) {
+		return tink_Url.parse(s);
+	}
+	static noop(_) {
+	}
+	static parse(s,onError) {
+		if(s == null) {
+			return tink_Url.parse("");
+		}
+		if(onError == null) {
+			onError = tink_Url.noop;
+		}
+		s = StringTools.trim(s);
+		if(s.startsWith("data:")) {
+			return { scheme : "data", payload : HxOverrides.substr(s,5,null), hosts : []};
+		}
+		let FORMAT = new EReg("^(([a-zA-Z][a-zA-Z0-9\\-+.]*):)?((//(([^@/]+)@)?([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?)$","");
+		let HOST = new EReg("^(\\[(.*)\\]|([^:]*))(:(.*))?$","");
+		FORMAT.match(s);
+		let hosts;
+		let _g = FORMAT.matched(7);
+		if(_g == null) {
+			hosts = [];
+		} else {
+			let v = _g;
+			let _g1 = [];
+			let _g2 = 0;
+			let _g3 = v.split(",");
+			while(_g2 < _g3.length) {
+				let host = _g3[_g2];
+				++_g2;
+				HOST.match(host);
+				let host1;
+				let _g = HOST.matched(3);
+				let _g4 = HOST.matched(2);
+				if(_g4 == null) {
+					let ipv4 = _g;
+					host1 = ipv4;
+				} else if(_g == null) {
+					let ipv6 = _g4;
+					host1 = "[" + ipv6 + "]";
+				} else {
+					onError("invalid host " + host);
+					host1 = null;
+				}
+				let port;
+				let _g5 = HOST.matched(5);
+				if(_g5 == null) {
+					port = null;
+				} else {
+					let v = _g5;
+					let _g = Std.parseInt(v);
+					if(_g == null) {
+						onError("invalid port " + v);
+						port = null;
+					} else {
+						let p = _g;
+						port = p;
+					}
+				}
+				_g1.push(tink_url_Host._new(host1,port));
+			}
+			hosts = _g1;
+		}
+		let path = FORMAT.matched(8);
+		if(hosts.length > 0 && path.charAt(0) != "/") {
+			path = "/" + path;
+		}
+		return { scheme : FORMAT.matched(2), payload : FORMAT.matched(3), hosts : hosts, auth : FORMAT.matched(6), path : tink_url_Path.ofString(path), query : FORMAT.matched(10), hash : FORMAT.matched(12)};
+	}
+	static make(parts) {
+		let parts1 = { payload : "", path : parts.path, query : parts.query, hosts : parts.hosts, auth : parts.auth, scheme : parts.scheme, hash : parts.hash};
+		tink_Url.makePayload(parts1);
+		return parts1;
+	}
+}
+class tink_SingleHostUrl {
+	static _new(v) {
+		return v;
+	}
+	static ofUrl(u) {
+		let v;
+		let _g = u.hosts;
+		switch(_g.length) {
+		case 0:
+			v = u;
+			break;
+		case 1:
+			let _g1 = _g[0];
+			v = u;
+			break;
+		default:
+			let v1 = _g;
+			v = tink_Url.make({ path : u.path, query : u.query, hosts : [u.hosts[0]], auth : u.auth, scheme : u.scheme, hash : u.hash});
+		}
+		return v;
+	}
+	static ofString(s) {
+		return tink_SingleHostUrl.ofUrl(tink_Url.fromString(s));
+	}
+}
+class tink_chunk_ByteChunk extends tink_chunk_ChunkBase {
+	constructor(data,from,to) {
+		super();
+		this.data = data;
+		this.from = from;
+		this.to = to;
+	}
+	get_wrapped() {
+		if(this.wrapped == null) {
+			this.wrapped = haxe_io_Bytes.ofData(this.data);
+		}
+		return this.wrapped;
+	}
+	getByte(index) {
+		return this.data.bytes[this.from + index];
+	}
+	flatten(into) {
+		into.push(this);
+	}
+	getLength() {
+		return this.to - this.from;
+	}
+	getSlice(from,to) {
+		if(to > this.to - this.from) {
+			to = this.to - this.from;
+		}
+		if(from < 0) {
+			from = 0;
+		}
+		if(to <= from) {
+			return null;
+		} else if(to == this.to - this.from && from == 0) {
+			return this;
+		} else {
+			return new tink_chunk_ByteChunk(this.data,this.from + from,to + this.from);
+		}
+	}
+	slice(from,to) {
+		let _g = this.getSlice(from,to);
+		if(_g == null) {
+			return tink_Chunk.EMPTY;
+		} else {
+			let v = _g;
+			return v;
+		}
+	}
+	blitTo(target,offset) {
+		if(this.wrapped == null) {
+			this.wrapped = haxe_io_Bytes.ofData(this.data);
+		}
+		target.blit(offset,this.wrapped,this.from,this.to - this.from);
+	}
+	toBytes() {
+		if(this.wrapped == null) {
+			this.wrapped = haxe_io_Bytes.ofData(this.data);
+		}
+		return this.wrapped.sub(this.from,this.to - this.from);
+	}
+	toString() {
+		if(this.wrapped == null) {
+			this.wrapped = haxe_io_Bytes.ofData(this.data);
+		}
+		return this.wrapped.getString(this.from,this.to - this.from);
+	}
+	static of(b) {
+		if(b.length == 0) {
+			return tink_Chunk.EMPTY;
+		}
+		let ret = new tink_chunk_ByteChunk(b.b.bufferValue,0,b.length);
+		ret.wrapped = b;
+		return ret;
+	}
+}
+tink_chunk_ByteChunk.__name__ = "tink.chunk.ByteChunk";
+tink_chunk_ByteChunk.__interfaces__ = [tink_chunk_ChunkObject];
+tink_chunk_ByteChunk.__super__ = tink_chunk_ChunkBase;
+Object.assign(tink_chunk_ByteChunk.prototype, {
+	__class__: tink_chunk_ByteChunk
+});
+class tink_chunk_ChunkCursor {
+	constructor() {
+		this.currentByte = -1;
+		this.currentPos = 0;
+		this.length = 0;
+		this.curLength = 0;
+		this.curOffset = 0;
+		this.curPartIndex = 0;
+	}
+	clone() {
+		let ret = new tink_chunk_ChunkCursor();
+		ret.parts = this.parts.slice();
+		ret.curPart = this.curPart;
+		ret.curPartIndex = this.curPartIndex;
+		ret.curOffset = this.curOffset;
+		ret.curLength = this.curLength;
+		ret.length = this.length;
+		ret.currentPos = this.currentPos;
+		ret.currentByte = this.currentByte;
+		return ret;
+	}
+	reset() {
+		this.length = 0;
+		this.currentPos = 0;
+		this.currentByte = -1;
+		this.curOffset = 0;
+		let _g = 0;
+		let _g1 = this.parts;
+		while(_g < _g1.length) {
+			let p = _g1[_g];
+			++_g;
+			this.length += p.to - p.from;
+		}
+		this.curPart = this.parts[this.curPartIndex = 0];
+		if(this.curPart != null) {
+			let _this = this.curPart;
+			this.curLength = _this.to - _this.from;
+			let _this1 = this.curPart;
+			this.currentByte = _this1.data.bytes[_this1.from];
+		}
+	}
+	flush() {
+		let ret = this.left();
+		this.shift();
+		return ret;
+	}
+	prune() {
+		this.shift();
+	}
+	add(chunk) {
+		chunk.flatten(this.parts);
+		this.reset();
+	}
+	shift(chunk) {
+		this.parts.splice(0,this.curPartIndex);
+		let _g = this.parts[0];
+		if(_g != null) {
+			let chunk = _g;
+			let _g1 = chunk.getSlice(this.curOffset,this.curLength);
+			if(_g1 == null) {
+				this.parts.shift();
+			} else {
+				let rest = _g1;
+				this.parts[0] = rest;
+			}
+		}
+		if(chunk != null) {
+			this.add(chunk);
+		} else {
+			this.reset();
+		}
+	}
+	clear() {
+		this.parts = [];
+		this.reset();
+	}
+	left() {
+		if(this.curPart == null) {
+			return tink_Chunk.EMPTY;
+		}
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.curPartIndex;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(this.parts[i]);
+		}
+		let left = _g;
+		left.push(this.curPart.slice(0,this.curOffset));
+		return tink_Chunk.join(left);
+	}
+	right() {
+		if(this.curPart == null) {
+			return tink_Chunk.EMPTY;
+		}
+		let _g = [];
+		let _g1 = this.curPartIndex;
+		let _g2 = this.parts.length;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(this.parts[i]);
+		}
+		let right = _g;
+		if(right.length > 0) {
+			right[0] = this.curPart.slice(this.curOffset,this.curLength);
+		}
+		return tink_Chunk.join(right);
+	}
+	seek(seekable,options) {
+		if(this.curPart == null || seekable == null || seekable.length == 0) {
+			return haxe_ds_Option.None;
+		}
+		let max = seekable.length - 1;
+		let first = seekable[0];
+		let candidates = [];
+		let count = 0;
+		let copy = this.clone();
+		copy.shift();
+		let _gthis = this;
+		let part = function(b,offset) {
+			let data = b.data;
+			let _g = b.from + offset;
+			let _g1 = b.to;
+			while(_g < _g1) {
+				let i = _g++;
+				let byte = data.bytes[i];
+				if(candidates.length > 0) {
+					let c = 0;
+					while(c < count) {
+						let pos = candidates[c];
+						if(seekable[pos] == byte) {
+							if(pos == max) {
+								copy.moveTo(copy.currentPos + (i - (b.from + offset) - seekable.length + 1));
+								let before = copy.left();
+								let delta = before.getLength() + seekable.length;
+								_gthis.moveTo(_gthis.currentPos + delta);
+								if(options == null) {
+									_gthis.shift();
+								} else {
+									let _g = options.withoutPruning;
+									if(_g == null) {
+										_gthis.shift();
+									} else if(_g == false) {
+										_gthis.shift();
+									}
+								}
+								return haxe_ds_Option.Some(before);
+							} else {
+								candidates[c++] = pos + 1;
+							}
+						} else {
+							count -= 1;
+							let last = candidates.pop();
+							if(count > c) {
+								candidates[c] = last;
+							}
+						}
+					}
+				}
+				if(byte == first) {
+					count = candidates.push(1);
+				}
+			}
+			copy.moveTo(copy.currentPos + (b.to - (b.from + offset)));
+			return haxe_ds_Option.None;
+		};
+		let _g = part(this.curPart,this.curOffset);
+		if(_g._hx_index == 1) {
+			let _g = this.curPartIndex + 1;
+			let _g1 = this.parts.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let _g1 = part(this.parts[i],0);
+				switch(_g1._hx_index) {
+				case 0:
+					let v = _g1.v;
+					return haxe_ds_Option.Some(v);
+				case 1:
+					break;
+				}
+			}
+			return haxe_ds_Option.None;
+		} else {
+			let v = _g;
+			return v;
+		}
+	}
+	sweep(len) {
+		let data = this.right().slice(0,len);
+		this.moveTo(this.currentPos + len);
+		return data;
+	}
+	sweepTo(pos) {
+		return this.sweep(pos - this.currentPos);
+	}
+	moveBy(delta) {
+		return this.moveTo(this.currentPos + delta);
+	}
+	moveTo(position) {
+		if(this.length == 0) {
+			return 0;
+		}
+		if(position > this.length) {
+			position = this.length - 1;
+		}
+		if(position < 0) {
+			position = 0;
+		}
+		this.currentPos = position;
+		if(position == this.length) {
+			this.ffwd();
+		} else {
+			let _g = 0;
+			let _g1 = this.parts.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let c = this.parts[i];
+				let _g1 = c.to - c.from;
+				let enough = _g1;
+				if(enough > position) {
+					this.curPart = c;
+					this.curPartIndex = i;
+					this.curOffset = position;
+					this.curLength = c.to - c.from;
+					this.currentByte = c.data.bytes[c.from + position];
+					break;
+				} else {
+					let v = _g1;
+					position -= v;
+				}
+			}
+		}
+		return this.currentPos;
+	}
+	ffwd() {
+		this.currentByte = -1;
+		this.curLength = 0;
+		this.curOffset = 0;
+		this.curPart = null;
+		this.curPartIndex = this.parts.length;
+	}
+	next() {
+		if(this.currentPos == this.length) {
+			return false;
+		}
+		this.currentPos++;
+		if(this.currentPos == this.length) {
+			this.ffwd();
+			return false;
+		}
+		if(this.curOffset == this.curLength - 1) {
+			this.curOffset = 0;
+			this.curPart = this.parts[++this.curPartIndex];
+			let _this = this.curPart;
+			this.curLength = _this.to - _this.from;
+			let _this1 = this.curPart;
+			this.currentByte = _this1.data.bytes[_this1.from];
+		} else {
+			let _this = this.curPart;
+			this.currentByte = _this.data.bytes[_this.from + ++this.curOffset];
+		}
+		return true;
+	}
+	static create(parts) {
+		let ret = new tink_chunk_ChunkCursor();
+		ret.parts = parts;
+		ret.reset();
+		return ret;
+	}
+}
+tink_chunk_ChunkCursor.__name__ = "tink.chunk.ChunkCursor";
+Object.assign(tink_chunk_ChunkCursor.prototype, {
+	__class__: tink_chunk_ChunkCursor
+});
+class tink_chunk_ChunkIterator {
+	constructor(target) {
+		this.target = target;
+		this._hasNext = target.length > target.currentPos;
+	}
+	hasNext() {
+		return this._hasNext;
+	}
+	next() {
+		let ret = this.target.currentByte;
+		this._hasNext = this.target.next();
+		return ret;
+	}
+}
+tink_chunk_ChunkIterator.__name__ = "tink.chunk.ChunkIterator";
+Object.assign(tink_chunk_ChunkIterator.prototype, {
+	__class__: tink_chunk_ChunkIterator
+});
+class tink_chunk_ChunkTools {
+	static readUInt8(chunk,offset) {
+		if(chunk.getLength() < offset + 1) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + 1 + ")");
+		}
+		let val = chunk.getByte(offset);
+		return val;
+	}
+	static readInt8(chunk,offset) {
+		let val = tink_chunk_ChunkTools.readUInt8(chunk,offset);
+		if(val > 127) {
+			return val - 256;
+		} else {
+			return val;
+		}
+	}
+	static readUInt16LE(chunk,offset) {
+		if(chunk.getLength() < offset + 2) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + 2 + ")");
+		}
+		let first = chunk.getByte(offset);
+		let last = chunk.getByte(offset + 1);
+		return first + (last << 8);
+	}
+	static readInt16LE(chunk,offset) {
+		let val = tink_chunk_ChunkTools.readUInt16LE(chunk,offset);
+		if(val > 32767) {
+			return val - 65536;
+		} else {
+			return val;
+		}
+	}
+	static readUInt24LE(chunk,offset) {
+		if(chunk.getLength() < offset + 3) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + 3 + ")");
+		}
+		let first = chunk.getByte(offset);
+		let mid = chunk.getByte(offset + 1);
+		let last = chunk.getByte(offset + 2);
+		return first + (mid << 8) + (last << 16);
+	}
+	static readInt24LE(chunk,offset) {
+		let val = tink_chunk_ChunkTools.readUInt24LE(chunk,offset);
+		if(val > 8388607) {
+			return val - 16777216;
+		} else {
+			return val;
+		}
+	}
+	static readInt32LE(chunk,offset) {
+		if(chunk.getLength() < offset + 4) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + 4 + ")");
+		}
+		let val = chunk.getByte(offset) + (chunk.getByte(offset + 1) << 8) + (chunk.getByte(offset + 2) << 16) + (chunk.getByte(offset + 3) << 24);
+		return val;
+	}
+	static readDoubleLE(chunk,offset) {
+		let l = tink_chunk_ChunkTools.readInt32LE(chunk,0);
+		let h = tink_chunk_ChunkTools.readInt32LE(chunk,4);
+		return haxe_io_FPHelper.i64ToDouble(l,h);
+	}
+	static readNullTerminatedString(chunk,offset) {
+		try {
+			return new haxe_io_BytesInput(chunk.toBytes(),offset).readUntil(0);
+		} catch( _g ) {
+			return chunk.toString();
+		}
+	}
+	static writeUInt8(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(1));
+		bytes.b[0] = v & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeInt8(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(1));
+		v &= 255;
+		if(v < 0) {
+			v += 256;
+		}
+		bytes.b[0] = v;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeUInt16LE(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(2));
+		bytes.b[0] = v & 255;
+		bytes.b[1] = v >>> 8 & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeInt16LE(v) {
+		return tink_chunk_ChunkTools.writeUInt16LE(v);
+	}
+	static writeUInt24LE(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(3));
+		bytes.b[0] = v & 255;
+		bytes.b[1] = v >>> 8 & 255;
+		bytes.b[2] = v >>> 16 & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeInt24LE(v) {
+		return tink_chunk_ChunkTools.writeUInt24LE(v);
+	}
+	static writeInt32LE(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(4));
+		bytes.b[0] = v & 255;
+		bytes.b[1] = v >>> 8 & 255;
+		bytes.b[2] = v >>> 16 & 255;
+		bytes.b[3] = v >>> 24 & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static writeDoubleLE(v) {
+		let bytes = new haxe_io_Bytes(new ArrayBuffer(8));
+		let i64 = haxe_io_FPHelper.doubleToI64(v);
+		let l = i64.low;
+		let h = i64.high;
+		bytes.b[0] = l & 255;
+		bytes.b[1] = l >>> 8 & 255;
+		bytes.b[2] = l >>> 16 & 255;
+		bytes.b[3] = l >>> 24 & 255;
+		bytes.b[4] = h & 255;
+		bytes.b[5] = h >>> 8 & 255;
+		bytes.b[6] = h >>> 16 & 255;
+		bytes.b[7] = h >>> 24 & 255;
+		return tink_chunk_ByteChunk.of(bytes);
+	}
+	static lpad(chunk,pad,length) {
+		if(pad.getLength() != 0) {
+			while(chunk.getLength() < length) chunk = tink_Chunk.concat(pad,chunk);
+		}
+		return chunk;
+	}
+	static rpad(chunk,pad,length) {
+		if(pad.getLength() != 0) {
+			while(chunk.getLength() < length) chunk = tink_Chunk.concat(chunk,pad);
+		}
+		return chunk;
+	}
+	static check(chunk,offset,length) {
+		if(chunk.getLength() < offset + length) {
+			throw haxe_Exception.thrown("Out of range (chunk length = " + chunk.getLength() + ", read offset = " + offset + ", read length = " + length + ")");
+		}
+	}
+}
+tink_chunk_ChunkTools.__name__ = "tink.chunk.ChunkTools";
+class tink_chunk_CompoundChunk extends tink_chunk_ChunkBase {
+	constructor() {
+		super();
+	}
+	getByte(i) {
+		let index = this.findChunk(i);
+		return this.chunks[index].getByte(i - this.offsets[index]);
+	}
+	getLength() {
+		return this.length;
+	}
+	findChunk(target) {
+		let min = 0;
+		let max = this.offsets.length - 1;
+		while(min + 1 < max) {
+			let guess = min + max >> 1;
+			if(this.offsets[guess] > target) {
+				max = guess;
+			} else {
+				min = guess;
+			}
+		}
+		return min;
+	}
+	flatten(into) {
+		let _g = 0;
+		let _g1 = this.chunks;
+		while(_g < _g1.length) {
+			let c = _g1[_g];
+			++_g;
+			c.flatten(into);
+		}
+	}
+	slice(from,to) {
+		let idxFrom = this.findChunk(from);
+		let idxTo = this.findChunk(to);
+		if(idxFrom == idxTo) {
+			let offset = this.offsets[idxFrom];
+			return this.chunks[idxFrom].slice(from - offset,to - offset);
+		}
+		let ret = this.chunks.slice(idxFrom,idxTo + 1);
+		let c = ret[0];
+		ret[0] = c.slice(from - this.offsets[idxFrom],this.offsets[idxFrom + 1]);
+		let c1 = ret[ret.length - 1];
+		ret[ret.length - 1] = c1.slice(0,to - this.offsets[idxTo]);
+		return tink_chunk_CompoundChunk.create(ret,this.depth);
+	}
+	blitTo(target,offset) {
+		let _g = 0;
+		let _g1 = this.chunks.length;
+		while(_g < _g1) {
+			let i = _g++;
+			this.chunks[i].blitTo(target,offset + this.offsets[i]);
+		}
+	}
+	toString() {
+		return this.toBytes().toString();
+	}
+	toBytes() {
+		let ret = new haxe_io_Bytes(new ArrayBuffer(this.length));
+		this.blitTo(ret,0);
+		return ret;
+	}
+	static asCompound(c) {
+		if(((c) instanceof tink_chunk_CompoundChunk)) {
+			return c;
+		} else {
+			return null;
+		}
+	}
+	static cons(a,b) {
+		let _g = a.getLength();
+		let _g1 = b.getLength();
+		if(_g == 0) {
+			if(_g1 == 0) {
+				return tink_Chunk.EMPTY;
+			} else {
+				return b;
+			}
+		} else if(_g1 == 0) {
+			return a;
+		} else {
+			let la = _g;
+			let lb = _g1;
+			let _g2 = tink_chunk_CompoundChunk.asCompound(a);
+			let _g3 = tink_chunk_CompoundChunk.asCompound(b);
+			if(_g2 == null) {
+				if(_g3 == null) {
+					return tink_chunk_CompoundChunk.create([a,b],2);
+				} else {
+					let v = _g3;
+					if(v.depth < 100) {
+						return tink_chunk_CompoundChunk.create([a,b],v.depth + 1);
+					} else {
+						let flat = [];
+						v.flatten(flat);
+						b.flatten(flat);
+						return tink_chunk_CompoundChunk.create(flat,2);
+					}
+				}
+			} else if(_g3 == null) {
+				let v = _g2;
+				if(v.depth < 100) {
+					return tink_chunk_CompoundChunk.create([a,b],v.depth + 1);
+				} else {
+					let flat = [];
+					v.flatten(flat);
+					b.flatten(flat);
+					return tink_chunk_CompoundChunk.create(flat,2);
+				}
+			} else {
+				let a = _g2;
+				let b = _g3;
+				let depth = a.depth > b.depth ? a.depth : b.depth;
+				return tink_chunk_CompoundChunk.create(a.chunks.concat(b.chunks),depth);
+			}
+		}
+	}
+	static create(chunks,depth) {
+		let ret = new tink_chunk_CompoundChunk();
+		let offsets = [0];
+		let length = 0;
+		let _g = 0;
+		while(_g < chunks.length) {
+			let c = chunks[_g];
+			++_g;
+			offsets.push(length += c.getLength());
+		}
+		ret.chunks = chunks;
+		ret.offsets = offsets;
+		ret.length = length;
+		ret.depth = depth;
+		return ret;
+	}
+}
+tink_chunk_CompoundChunk.__name__ = "tink.chunk.CompoundChunk";
+tink_chunk_CompoundChunk.__interfaces__ = [tink_chunk_ChunkObject];
+tink_chunk_CompoundChunk.__super__ = tink_chunk_ChunkBase;
+Object.assign(tink_chunk_CompoundChunk.prototype, {
+	__class__: tink_chunk_CompoundChunk
+});
+class tink_chunk_Seekable {
+	static _new(a) {
+		return a;
+	}
+	static get_length(this1) {
+		return this1.length;
+	}
+	static get(this1,index) {
+		return this1[index];
+	}
+	static ofChunk(c) {
+		return tink_chunk_Seekable.ofBytes(c.toBytes());
+	}
+	static ofBytes(b) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = b.length;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(b.b[i]);
+		}
+		return _g;
+	}
+	static ofString(s) {
+		return tink_chunk_Seekable.ofBytes(haxe_io_Bytes.ofString(s));
+	}
+}
+class tink_chunk_nodejs_BufferChunk {
+	constructor(buffer) {
+		this.buffer = buffer;
+	}
+	getByte(i) {
+		return this.buffer[i];
+	}
+	getCursor() {
+		return tink_chunk_ByteChunk.of(this.toBytes()).getCursor();
+	}
+	flatten(into) {
+		tink_chunk_ByteChunk.of(this.toBytes()).flatten(into);
+	}
+	getLength() {
+		return this.buffer.length;
+	}
+	slice(from,to) {
+		if(to > this.getLength()) {
+			to = this.getLength();
+		}
+		if(from < 0) {
+			from = 0;
+		}
+		if(to <= from) {
+			return tink_Chunk.EMPTY;
+		} else if(to == this.getLength() && from == 0) {
+			return this;
+		} else {
+			return new tink_chunk_nodejs_BufferChunk(this.buffer.slice(from,to));
+		}
+	}
+	toString() {
+		return this.buffer.toString();
+	}
+	toBytes() {
+		let copy = js_node_buffer_Buffer.allocUnsafe(this.buffer.length);
+		this.buffer.copy(copy);
+		return js_node_buffer__$Buffer_Helper.bytesOfBuffer(copy);
+	}
+	blitTo(target,offset) {
+		let data = target.b;
+		this.buffer.copy(js_node_buffer_Buffer.from(data.buffer,data.byteOffset,target.length),offset);
+	}
+}
+tink_chunk_nodejs_BufferChunk.__name__ = "tink.chunk.nodejs.BufferChunk";
+tink_chunk_nodejs_BufferChunk.__interfaces__ = [tink_chunk_ChunkObject];
+Object.assign(tink_chunk_nodejs_BufferChunk.prototype, {
+	__class__: tink_chunk_nodejs_BufferChunk
+});
+class tink_core_Annex {
+	constructor(target) {
+		this.target = target;
+		this.registry = new haxe_ds_ObjectMap();
+	}
+}
+tink_core_Annex.__name__ = "tink.core.Annex";
+Object.assign(tink_core_Annex.prototype, {
+	__class__: tink_core_Annex
+});
+class tink_core_Callback {
+	static _new(f) {
+		return f;
+	}
+	static toFunction(this1) {
+		return this1;
+	}
+	static invoke(this1,data) {
+		if(tink_core_Callback.depth < 500) {
+			tink_core_Callback.depth++;
+			this1(data);
+			tink_core_Callback.depth--;
+		} else {
+			tink_core_Callback.defer(function() {
+				this1(data);
+			});
+		}
+	}
+	static fromNiladic(f) {
+		return f;
+	}
+	static fromMany(callbacks) {
+		return function(v) {
+			let _g = 0;
+			while(_g < callbacks.length) {
+				let callback = callbacks[_g];
+				++_g;
+				tink_core_Callback.invoke(callback,v);
+			}
+		};
+	}
+	static defer(f) {
+		global.setImmediate(f);
+	}
+}
+class tink_core_LinkObject {
+}
+tink_core_LinkObject.__name__ = "tink.core.LinkObject";
+tink_core_LinkObject.__isInterface__ = true;
+Object.assign(tink_core_LinkObject.prototype, {
+	__class__: tink_core_LinkObject
+});
+class tink_core_CallbackLinkRef {
+	constructor() {
+	}
+	set_link(param) {
+		let this1 = this.link;
+		if(this1 != null) {
+			this1.cancel();
+		}
+		return this.link = param;
+	}
+	cancel() {
+		let this1 = this.link;
+		if(this1 != null) {
+			this1.cancel();
+		}
+	}
+}
+tink_core_CallbackLinkRef.__name__ = "tink.core.CallbackLinkRef";
+tink_core_CallbackLinkRef.__interfaces__ = [tink_core_LinkObject];
+Object.assign(tink_core_CallbackLinkRef.prototype, {
+	__class__: tink_core_CallbackLinkRef
+});
+class tink_core_CallbackLink {
+	static _new(link) {
+		return new tink_core_SimpleLink(link);
+	}
+	static cancel(this1) {
+		if(this1 != null) {
+			this1.cancel();
+		}
+	}
+	static dissolve(this1) {
+		if(this1 != null) {
+			this1.cancel();
+		}
+	}
+	static noop() {
+	}
+	static toFunction(this1) {
+		if(this1 == null) {
+			return tink_core_CallbackLink.noop;
+		} else {
+			return $bind(this1,this1.cancel);
+		}
+	}
+	static toCallback(this1) {
+		if(this1 == null) {
+			return tink_core_CallbackLink.noop;
+		} else {
+			return $bind(this1,this1.cancel);
+		}
+	}
+	static fromFunction(f) {
+		return new tink_core_SimpleLink(f);
+	}
+	static join(this1,b) {
+		return new tink_core__$Callback_LinkPair(this1,b);
+	}
+	static fromMany(callbacks) {
+		return new tink_core_SimpleLink(function() {
+			if(callbacks != null) {
+				let _g = 0;
+				while(_g < callbacks.length) {
+					let cb = callbacks[_g];
+					++_g;
+					if(cb != null) {
+						cb.cancel();
+					}
+				}
+			} else {
+				callbacks = null;
+			}
+		});
+	}
+}
+class tink_core_SimpleLink {
+	constructor(f) {
+		this.f = f;
+	}
+	cancel() {
+		if(this.f != null) {
+			this.f();
+			this.f = null;
+		}
+	}
+}
+tink_core_SimpleLink.__name__ = "tink.core.SimpleLink";
+tink_core_SimpleLink.__interfaces__ = [tink_core_LinkObject];
+Object.assign(tink_core_SimpleLink.prototype, {
+	__class__: tink_core_SimpleLink
+});
+class tink_core__$Callback_LinkPair {
+	constructor(a,b) {
+		this.dissolved = false;
+		this.a = a;
+		this.b = b;
+	}
+	cancel() {
+		if(!this.dissolved) {
+			this.dissolved = true;
+			let this1 = this.a;
+			if(this1 != null) {
+				this1.cancel();
+			}
+			let this2 = this.b;
+			if(this2 != null) {
+				this2.cancel();
+			}
+			this.a = null;
+			this.b = null;
+		}
+	}
+}
+tink_core__$Callback_LinkPair.__name__ = "tink.core._Callback.LinkPair";
+tink_core__$Callback_LinkPair.__interfaces__ = [tink_core_LinkObject];
+Object.assign(tink_core__$Callback_LinkPair.prototype, {
+	__class__: tink_core__$Callback_LinkPair
+});
+class tink_core__$Callback_ListCell {
+	constructor(cb,list) {
+		if(cb == null) {
+			throw haxe_Exception.thrown("callback expected but null received");
+		}
+		this.cb = cb;
+		this.list = list;
+	}
+	invoke(data) {
+		if(this.list != null) {
+			this.cb(data);
+		}
+	}
+	clear() {
+		this.cb = null;
+		this.list = null;
+	}
+	cancel() {
+		if(this.list != null) {
+			let list = this.list;
+			this.cb = null;
+			this.list = null;
+			if(--list.used <= list.cells.length >> 1) {
+				list.compact();
+			}
+		}
+	}
+}
+tink_core__$Callback_ListCell.__name__ = "tink.core._Callback.ListCell";
+tink_core__$Callback_ListCell.__interfaces__ = [tink_core_LinkObject];
+Object.assign(tink_core__$Callback_ListCell.prototype, {
+	__class__: tink_core__$Callback_ListCell
+});
+class tink_core_Disposable {
+}
+tink_core_Disposable.__name__ = "tink.core.Disposable";
+tink_core_Disposable.__isInterface__ = true;
+Object.assign(tink_core_Disposable.prototype, {
+	__class__: tink_core_Disposable
+});
+class tink_core_OwnedDisposable {
+}
+tink_core_OwnedDisposable.__name__ = "tink.core.OwnedDisposable";
+tink_core_OwnedDisposable.__isInterface__ = true;
+tink_core_OwnedDisposable.__interfaces__ = [tink_core_Disposable];
+Object.assign(tink_core_OwnedDisposable.prototype, {
+	__class__: tink_core_OwnedDisposable
+});
+class tink_core_SimpleDisposable {
+	constructor(dispose) {
+		if(tink_core_SimpleDisposable._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(dispose);
+	}
+	_hx_constructor(dispose) {
+		this.disposeHandlers = [];
+		this.f = dispose;
+	}
+	get_disposed() {
+		return this.disposeHandlers == null;
+	}
+	ondispose(d) {
+		let _g = this.disposeHandlers;
+		if(_g == null) {
+			d();
+		} else {
+			let v = _g;
+			v.push(d);
+		}
+	}
+	dispose() {
+		let _g = this.disposeHandlers;
+		if(_g != null) {
+			let v = _g;
+			this.disposeHandlers = null;
+			let f = this.f;
+			this.f = tink_core_SimpleDisposable.noop;
+			f();
+			let _g1 = 0;
+			while(_g1 < v.length) {
+				let h = v[_g1];
+				++_g1;
+				h();
+			}
+		}
+	}
+	static noop() {
+	}
+}
+tink_core_SimpleDisposable.__name__ = "tink.core.SimpleDisposable";
+tink_core_SimpleDisposable.__interfaces__ = [tink_core_OwnedDisposable];
+Object.assign(tink_core_SimpleDisposable.prototype, {
+	__class__: tink_core_SimpleDisposable
+});
+class tink_core_CallbackList extends tink_core_SimpleDisposable {
+	constructor(destructive) {
+		tink_core_SimpleDisposable._hx_skip_constructor = true;
+		super();
+		tink_core_SimpleDisposable._hx_skip_constructor = false;
+		this._hx_constructor(destructive);
+	}
+	_hx_constructor(destructive) {
+		if(destructive == null) {
+			destructive = false;
+		}
+		this.onfill = function() {
+		};
+		this.ondrain = function() {
+		};
+		this.busy = false;
+		this.queue = [];
+		this.used = 0;
+		let _gthis = this;
+		super._hx_constructor(function() {
+			if(!_gthis.busy) {
+				_gthis.destroy();
+			}
+		});
+		this.destructive = destructive;
+		this.cells = [];
+	}
+	get_length() {
+		return this.used;
+	}
+	release() {
+		if(--this.used <= this.cells.length >> 1) {
+			this.compact();
+		}
+	}
+	destroy() {
+		let _g = 0;
+		let _g1 = this.cells;
+		while(_g < _g1.length) {
+			let c = _g1[_g];
+			++_g;
+			c.cb = null;
+			c.list = null;
+		}
+		this.queue = null;
+		this.cells = null;
+		if(this.used > 0) {
+			this.used = 0;
+			let fn = this.ondrain;
+			if(tink_core_Callback.depth < 500) {
+				tink_core_Callback.depth++;
+				fn();
+				tink_core_Callback.depth--;
+			} else {
+				tink_core_Callback.defer(fn);
+			}
+		}
+	}
+	drain() {
+		let fn = this.ondrain;
+		if(tink_core_Callback.depth < 500) {
+			tink_core_Callback.depth++;
+			fn();
+			tink_core_Callback.depth--;
+		} else {
+			tink_core_Callback.defer(fn);
+		}
+	}
+	add(cb) {
+		if(this.disposeHandlers == null) {
+			return null;
+		}
+		let node = new tink_core__$Callback_ListCell(cb,this);
+		this.cells.push(node);
+		if(this.used++ == 0) {
+			let fn = this.onfill;
+			if(tink_core_Callback.depth < 500) {
+				tink_core_Callback.depth++;
+				fn();
+				tink_core_Callback.depth--;
+			} else {
+				tink_core_Callback.defer(fn);
+			}
+		}
+		return node;
+	}
+	invoke(data) {
+		let _gthis = this;
+		if(tink_core_Callback.depth < 500) {
+			tink_core_Callback.depth++;
+			if(_gthis.disposeHandlers != null) {
+				if(_gthis.busy) {
+					if(_gthis.destructive != true) {
+						let _g = _gthis;
+						let data1 = data;
+						let tmp = function() {
+							_g.invoke(data1);
+						};
+						_gthis.queue.push(tmp);
+					}
+				} else {
+					_gthis.busy = true;
+					if(_gthis.destructive) {
+						_gthis.dispose();
+					}
+					let length = _gthis.cells.length;
+					let _g = 0;
+					let _g1 = length;
+					while(_g < _g1) {
+						let i = _g++;
+						let _this = _gthis.cells[i];
+						if(_this.list != null) {
+							_this.cb(data);
+						}
+					}
+					_gthis.busy = false;
+					if(_gthis.disposeHandlers == null) {
+						_gthis.destroy();
+					} else {
+						if(_gthis.used < _gthis.cells.length) {
+							_gthis.compact();
+						}
+						if(_gthis.queue.length > 0) {
+							(_gthis.queue.shift())();
+						}
+					}
+				}
+			}
+			tink_core_Callback.depth--;
+		} else {
+			tink_core_Callback.defer(function() {
+				if(_gthis.disposeHandlers != null) {
+					if(_gthis.busy) {
+						if(_gthis.destructive != true) {
+							let _g = _gthis;
+							let data1 = data;
+							let tmp = function() {
+								_g.invoke(data1);
+							};
+							_gthis.queue.push(tmp);
+						}
+					} else {
+						_gthis.busy = true;
+						if(_gthis.destructive) {
+							_gthis.dispose();
+						}
+						let length = _gthis.cells.length;
+						let _g = 0;
+						let _g1 = length;
+						while(_g < _g1) {
+							let i = _g++;
+							let _this = _gthis.cells[i];
+							if(_this.list != null) {
+								_this.cb(data);
+							}
+						}
+						_gthis.busy = false;
+						if(_gthis.disposeHandlers == null) {
+							_gthis.destroy();
+						} else {
+							if(_gthis.used < _gthis.cells.length) {
+								_gthis.compact();
+							}
+							if(_gthis.queue.length > 0) {
+								(_gthis.queue.shift())();
+							}
+						}
+					}
+				}
+			});
+		}
+	}
+	compact() {
+		if(this.busy) {
+			return;
+		} else if(this.used == 0) {
+			this.resize(0);
+			let fn = this.ondrain;
+			if(tink_core_Callback.depth < 500) {
+				tink_core_Callback.depth++;
+				fn();
+				tink_core_Callback.depth--;
+			} else {
+				tink_core_Callback.defer(fn);
+			}
+		} else {
+			let compacted = 0;
+			let _g = 0;
+			let _g1 = this.cells.length;
+			while(_g < _g1) {
+				let i = _g++;
+				let _g1 = this.cells[i];
+				let _g2 = _g1.list;
+				if(_g1.cb != null) {
+					let v = _g1;
+					if(compacted != i) {
+						this.cells[compacted] = v;
+					}
+					if(++compacted == this.used) {
+						break;
+					}
+				}
+			}
+			this.resize(this.used);
+		}
+	}
+	resize(length) {
+		this.cells.length = length;
+	}
+	clear() {
+		if(this.busy) {
+			this.queue.push($bind(this,this.clear));
+		}
+		let _g = 0;
+		let _g1 = this.cells;
+		while(_g < _g1.length) {
+			let cell = _g1[_g];
+			++_g;
+			cell.cb = null;
+			cell.list = null;
+		}
+		this.resize(0);
+	}
+}
+tink_core_CallbackList.__name__ = "tink.core.CallbackList";
+tink_core_CallbackList.__super__ = tink_core_SimpleDisposable;
+Object.assign(tink_core_CallbackList.prototype, {
+	__class__: tink_core_CallbackList
+});
+class tink_core_AlreadyDisposed {
+	constructor() {
+	}
+	get_disposed() {
+		return true;
+	}
+	ondispose(d) {
+		d();
+	}
+	dispose() {
+	}
+}
+tink_core_AlreadyDisposed.__name__ = "tink.core.AlreadyDisposed";
+tink_core_AlreadyDisposed.__interfaces__ = [tink_core_OwnedDisposable];
+Object.assign(tink_core_AlreadyDisposed.prototype, {
+	__class__: tink_core_AlreadyDisposed
+});
+class tink_core_TypedError {
+	constructor(code,message,pos) {
+		if(code == null) {
+			code = 500;
+		}
+		this.isTinkError = true;
+		this.code = code;
+		this.message = message;
+		this.pos = pos;
+		this.exceptionStack = [];
+		this.callStack = [];
+	}
+	printPos() {
+		return this.pos.className + "." + this.pos.methodName + ":" + this.pos.lineNumber;
+	}
+	toString() {
+		let ret = "Error#" + this.code + ": " + this.message;
+		if(this.pos != null) {
+			ret += " @ " + this.printPos();
+		}
+		return ret;
+	}
+	toPromise() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(this)));
+	}
+	throwSelf() {
+		let any = this;
+		throw haxe_Exception.thrown(any);
+	}
+	toJsError() {
+		if(((this.data) instanceof Error)) {
+			return this.data;
+		} else {
+			return new tink_core__$Error_TinkError(this);
+		}
+	}
+	static withData(code,message,data,pos) {
+		return tink_core_TypedError.typed(code,message,data,pos);
+	}
+	static typed(code,message,data,pos) {
+		let ret = new tink_core_TypedError(code,message,pos);
+		ret.data = data;
+		return ret;
+	}
+	static ofJsError(e,pos) {
+		return tink_core_TypedError.withData(500,e.message,e,pos);
+	}
+	static asError(v) {
+		if(v != null && v.isTinkError) {
+			return v;
+		} else {
+			return null;
+		}
+	}
+	static catchExceptions(f,report,pos) {
+		try {
+			return tink_core_Outcome.Success(f());
+		} catch( _g ) {
+			let ex = haxe_Exception.caught(_g).unwrap();
+			let e = tink_core_TypedError.asError(ex);
+			let tmp;
+			if(e == null) {
+				tmp = report == null ? tink_core_TypedError.withData(null,"Unexpected Error",ex,pos) : report(ex);
+			} else {
+				let e1 = e;
+				tmp = e1;
+			}
+			return tink_core_Outcome.Failure(tmp);
+		}
+	}
+	static reporter(code,message,pos) {
+		return function(e) {
+			return tink_core_TypedError.withData(code,message,e,pos);
+		};
+	}
+	static rethrow(any) {
+		throw haxe_Exception.thrown(any);
+	}
+	static tryFinally(f,cleanup) {
+		try { return f(); } finally { cleanup(); }
+		return null;
+	}
+}
+tink_core_TypedError.__name__ = "tink.core.TypedError";
+Object.assign(tink_core_TypedError.prototype, {
+	__class__: tink_core_TypedError
+});
+class tink_core_Stack {
+	static toString(this1) {
+		return "Error stack not available. Compile with -D error_stack.";
+	}
+}
+class tink_core__$Error_TinkError extends Error {
+	constructor(e) {
+		super();
+		this.message = e.message;
+		this.data = e;
+	}
+}
+tink_core__$Error_TinkError.__name__ = "tink.core._Error.TinkError";
+tink_core__$Error_TinkError.__super__ = Error;
+Object.assign(tink_core__$Error_TinkError.prototype, {
+	__class__: tink_core__$Error_TinkError
+});
+class tink_core__$Future_FutureObject {
+	constructor() {
+		if(tink_core__$Future_FutureObject._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+	}
+	getStatus() {
+		return tink_core_FutureStatus.NeverEver;
+	}
+	handle(callback) {
+		return null;
+	}
+	eager() {
+	}
+}
+tink_core__$Future_FutureObject.__name__ = "tink.core._Future.FutureObject";
+Object.assign(tink_core__$Future_FutureObject.prototype, {
+	__class__: tink_core__$Future_FutureObject
+});
+class tink_core__$Lazy_Computable {
+}
+tink_core__$Lazy_Computable.__name__ = "tink.core._Lazy.Computable";
+tink_core__$Lazy_Computable.__isInterface__ = true;
+Object.assign(tink_core__$Lazy_Computable.prototype, {
+	__class__: tink_core__$Lazy_Computable
+});
+class tink_core__$Lazy_LazyObject {
+}
+tink_core__$Lazy_LazyObject.__name__ = "tink.core._Lazy.LazyObject";
+tink_core__$Lazy_LazyObject.__isInterface__ = true;
+tink_core__$Lazy_LazyObject.__interfaces__ = [tink_core__$Lazy_Computable];
+Object.assign(tink_core__$Lazy_LazyObject.prototype, {
+	__class__: tink_core__$Lazy_LazyObject
+});
+class tink_core__$Lazy_LazyConst {
+	constructor(value) {
+		this.value = value;
+	}
+	isComputed() {
+		return true;
+	}
+	get() {
+		return this.value;
+	}
+	compute() {
+	}
+	underlying() {
+		return null;
+	}
+}
+tink_core__$Lazy_LazyConst.__name__ = "tink.core._Lazy.LazyConst";
+tink_core__$Lazy_LazyConst.__interfaces__ = [tink_core__$Lazy_LazyObject];
+Object.assign(tink_core__$Lazy_LazyConst.prototype, {
+	__class__: tink_core__$Lazy_LazyConst
+});
+class tink_core__$Future_SyncFuture extends tink_core__$Future_FutureObject {
+	constructor(value) {
+		super();
+		this.value = value;
+	}
+	getStatus() {
+		return tink_core_FutureStatus.Ready(this.value);
+	}
+	handle(cb) {
+		tink_core_Callback.invoke(cb,tink_core_Lazy.get(this.value));
+		return null;
+	}
+	eager() {
+		if(!this.value.isComputed()) {
+			tink_core_Lazy.get(this.value);
+		}
+	}
+}
+tink_core__$Future_SyncFuture.__name__ = "tink.core._Future.SyncFuture";
+tink_core__$Future_SyncFuture.__super__ = tink_core__$Future_FutureObject;
+Object.assign(tink_core__$Future_SyncFuture.prototype, {
+	__class__: tink_core__$Future_SyncFuture
+});
+class tink_core_Future {
+	static never() {
+		return tink_core_Future.NEVER_INST;
+	}
+	static get_status(this1) {
+		return this1.getStatus();
+	}
+	static _new(wakeup) {
+		return new tink_core__$Future_SuspendableFuture(wakeup);
+	}
+	static handle(this1,callback) {
+		return this1.handle(callback);
+	}
+	static eager(this1) {
+		this1.eager();
+		return this1;
+	}
+	static noise(this1) {
+		if(this1.getStatus()._hx_index == 4) {
+			return tink_core_Future.never();
+		} else {
+			return tink_core_Future.map(this1,function(_) {
+				return null;
+			});
+		}
+	}
+	static first(this1,that) {
+		let _g = this1;
+		let _g1 = _g.getStatus();
+		switch(_g1._hx_index) {
+		case 3:
+			let _g2 = _g1.result;
+			let _g3 = that.getStatus();
+			switch(_g3._hx_index) {
+			case 3:
+				let _g4 = _g3.result;
+				let v = _g;
+				return v;
+			case 4:
+				let v1 = _g;
+				return v1;
+			default:
+				let v2 = _g;
+				return v2;
+			}
+			break;
+		case 4:
+			let v3 = that;
+			return v3;
+		default:
+			let _g5 = that.getStatus();
+			switch(_g5._hx_index) {
+			case 3:
+				let _g6 = _g5.result;
+				let v4 = that;
+				return v4;
+			case 4:
+				let v5 = _g;
+				return v5;
+			default:
+				return new tink_core__$Future_SuspendableFuture(function(fire) {
+					return new tink_core__$Callback_LinkPair(this1.handle(fire),that.handle(fire));
+				});
+			}
+		}
+	}
+	static map(this1,f,gather) {
+		let _g = this1.getStatus();
+		switch(_g._hx_index) {
+		case 3:
+			let l = _g.result;
+			let this2 = l;
+			let f1 = f;
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyFunc(function() {
+				return f1(this2.get());
+			},this2));
+		case 4:
+			return tink_core_Future.never();
+		default:
+			return new tink_core__$Future_SuspendableFuture(function(fire) {
+				return this1.handle(function(v) {
+					fire(f(v));
+				});
+			});
+		}
+	}
+	static flatMap(this1,next,gather) {
+		let _g = this1.getStatus();
+		switch(_g._hx_index) {
+		case 3:
+			let l = _g.result;
+			return new tink_core__$Future_SuspendableFuture(function(fire) {
+				return next(tink_core_Lazy.get(l)).handle(function(v) {
+					fire(v);
+				});
+			});
+		case 4:
+			return tink_core_Future.never();
+		default:
+			return new tink_core__$Future_SuspendableFuture(function($yield) {
+				let inner = new tink_core_CallbackLinkRef();
+				let outer = this1.handle(function(v) {
+					let param = next(v).handle($yield);
+					let this1 = inner.link;
+					if(this1 != null) {
+						this1.cancel();
+					}
+					inner.link = param;
+				});
+				return new tink_core__$Callback_LinkPair(outer,inner);
+			});
+		}
+	}
+	static swap(this1,v) {
+		return tink_core_Future.map(this1,function(_) {
+			return v;
+		});
+	}
+	static next(this1,n) {
+		return tink_core_Future.flatMap(this1,n);
+	}
+	static withSideEffect(this1,c) {
+		return tink_core_Future.map(this1,function(v) {
+			tink_core_Callback.invoke(c,v);
+			return v;
+		});
+	}
+	static gather(this1) {
+		return this1;
+	}
+	static merge(this1,that,combine) {
+		let _g = this1.getStatus();
+		let _g1 = that.getStatus();
+		if(_g._hx_index == 4) {
+			return tink_core_Future.never();
+		} else if(_g1._hx_index == 4) {
+			return tink_core_Future.never();
+		} else {
+			return new tink_core__$Future_SuspendableFuture(function($yield) {
+				let check = function(v) {
+					let _g = this1.getStatus();
+					let _g1 = that.getStatus();
+					if(_g._hx_index == 3) {
+						if(_g1._hx_index == 3) {
+							let b = _g1.result;
+							let a = _g.result;
+							$yield(combine(tink_core_Lazy.get(a),tink_core_Lazy.get(b)));
+						}
+					}
+				};
+				return new tink_core__$Callback_LinkPair(this1.handle(check),that.handle(check));
+			});
+		}
+	}
+	static flatten(f) {
+		return tink_core_Future.flatMap(f,function(v) {
+			return v;
+		});
+	}
+	static ofJsPromise(promise,transformError) {
+		return tink_core_Future.irreversible(function(cb) {
+			promise.then(function(a) {
+				let _g = cb;
+				let a1 = tink_core_Outcome.Success(a);
+				tink_core_Callback.defer(function() {
+					_g(a1);
+				});
+			},function(e) {
+				let cb1 = cb;
+				let tmp;
+				if(transformError == null) {
+					let e1 = e;
+					tmp = tink_core_TypedError.withData(500,e1.message,e1,{ fileName : "tink/core/Future.hx", lineNumber : 176, className : "tink.core._Future.Future_Impl_", methodName : "ofJsPromise"});
+				} else {
+					let f = transformError;
+					tmp = f(e);
+				}
+				cb1(tink_core_Outcome.Failure(tmp));
+			});
+		});
+	}
+	static fromJsPromise(promise) {
+		return tink_core_Future.ofJsPromise(promise);
+	}
+	static neverToAny(l) {
+		return l;
+	}
+	static ofAny(v) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+	}
+	static asPromise(s) {
+		return s;
+	}
+	static ofMany(futures,gather) {
+		return tink_core_Future.inSequence(futures);
+	}
+	static inParallel(futures,concurrency) {
+		return tink_core_Future.many(futures,concurrency);
+	}
+	static inSequence(futures) {
+		return tink_core_Future.many(futures,1);
+	}
+	static many(a,concurrency) {
+		return tink_core_Future.processMany(a,concurrency,tink_core_Outcome.Success,function(o) {
+			return tink_core_OutcomeTools.orNull(o);
+		});
+	}
+	static processMany(a,concurrency,fn,lift) {
+		if(a.length == 0) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(lift(tink_core_Outcome.Success([]))));
+		} else {
+			return new tink_core__$Future_SuspendableFuture(function($yield) {
+				let links = [];
+				let _g = [];
+				let _g1 = 0;
+				while(_g1 < a.length) {
+					let x = a[_g1];
+					++_g1;
+					_g.push(null);
+				}
+				let ret = _g;
+				let index = 0;
+				let pending = 0;
+				let done = false;
+				let concurrency1;
+				if(concurrency == null) {
+					concurrency1 = a.length;
+				} else {
+					let v = concurrency;
+					concurrency1 = v < 1 ? 1 : v > a.length ? a.length : v;
+				}
+				let fireWhenReady = function() {
+					if(index == ret.length) {
+						if(pending == 0) {
+							let v = lift(tink_core_Outcome.Success(ret));
+							done = true;
+							$yield(v);
+							return true;
+						} else {
+							return false;
+						}
+					} else {
+						return false;
+					}
+				};
+				let step = null;
+				step = function() {
+					if(!done && !fireWhenReady()) {
+						while(index < ret.length) {
+							index += 1;
+							let index1 = index - 1;
+							let p = a[index1];
+							let check = function(o) {
+								let _g = fn(o);
+								switch(_g._hx_index) {
+								case 0:
+									let v = _g.data;
+									ret[index1] = v;
+									fireWhenReady();
+									break;
+								case 1:
+									let e = _g.failure;
+									let _g1 = 0;
+									while(_g1 < links.length) {
+										let l = links[_g1];
+										++_g1;
+										if(l != null) {
+											l.cancel();
+										}
+									}
+									let v1 = lift(tink_core_Outcome.Failure(e));
+									done = true;
+									$yield(v1);
+									break;
+								}
+							};
+							let _g = p.getStatus();
+							if(_g._hx_index == 3) {
+								let _hx_tmp;
+								_hx_tmp = tink_core_Lazy.get(_g.result);
+								let v = _hx_tmp;
+								check(v);
+								if(!done) {
+									continue;
+								}
+							} else {
+								pending += 1;
+								links.push(p.handle(function(o) {
+									pending -= 1;
+									check(o);
+									if(!done) {
+										step();
+									}
+								}));
+							}
+							break;
+						}
+					}
+				};
+				let _g2 = 0;
+				let _g3 = concurrency1;
+				while(_g2 < _g3) {
+					let i = _g2++;
+					step();
+				}
+				return tink_core_CallbackLink.fromMany(links);
+			});
+		}
+	}
+	static lazy(l) {
+		return new tink_core__$Future_SyncFuture(l);
+	}
+	static sync(v) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+	}
+	static isFuture(maybeFuture) {
+		return ((maybeFuture) instanceof tink_core__$Future_FutureObject);
+	}
+	static async(init,lazy) {
+		if(lazy == null) {
+			lazy = false;
+		}
+		let ret = tink_core_Future.irreversible(init);
+		if(lazy) {
+			return ret;
+		} else {
+			ret.eager();
+			return ret;
+		}
+	}
+	static irreversible(init) {
+		return new tink_core__$Future_SuspendableFuture(function($yield) {
+			init($yield);
+			return null;
+		});
+	}
+	static or(a,b) {
+		return tink_core_Future.first(a,b);
+	}
+	static either(a,b) {
+		return tink_core_Future.first(tink_core_Future.map(a,haxe_ds_Either.Left),tink_core_Future.map(b,haxe_ds_Either.Right));
+	}
+	static and(a,b) {
+		return tink_core_Future.merge(a,b,function(a,b) {
+			return new tink_core_MPair(a,b);
+		});
+	}
+	static _tryFailingFlatMap(f,map) {
+		return tink_core_Future.flatMap(f,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return map(d);
+			case 1:
+				let f = o.failure;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(f)));
+			}
+		});
+	}
+	static _tryFlatMap(f,map) {
+		return tink_core_Future.flatMap(f,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return tink_core_Future.map(map(d),tink_core_Outcome.Success);
+			case 1:
+				let f = o.failure;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(f)));
+			}
+		});
+	}
+	static _tryFailingMap(f,map) {
+		return tink_core_Future.map(f,function(o) {
+			return tink_core_OutcomeTools.flatMap(o,tink_core__$Outcome_OutcomeMapper.withSameError(map));
+		});
+	}
+	static _tryMap(f,map) {
+		return tink_core_Future.map(f,function(o) {
+			return tink_core_OutcomeTools.map(o,map);
+		});
+	}
+	static _flatMap(f,map) {
+		return tink_core_Future.flatMap(f,map);
+	}
+	static _map(f,map) {
+		return tink_core_Future.map(f,map);
+	}
+	static trigger() {
+		return new tink_core_FutureTrigger();
+	}
+	static delay(ms,value) {
+		let this1 = tink_core_Future.irreversible(function(cb) {
+			haxe_Timer.delay(function() {
+				cb(tink_core_Lazy.get(value));
+			},ms);
+		});
+		this1.eager();
+		return this1;
+	}
+}
+var tink_core_FutureStatus = $hxEnums["tink.core.FutureStatus"] = { __ename__:true,__constructs__:null
+	,Suspended: {_hx_name:"Suspended",_hx_index:0,__enum__:"tink.core.FutureStatus",toString:$estr}
+	,Awaited: {_hx_name:"Awaited",_hx_index:1,__enum__:"tink.core.FutureStatus",toString:$estr}
+	,EagerlyAwaited: {_hx_name:"EagerlyAwaited",_hx_index:2,__enum__:"tink.core.FutureStatus",toString:$estr}
+	,Ready: ($_=function(result) { return {_hx_index:3,result:result,__enum__:"tink.core.FutureStatus",toString:$estr}; },$_._hx_name="Ready",$_.__params__ = ["result"],$_)
+	,NeverEver: {_hx_name:"NeverEver",_hx_index:4,__enum__:"tink.core.FutureStatus",toString:$estr}
+};
+tink_core_FutureStatus.__constructs__ = [tink_core_FutureStatus.Suspended,tink_core_FutureStatus.Awaited,tink_core_FutureStatus.EagerlyAwaited,tink_core_FutureStatus.Ready,tink_core_FutureStatus.NeverEver];
+class tink_core_FutureTrigger extends tink_core__$Future_FutureObject {
+	constructor() {
+		tink_core__$Future_FutureObject._hx_skip_constructor = true;
+		super();
+		tink_core__$Future_FutureObject._hx_skip_constructor = false;
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.status = tink_core_FutureStatus.Awaited;
+		super._hx_constructor();
+		this.list = new tink_core_CallbackList(true);
+	}
+	getStatus() {
+		return this.status;
+	}
+	handle(callback) {
+		let _g = this.status;
+		if(_g._hx_index == 3) {
+			let result = _g.result;
+			tink_core_Callback.invoke(callback,tink_core_Lazy.get(result));
+			return null;
+		} else {
+			let v = _g;
+			let _this = this.list;
+			if(_this.disposeHandlers == null) {
+				return null;
+			} else {
+				let node = new tink_core__$Callback_ListCell(callback,_this);
+				_this.cells.push(node);
+				if(_this.used++ == 0) {
+					let fn = _this.onfill;
+					if(tink_core_Callback.depth < 500) {
+						tink_core_Callback.depth++;
+						fn();
+						tink_core_Callback.depth--;
+					} else {
+						tink_core_Callback.defer(fn);
+					}
+				}
+				return node;
+			}
+		}
+	}
+	asFuture() {
+		return this;
+	}
+	trigger(result) {
+		let _g = this.status;
+		if(_g._hx_index == 3) {
+			let _g1 = _g.result;
+			return false;
+		} else {
+			this.status = tink_core_FutureStatus.Ready(new tink_core__$Lazy_LazyConst(result));
+			this.list.invoke(result);
+			return true;
+		}
+	}
+}
+tink_core_FutureTrigger.__name__ = "tink.core.FutureTrigger";
+tink_core_FutureTrigger.__super__ = tink_core__$Future_FutureObject;
+Object.assign(tink_core_FutureTrigger.prototype, {
+	__class__: tink_core_FutureTrigger
+});
+class tink_core_JsPromiseTools {
+	static toSurprise(promise) {
+		return tink_core_Future.ofJsPromise(promise);
+	}
+	static toPromise(promise) {
+		return tink_core_Future.ofJsPromise(promise);
+	}
+}
+tink_core_JsPromiseTools.__name__ = "tink.core.JsPromiseTools";
+class tink_core__$Future_SuspendableFuture extends tink_core__$Future_FutureObject {
+	constructor(wakeup) {
+		tink_core__$Future_FutureObject._hx_skip_constructor = true;
+		super();
+		tink_core__$Future_FutureObject._hx_skip_constructor = false;
+		this._hx_constructor(wakeup);
+	}
+	_hx_constructor(wakeup) {
+		this.status = tink_core_FutureStatus.Suspended;
+		super._hx_constructor();
+		this.wakeup = wakeup;
+		this.callbacks = new tink_core_CallbackList(true);
+		let _gthis = this;
+		this.callbacks.ondrain = function() {
+			if(_gthis.status == tink_core_FutureStatus.Awaited) {
+				_gthis.status = tink_core_FutureStatus.Suspended;
+				let this1 = _gthis.link;
+				if(this1 != null) {
+					this1.cancel();
+				}
+				_gthis.link = null;
+			}
+		};
+		this.callbacks.onfill = function() {
+			if(_gthis.status == tink_core_FutureStatus.Suspended) {
+				_gthis.status = tink_core_FutureStatus.Awaited;
+				_gthis.arm();
+			}
+		};
+	}
+	getStatus() {
+		return this.status;
+	}
+	trigger(value) {
+		let _g = this.status;
+		if(_g._hx_index == 3) {
+			let _g1 = _g.result;
+		} else {
+			this.status = tink_core_FutureStatus.Ready(new tink_core__$Lazy_LazyConst(value));
+			let link = this.link;
+			this.link = null;
+			this.wakeup = null;
+			this.callbacks.invoke(value);
+			if(link != null) {
+				link.cancel();
+			}
+		}
+	}
+	handle(callback) {
+		let _g = this.status;
+		if(_g._hx_index == 3) {
+			let result = _g.result;
+			tink_core_Callback.invoke(callback,tink_core_Lazy.get(result));
+			return null;
+		} else {
+			let _this = this.callbacks;
+			if(_this.disposeHandlers == null) {
+				return null;
+			} else {
+				let node = new tink_core__$Callback_ListCell(callback,_this);
+				_this.cells.push(node);
+				if(_this.used++ == 0) {
+					let fn = _this.onfill;
+					if(tink_core_Callback.depth < 500) {
+						tink_core_Callback.depth++;
+						fn();
+						tink_core_Callback.depth--;
+					} else {
+						tink_core_Callback.defer(fn);
+					}
+				}
+				return node;
+			}
+		}
+	}
+	arm() {
+		let _gthis = this;
+		this.link = this.wakeup(function(x) {
+			_gthis.trigger(x);
+		});
+	}
+	eager() {
+		switch(this.status._hx_index) {
+		case 0:
+			this.status = tink_core_FutureStatus.EagerlyAwaited;
+			this.arm();
+			break;
+		case 1:
+			this.status = tink_core_FutureStatus.EagerlyAwaited;
+			break;
+		default:
+		}
+	}
+}
+tink_core__$Future_SuspendableFuture.__name__ = "tink.core._Future.SuspendableFuture";
+tink_core__$Future_SuspendableFuture.__super__ = tink_core__$Future_FutureObject;
+Object.assign(tink_core__$Future_SuspendableFuture.prototype, {
+	__class__: tink_core__$Future_SuspendableFuture
+});
+class tink_core_Lazy {
+	static get_computed(this1) {
+		return this1.isComputed();
+	}
+	static get(this1) {
+		this1.compute();
+		return this1.get();
+	}
+	static fromNoise(l) {
+		return l;
+	}
+	static ofFunc(f) {
+		return new tink_core__$Lazy_LazyFunc(f);
+	}
+	static map(this1,f) {
+		return new tink_core__$Lazy_LazyFunc(function() {
+			return f(this1.get());
+		},this1);
+	}
+	static flatMap(this1,f) {
+		return new tink_core__$Lazy_LazyFunc(function() {
+			return tink_core_Lazy.get(f(this1.get()));
+		},this1);
+	}
+	static ofConst(c) {
+		return new tink_core__$Lazy_LazyConst(c);
+	}
+}
+class tink_core__$Lazy_LazyFunc {
+	constructor(f,from) {
+		this.f = f;
+		this.from = from;
+	}
+	underlying() {
+		return this.from;
+	}
+	isComputed() {
+		return this.f == null;
+	}
+	get() {
+		return this.result;
+	}
+	compute() {
+		let _g = this.f;
+		if(_g != null) {
+			let v = _g;
+			this.f = null;
+			let _g1 = this.from;
+			if(_g1 != null) {
+				let cur = _g1;
+				this.from = null;
+				let stack = [];
+				while(cur != null && !cur.isComputed()) {
+					stack.push(cur);
+					cur = cur.underlying();
+				}
+				stack.reverse();
+				let _g = 0;
+				while(_g < stack.length) {
+					let c = stack[_g];
+					++_g;
+					c.compute();
+				}
+			}
+			this.result = v();
+		}
+	}
+}
+tink_core__$Lazy_LazyFunc.__name__ = "tink.core._Lazy.LazyFunc";
+tink_core__$Lazy_LazyFunc.__interfaces__ = [tink_core__$Lazy_LazyObject];
+Object.assign(tink_core__$Lazy_LazyFunc.prototype, {
+	__class__: tink_core__$Lazy_LazyFunc
+});
+class tink_core_NamedWith {
+	constructor(name,value) {
+		this.name = name;
+		this.value = value;
+	}
+}
+tink_core_NamedWith.__name__ = "tink.core.NamedWith";
+Object.assign(tink_core_NamedWith.prototype, {
+	__class__: tink_core_NamedWith
+});
+class tink_core_Noise {
+	static ofAny(t) {
+		return null;
+	}
+}
+class tink_core_OptionTools {
+	static force(o,pos) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return v;
+		} else {
+			throw haxe_Exception.thrown(new tink_core_TypedError(404,"Some value expected but none found",pos));
+		}
+	}
+	static sure(o,pos) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return v;
+		} else {
+			throw haxe_Exception.thrown(new tink_core_TypedError(404,"Some value expected but none found",pos));
+		}
+	}
+	static toOutcome(o,pos) {
+		switch(o._hx_index) {
+		case 0:
+			let value = o.v;
+			return tink_core_Outcome.Success(value);
+		case 1:
+			return tink_core_Outcome.Failure(new tink_core_TypedError(404,"Some value expected but none found in " + pos.fileName + "@line " + pos.lineNumber,{ fileName : "tink/core/Option.hx", lineNumber : 31, className : "tink.core.OptionTools", methodName : "toOutcome"}));
+		}
+	}
+	static or(o,l) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return v;
+		} else {
+			return tink_core_Lazy.get(l);
+		}
+	}
+	static orTry(o,fallback) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return o;
+		} else {
+			return tink_core_Lazy.get(fallback);
+		}
+	}
+	static orNull(o) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return v;
+		} else {
+			return null;
+		}
+	}
+	static filter(o,f) {
+		if(o._hx_index == 0) {
+			if(f(o.v) == false) {
+				return haxe_ds_Option.None;
+			} else {
+				return o;
+			}
+		} else {
+			return o;
+		}
+	}
+	static satisfies(o,f) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return f(v);
+		} else {
+			return false;
+		}
+	}
+	static equals(o,v) {
+		if(o._hx_index == 0) {
+			let v1 = o.v;
+			return v1 == v;
+		} else {
+			return false;
+		}
+	}
+	static map(o,f) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return haxe_ds_Option.Some(f(v));
+		} else {
+			return haxe_ds_Option.None;
+		}
+	}
+	static flatMap(o,f) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return f(v);
+		} else {
+			return haxe_ds_Option.None;
+		}
+	}
+	static iterator(o) {
+		return new tink_core_OptionIter(o);
+	}
+	static toArray(o) {
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return [v];
+		} else {
+			return [];
+		}
+	}
+}
+tink_core_OptionTools.__name__ = "tink.core.OptionTools";
+class tink_core_OptionIter {
+	constructor(o) {
+		this.alive = true;
+		if(o._hx_index == 0) {
+			let v = o.v;
+			this.value = v;
+		} else {
+			this.alive = false;
+		}
+	}
+	hasNext() {
+		return this.alive;
+	}
+	next() {
+		this.alive = false;
+		return this.value;
+	}
+}
+tink_core_OptionIter.__name__ = "tink.core.OptionIter";
+Object.assign(tink_core_OptionIter.prototype, {
+	__class__: tink_core_OptionIter
+});
+var tink_core_Outcome = $hxEnums["tink.core.Outcome"] = { __ename__:true,__constructs__:null
+	,Success: ($_=function(data) { return {_hx_index:0,data:data,__enum__:"tink.core.Outcome",toString:$estr}; },$_._hx_name="Success",$_.__params__ = ["data"],$_)
+	,Failure: ($_=function(failure) { return {_hx_index:1,failure:failure,__enum__:"tink.core.Outcome",toString:$estr}; },$_._hx_name="Failure",$_.__params__ = ["failure"],$_)
+};
+tink_core_Outcome.__constructs__ = [tink_core_Outcome.Success,tink_core_Outcome.Failure];
+class tink_core_OutcomeTools {
+	static sure(outcome) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return data;
+		case 1:
+			let failure = outcome.failure;
+			let _g = tink_core_TypedError.asError(failure);
+			if(_g == null) {
+				throw haxe_Exception.thrown(failure);
+			} else {
+				let e = _g;
+				return e.throwSelf();
+			}
+			break;
+		}
+	}
+	static toOption(outcome) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return haxe_ds_Option.Some(data);
+		case 1:
+			let _g = outcome.failure;
+			return haxe_ds_Option.None;
+		}
+	}
+	static orNull(outcome) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return data;
+		case 1:
+			let _g = outcome.failure;
+			return null;
+		}
+	}
+	static orUse(outcome,fallback) {
+		return tink_core_OutcomeTools.or(outcome,fallback);
+	}
+	static or(outcome,fallback) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return data;
+		case 1:
+			let _g = outcome.failure;
+			return tink_core_Lazy.get(fallback);
+		}
+	}
+	static orTry(outcome,fallback) {
+		switch(outcome._hx_index) {
+		case 0:
+			let _g = outcome.data;
+			return outcome;
+		case 1:
+			let _g1 = outcome.failure;
+			return tink_core_Lazy.get(fallback);
+		}
+	}
+	static equals(outcome,to) {
+		switch(outcome._hx_index) {
+		case 0:
+			let data = outcome.data;
+			return data == to;
+		case 1:
+			let _g = outcome.failure;
+			return false;
+		}
+	}
+	static map(outcome,transform) {
+		switch(outcome._hx_index) {
+		case 0:
+			let a = outcome.data;
+			return tink_core_Outcome.Success(transform(a));
+		case 1:
+			let f = outcome.failure;
+			return tink_core_Outcome.Failure(f);
+		}
+	}
+	static isSuccess(outcome) {
+		if(outcome._hx_index == 0) {
+			let _g = outcome.data;
+			return true;
+		} else {
+			return false;
+		}
+	}
+	static flatMap(o,mapper) {
+		return tink_core__$Outcome_OutcomeMapper.apply(mapper,o);
+	}
+	static swap(outcome,v) {
+		switch(outcome._hx_index) {
+		case 0:
+			let a = outcome.data;
+			return tink_core_Outcome.Success(v);
+		case 1:
+			let f = outcome.failure;
+			return tink_core_Outcome.Failure(f);
+		}
+	}
+	static next(outcome,f) {
+		switch(outcome._hx_index) {
+		case 0:
+			let v = outcome.data;
+			return f(v);
+		case 1:
+			let e = outcome.failure;
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+		}
+	}
+	static attempt(f,report) {
+		try {
+			return tink_core_Outcome.Success(f());
+		} catch( _g ) {
+			let e = haxe_Exception.caught(_g).unwrap();
+			return tink_core_Outcome.Failure(report(e));
+		}
+	}
+	static satisfies(o,f) {
+		if(o._hx_index == 0) {
+			let d = o.data;
+			return f(d);
+		} else {
+			return false;
+		}
+	}
+	static flatten(o) {
+		switch(o._hx_index) {
+		case 0:
+			let _g = o.data;
+			switch(_g._hx_index) {
+			case 0:
+				let d = _g.data;
+				return tink_core_Outcome.Success(d);
+			case 1:
+				let f = _g.failure;
+				return tink_core_Outcome.Failure(f);
+			}
+			break;
+		case 1:
+			let f1 = o.failure;
+			return tink_core_Outcome.Failure(f1);
+		}
+	}
+}
+tink_core_OutcomeTools.__name__ = "tink.core.OutcomeTools";
+class tink_core__$Outcome_OutcomeMapper {
+	static _new(f) {
+		return { f : f};
+	}
+	static apply(this1,o) {
+		return this1.f(o);
+	}
+	static withSameError(f) {
+		return tink_core__$Outcome_OutcomeMapper._new(function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return f(d);
+			case 1:
+				let f1 = o.failure;
+				return tink_core_Outcome.Failure(f1);
+			}
+		});
+	}
+	static withEitherError(f) {
+		return tink_core__$Outcome_OutcomeMapper._new(function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				let _g = f(d);
+				switch(_g._hx_index) {
+				case 0:
+					let d1 = _g.data;
+					return tink_core_Outcome.Success(d1);
+				case 1:
+					let f1 = _g.failure;
+					return tink_core_Outcome.Failure(haxe_ds_Either.Right(f1));
+				}
+				break;
+			case 1:
+				let f2 = o.failure;
+				return tink_core_Outcome.Failure(haxe_ds_Either.Left(f2));
+			}
+		});
+	}
+}
+class tink_core_Pair {
+	static _new(a,b) {
+		return new tink_core_MPair(a,b);
+	}
+	static get_a(this1) {
+		return this1.a;
+	}
+	static get_b(this1) {
+		return this1.b;
+	}
+	static toBool(this1) {
+		return this1 != null;
+	}
+	static isNil(this1) {
+		return this1 == null;
+	}
+	static nil() {
+		return null;
+	}
+}
+class tink_core_MPair {
+	constructor(a,b) {
+		this.a = a;
+		this.b = b;
+	}
+}
+tink_core_MPair.__name__ = "tink.core.MPair";
+Object.assign(tink_core_MPair.prototype, {
+	__class__: tink_core_MPair
+});
+class tink_core_ProgressValue {
+	static _new(value,total) {
+		return new tink_core_MPair(value,total);
+	}
+	static normalize(this1) {
+		let o = this1.b;
+		if(o._hx_index == 0) {
+			let v = o.v;
+			return haxe_ds_Option.Some(this1.a / v);
+		} else {
+			return haxe_ds_Option.None;
+		}
+	}
+	static get_value(this1) {
+		return this1.a;
+	}
+	static get_total(this1) {
+		return this1.b;
+	}
+}
+class tink_core_Progress {
+	static listen(this1,cb) {
+		return this1.progressed.listen(cb);
+	}
+	static handle(this1,cb) {
+		return this1.result.handle(cb);
+	}
+	static trigger() {
+		return new tink_core_ProgressTrigger();
+	}
+	static make(f) {
+		return new tink_core__$Progress_SuspendableProgress(function(fire) {
+			return f(function(value,total) {
+				fire(tink_core_ProgressStatus.InProgress(new tink_core_MPair(value,total)));
+			},function(result) {
+				fire(tink_core_ProgressStatus.Finished(result));
+			});
+		});
+	}
+	static map(this1,f) {
+		return new tink_core__$Progress_ProgressObject(tink_core_Signal.map(this1.changed,function(s) {
+			return tink_core_ProgressStatusTools.map(s,f);
+		}),function() {
+			return tink_core_ProgressStatusTools.map(this1.getStatus(),f);
+		});
+	}
+	static asFuture(this1) {
+		return this1.result;
+	}
+	static promise(v) {
+		return new tink_core__$Progress_SuspendableProgress(function(fire) {
+			let inner = new tink_core_CallbackLinkRef();
+			return new tink_core__$Callback_LinkPair(v.handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let p = o.data;
+					let param = p.changed.listen(function(s) {
+						fire(tink_core_ProgressStatusTools.map(s,tink_core_Outcome.Success));
+					});
+					let this1 = inner.link;
+					if(this1 != null) {
+						this1.cancel();
+					}
+					inner.link = param;
+					break;
+				case 1:
+					let e = o.failure;
+					fire(tink_core_ProgressStatus.Finished(tink_core_Outcome.Failure(e)));
+					break;
+				}
+			}),inner);
+		});
+	}
+	static flatten(v) {
+		return tink_core_Progress.map(tink_core_Progress.promise(v),function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let _g = o.data;
+				switch(_g._hx_index) {
+				case 0:
+					let v = _g.data;
+					return tink_core_Outcome.Success(v);
+				case 1:
+					let e = _g.failure;
+					return tink_core_Outcome.Failure(e);
+				}
+				break;
+			case 1:
+				let e1 = o.failure;
+				return tink_core_Outcome.Failure(e1);
+			}
+		});
+	}
+	static future(v) {
+		return new tink_core__$Progress_SuspendableProgress(function(fire) {
+			let inner = new tink_core_CallbackLinkRef();
+			return new tink_core__$Callback_LinkPair(v.handle(function(p) {
+				let param = p.changed.listen(fire);
+				let this1 = inner.link;
+				if(this1 != null) {
+					this1.cancel();
+				}
+				inner.link = param;
+			}),inner);
+		});
+	}
+	static next(this1,f) {
+		return tink_core_Future.flatMap(this1.result,f);
+	}
+}
+class tink_core__$Progress_ProgressObject {
+	constructor(changed,getStatus) {
+		if(tink_core__$Progress_ProgressObject._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(changed,getStatus);
+	}
+	_hx_constructor(changed,getStatus) {
+		this.changed = changed;
+		this.progressed = new tink_core__$Signal_Suspendable(function(fire) {
+			return changed.listen(function(s) {
+				if(s._hx_index == 0) {
+					let v = s.v;
+					fire(v);
+				}
+			});
+		},null);
+		this.getStatus = getStatus;
+		this.result = new tink_core__$Future_SuspendableFuture(function(fire) {
+			let _g = getStatus();
+			if(_g._hx_index == 1) {
+				let v = _g.v;
+				fire(v);
+				return null;
+			} else {
+				return changed.listen(function(s) {
+					if(s._hx_index == 1) {
+						let v = s.v;
+						fire(v);
+					}
+				});
+			}
+		});
+	}
+	get_status() {
+		return this.getStatus();
+	}
+}
+tink_core__$Progress_ProgressObject.__name__ = "tink.core._Progress.ProgressObject";
+Object.assign(tink_core__$Progress_ProgressObject.prototype, {
+	__class__: tink_core__$Progress_ProgressObject
+});
+class tink_core__$Progress_SuspendableProgress extends tink_core__$Progress_ProgressObject {
+	constructor(wakeup,status) {
+		if(status == null) {
+			status = tink_core_ProgressStatus.InProgress(tink_core_ProgressValue.ZERO);
+		}
+		let disposable = tink_core_AlreadyDisposed.INST;
+		let changed;
+		switch(status._hx_index) {
+		case 0:
+			let _g = status.v;
+			changed = new tink_core__$Signal_Suspendable(function(fire) {
+				return wakeup(function(s) {
+					status = s;
+					fire(status);
+				});
+			},function(d) {
+				disposable = d;
+			});
+			break;
+		case 1:
+			let _g1 = status.v;
+			changed = tink_core_Signal.dead();
+			break;
+		}
+		super(changed,function() {
+			return status;
+		});
+	}
+	noop(_,_1) {
+		return null;
+	}
+}
+tink_core__$Progress_SuspendableProgress.__name__ = "tink.core._Progress.SuspendableProgress";
+tink_core__$Progress_SuspendableProgress.__super__ = tink_core__$Progress_ProgressObject;
+Object.assign(tink_core__$Progress_SuspendableProgress.prototype, {
+	__class__: tink_core__$Progress_SuspendableProgress
+});
+class tink_core_ProgressTrigger extends tink_core__$Progress_ProgressObject {
+	constructor(status) {
+		tink_core__$Progress_ProgressObject._hx_skip_constructor = true;
+		super();
+		tink_core__$Progress_ProgressObject._hx_skip_constructor = false;
+		this._hx_constructor(status);
+	}
+	_hx_constructor(status) {
+		this._changed = null;
+		if(status == null) {
+			status = tink_core_ProgressStatus.InProgress(tink_core_ProgressValue.ZERO);
+			this._status = status;
+		}
+		let _gthis = this;
+		let tmp;
+		if(status == null) {
+			tmp = false;
+		} else if(status._hx_index == 1) {
+			let _g = status.v;
+			tmp = true;
+		} else {
+			tmp = false;
+		}
+		super._hx_constructor(tmp ? tink_core_Signal.dead() : this._changed = tink_core_Signal.trigger(),function() {
+			return _gthis._status;
+		});
+	}
+	asProgress() {
+		return this;
+	}
+	progress(v,total) {
+		let _g = this._status;
+		let tmp;
+		if(_g._hx_index == 1) {
+			let _g1 = _g.v;
+			tmp = true;
+		} else {
+			tmp = false;
+		}
+		if(!tmp) {
+			let _this = this._changed;
+			let this1 = new tink_core_MPair(v,total);
+			_this.handlers.invoke(this._status = tink_core_ProgressStatus.InProgress(this1));
+		}
+	}
+	finish(v) {
+		let _g = this._status;
+		let tmp;
+		if(_g._hx_index == 1) {
+			let _g1 = _g.v;
+			tmp = true;
+		} else {
+			tmp = false;
+		}
+		if(!tmp) {
+			this._changed.handlers.invoke(this._status = tink_core_ProgressStatus.Finished(v));
+		}
+	}
+}
+tink_core_ProgressTrigger.__name__ = "tink.core.ProgressTrigger";
+tink_core_ProgressTrigger.__super__ = tink_core__$Progress_ProgressObject;
+Object.assign(tink_core_ProgressTrigger.prototype, {
+	__class__: tink_core_ProgressTrigger
+});
+class tink_core_UnitInterval {
+	static toPercentageString(this1,dp) {
+		let m = Math.pow(10,dp);
+		let v = Math.round(this1 * m * 100) / m;
+		let s = v == null ? "null" : "" + v;
+		let _g = s.indexOf(".");
+		if(_g == -1) {
+			return s + "." + StringTools.lpad("","0",dp) + "%";
+		} else {
+			let i = _g;
+			if(s.length - i > dp) {
+				return HxOverrides.substr(s,0,dp + i + 1) + "%";
+			} else {
+				let i = _g;
+				return StringTools.rpad(s,"0",i + dp + 1) + "%";
+			}
+		}
+	}
+}
+var tink_core_ProgressStatus = $hxEnums["tink.core.ProgressStatus"] = { __ename__:true,__constructs__:null
+	,InProgress: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"tink.core.ProgressStatus",toString:$estr}; },$_._hx_name="InProgress",$_.__params__ = ["v"],$_)
+	,Finished: ($_=function(v) { return {_hx_index:1,v:v,__enum__:"tink.core.ProgressStatus",toString:$estr}; },$_._hx_name="Finished",$_.__params__ = ["v"],$_)
+};
+tink_core_ProgressStatus.__constructs__ = [tink_core_ProgressStatus.InProgress,tink_core_ProgressStatus.Finished];
+class tink_core_ProgressStatusTools {
+	static map(p,f) {
+		switch(p._hx_index) {
+		case 0:
+			let v = p.v;
+			return tink_core_ProgressStatus.InProgress(v);
+		case 1:
+			let v1 = p.v;
+			return tink_core_ProgressStatus.Finished(f(v1));
+		}
+	}
+}
+tink_core_ProgressStatusTools.__name__ = "tink.core.ProgressStatusTools";
+class tink_core_TotalTools {
+	static eq(a,b) {
+		switch(a._hx_index) {
+		case 0:
+			if(b._hx_index == 0) {
+				let t2 = b.v;
+				let t1 = a.v;
+				return t1 == t2;
+			} else {
+				return false;
+			}
+			break;
+		case 1:
+			if(b._hx_index == 1) {
+				return true;
+			} else {
+				return false;
+			}
+			break;
+		}
+	}
+}
+tink_core_TotalTools.__name__ = "tink.core.TotalTools";
+class tink_core_ProgressTools {
+	static asPromise(p) {
+		return p.result;
+	}
+}
+tink_core_ProgressTools.__name__ = "tink.core.ProgressTools";
+class tink_core_Promise {
+	static never() {
+		return tink_core_Future.never();
+	}
+	static _new(f) {
+		return new tink_core__$Future_SuspendableFuture(function(cb) {
+			return f(function(v) {
+				cb(tink_core_Outcome.Success(v));
+			},function(e) {
+				cb(tink_core_Outcome.Failure(e));
+			});
+		});
+	}
+	static eager(this1) {
+		this1.eager();
+		return this1;
+	}
+	static map(this1,f) {
+		return tink_core_Future.map(this1,f);
+	}
+	static flatMap(this1,f) {
+		return tink_core_Future.flatMap(this1,f);
+	}
+	static tryRecover(this1,f) {
+		return tink_core_Future.flatMap(this1,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(o));
+			case 1:
+				let e = o.failure;
+				return f(e);
+			}
+		});
+	}
+	static recover(this1,f) {
+		return tink_core_Future.flatMap(this1,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(d));
+			case 1:
+				let e = o.failure;
+				return f(e);
+			}
+		});
+	}
+	static mapError(this1,f) {
+		return tink_core_Future.map(this1,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let _g = o.data;
+				return o;
+			case 1:
+				let e = o.failure;
+				return tink_core_Outcome.Failure(f(e));
+			}
+		});
+	}
+	static withSideEffect(this1,c) {
+		let c1 = function(o) {
+			if(o._hx_index == 0) {
+				let data = o.data;
+				tink_core_Callback.invoke(c,data);
+			}
+		};
+		return tink_core_Future.map(this1,function(v) {
+			tink_core_Callback.invoke(c1,v);
+			return v;
+		});
+	}
+	static handle(this1,cb) {
+		return this1.handle(cb);
+	}
+	static noise(this1) {
+		if(this1.getStatus()._hx_index == 4) {
+			return tink_core_Promise.never();
+		} else {
+			return tink_core_Promise.next(this1,function(v) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(null)));
+			});
+		}
+	}
+	static isSuccess(this1) {
+		return tink_core_Future.map(this1,function(o) {
+			return tink_core_OutcomeTools.isSuccess(o);
+		});
+	}
+	static next(this1,f,gather) {
+		return tink_core_Future.flatMap(this1,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let d = o.data;
+				return f(d);
+			case 1:
+				let f1 = o.failure;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(f1)));
+			}
+		});
+	}
+	static swap(this1,v) {
+		return tink_core_Promise.next(this1,function(_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(v)));
+		});
+	}
+	static swapError(this1,e) {
+		return tink_core_Promise.mapError(this1,function(_) {
+			return e;
+		});
+	}
+	static merge(this1,other,merger,gather) {
+		return tink_core_Future.flatMap(tink_core_Future.merge(this1,other,function(a,b) {
+			switch(a._hx_index) {
+			case 0:
+				let _g = a.data;
+				switch(b._hx_index) {
+				case 0:
+					let b1 = b.data;
+					let a1 = _g;
+					return merger(a1,b1);
+				case 1:
+					let e = b.failure;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+				}
+				break;
+			case 1:
+				let e1 = a.failure;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e1)));
+			}
+		}),function(o) {
+			return o;
+		});
+	}
+	static irreversible(f) {
+		let f1 = function(res,rej) {
+			f(res,rej);
+			return null;
+		};
+		return new tink_core__$Future_SuspendableFuture(function(cb) {
+			return f1(function(v) {
+				cb(tink_core_Outcome.Success(v));
+			},function(e) {
+				cb(tink_core_Outcome.Failure(e));
+			});
+		});
+	}
+	static and(a,b) {
+		return tink_core_Promise.merge(a,b,function(a,b) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_core_MPair(a,b))));
+		});
+	}
+	static iterate(promises,$yield,fallback,fallThroughOnError) {
+		if(fallThroughOnError == null) {
+			fallThroughOnError = false;
+		}
+		return tink_core_Future.irreversible(function(cb) {
+			let iter = $getIterator(promises);
+			let next = null;
+			next = function() {
+				if(iter.hasNext()) {
+					iter.next().handle(function(o) {
+						switch(o._hx_index) {
+						case 0:
+							let v = o.data;
+							$yield(v).handle(function(o) {
+								switch(o._hx_index) {
+								case 0:
+									let _g = o.data;
+									switch(_g._hx_index) {
+									case 0:
+										let ret = _g.v;
+										cb(tink_core_Outcome.Success(ret));
+										break;
+									case 1:
+										next();
+										break;
+									}
+									break;
+								case 1:
+									let e = o.failure;
+									cb(tink_core_Outcome.Failure(e));
+									break;
+								}
+							});
+							break;
+						case 1:
+							let e = o.failure;
+							if(fallThroughOnError) {
+								next();
+							} else {
+								cb(tink_core_Outcome.Failure(e));
+							}
+							break;
+						}
+					});
+				} else {
+					fallback.handle(cb);
+				}
+			};
+			next();
+		});
+	}
+	static retry(gen,next) {
+		let stamp = function() {
+			let hrtime = process.hrtime();
+			return (hrtime[0] + hrtime[1] / 1e9) * 1000;
+		};
+		let start = stamp();
+		let attempt = null;
+		attempt = function(count) {
+			let f = function(error) {
+				return tink_core_Promise.next(next({ attempt : count, error : error, elapsed : stamp() - start}),function(_) {
+					return attempt(count + 1);
+				});
+			};
+			return tink_core_Future.flatMap(gen(),function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let d = o.data;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(o));
+				case 1:
+					let e = o.failure;
+					return f(e);
+				}
+			});
+		};
+		return attempt(1);
+	}
+	static ofJsPromise(promise,transformError) {
+		return tink_core_Future.ofJsPromise(promise,transformError);
+	}
+	static fromJsPromise(promise) {
+		return tink_core_Future.ofJsPromise(promise);
+	}
+	static toJsPromise(this1) {
+		return new Promise(function(resolve,reject) {
+			this1.handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let v = o.data;
+					resolve(v);
+					break;
+				case 1:
+					let e = o.failure;
+					reject(e.toJsError());
+					break;
+				}
+			});
+		});
+	}
+	static ofSpecific(s) {
+		return s;
+	}
+	static fromNever(l) {
+		return l;
+	}
+	static ofTrigger(f) {
+		return f;
+	}
+	static ofHappyTrigger(f) {
+		return tink_core_Future.map(f,tink_core_Outcome.Success);
+	}
+	static ofFuture(f) {
+		return tink_core_Future.map(f,tink_core_Outcome.Success);
+	}
+	static ofOutcome(o) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(o));
+	}
+	static ofError(e) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+	}
+	static ofData(d) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(d)));
+	}
+	static asFuture(this1) {
+		return this1;
+	}
+	static lazy(p) {
+		return new tink_core__$Future_SuspendableFuture(function(cb) {
+			return tink_core_Lazy.get(p).handle(cb);
+		});
+	}
+	static inParallel(a,concurrency) {
+		return tink_core_Promise.many(a,concurrency);
+	}
+	static many(a,concurrency) {
+		return tink_core_Future.processMany(a,concurrency,function(o) {
+			return o;
+		},function(o) {
+			return o;
+		});
+	}
+	static inSequence(a) {
+		return tink_core_Promise.many(a,1);
+	}
+	static cache(gen) {
+		let p = null;
+		return function() {
+			let ret = p;
+			if(ret == null) {
+				let sync = false;
+				ret = tink_core_Promise.next(gen(),function(o) {
+					o.b.handle(function(_) {
+						sync = true;
+						p = null;
+					});
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(o.a)));
+				});
+				if(!sync) {
+					p = ret;
+				}
+			}
+			return tink_core_Future.map(ret,function(o) {
+				if(!tink_core_OutcomeTools.isSuccess(o)) {
+					p = null;
+				}
+				return o;
+			});
+		};
+	}
+	static lift(p) {
+		return p;
+	}
+	static trigger() {
+		return new tink_core_FutureTrigger();
+	}
+	static resolve(v) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(v)));
+	}
+	static reject(e) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+	}
+}
+class tink_core_Next {
+	static ofSafe(f) {
+		return function(x) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(x)));
+		};
+	}
+	static ofSync(f) {
+		return function(x) {
+			return tink_core_Future.map(f(x),tink_core_Outcome.Success);
+		};
+	}
+	static ofSafeSync(f) {
+		return function(x) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(f(x))));
+		};
+	}
+	static _chain(a,b) {
+		return function(v) {
+			return tink_core_Promise.next(a(v),b);
+		};
+	}
+}
+class tink_core_Recover {
+	static ofSync(f) {
+		return function(e) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(e)));
+		};
+	}
+}
+class tink_core_Combiner {
+	static ofSync(f) {
+		return function(x1,x2) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(x1,x2)));
+		};
+	}
+	static ofSafe(f) {
+		return function(x1,x2) {
+			return tink_core_Future.map(f(x1,x2),tink_core_Outcome.Success);
+		};
+	}
+	static ofSafeSync(f) {
+		return function(x1,x2) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(f(x1,x2))));
+		};
+	}
+}
+class tink_core_PromiseTrigger {
+	static _new() {
+		return new tink_core_FutureTrigger();
+	}
+	static resolve(this1,v) {
+		return this1.trigger(tink_core_Outcome.Success(v));
+	}
+	static reject(this1,e) {
+		return this1.trigger(tink_core_Outcome.Failure(e));
+	}
+	static asPromise(this1) {
+		return this1;
+	}
+}
+class tink_core_Ref {
+	static _new() {
+		return new Array(1);
+	}
+	static get_value(this1) {
+		return this1[0];
+	}
+	static set_value(this1,param) {
+		return this1[0] = param;
+	}
+	static toString(this1) {
+		return "@[" + Std.string(this1[0]) + "]";
+	}
+	static to(v) {
+		let ret = new Array(1);
+		ret[0] = v;
+		return ret;
+	}
+}
+class tink_core_Gather {
+	static _new(v) {
+		return v;
+	}
+	static ofBool(b) {
+		return b;
+	}
+}
+class tink_core_Signal {
+	static _new(f,init) {
+		return new tink_core__$Signal_Suspendable(f,init);
+	}
+	static handle(this1,handler) {
+		return this1.listen(handler);
+	}
+	static map(this1,f,gather) {
+		return tink_core__$Signal_Suspendable.over(this1,function(fire) {
+			return this1.listen(function(v) {
+				fire(f(v));
+			});
+		});
+	}
+	static flatMap(this1,f,gather) {
+		return tink_core__$Signal_Suspendable.over(this1,function(fire) {
+			return this1.listen(function(v) {
+				f(v).handle(fire);
+			});
+		});
+	}
+	static filter(this1,f,gather) {
+		return tink_core__$Signal_Suspendable.over(this1,function(fire) {
+			return this1.listen(function(v) {
+				if(f(v)) {
+					fire(v);
+				}
+			});
+		});
+	}
+	static select(this1,selector,gather) {
+		return tink_core__$Signal_Suspendable.over(this1,function(fire) {
+			return this1.listen(function(v) {
+				let _g = selector(v);
+				if(_g._hx_index == 0) {
+					let v = _g.v;
+					fire(v);
+				}
+			});
+		});
+	}
+	static join(this1,that,gather) {
+		if(this1.get_disposed()) {
+			return that;
+		} else if(that.get_disposed()) {
+			return this1;
+		} else {
+			return new tink_core__$Signal_Suspendable(function(fire) {
+				let cb = fire;
+				return new tink_core__$Callback_LinkPair(this1.listen(cb),that.listen(cb));
+			},function(self) {
+				let release = function() {
+					if(this1.get_disposed() && that.get_disposed()) {
+						self.dispose();
+					}
+				};
+				this1.ondispose(release);
+				that.ondispose(release);
+			});
+		}
+	}
+	static nextTime(this1,condition) {
+		return tink_core_Signal.pickNext(this1,function(v) {
+			if(condition == null || condition(v)) {
+				return haxe_ds_Option.Some(v);
+			} else {
+				return haxe_ds_Option.None;
+			}
+		});
+	}
+	static pickNext(this1,selector) {
+		let ret = new tink_core_FutureTrigger();
+		let link = null;
+		link = this1.listen(function(v) {
+			let _g = selector(v);
+			switch(_g._hx_index) {
+			case 0:
+				let v1 = _g.v;
+				ret.trigger(v1);
+				break;
+			case 1:
+				break;
+			}
+		});
+		ret.handle(link == null ? tink_core_CallbackLink.noop : ($_=link,$bind($_,$_.cancel)));
+		return ret;
+	}
+	static until(this1,end) {
+		return new tink_core__$Signal_Suspendable(function($yield) {
+			return this1.listen($yield);
+		},function(self) {
+			end.handle($bind(self,self.dispose));
+		});
+	}
+	static next(this1,condition) {
+		return tink_core_Signal.nextTime(this1,condition);
+	}
+	static noise(this1) {
+		return tink_core_Signal.map(this1,function(_) {
+			return null;
+		});
+	}
+	static gather(this1) {
+		return this1;
+	}
+	static create(f) {
+		return new tink_core__$Signal_Suspendable(f,null);
+	}
+	static generate(generator,init) {
+		return new tink_core__$Signal_Suspendable(function(fire) {
+			generator(fire);
+			return null;
+		},init);
+	}
+	static trigger() {
+		return new tink_core_SignalTrigger();
+	}
+	static ofClassical(add,remove,gather) {
+		return new tink_core__$Signal_Suspendable(function(fire) {
+			add(fire);
+			let _g = remove;
+			let a1 = fire;
+			return new tink_core_SimpleLink(function() {
+				_g(a1);
+			});
+		});
+	}
+	static dead() {
+		return tink_core__$Signal_Disposed.INST;
+	}
+}
+class tink_core__$Signal_SignalObject {
+}
+tink_core__$Signal_SignalObject.__name__ = "tink.core._Signal.SignalObject";
+tink_core__$Signal_SignalObject.__isInterface__ = true;
+tink_core__$Signal_SignalObject.__interfaces__ = [tink_core_Disposable];
+Object.assign(tink_core__$Signal_SignalObject.prototype, {
+	__class__: tink_core__$Signal_SignalObject
+});
+class tink_core__$Signal_Disposed extends tink_core_AlreadyDisposed {
+	constructor() {
+		super();
+	}
+	listen(cb) {
+		return null;
+	}
+}
+tink_core__$Signal_Disposed.__name__ = "tink.core._Signal.Disposed";
+tink_core__$Signal_Disposed.__interfaces__ = [tink_core__$Signal_SignalObject];
+tink_core__$Signal_Disposed.__super__ = tink_core_AlreadyDisposed;
+Object.assign(tink_core__$Signal_Disposed.prototype, {
+	__class__: tink_core__$Signal_Disposed
+});
+class tink_core__$Signal_Suspendable {
+	constructor(activate,init) {
+		this.handlers = new tink_core_CallbackList();
+		this.activate = activate;
+		this.init = init;
+		let _gthis = this;
+		this.handlers.ondrain = function() {
+			let this1 = _gthis.subscription;
+			if(this1 != null) {
+				this1.cancel();
+			}
+		};
+		this.handlers.onfill = function() {
+			if(init != null) {
+				let f = init;
+				init = null;
+				f(_gthis);
+			}
+			_gthis.subscription = activate(($_=_gthis.handlers,$bind($_,$_.invoke)));
+		};
+	}
+	get_disposed() {
+		return this.handlers.disposeHandlers == null;
+	}
+	dispose() {
+		this.handlers.dispose();
+	}
+	ondispose(handler) {
+		this.handlers.ondispose(handler);
+	}
+	listen(cb) {
+		let _this = this.handlers;
+		if(_this.disposeHandlers == null) {
+			return null;
+		} else {
+			let node = new tink_core__$Callback_ListCell(cb,_this);
+			_this.cells.push(node);
+			if(_this.used++ == 0) {
+				let fn = _this.onfill;
+				if(tink_core_Callback.depth < 500) {
+					tink_core_Callback.depth++;
+					fn();
+					tink_core_Callback.depth--;
+				} else {
+					tink_core_Callback.defer(fn);
+				}
+			}
+			return node;
+		}
+	}
+	static over(s,activate) {
+		if(s.get_disposed()) {
+			return tink_core_Signal.dead();
+		} else {
+			let ret = new tink_core__$Signal_Suspendable(activate);
+			s.ondispose($bind(ret,ret.dispose));
+			return ret;
+		}
+	}
+}
+tink_core__$Signal_Suspendable.__name__ = "tink.core._Signal.Suspendable";
+tink_core__$Signal_Suspendable.__interfaces__ = [tink_core_OwnedDisposable,tink_core__$Signal_SignalObject];
+Object.assign(tink_core__$Signal_Suspendable.prototype, {
+	__class__: tink_core__$Signal_Suspendable
+});
+class tink_core_SignalTrigger {
+	constructor() {
+		this.handlers = new tink_core_CallbackList();
+	}
+	get_disposed() {
+		return this.handlers.disposeHandlers == null;
+	}
+	dispose() {
+		this.handlers.dispose();
+	}
+	ondispose(d) {
+		this.handlers.ondispose(d);
+	}
+	trigger(event) {
+		this.handlers.invoke(event);
+	}
+	getLength() {
+		return this.handlers.used;
+	}
+	listen(cb) {
+		let _this = this.handlers;
+		if(_this.disposeHandlers == null) {
+			return null;
+		} else {
+			let node = new tink_core__$Callback_ListCell(cb,_this);
+			_this.cells.push(node);
+			if(_this.used++ == 0) {
+				let fn = _this.onfill;
+				if(tink_core_Callback.depth < 500) {
+					tink_core_Callback.depth++;
+					fn();
+					tink_core_Callback.depth--;
+				} else {
+					tink_core_Callback.defer(fn);
+				}
+			}
+			return node;
+		}
+	}
+	clear() {
+		this.handlers.clear();
+	}
+	asSignal() {
+		return this;
+	}
+}
+tink_core_SignalTrigger.__name__ = "tink.core.SignalTrigger";
+tink_core_SignalTrigger.__interfaces__ = [tink_core_OwnedDisposable,tink_core__$Signal_SignalObject];
+Object.assign(tink_core_SignalTrigger.prototype, {
+	__class__: tink_core_SignalTrigger
+});
+class tink_http_Chunked {
+	static encoder() {
+		if(tink_http_Chunked._encoder == null) {
+			tink_http_Chunked._encoder = new tink_http_ChunkedEncoder();
+		}
+		return tink_http_Chunked._encoder;
+	}
+	static decoder() {
+		if(tink_http_Chunked._decoder == null) {
+			tink_http_Chunked._decoder = new tink_http_ChunkedDecoder();
+		}
+		return tink_http_Chunked._decoder;
+	}
+	static encode(source) {
+		return tink_http_Chunked.encoder().transform(source);
+	}
+	static decode(source) {
+		return tink_http_Chunked.decoder().transform(source);
+	}
+}
+tink_http_Chunked.__name__ = "tink.http.Chunked";
+class tink_io_Transformer {
+}
+tink_io_Transformer.__name__ = "tink.io.Transformer";
+tink_io_Transformer.__isInterface__ = true;
+Object.assign(tink_io_Transformer.prototype, {
+	__class__: tink_io_Transformer
+});
+class tink_http_ChunkedEncoder {
+	constructor() {
+	}
+	transform(source) {
+		return tink_io_Source.chunked(source).map(tink_streams_Mapping.ofPlain(function(chunk) {
+			return tink_Chunk.concat(tink_Chunk.concat(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString("" + StringTools.hex(chunk.getLength()) + "\r\n")),chunk),tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString("\r\n")));
+		})).append(tink_streams_Stream.ofIterator(new haxe_iterators_ArrayIterator([tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString("0\r\n"))])));
+	}
+}
+tink_http_ChunkedEncoder.__name__ = "tink.http.ChunkedEncoder";
+tink_http_ChunkedEncoder.__interfaces__ = [tink_io_Transformer];
+Object.assign(tink_http_ChunkedEncoder.prototype, {
+	__class__: tink_http_ChunkedEncoder
+});
+class tink_http_ChunkedDecoder {
+	constructor() {
+	}
+	transform(source) {
+		return tink_io_RealSourceTools.parseStream(source,new tink_http_ChunkedParser()).map(tink_streams_Mapping.ofPlain(function(v) {
+			if(tink_Chunk.reqString(v,null.toString())) {
+				return tink_Chunk.EMPTY;
+			} else {
+				return v;
+			}
+		}));
+	}
+}
+tink_http_ChunkedDecoder.__name__ = "tink.http.ChunkedDecoder";
+tink_http_ChunkedDecoder.__interfaces__ = [tink_io_Transformer];
+Object.assign(tink_http_ChunkedDecoder.prototype, {
+	__class__: tink_http_ChunkedDecoder
+});
+class tink_io_StreamParserObject {
+}
+tink_io_StreamParserObject.__name__ = "tink.io.StreamParserObject";
+tink_io_StreamParserObject.__isInterface__ = true;
+Object.assign(tink_io_StreamParserObject.prototype, {
+	__class__: tink_io_StreamParserObject
+});
+class tink_http_ChunkedParser {
+	constructor() {
+		this.reset();
+	}
+	reset() {
+		this.chunkSize = -1;
+	}
+	progress(cursor) {
+		if(this.chunkSize < 0) {
+			let _g = cursor.seek(tink_http_ChunkedParser.LINEBREAK);
+			switch(_g._hx_index) {
+			case 0:
+				let v = _g.v;
+				this.chunkSize = Std.parseInt("0x" + (v == null ? "null" : v.toString()));
+				break;
+			case 1:
+				break;
+			}
+			return tink_io_ParseStep.Progressed;
+		} else if(this.chunkSize == 0) {
+			return tink_io_ParseStep.Progressed;
+		} else if(cursor.length >= this.chunkSize + 2) {
+			let _g = cursor.seek(tink_http_ChunkedParser.LINEBREAK);
+			switch(_g._hx_index) {
+			case 0:
+				let v = _g.v;
+				this.reset();
+				return tink_io_ParseStep.Done(v);
+			case 1:
+				return tink_io_ParseStep.Failed(new tink_core_TypedError(null,"Invalid encoding",{ fileName : "tink/http/Chunked.hx", lineNumber : 82, className : "tink.http.ChunkedParser", methodName : "progress"}));
+			}
+		} else {
+			return tink_io_ParseStep.Progressed;
+		}
+	}
+	eof(rest) {
+		if(this.chunkSize == 0) {
+			return tink_core_Outcome.Success(tink_Chunk.EMPTY);
+		} else {
+			return tink_core_Outcome.Failure(new tink_core_TypedError(null,"Unexpected end of input",{ fileName : "tink/http/Chunked.hx", lineNumber : 89, className : "tink.http.ChunkedParser", methodName : "eof"}));
+		}
+	}
+}
+tink_http_ChunkedParser.__name__ = "tink.http.ChunkedParser";
+tink_http_ChunkedParser.__interfaces__ = [tink_io_StreamParserObject];
+Object.assign(tink_http_ChunkedParser.prototype, {
+	__class__: tink_http_ChunkedParser
+});
+class tink_http_Client {
+	static fetch(url,options) {
+		return tink_http_Fetch.fetch(url,options);
+	}
+	static augment(this1,pipeline) {
+		return tink_http__$Client_CustomClient.create(this1,pipeline.before,pipeline.after);
+	}
+}
+class tink_http_ClientObject {
+}
+tink_http_ClientObject.__name__ = "tink.http.ClientObject";
+tink_http_ClientObject.__isInterface__ = true;
+Object.assign(tink_http_ClientObject.prototype, {
+	__class__: tink_http_ClientObject
+});
+class tink_http__$Client_CustomClient {
+	constructor(preprocessors,postprocessors,real) {
+		this.preprocessors = preprocessors;
+		this.postprocessors = postprocessors;
+		this.real = real;
+	}
+	pipe(value,transforms,index) {
+		if(index == null) {
+			index = 0;
+		}
+		if(transforms != null && index < transforms.length) {
+			let _g = this;
+			let transforms1 = transforms;
+			let index1 = index + 1;
+			let tmp = function(value) {
+				return _g.pipe(value,transforms1,index1);
+			};
+			return tink_core_Promise.next(transforms[index](value),tmp);
+		} else {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(value)));
+		}
+	}
+	request(req) {
+		let _gthis = this;
+		return tink_core_Promise.next(this.pipe(req,this.preprocessors),function(req) {
+			let tmp = _gthis.real.request(req);
+			let _g = _gthis;
+			let transforms;
+			if(_gthis.postprocessors == null) {
+				transforms = null;
+			} else {
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = _gthis.postprocessors;
+				while(_g1 < _g2.length) {
+					let p = _g2[_g1];
+					++_g1;
+					_g.push(p(req));
+				}
+				transforms = _g;
+			}
+			return tink_core_Promise.next(tmp,function(value) {
+				return _g.pipe(value,transforms);
+			});
+		});
+	}
+	static concat(a,b) {
+		if(a == null) {
+			let v = b;
+			return v;
+		} else if(b == null) {
+			let v = a;
+			return v;
+		} else {
+			return a.concat(b);
+		}
+	}
+	static create(c,preprocessors,postprocessors) {
+		let _g = ((c) instanceof tink_http__$Client_CustomClient) ? c : null;
+		if(_g == null) {
+			return new tink_http__$Client_CustomClient(preprocessors,postprocessors,c);
+		} else {
+			let v = _g;
+			return new tink_http__$Client_CustomClient(tink_http__$Client_CustomClient.concat(preprocessors,v.preprocessors),tink_http__$Client_CustomClient.concat(v.postprocessors,postprocessors),v.real);
+		}
+	}
+}
+tink_http__$Client_CustomClient.__name__ = "tink.http._Client.CustomClient";
+tink_http__$Client_CustomClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http__$Client_CustomClient.prototype, {
+	__class__: tink_http__$Client_CustomClient
+});
+class tink_http_Container {
+}
+tink_http_Container.__name__ = "tink.http.Container";
+tink_http_Container.__isInterface__ = true;
+Object.assign(tink_http_Container.prototype, {
+	__class__: tink_http_Container
+});
+var tink_http_ContainerResult = $hxEnums["tink.http.ContainerResult"] = { __ename__:true,__constructs__:null
+	,Running: ($_=function(running) { return {_hx_index:0,running:running,__enum__:"tink.http.ContainerResult",toString:$estr}; },$_._hx_name="Running",$_.__params__ = ["running"],$_)
+	,Failed: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.http.ContainerResult",toString:$estr}; },$_._hx_name="Failed",$_.__params__ = ["e"],$_)
+	,Shutdown: {_hx_name:"Shutdown",_hx_index:2,__enum__:"tink.http.ContainerResult",toString:$estr}
+};
+tink_http_ContainerResult.__constructs__ = [tink_http_ContainerResult.Running,tink_http_ContainerResult.Failed,tink_http_ContainerResult.Shutdown];
+class tink_http_Fetch {
+	static fetch(url,options) {
+		return tink_core_Future.async(function(cb) {
+			let uri = url.path;
+			if(url.query != null) {
+				uri += "?" + (url.query == null ? "null" : url.query);
+			}
+			let method = "GET";
+			let headers = null;
+			let body = tink_io_Source.EMPTY;
+			let type = tink_http_ClientType.Default;
+			let followRedirect = true;
+			if(options != null) {
+				if(options.method != null) {
+					method = options.method;
+				}
+				if(options.headers != null) {
+					headers = options.headers;
+				}
+				if(options.body != null) {
+					body = options.body;
+				}
+				if(options.client != null) {
+					type = options.client;
+				}
+				if(options.followRedirect == false) {
+					followRedirect = false;
+				}
+			}
+			let client = tink_http_Fetch.getClient(type);
+			if(options != null && options.augment != null) {
+				let pipeline = options.augment;
+				client = tink_http__$Client_CustomClient.create(client,pipeline.before,pipeline.after);
+			}
+			client.request(new tink_http_OutgoingRequest(new tink_http_OutgoingRequestHeader(method,url,null,headers),body)).handle(function(res) {
+				switch(res._hx_index) {
+				case 0:
+					let res1 = res.data;
+					let _g = res1.header.statusCode;
+					switch(_g) {
+					case 301:case 302:case 303:case 307:case 308:
+						let code = _g;
+						if(followRedirect) {
+							tink_core_Promise.next(new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(res1.header.byName("location".toLowerCase()))),function(location) {
+								let this1 = tink_Url.resolve(url,tink_Url.fromString(location));
+								let this2;
+								if(code == 303) {
+									let __o0 = options;
+									let __tink_tmp0 = { method : "GET"};
+									let _g = __o0.headers;
+									if(_g != null) {
+										let v = _g;
+										__tink_tmp0.headers = v;
+									}
+									let _g1 = __o0.followRedirect;
+									if(_g1 != null) {
+										let v = _g1;
+										__tink_tmp0.followRedirect = v;
+									}
+									let _g2 = __o0.client;
+									if(_g2 != null) {
+										let v = _g2;
+										__tink_tmp0.client = v;
+									}
+									let _g3 = __o0.body;
+									if(_g3 != null) {
+										let v = _g3;
+										__tink_tmp0.body = v;
+									}
+									let _g4 = __o0.augment;
+									if(_g4 != null) {
+										let v = _g4;
+										__tink_tmp0.augment = v;
+									}
+									this2 = __tink_tmp0;
+								} else {
+									this2 = options;
+								}
+								return tink_http_Fetch.fetch(this1,this2);
+							}).handle(cb);
+						} else {
+							cb(tink_core_Outcome.Success(res1));
+						}
+						break;
+					default:
+						cb(tink_core_Outcome.Success(res1));
+					}
+					break;
+				case 1:
+					let e = res.failure;
+					cb(tink_core_Outcome.Failure(e));
+					break;
+				}
+			});
+		});
+	}
+	static getClient(type) {
+		if(!tink_http_Fetch.cache.exists(type)) {
+			let c;
+			switch(type._hx_index) {
+			case 0:
+				c = new tink_http_clients_NodeClient();
+				break;
+			case 1:
+				let c1 = type.container;
+				c = new tink_http_clients_LocalContainerClient(c1);
+				break;
+			case 2:
+				c = new tink_http_clients_CurlClient();
+				break;
+			case 3:
+				c = new tink_http_clients_StdClient();
+				break;
+			case 4:
+				let c2 = type.v;
+				c = c2;
+				break;
+			}
+			tink_http_Fetch.cache.set(type,c);
+		}
+		return tink_http_Fetch.cache.get(type);
+	}
+}
+tink_http_Fetch.__name__ = "tink.http.Fetch";
+var tink_http_ClientType = $hxEnums["tink.http.ClientType"] = { __ename__:true,__constructs__:null
+	,Default: {_hx_name:"Default",_hx_index:0,__enum__:"tink.http.ClientType",toString:$estr}
+	,Local: ($_=function(container) { return {_hx_index:1,container:container,__enum__:"tink.http.ClientType",toString:$estr}; },$_._hx_name="Local",$_.__params__ = ["container"],$_)
+	,Curl: {_hx_name:"Curl",_hx_index:2,__enum__:"tink.http.ClientType",toString:$estr}
+	,StdLib: {_hx_name:"StdLib",_hx_index:3,__enum__:"tink.http.ClientType",toString:$estr}
+	,Custom: ($_=function(v) { return {_hx_index:4,v:v,__enum__:"tink.http.ClientType",toString:$estr}; },$_._hx_name="Custom",$_.__params__ = ["v"],$_)
+};
+tink_http_ClientType.__constructs__ = [tink_http_ClientType.Default,tink_http_ClientType.Local,tink_http_ClientType.Curl,tink_http_ClientType.StdLib,tink_http_ClientType.Custom];
+class tink_http_FetchResponse {
+	static all(this1) {
+		return tink_core_Promise.next(this1,function(r) {
+			return tink_core_Promise.next(tink_io_RealSourceTools.all(r.body),function(chunk) {
+				if(r.header.statusCode >= 400) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(tink_core_TypedError.withData(r.header.statusCode,r.header.reason,chunk.toString(),{ fileName : "tink/http/Fetch.hx", lineNumber : 125, className : "tink.http._Fetch.FetchResponse_Impl_", methodName : "all"}))));
+				} else {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_Message(r.header,chunk))));
+				}
+			});
+		});
+	}
+	static progress(this1) {
+		return tink_core_Promise.next(this1,function(r) {
+			if(r.header.statusCode >= 400) {
+				return tink_core_Promise.next(tink_io_RealSourceTools.all(r.body),function(chunk) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(tink_core_TypedError.withData(r.header.statusCode,r.header.reason,chunk.toString(),{ fileName : "tink/http/Fetch.hx", lineNumber : 137, className : "tink.http._Fetch.FetchResponse_Impl_", methodName : "progress"}))));
+				});
+			} else {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_Message(r.header,tink_core_Progress.make(function(progress,finish) {
+					let total;
+					let _g = r.header.getContentLength();
+					switch(_g._hx_index) {
+					case 0:
+						let len = _g.data;
+						total = haxe_ds_Option.Some(len);
+						break;
+					case 1:
+						let _g1 = _g.failure;
+						total = haxe_ds_Option.None;
+						break;
+					}
+					let chunk = tink_Chunk.EMPTY;
+					progress(chunk.getLength(),total);
+					return tink_io_Source.chunked(r.body).forEach(tink_streams_Handler.ofSafeSync(function(part) {
+						chunk = tink_Chunk.concat(chunk,part);
+						progress(chunk.getLength(),total);
+						return tink_streams_Handled.Resume;
+					})).handle(function(o) {
+						switch(o._hx_index) {
+						case 0:
+							let _g = o.rest;
+							finish(tink_core_Outcome.Failure(new tink_core_TypedError(null,"unreachable",{ fileName : "tink/http/Fetch.hx", lineNumber : 157, className : "tink.http._Fetch.FetchResponse_Impl_", methodName : "progress"})));
+							break;
+						case 2:
+							let e = o.error;
+							finish(tink_core_Outcome.Failure(e));
+							break;
+						case 3:
+							finish(tink_core_Outcome.Success(chunk));
+							break;
+						}
+					});
+				})))));
+			}
+		});
+	}
+}
+class tink_http_Handler {
+	static ofFunc(f) {
+		return new tink_http_SimpleHandler(f);
+	}
+	static toNodeHandler(this1,options) {
+		let body = options == null ? function(msg) {
+			let options = null;
+			if(options == null) {
+				options = { };
+			}
+			return tink_http_IncomingRequestBody.Plain(tink_io_nodejs_NodejsSource.wrap("Incoming HTTP message from " + msg.socket.remoteAddress,msg,options.chunkSize,options.onEnd));
+		} : options.body == null ? function(msg) {
+			let options = null;
+			if(options == null) {
+				options = { };
+			}
+			return tink_http_IncomingRequestBody.Plain(tink_io_nodejs_NodejsSource.wrap("Incoming HTTP message from " + msg.socket.remoteAddress,msg,options.chunkSize,options.onEnd));
+		} : options.body;
+		return function(req,res) {
+			this1.process(new tink_http_IncomingRequest(req.socket.remoteAddress,tink_http_IncomingRequestHeader.fromIncomingMessage(req),body(req))).handle(function(out) {
+				let headers_h = Object.create(null);
+				let _g_current = 0;
+				let _g_array = out.header.fields;
+				while(_g_current < _g_array.length) {
+					let h = _g_array[_g_current++];
+					if(!Object.prototype.hasOwnProperty.call(headers_h,h.name)) {
+						let v = [];
+						headers_h[h.name] = v;
+					}
+					headers_h[h.name].push(h.value);
+				}
+				let name = new haxe_ds__$StringMap_StringMapKeyIterator(headers_h);
+				while(name.hasNext()) {
+					let name1 = name.next();
+					res.setHeader(name1,headers_h[name1]);
+				}
+				res.writeHead(out.header.statusCode,out.header.reason);
+				tink_io_Source.pipeTo(out.body,tink_io_nodejs_NodejsSink.wrap("Outgoing HTTP response to " + req.socket.remoteAddress,res)).handle(function(x) {
+					res.end();
+				});
+			});
+		};
+	}
+}
+class tink_http_HandlerObject {
+}
+tink_http_HandlerObject.__name__ = "tink.http.HandlerObject";
+tink_http_HandlerObject.__isInterface__ = true;
+Object.assign(tink_http_HandlerObject.prototype, {
+	__class__: tink_http_HandlerObject
+});
+class tink_http_SimpleHandler {
+	constructor(f) {
+		this.f = f;
+	}
+	process(req) {
+		return this.f(req);
+	}
+}
+tink_http_SimpleHandler.__name__ = "tink.http.SimpleHandler";
+tink_http_SimpleHandler.__interfaces__ = [tink_http_HandlerObject];
+Object.assign(tink_http_SimpleHandler.prototype, {
+	__class__: tink_http_SimpleHandler
+});
+class tink_http_ReadonlyMap {
+	static get(this1,key) {
+		return this1.get(key);
+	}
+	static exists(this1,key) {
+		return this1.exists(key);
+	}
+	static iterator(this1) {
+		return this1.iterator();
+	}
+	static keys(this1) {
+		return this1.keys();
+	}
+}
+class tink_http_ContentType {
+	constructor() {
+		this.subtype = "*";
+		this.type = "*";
+		this.extensions = new haxe_ds_StringMap();
+	}
+	get_fullType() {
+		return "" + this.type + "/" + this.subtype;
+	}
+	toString() {
+		return this.raw;
+	}
+	static ofString(s) {
+		let ret = new tink_http_ContentType();
+		ret.raw = s;
+		let parsed = tink_http_HeaderValue.parse(s);
+		let value = parsed[0].value;
+		let _g = value.indexOf("/");
+		if(_g == -1) {
+			ret.type = value;
+		} else {
+			let pos = _g;
+			ret.type = value.substring(0,pos);
+			ret.subtype = value.substring(pos + 1);
+		}
+		ret.extensions = parsed[0].extensions;
+		return ret;
+	}
+}
+tink_http_ContentType.__name__ = "tink.http.ContentType";
+Object.assign(tink_http_ContentType.prototype, {
+	__class__: tink_http_ContentType
+});
+class tink_http_Header {
+	constructor(fields) {
+		if(tink_http_Header._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(fields);
+	}
+	_hx_constructor(fields) {
+		let tmp;
+		if(fields == null) {
+			tmp = [];
+		} else {
+			let v = fields;
+			tmp = v;
+		}
+		this.fields = tmp;
+	}
+	get(name) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.fields;
+		while(_g1 < _g2.length) {
+			let f = _g2[_g1];
+			++_g1;
+			if(f.name == name) {
+				_g.push(f.value);
+			}
+		}
+		return _g;
+	}
+	byName(name) {
+		let _g = this.get(name);
+		switch(_g.length) {
+		case 0:
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"No " + name + " header found",{ fileName : "tink/http/Header.hx", lineNumber : 91, className : "tink.http.Header", methodName : "byName"}));
+		case 1:
+			let v = _g[0];
+			return tink_core_Outcome.Success(v);
+		default:
+			let v1 = _g;
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Multiple entries for " + name + " header",{ fileName : "tink/http/Header.hx", lineNumber : 95, className : "tink.http.Header", methodName : "byName"}));
+		}
+	}
+	contentType() {
+		return tink_core_OutcomeTools.map(this.byName("content-type"),tink_http_ContentType.ofString);
+	}
+	iterator() {
+		return new haxe_iterators_ArrayIterator(this.fields);
+	}
+	concat(fields) {
+		return new tink_http_Header(this.fields.concat(fields));
+	}
+	getContentLength() {
+		let _g = this.byName("content-length");
+		switch(_g._hx_index) {
+		case 0:
+			let _hx_tmp = Std.parseInt(_g.data);
+			if(_hx_tmp == null) {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Invalid Content-Length Header",{ fileName : "tink/http/Header.hx", lineNumber : 120, className : "tink.http.Header", methodName : "getContentLength"}));
+			} else {
+				let v = _hx_tmp;
+				return tink_core_Outcome.Success(v);
+			}
+			break;
+		case 1:
+			let e = _g.failure;
+			return tink_core_Outcome.Failure(e);
+		}
+	}
+	accepts(type) {
+		let prefix = type.split("/")[0];
+		return tink_core_OutcomeTools.map(this.byName("accept"),function(v) {
+			let _g = 0;
+			let _g1 = tink_http_HeaderValue.parse(v);
+			while(_g < _g1.length) {
+				let entry = _g1[_g];
+				++_g;
+				if(entry.value == "*/*" || entry.value == type) {
+					return true;
+				}
+				let _g2 = entry.value.split("/");
+				if(_g2.length == 2) {
+					if(_g2[1] == "*") {
+						let p = _g2[0];
+						if(prefix == p) {
+							return true;
+						}
+					}
+				}
+			}
+			return false;
+		});
+	}
+	get_LINEBREAK() {
+		return "\r\n";
+	}
+	toString() {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this.fields;
+		while(_g1 < _g2.length) {
+			let f = _g2[_g1];
+			++_g1;
+			_g.push(f.toString());
+		}
+		return _g.join("\r\n") + "\r\n" + "\r\n";
+	}
+	headerNotFound(name) {
+		return "No " + name + " header found";
+	}
+}
+tink_http_Header.__name__ = "tink.http.Header";
+Object.assign(tink_http_Header.prototype, {
+	__class__: tink_http_Header
+});
+class tink_http_HeaderValue {
+	static getExtension(this1) {
+		return tink_http_HeaderValue.parse(this1)[0].extensions;
+	}
+	static parse(this1) {
+		return tink_http_HeaderValue.parseWith(this1,function(_,params) {
+			let _g = new haxe_ds_StringMap();
+			let p = params;
+			while(p.hasNext()) {
+				let p1 = p.next();
+				let key = p1.name;
+				let value;
+				let _g1 = tink_url_Portion.toString(p1.value);
+				let quoted = _g1;
+				if(HxOverrides.cca(quoted,0) == 34) {
+					value = HxOverrides.substr(quoted,1,quoted.length - 2);
+				} else {
+					let v = _g1;
+					value = v;
+				}
+				_g.h[key] = value;
+			}
+			return _g;
+		});
+	}
+	static parseWith(this1,parseExtension) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this1.split(",");
+		while(_g1 < _g2.length) {
+			let v = _g2[_g1];
+			++_g1;
+			v = StringTools.trim(v);
+			let i;
+			let _g3 = v.indexOf(";");
+			if(_g3 == -1) {
+				i = v.length;
+			} else {
+				let i1 = _g3;
+				i = i1;
+			}
+			let value = HxOverrides.substr(v,0,i);
+			let sep = ";";
+			let pos = i + 1;
+			if(pos == null) {
+				pos = 0;
+			}
+			if(sep == null) {
+				sep = "&";
+			}
+			_g.push({ value : value, extensions : parseExtension(value,new tink_url__$Query_QueryStringParser(v,sep,"=",pos))});
+		}
+		return _g;
+	}
+	static basicAuth(username,password) {
+		return "Basic " + haxe_crypto_Base64.encode(haxe_io_Bytes.ofString("" + username + ":" + password)).toString();
+	}
+	static ofDate(d) {
+		return DateTools.format(d,tink_http_HeaderValue.DAYS[d.getDay()] + ", %d " + tink_http_HeaderValue.MONTHS[d.getMonth()] + " %Y %H:%M:%S GMT");
+	}
+	static ofInt(i) {
+		if(i == null) {
+			return "null";
+		} else {
+			return "" + i;
+		}
+	}
+}
+class tink_http_HeaderName {
+	static _new(s) {
+		return s;
+	}
+	static ofString(s) {
+		return s.toLowerCase();
+	}
+}
+class tink_http_HeaderField extends tink_core_NamedWith {
+	constructor(name,value) {
+		super(name,value);
+	}
+	toString() {
+		if(this.value == null) {
+			return this.name;
+		} else {
+			return "" + this.name + ": " + this.value;
+		}
+	}
+	static ofString(s) {
+		let _g = s.indexOf(":");
+		if(_g == -1) {
+			return new tink_http_HeaderField(s.toLowerCase(),null);
+		} else {
+			let v = _g;
+			return new tink_http_HeaderField(HxOverrides.substr(s,0,v).toLowerCase(),StringTools.trim(HxOverrides.substr(s,v + 1,null)));
+		}
+	}
+	static setCookie(key,value,options) {
+		if(options == null) {
+			options = { };
+		}
+		let buf_b = "";
+		buf_b += Std.string(encodeURIComponent(key) + "=" + encodeURIComponent(value));
+		if(options.expires != null) {
+			let value = tink_http_HeaderValue.ofDate(options.expires);
+			if(value != null) {
+				buf_b += "; ";
+				buf_b += "expires=";
+				buf_b += Std.string(value);
+			}
+		}
+		let value1 = options.domain;
+		if(value1 != null) {
+			buf_b += "; ";
+			buf_b += "domain=";
+			buf_b += Std.string(value1);
+		}
+		let value2 = options.path;
+		if(value2 != null) {
+			buf_b += "; ";
+			buf_b += "path=";
+			buf_b += Std.string(value2);
+		}
+		if(options.secure) {
+			buf_b += "; ";
+			buf_b += "secure";
+			buf_b += "";
+		}
+		if(options.scriptable != true) {
+			buf_b += "; ";
+			buf_b += "HttpOnly";
+			buf_b += "";
+		}
+		return new tink_http_HeaderField("set-cookie",buf_b);
+	}
+}
+tink_http_HeaderField.__name__ = "tink.http.HeaderField";
+tink_http_HeaderField.__super__ = tink_core_NamedWith;
+Object.assign(tink_http_HeaderField.prototype, {
+	__class__: tink_http_HeaderField
+});
+class tink_io_BytewiseParser {
+	read(char) {
+		throw haxe_Exception.thrown("abstract");
+	}
+	progress(cursor) {
+		do {
+			let _g = this.read(cursor.currentByte);
+			switch(_g._hx_index) {
+			case 0:
+				break;
+			case 1:
+				let r = _g.r;
+				cursor.next();
+				return tink_io_ParseStep.Done(r);
+			case 2:
+				let e = _g.e;
+				return tink_io_ParseStep.Failed(e);
+			}
+		} while(cursor.next());
+		return tink_io_ParseStep.Progressed;
+	}
+	eof(rest) {
+		let _g = this.read(-1);
+		switch(_g._hx_index) {
+		case 0:
+			return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Unexpected end of input",{ fileName : "tink/io/StreamParser.hx", lineNumber : 180, className : "tink.io.BytewiseParser", methodName : "eof"}));
+		case 1:
+			let r = _g.r;
+			return tink_core_Outcome.Success(r);
+		case 2:
+			let e = _g.e;
+			return tink_core_Outcome.Failure(e);
+		}
+	}
+}
+tink_io_BytewiseParser.__name__ = "tink.io.BytewiseParser";
+tink_io_BytewiseParser.__interfaces__ = [tink_io_StreamParserObject];
+Object.assign(tink_io_BytewiseParser.prototype, {
+	__class__: tink_io_BytewiseParser
+});
+var tink_io_ParseStep = $hxEnums["tink.io.ParseStep"] = { __ename__:true,__constructs__:null
+	,Progressed: {_hx_name:"Progressed",_hx_index:0,__enum__:"tink.io.ParseStep",toString:$estr}
+	,Done: ($_=function(r) { return {_hx_index:1,r:r,__enum__:"tink.io.ParseStep",toString:$estr}; },$_._hx_name="Done",$_.__params__ = ["r"],$_)
+	,Failed: ($_=function(e) { return {_hx_index:2,e:e,__enum__:"tink.io.ParseStep",toString:$estr}; },$_._hx_name="Failed",$_.__params__ = ["e"],$_)
+};
+tink_io_ParseStep.__constructs__ = [tink_io_ParseStep.Progressed,tink_io_ParseStep.Done,tink_io_ParseStep.Failed];
+class tink_http_HeaderParser extends tink_io_BytewiseParser {
+	constructor(makeHeader) {
+		super();
+		this.last = -1;
+		this.buf = new StringBuf();
+		this.makeHeader = makeHeader;
+	}
+	read(c) {
+		let _g = this.last;
+		switch(c) {
+		case -1:
+			return this.nextLine();
+		case 10:
+			if(_g == 13) {
+				return this.nextLine();
+			} else {
+				let other = c;
+				this.last = other;
+				this.buf.b += String.fromCodePoint(other);
+				return tink_io_ParseStep.Progressed;
+			}
+			break;
+		case 13:
+			if(_g == 13) {
+				let c = this.last;
+				this.buf.b += String.fromCodePoint(c);
+				return tink_io_ParseStep.Progressed;
+			} else {
+				this.last = 13;
+				return tink_io_ParseStep.Progressed;
+			}
+			break;
+		default:
+			if(_g == 13) {
+				let other = c;
+				let c1 = this.last;
+				this.buf.b += String.fromCodePoint(c1);
+				this.buf.b += String.fromCodePoint(other);
+				this.last = -1;
+				return tink_io_ParseStep.Progressed;
+			} else {
+				let other = c;
+				this.last = other;
+				this.buf.b += String.fromCodePoint(other);
+				return tink_io_ParseStep.Progressed;
+			}
+		}
+	}
+	nextLine() {
+		let line = this.buf.b;
+		this.buf = new StringBuf();
+		this.last = -1;
+		if(line == "") {
+			if(this.header == null) {
+				return tink_io_ParseStep.Progressed;
+			} else {
+				return tink_io_ParseStep.Done(this.header);
+			}
+		} else if(this.header == null) {
+			let _g = this.makeHeader(line,this.fields = []);
+			switch(_g._hx_index) {
+			case 0:
+				let _g1 = _g.data;
+				if(_g1 == null) {
+					return tink_io_ParseStep.Done(this.header = null);
+				} else {
+					let v = _g1;
+					this.header = v;
+					return tink_io_ParseStep.Progressed;
+				}
+				break;
+			case 1:
+				let e = _g.failure;
+				return tink_io_ParseStep.Failed(e);
+			}
+		} else {
+			this.fields.push(tink_http_HeaderField.ofString(line));
+			return tink_io_ParseStep.Progressed;
+		}
+	}
+}
+tink_http_HeaderParser.__name__ = "tink.http.HeaderParser";
+tink_http_HeaderParser.__super__ = tink_io_BytewiseParser;
+Object.assign(tink_http_HeaderParser.prototype, {
+	__class__: tink_http_HeaderParser
+});
+class tink_http_Message {
+	constructor(header,body) {
+		if(tink_http_Message._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor(header,body);
+	}
+	_hx_constructor(header,body) {
+		this.header = header;
+		this.body = body;
+	}
+}
+tink_http_Message.__name__ = "tink.http.Message";
+Object.assign(tink_http_Message.prototype, {
+	__class__: tink_http_Message
+});
+class tink_http_Method {
+	static ofString(s,fallback) {
+		let _g = s.toUpperCase();
+		switch(_g) {
+		case "DELETE":
+			return "DELETE";
+		case "GET":
+			return "GET";
+		case "HEAD":
+			return "HEAD";
+		case "OPTIONS":
+			return "OPTIONS";
+		case "PATCH":
+			return "PATCH";
+		case "POST":
+			return "POST";
+		case "PUT":
+			return "PUT";
+		default:
+			let v = _g;
+			return fallback(v);
+		}
+	}
+}
+class tink_http_RequestHeader extends tink_http_Header {
+	constructor(method,url,protocol,fields) {
+		tink_http_Header._hx_skip_constructor = true;
+		super();
+		tink_http_Header._hx_skip_constructor = false;
+		this._hx_constructor(method,url,protocol,fields);
+	}
+	_hx_constructor(method,url,protocol,fields) {
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		this.method = method;
+		this.url = url;
+		this.protocol = protocol;
+		super._hx_constructor(fields);
+	}
+	concat(fields) {
+		return new tink_http_RequestHeader(this.method,this.url,this.protocol,this.fields.concat(fields));
+	}
+	toString() {
+		let this1 = this.url;
+		return "" + this.method + " " + (this1.query == null ? this1.path : (this1.path == null ? "null" : this1.path) + "?" + (this1.query == null ? "null" : this1.query)) + " " + this.protocol + "\r\n" + super.toString();
+	}
+}
+tink_http_RequestHeader.__name__ = "tink.http.RequestHeader";
+tink_http_RequestHeader.__super__ = tink_http_Header;
+Object.assign(tink_http_RequestHeader.prototype, {
+	__class__: tink_http_RequestHeader
+});
+class tink_http_IncomingRequestHeader extends tink_http_RequestHeader {
+	constructor(method,url,protocol,fields) {
+		super(method,url,protocol,fields);
+	}
+	getCookies() {
+		if(this.cookies == null) {
+			let _g = new haxe_ds_StringMap();
+			let _g1 = 0;
+			let _g2 = this.get("cookie".toLowerCase());
+			while(_g1 < _g2.length) {
+				let header = _g2[_g1];
+				++_g1;
+				let sep = ";";
+				if(sep == null) {
+					sep = "&";
+				}
+				let entry = new tink_url__$Query_QueryStringParser(header,sep,"=",0);
+				while(entry.hasNext()) {
+					let entry1 = entry.next();
+					let key = entry1.name;
+					let value = tink_url_Portion.toString(entry1.value);
+					_g.h[key] = value;
+				}
+			}
+			this.cookies = _g;
+		}
+		return this.cookies;
+	}
+	concat(fields) {
+		return new tink_http_IncomingRequestHeader(this.method,this.url,this.protocol,this.fields.concat(fields));
+	}
+	cookieNames() {
+		return new haxe_ds__$StringMap_StringMapKeyIterator(this.cookies.h);
+	}
+	getCookie(name) {
+		return this.getCookies().h[name];
+	}
+	getAuth() {
+		return this.getAuthWith(function(s,p) {
+			switch(s) {
+			case "Basic":
+				let decoded;
+				try {
+					decoded = haxe_crypto_Base64.decode(p).toString();
+				} catch( _g ) {
+					let e = haxe_Exception.caught(_g).unwrap();
+					return tink_core_Outcome.Failure(tink_core_TypedError.withData(null,"Error in decoding basic auth",e,{ fileName : "tink/http/Request.hx", lineNumber : 67, className : "tink.http.IncomingRequestHeader", methodName : "getAuth"}));
+				}
+				let _g = decoded.indexOf(":");
+				if(_g == -1) {
+					return tink_core_Outcome.Failure(new tink_core_TypedError(null,"Cannot parse username and password because \":\" is missing",{ fileName : "tink/http/Request.hx", lineNumber : 69, className : "tink.http.IncomingRequestHeader", methodName : "getAuth"}));
+				} else {
+					let i = _g;
+					return tink_core_Outcome.Success(tink_http_Authorization.Basic(HxOverrides.substr(decoded,0,i),HxOverrides.substr(decoded,i + 1,null)));
+				}
+				break;
+			case "Bearer":
+				return tink_core_Outcome.Success(tink_http_Authorization.Bearer(p));
+			default:
+				let s1 = s;
+				return tink_core_Outcome.Success(tink_http_Authorization.Others(s1,p));
+			}
+		});
+	}
+	getAuthWith(parser) {
+		return tink_core_OutcomeTools.flatMap(this.byName("authorization"),tink_core__$Outcome_OutcomeMapper.withSameError(function(v) {
+			let _g = v.indexOf(" ");
+			if(_g == -1) {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Invalid Authorization Header",{ fileName : "tink/http/Request.hx", lineNumber : 81, className : "tink.http.IncomingRequestHeader", methodName : "getAuthWith"}));
+			} else {
+				let i = _g;
+				return parser(HxOverrides.substr(v,0,i),HxOverrides.substr(v,i + 1,null));
+			}
+		}));
+	}
+	static parser() {
+		return new tink_http_HeaderParser(function(line,headers) {
+			let _g = line.split(" ");
+			if(_g.length == 3) {
+				let method = _g[0];
+				let url = _g[1];
+				let protocol = _g[2];
+				return tink_core_Outcome.Success(new tink_http_IncomingRequestHeader(method,tink_Url.fromString(url),protocol,headers));
+			} else {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Invalid HTTP header",{ fileName : "tink/http/Request.hx", lineNumber : 95, className : "tink.http.IncomingRequestHeader", methodName : "parser"}));
+			}
+		});
+	}
+	static fromIncomingMessage(req) {
+		let req1 = req.method;
+		let tmp = tink_Url.fromString(req.url);
+		let tmp1 = "HTTP/" + req.httpVersion;
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = req.rawHeaders.length / 2 | 0;
+		while(_g1 < _g2) {
+			let i = _g1++;
+			_g.push(new tink_http_HeaderField(req.rawHeaders[2 * i].toLowerCase(),req.rawHeaders[2 * i + 1]));
+		}
+		return new tink_http_IncomingRequestHeader(req1,tmp,tmp1,_g);
+	}
+}
+tink_http_IncomingRequestHeader.__name__ = "tink.http.IncomingRequestHeader";
+tink_http_IncomingRequestHeader.__super__ = tink_http_RequestHeader;
+Object.assign(tink_http_IncomingRequestHeader.prototype, {
+	__class__: tink_http_IncomingRequestHeader
+});
+class tink_http_OutgoingRequestHeader extends tink_http_RequestHeader {
+	constructor(method,url,protocol,fields) {
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		let _g = tink_http_OutgoingRequestHeader.extractAuth(url);
+		if(_g._hx_index == 0) {
+			let v = _g.v;
+			url = v.url;
+			fields = fields.concat(v.headers);
+		}
+		super(method,url,protocol,fields);
+	}
+	concat(fields) {
+		return new tink_http_OutgoingRequestHeader(this.method,this.url,this.protocol,this.fields.concat(fields));
+	}
+	static extractAuth(url) {
+		let _g = url.auth;
+		if(_g == null) {
+			return haxe_ds_Option.None;
+		} else {
+			let v = _g;
+			let tmp = [new tink_http_HeaderField("authorization",tink_http_HeaderValue.basicAuth(v == null ? null : v.split(":")[0],v == null ? null : v.split(":")[1]))];
+			let url1 = url.scheme;
+			let _g1 = [];
+			let _g2 = 0;
+			let _g3 = url.hosts;
+			while(_g2 < _g3.length) {
+				let host = _g3[_g2];
+				++_g2;
+				_g1.push(host);
+			}
+			return haxe_ds_Option.Some({ headers : tmp, url : tink_Url.make({ scheme : url1, hosts : _g1, path : url.path, query : url.query})});
+		}
+	}
+}
+tink_http_OutgoingRequestHeader.__name__ = "tink.http.OutgoingRequestHeader";
+tink_http_OutgoingRequestHeader.__super__ = tink_http_RequestHeader;
+Object.assign(tink_http_OutgoingRequestHeader.prototype, {
+	__class__: tink_http_OutgoingRequestHeader
+});
+class tink_http_OutgoingRequest extends tink_http_Message {
+	constructor(header,body) {
+		super(header,body);
+	}
+}
+tink_http_OutgoingRequest.__name__ = "tink.http.OutgoingRequest";
+tink_http_OutgoingRequest.__super__ = tink_http_Message;
+Object.assign(tink_http_OutgoingRequest.prototype, {
+	__class__: tink_http_OutgoingRequest
+});
+class tink_http_IncomingRequest extends tink_http_Message {
+	constructor(clientIp,header,body) {
+		tink_http_Message._hx_skip_constructor = true;
+		super();
+		tink_http_Message._hx_skip_constructor = false;
+		this._hx_constructor(clientIp,header,body);
+	}
+	_hx_constructor(clientIp,header,body) {
+		this.clientIp = clientIp;
+		super._hx_constructor(header,body);
+	}
+	static parse(clientIp,source) {
+		return tink_core_Promise.next(tink_io_RealSourceTools.parse(source,tink_http_IncomingRequestHeader.parser()),function(parts) {
+			let clientIp1 = clientIp;
+			let parts1 = parts.a;
+			let _g = parts.a.getContentLength();
+			let d;
+			switch(_g._hx_index) {
+			case 0:
+				let len = _g.data;
+				d = tink_io_Source.limit(parts.b,len);
+				break;
+			case 1:
+				let _g1 = _g.failure;
+				let _g2 = parts.a.method;
+				let _g3 = parts.a.byName("transfer-encoding");
+				switch(_g2) {
+				case "GET":case "OPTIONS":
+					d = tink_io_Source.EMPTY;
+					break;
+				default:
+					if(_g3._hx_index == 0) {
+						let _this = _g3.data.split(",");
+						let f = StringTools.trim;
+						let result = new Array(_this.length);
+						let _g = 0;
+						let _g1 = _this.length;
+						while(_g < _g1) {
+							let i = _g++;
+							result[i] = f(_this[i]);
+						}
+						let encodings = result;
+						if(encodings.indexOf("chunked") != -1) {
+							let source = parts.b;
+							d = tink_http_Chunked.decoder().transform(source);
+						} else {
+							return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(new tink_core_TypedError(411,"Content-Length header missing",{ fileName : "tink/http/Request.hx", lineNumber : 171, className : "tink.http.IncomingRequest", methodName : "parse"}))));
+						}
+					} else {
+						return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(new tink_core_TypedError(411,"Content-Length header missing",{ fileName : "tink/http/Request.hx", lineNumber : 171, className : "tink.http.IncomingRequest", methodName : "parse"}))));
+					}
+				}
+				break;
+			}
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_IncomingRequest(clientIp1,parts1,tink_http_IncomingRequestBody.Plain(d)))));
+		});
+	}
+}
+tink_http_IncomingRequest.__name__ = "tink.http.IncomingRequest";
+tink_http_IncomingRequest.__super__ = tink_http_Message;
+Object.assign(tink_http_IncomingRequest.prototype, {
+	__class__: tink_http_IncomingRequest
+});
+var tink_http_IncomingRequestBody = $hxEnums["tink.http.IncomingRequestBody"] = { __ename__:true,__constructs__:null
+	,Plain: ($_=function(source) { return {_hx_index:0,source:source,__enum__:"tink.http.IncomingRequestBody",toString:$estr}; },$_._hx_name="Plain",$_.__params__ = ["source"],$_)
+	,Parsed: ($_=function(parts) { return {_hx_index:1,parts:parts,__enum__:"tink.http.IncomingRequestBody",toString:$estr}; },$_._hx_name="Parsed",$_.__params__ = ["parts"],$_)
+};
+tink_http_IncomingRequestBody.__constructs__ = [tink_http_IncomingRequestBody.Plain,tink_http_IncomingRequestBody.Parsed];
+var tink_http_Authorization = $hxEnums["tink.http.Authorization"] = { __ename__:true,__constructs__:null
+	,Basic: ($_=function(user,pass) { return {_hx_index:0,user:user,pass:pass,__enum__:"tink.http.Authorization",toString:$estr}; },$_._hx_name="Basic",$_.__params__ = ["user","pass"],$_)
+	,Bearer: ($_=function(token) { return {_hx_index:1,token:token,__enum__:"tink.http.Authorization",toString:$estr}; },$_._hx_name="Bearer",$_.__params__ = ["token"],$_)
+	,Others: ($_=function(scheme,param) { return {_hx_index:2,scheme:scheme,param:param,__enum__:"tink.http.Authorization",toString:$estr}; },$_._hx_name="Others",$_.__params__ = ["scheme","param"],$_)
+};
+tink_http_Authorization.__constructs__ = [tink_http_Authorization.Basic,tink_http_Authorization.Bearer,tink_http_Authorization.Others];
+class tink_http_ResponseHeader {
+	static _new(statusCode,reason,fields,protocol) {
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		return new tink_http_ResponseHeaderBase(statusCode,reason,fields,protocol);
+	}
+	static fromStatusCode(code) {
+		return new tink_http_ResponseHeaderBase(code,null,null,"HTTP/1.1");
+	}
+	static fromHeaderFields(fields) {
+		return new tink_http_ResponseHeaderBase(200,null,fields,"HTTP/1.1");
+	}
+	static parser() {
+		return tink_http_ResponseHeaderBase.parser();
+	}
+}
+class tink_http_ResponseHeaderBase extends tink_http_Header {
+	constructor(statusCode,reason,fields,protocol) {
+		tink_http_Header._hx_skip_constructor = true;
+		super();
+		tink_http_Header._hx_skip_constructor = false;
+		this._hx_constructor(statusCode,reason,fields,protocol);
+	}
+	_hx_constructor(statusCode,reason,fields,protocol) {
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		this.statusCode = statusCode;
+		this.reason = reason == null ? httpstatus_HttpStatusMessage.fromCode(statusCode) : reason;
+		this.protocol = protocol;
+		super._hx_constructor(fields);
+	}
+	concat(fields) {
+		let statusCode = this.statusCode;
+		let reason = this.reason;
+		let fields1 = this.fields.concat(fields);
+		let protocol = this.protocol;
+		if(protocol == null) {
+			protocol = "HTTP/1.1";
+		}
+		return new tink_http_ResponseHeaderBase(statusCode,reason,fields1,protocol);
+	}
+	toString() {
+		return "" + this.protocol + " " + this.statusCode + " " + this.reason + "\r\n" + super.toString();
+	}
+	static parser() {
+		return new tink_http_HeaderParser(function(line,headers) {
+			let v = line.split(" ");
+			if(v.length >= 3) {
+				let statusCode = Std.parseInt(v[1]);
+				let reason = v.slice(2).join(" ");
+				let protocol = v[0];
+				if(protocol == null) {
+					protocol = "HTTP/1.1";
+				}
+				return tink_core_Outcome.Success(new tink_http_ResponseHeaderBase(statusCode,reason,headers,protocol));
+			} else {
+				return tink_core_Outcome.Failure(new tink_core_TypedError(422,"Invalid HTTP response header",{ fileName : "tink/http/Response.hx", lineNumber : 56, className : "tink.http.ResponseHeaderBase", methodName : "parser"}));
+			}
+		});
+	}
+}
+tink_http_ResponseHeaderBase.__name__ = "tink.http.ResponseHeaderBase";
+tink_http_ResponseHeaderBase.__super__ = tink_http_Header;
+Object.assign(tink_http_ResponseHeaderBase.prototype, {
+	__class__: tink_http_ResponseHeaderBase
+});
+class tink_http__$Response_OutgoingResponseData extends tink_http_Message {
+	constructor(header,body) {
+		super(header,body);
+	}
+}
+tink_http__$Response_OutgoingResponseData.__name__ = "tink.http._Response.OutgoingResponseData";
+tink_http__$Response_OutgoingResponseData.__super__ = tink_http_Message;
+Object.assign(tink_http__$Response_OutgoingResponseData.prototype, {
+	__class__: tink_http__$Response_OutgoingResponseData
+});
+class tink_http_OutgoingResponse {
+	static _new(header,body) {
+		return new tink_http__$Response_OutgoingResponseData(header,body);
+	}
+	static blob(code,chunk,contentType,headers) {
+		if(code == null) {
+			code = 200;
+		}
+		let this1 = httpstatus_HttpStatusMessage.fromCode(code);
+		let fields = new tink_http_HeaderField("Content-Type".toLowerCase(),contentType);
+		let this2 = "Content-Length".toLowerCase();
+		let fields1 = Std.string(chunk.getLength());
+		let fields2;
+		if(headers == null) {
+			fields2 = [];
+		} else {
+			let v = headers;
+			fields2 = v;
+		}
+		return new tink_http__$Response_OutgoingResponseData(new tink_http_ResponseHeaderBase(code,this1,[fields,new tink_http_HeaderField(this2,fields1)].concat(fields2),"HTTP/1.1"),new tink_streams_Single(new tink_core__$Lazy_LazyConst(chunk)));
+	}
+	static chunked(contentType,headers,source) {
+	}
+	static ofString(s) {
+		return tink_http_OutgoingResponse.blob(null,tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(s)),"text/plain");
+	}
+	static ofChunk(c) {
+		return tink_http_OutgoingResponse.blob(null,c,"application/octet-stream");
+	}
+	static reportError(e) {
+		let code = e.code;
+		if(code < 100 || code > 999) {
+			code = 500;
+		}
+		return new tink_http__$Response_OutgoingResponseData(new tink_http_ResponseHeaderBase(code,httpstatus_HttpStatusMessage.fromCode(code),[new tink_http_HeaderField("Content-Type".toLowerCase(),"application/json")],"HTTP/1.1"),new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(JSON.stringify({ error : e.message, details : e.data}))))));
+	}
+}
+class tink_http_IncomingResponse extends tink_http_Message {
+	constructor(header,body) {
+		super(header,body);
+	}
+	static readAll(res) {
+		return tink_core_Promise.next(tink_io_RealSourceTools.all(res.body),function(b) {
+			if(res.header.statusCode >= 400) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(tink_core_TypedError.withData(res.header.statusCode,res.header.reason,b.toString(),{ fileName : "tink/http/Response.hx", lineNumber : 115, className : "tink.http.IncomingResponse", methodName : "readAll"}))));
+			} else {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(b)));
+			}
+		});
+	}
+	static reportError(e) {
+		return new tink_http_IncomingResponse(new tink_http_ResponseHeaderBase(e.code,httpstatus_HttpStatusMessage.fromCode(e.code),[new tink_http_HeaderField("Content-Type".toLowerCase(),"application/json")],"HTTP/1.1"),new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(JSON.stringify({ error : e.message, details : e.data}))))));
+	}
+}
+tink_http_IncomingResponse.__name__ = "tink.http.IncomingResponse";
+tink_http_IncomingResponse.__super__ = tink_http_Message;
+Object.assign(tink_http_IncomingResponse.prototype, {
+	__class__: tink_http_IncomingResponse
+});
+var tink_http_BodyPart = $hxEnums["tink.http.BodyPart"] = { __ename__:true,__constructs__:null
+	,Value: ($_=function(v) { return {_hx_index:0,v:v,__enum__:"tink.http.BodyPart",toString:$estr}; },$_._hx_name="Value",$_.__params__ = ["v"],$_)
+	,File: ($_=function(handle) { return {_hx_index:1,handle:handle,__enum__:"tink.http.BodyPart",toString:$estr}; },$_._hx_name="File",$_.__params__ = ["handle"],$_)
+};
+tink_http_BodyPart.__constructs__ = [tink_http_BodyPart.Value,tink_http_BodyPart.File];
+class tink_http_UploadedFile {
+	static ofBlob(name,type,data) {
+		return { fileName : name, mimeType : type, size : data.length, read : function() {
+			return new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(data)));
+		}, saveTo : function(path) {
+			let name = "File sink " + path;
+			let dest = tink_io_nodejs_NodejsSink.wrap(name,js_node_Fs.createWriteStream(path));
+			return tink_core_Future.map(tink_io_Source.pipeTo(new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(data))),dest,{ end : true}),function(r) {
+				switch(r._hx_index) {
+				case 0:
+					return tink_core_Outcome.Success(null);
+				case 1:
+					let _g = r.result;
+					let _g1 = r.rest;
+					return tink_core_Outcome.Failure(new tink_core_TypedError(null,"File $path closed unexpectedly",{ fileName : "tink/http/StructuredBody.hx", lineNumber : 37, className : "tink.http._StructuredBody.UploadedFile_Impl_", methodName : "ofBlob"}));
+				case 2:
+					let _g2 = r.rest;
+					let e = r.e;
+					return tink_core_Outcome.Failure(e);
+				}
+			});
+		}};
+	}
+}
+class tink_http_clients_CurlClient {
+	constructor(curl) {
+		if(curl != null) {
+			this.curl = curl;
+		}
+	}
+	request(req) {
+		let _g = tink_http_clients_Helpers.checkScheme(req.header.url.scheme);
+		switch(_g._hx_index) {
+		case 0:
+			let e = _g.v;
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+		case 1:
+			let args = [];
+			args.push("-isS");
+			args.push("-X");
+			args.push(req.header.method);
+			switch(req.header.protocol) {
+			case "HTTP/1.0":
+				args.push("--http1.0");
+				break;
+			case "HTTP/1.1":
+				args.push("--http1.1");
+				break;
+			case "HTTP/2":
+				args.push("--http2");
+				break;
+			default:
+			}
+			let _g_current = 0;
+			let _g_array = req.header.fields;
+			while(_g_current < _g_array.length) {
+				let header = _g_array[_g_current++];
+				args.push("-H");
+				args.push("" + header.name + ": " + header.value);
+			}
+			args.push(tink_Url.toString(req.header.url));
+			return tink_core_Promise.next(tink_io_RealSourceTools.parse(this.curl(args,req.body),tink_http_ResponseHeaderBase.parser()),function(p) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_IncomingResponse(p.a,p.b))));
+			});
+		}
+	}
+	curl(args,body) {
+		args.push("--data-binary");
+		args.push("@-");
+		let $process = js_node_ChildProcess.spawn("curl",args);
+		let sink = tink_io_nodejs_NodejsSink.wrap("stdin",$process.stdin);
+		tink_io_Source.pipeTo(body,sink,{ end : true}).eager();
+		return tink_io_Source.ofPromised(tink_core_Future.flatMap(tink_core_Future.async(function(cb) {
+			$process.once("exit",function(code,signal) {
+				cb(code);
+			});
+		}),function(code) {
+			if(code == 0) {
+				let options = null;
+				if(options == null) {
+					options = { };
+				}
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(tink_io_nodejs_NodejsSource.wrap("stdout",$process.stdout,options.chunkSize,options.onEnd))));
+			} else {
+				let v = code;
+				let options = null;
+				if(options == null) {
+					options = { };
+				}
+				return tink_core_Promise.next(tink_io_RealSourceTools.all(tink_io_nodejs_NodejsSource.wrap("stderr",$process.stderr,options.chunkSize,options.onEnd)),function(stderr) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(new tink_core_TypedError(v,stderr.toString(),{ fileName : "tink/http/clients/CurlClient.hx", lineNumber : 62, className : "tink.http.clients.CurlClient", methodName : "curl"}))));
+				});
+			}
+		}));
+	}
+}
+tink_http_clients_CurlClient.__name__ = "tink.http.clients.CurlClient";
+tink_http_clients_CurlClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http_clients_CurlClient.prototype, {
+	__class__: tink_http_clients_CurlClient
+});
+class tink_http_clients_Helpers {
+	static checkScheme(s) {
+		if(s == null) {
+			return haxe_ds_Option.Some(new tink_core_TypedError(400,"Missing Scheme (expected http/https)",{ fileName : "tink/http/clients/Helpers.hx", lineNumber : 14, className : "tink.http.clients.Helpers", methodName : "missingSchemeError"}));
+		} else {
+			switch(s) {
+			case "http":case "https":
+				return haxe_ds_Option.None;
+			default:
+				let v = s;
+				return haxe_ds_Option.Some(new tink_core_TypedError(400,"Invalid Scheme \"" + v + "\" (expected http/https)",{ fileName : "tink/http/clients/Helpers.hx", lineNumber : 17, className : "tink.http.clients.Helpers", methodName : "invalidSchemeError"}));
+			}
+		}
+	}
+	static missingSchemeError() {
+		return new tink_core_TypedError(400,"Missing Scheme (expected http/https)",{ fileName : "tink/http/clients/Helpers.hx", lineNumber : 14, className : "tink.http.clients.Helpers", methodName : "missingSchemeError"});
+	}
+	static invalidSchemeError(v) {
+		return new tink_core_TypedError(400,"Invalid Scheme \"" + v + "\" (expected http/https)",{ fileName : "tink/http/clients/Helpers.hx", lineNumber : 17, className : "tink.http.clients.Helpers", methodName : "invalidSchemeError"});
+	}
+}
+tink_http_clients_Helpers.__name__ = "tink.http.clients.Helpers";
+class tink_http_clients_LocalContainerClient {
+	constructor(container) {
+		this.container = container;
+	}
+	request(req) {
+		let this1 = req.header.url;
+		return tink_core_Future.flatMap(this.container.serve(new tink_http_IncomingRequest("127.0.0.1",new tink_http_IncomingRequestHeader(req.header.method,tink_Url.fromString(this1.query == null ? this1.path : (this1.path == null ? "null" : this1.path) + "?" + (this1.query == null ? "null" : this1.query)),"HTTP/1.1",req.header.fields),tink_http_IncomingRequestBody.Plain(req.body))),function(res) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(new tink_http_IncomingResponse(res.header,res.body))));
+		});
+	}
+}
+tink_http_clients_LocalContainerClient.__name__ = "tink.http.clients.LocalContainerClient";
+tink_http_clients_LocalContainerClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http_clients_LocalContainerClient.prototype, {
+	__class__: tink_http_clients_LocalContainerClient
+});
+class tink_http_clients_NodeClient {
+	constructor() {
+	}
+	request(req) {
+		let _g = tink_http_clients_Helpers.checkScheme(req.header.url.scheme);
+		switch(_g._hx_index) {
+		case 0:
+			let e = _g.v;
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(e)));
+		case 1:
+			let options = this.getNodeOptions(req.header);
+			if(req.header.url.scheme == "https") {
+				return this.nodeRequest(js_node_Https,options,req);
+			} else {
+				return this.nodeRequest(js_node_Http,options,req);
+			}
+			break;
+		}
+	}
+	getNodeOptions(header) {
+		let header1 = header.method;
+		let this1 = header.url;
+		let tmp = this1.query == null ? this1.path : (this1.path == null ? "null" : this1.path) + "?" + (this1.query == null ? "null" : this1.query);
+		let tmp1 = tink_url_Host.get_name(header.url.hosts[0]);
+		let tmp2 = tink_url_Host.get_port(header.url.hosts[0]);
+		let map = { };
+		let _g_current = 0;
+		let _g_array = header.fields;
+		while(_g_current < _g_array.length) {
+			let h = _g_array[_g_current++];
+			let name = h.name;
+			if(name == "host") {
+				map[h.name] = h.value;
+			} else {
+				let list;
+				let _g = map[h.name];
+				if(_g == null) {
+					list = map[h.name] = [];
+				} else {
+					let arr = _g;
+					list = arr;
+				}
+				list.push(h.value);
+			}
+		}
+		return { method : header1, path : tmp, host : tmp1, port : tmp2, headers : map, agent : false};
+	}
+	nodeRequest(agent,options,req) {
+		return tink_core_Future.async(function(cb) {
+			let fwd = agent.request(options,function(msg) {
+				let cb1 = cb;
+				let statusCode = msg.statusCode;
+				let reason = msg.statusMessage;
+				let _g = [];
+				let _g1 = 0;
+				let _g2 = msg.rawHeaders.length >> 1;
+				while(_g1 < _g2) {
+					let i = _g1++;
+					_g.push(new tink_http_HeaderField(msg.rawHeaders[2 * i].toLowerCase(),msg.rawHeaders[2 * i + 1]));
+				}
+				let this1 = new tink_http_ResponseHeaderBase(statusCode,reason,_g,"HTTP/1.1");
+				let name = req.header.url == null ? "null" : tink_Url.toString(req.header.url);
+				let options = null;
+				if(options == null) {
+					options = { };
+				}
+				cb1(tink_core_Outcome.Success(new tink_http_IncomingResponse(this1,tink_io_nodejs_NodejsSource.wrap("Response from " + name,msg,options.chunkSize,options.onEnd))));
+			});
+			let fail = function(e) {
+				cb(tink_core_Outcome.Failure(e));
+			};
+			fwd.on("error",function(e) {
+				fail(tink_core_TypedError.withData(null,e.message,e,{ fileName : "tink/http/clients/NodeClient.hx", lineNumber : 83, className : "tink.http.clients.NodeClient", methodName : "nodeRequest"}));
+			});
+			tink_io_Source.pipeTo(req.body,tink_io_nodejs_NodejsSink.wrap("Request to " + (req.header.url == null ? "null" : tink_Url.toString(req.header.url)),fwd)).handle(function(res) {
+				fwd.end();
+				switch(res._hx_index) {
+				case 0:
+					break;
+				case 1:
+					let _g = res.result;
+					let _g1 = res.rest;
+					fail(new tink_core_TypedError(502,"Gateway Error",{ fileName : "tink/http/clients/NodeClient.hx", lineNumber : 92, className : "tink.http.clients.NodeClient", methodName : "nodeRequest"}));
+					break;
+				case 2:
+					let _g2 = res.rest;
+					let e = res.e;
+					fail(e);
+					break;
+				}
+			});
+		});
+	}
+}
+tink_http_clients_NodeClient.__name__ = "tink.http.clients.NodeClient";
+tink_http_clients_NodeClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http_clients_NodeClient.prototype, {
+	__class__: tink_http_clients_NodeClient
+});
+class tink_http_clients_StdClient {
+	constructor(worker) {
+		this.worker = tink_io_Worker.ensure(worker);
+	}
+	request(req) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			let r = new haxe_http_HttpNodeJs(tink_Url.toString(req.header.url));
+			let send = function(post) {
+				let code = 200;
+				r.onStatus = function(c) {
+					code = c;
+				};
+				let headers = function() {
+					return [];
+				};
+				r.onError = function(msg) {
+					if(code == 200) {
+						code = 500;
+					}
+					tink_io_Worker.work(_gthis.worker,new tink_core__$Lazy_LazyConst(true)).handle(function() {
+						cb(tink_core_Outcome.Failure(new tink_core_TypedError(code,msg,{ fileName : "tink/http/clients/StdClient.hx", lineNumber : 44, className : "tink.http.clients.StdClient", methodName : "request"})));
+					});
+				};
+				r.onData = function(data) {
+					tink_io_Worker.work(_gthis.worker,new tink_core__$Lazy_LazyConst(true)).handle(function() {
+						let cb1 = cb;
+						let fields = headers();
+						cb1(tink_core_Outcome.Success(new tink_http_IncomingResponse(new tink_http_ResponseHeaderBase(code,"OK",fields,"HTTP/1.1"),new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(data)))))));
+					});
+				};
+				tink_io_Worker.work(_gthis.worker,new tink_core__$Lazy_LazyFunc(function() {
+					r.request(post);
+				}));
+			};
+			let _g_current = 0;
+			let _g_array = req.header.fields;
+			while(_g_current < _g_array.length) {
+				let h = _g_array[_g_current++];
+				r.setHeader(h.name,h.value);
+			}
+			switch(req.header.method) {
+			case "GET":case "HEAD":case "OPTIONS":
+				send(false);
+				break;
+			default:
+				tink_io_IdealSourceTools.all(req.body).handle(function(bytes) {
+					r.setPostData(bytes.toString());
+					send(true);
+				});
+			}
+		});
+	}
+}
+tink_http_clients_StdClient.__name__ = "tink.http.clients.StdClient";
+tink_http_clients_StdClient.__interfaces__ = [tink_http_ClientObject];
+Object.assign(tink_http_clients_StdClient.prototype, {
+	__class__: tink_http_clients_StdClient
+});
+class tink_http_containers_LocalContainer {
+	constructor() {
+	}
+	run(handler) {
+		this.handler = handler;
+		this.running = true;
+		let _gthis = this;
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_http_ContainerResult.Running({ failures : new tink_core_SignalTrigger(), shutdown : function(hard) {
+			_gthis.running = false;
+			return tink_core_Future.map(new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(true)),tink_core_Outcome.Success);
+		}})));
+	}
+	serve(req) {
+		if(!this.running) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(new tink_http__$Response_OutgoingResponseData(new tink_http_ResponseHeaderBase(503,"Server stopped",[],"HTTP/1.1"),tink_io_Source.EMPTY)));
+		}
+		return this.handler.process(req);
+	}
+}
+tink_http_containers_LocalContainer.__name__ = "tink.http.containers.LocalContainer";
+tink_http_containers_LocalContainer.__interfaces__ = [tink_http_Container];
+Object.assign(tink_http_containers_LocalContainer.prototype, {
+	__class__: tink_http_containers_LocalContainer
+});
+class tink_io_PipeOptions {
+	static get_end(this1) {
+		if(this1 != null) {
+			return this1.end;
+		} else {
+			return false;
+		}
+	}
+	static get_destructive(this1) {
+		if(this1 != null) {
+			return this1.destructive;
+		} else {
+			return false;
+		}
+	}
+}
+var tink_io_PipeResult = $hxEnums["tink.io.PipeResult"] = { __ename__:true,__constructs__:null
+	,AllWritten: {_hx_name:"AllWritten",_hx_index:0,__enum__:"tink.io.PipeResult",toString:$estr}
+	,SinkEnded: ($_=function(result,rest) { return {_hx_index:1,result:result,rest:rest,__enum__:"tink.io.PipeResult",toString:$estr}; },$_._hx_name="SinkEnded",$_.__params__ = ["result","rest"],$_)
+	,SinkFailed: ($_=function(e,rest) { return {_hx_index:2,e:e,rest:rest,__enum__:"tink.io.PipeResult",toString:$estr}; },$_._hx_name="SinkFailed",$_.__params__ = ["e","rest"],$_)
+	,SourceFailed: ($_=function(e) { return {_hx_index:3,e:e,__enum__:"tink.io.PipeResult",toString:$estr}; },$_._hx_name="SourceFailed",$_.__params__ = ["e"],$_)
+};
+tink_io_PipeResult.__constructs__ = [tink_io_PipeResult.AllWritten,tink_io_PipeResult.SinkEnded,tink_io_PipeResult.SinkFailed,tink_io_PipeResult.SourceFailed];
+class tink_io_PipeResultTools {
+	static toOutcome(result) {
+		switch(result._hx_index) {
+		case 0:
+			return tink_core_Outcome.Success(haxe_ds_Option.None);
+		case 1:
+			let _g = result.rest;
+			let result1 = result.result;
+			return tink_core_Outcome.Success(haxe_ds_Option.Some(result1));
+		case 2:
+			let _g1 = result.rest;
+			let e = result.e;
+			return tink_core_Outcome.Failure(e);
+		case 3:
+			let e1 = result.e;
+			return tink_core_Outcome.Failure(e1);
+		}
+	}
+	static toResult(c,result,buffered) {
+		let mk = function(s) {
+			if(buffered == null) {
+				return s;
+			} else {
+				let v = buffered;
+				return s.prepend(new tink_streams_Single(new tink_core__$Lazy_LazyConst(v)));
+			}
+		};
+		switch(c._hx_index) {
+		case 0:
+			let rest = c.rest;
+			return tink_io_PipeResult.SinkEnded(result,mk(rest));
+		case 1:
+			let e = c.error;
+			let rest1 = c.at;
+			return tink_io_PipeResult.SinkFailed(e,mk(rest1));
+		case 2:
+			let e1 = c.error;
+			return tink_io_PipeResult.SourceFailed(e1);
+		case 3:
+			return tink_io_PipeResult.AllWritten;
+		}
+	}
+}
+tink_io_PipeResultTools.__name__ = "tink.io.PipeResultTools";
+class tink_io_SinkObject {
+}
+tink_io_SinkObject.__name__ = "tink.io.SinkObject";
+tink_io_SinkObject.__isInterface__ = true;
+Object.assign(tink_io_SinkObject.prototype, {
+	__class__: tink_io_SinkObject
+});
+class tink_io_SinkBase {
+	get_sealed() {
+		return true;
+	}
+	consume(source,options) {
+		throw haxe_Exception.thrown("not implemented");
+	}
+}
+tink_io_SinkBase.__name__ = "tink.io.SinkBase";
+tink_io_SinkBase.__interfaces__ = [tink_io_SinkObject];
+Object.assign(tink_io_SinkBase.prototype, {
+	__class__: tink_io_SinkBase
+});
+class tink_io__$Sink_Blackhole extends tink_io_SinkBase {
+	constructor() {
+		super();
+	}
+	consume(source,options) {
+		return tink_core_Future.map(source.forEach(tink_streams_Handler.ofSafeSync(function(_) {
+			return tink_streams_Handled.Resume;
+		})),function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let _g = o.rest;
+				throw haxe_Exception.thrown("unreachable");
+			case 2:
+				let e = o.error;
+				return tink_io_PipeResult.SourceFailed(e);
+			case 3:
+				return tink_io_PipeResult.AllWritten;
+			}
+		});
+	}
+}
+tink_io__$Sink_Blackhole.__name__ = "tink.io._Sink.Blackhole";
+tink_io__$Sink_Blackhole.__super__ = tink_io_SinkBase;
+Object.assign(tink_io__$Sink_Blackhole.prototype, {
+	__class__: tink_io__$Sink_Blackhole
+});
+class tink_io_SinkYielding {
+	static end(this1) {
+		if(this1.get_sealed()) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(false)));
+		} else {
+			return tink_core_Future.map(this1.consume(tink_io_Source.EMPTY,{ end : true}),function(r) {
+				switch(r._hx_index) {
+				case 0:
+					return tink_core_Outcome.Success(true);
+				case 1:
+					let _g = r.result;
+					let _g1 = r.rest;
+					return tink_core_Outcome.Success(true);
+				case 2:
+					let _g2 = r.rest;
+					let e = r.e;
+					return tink_core_Outcome.Failure(e);
+				}
+			});
+		}
+	}
+	static dirty(this1) {
+		return this1;
+	}
+	static ofError(e) {
+		return new tink_io__$Sink_ErrorSink(e);
+	}
+	static ofPromised(p) {
+		return new tink_io__$Sink_FutureSink(tink_core_Future.map(p,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let v = o.data;
+				return v;
+			case 1:
+				let e = o.failure;
+				return tink_io_SinkYielding.ofError(e);
+			}
+		}));
+	}
+	static ofNodeStream(name,r) {
+		return tink_io_nodejs_NodejsSink.wrap(name,r);
+	}
+	static ofOutput(name,target,options) {
+		let tmp;
+		if(options == null) {
+			tmp = tink_io_Worker.get();
+		} else {
+			let _g = options.worker;
+			if(_g == null) {
+				tmp = tink_io_Worker.get();
+			} else {
+				let w = _g;
+				tmp = w;
+			}
+		}
+		return new tink_io_std_OutputSink(name,target,tmp);
+	}
+}
+class tink_io__$Sink_FutureSink extends tink_io_SinkBase {
+	constructor(f) {
+		super();
+		this.f = f;
+	}
+	consume(source,options) {
+		return tink_core_Future.flatMap(this.f,function(sink) {
+			return sink.consume(source,options);
+		});
+	}
+}
+tink_io__$Sink_FutureSink.__name__ = "tink.io._Sink.FutureSink";
+tink_io__$Sink_FutureSink.__super__ = tink_io_SinkBase;
+Object.assign(tink_io__$Sink_FutureSink.prototype, {
+	__class__: tink_io__$Sink_FutureSink
+});
+class tink_io__$Sink_ErrorSink extends tink_io_SinkBase {
+	constructor(error) {
+		super();
+		this.error = error;
+	}
+	get_sealed() {
+		return false;
+	}
+	consume(source,options) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_PipeResult.SinkFailed(this.error,source)));
+	}
+}
+tink_io__$Sink_ErrorSink.__name__ = "tink.io._Sink.ErrorSink";
+tink_io__$Sink_ErrorSink.__super__ = tink_io_SinkBase;
+Object.assign(tink_io__$Sink_ErrorSink.prototype, {
+	__class__: tink_io__$Sink_ErrorSink
+});
+class tink_streams_StreamObject {
+}
+tink_streams_StreamObject.__name__ = "tink.streams.StreamObject";
+tink_streams_StreamObject.__isInterface__ = true;
+Object.assign(tink_streams_StreamObject.prototype, {
+	__class__: tink_streams_StreamObject
+});
+class tink_streams_StreamBase {
+	constructor() {
+		if(tink_streams_StreamBase._hx_skip_constructor) {
+			return;
+		}
+		this._hx_constructor();
+	}
+	_hx_constructor() {
+		this.retainCount = 0;
+	}
+	get_depleted() {
+		return false;
+	}
+	retain() {
+		this.retainCount++;
+		let retained = true;
+		let _gthis = this;
+		return function() {
+			if(retained) {
+				retained = false;
+				if(--_gthis.retainCount == 0) {
+					_gthis.destroy();
+				}
+			}
+		};
+	}
+	next() {
+		throw haxe_Exception.thrown("not implemented");
+	}
+	regroup(f) {
+		return new tink_streams__$Stream_RegroupStream(this,f);
+	}
+	map(f) {
+		return this.regroup(f);
+	}
+	filter(f) {
+		return this.regroup(f);
+	}
+	destroy() {
+	}
+	append(other) {
+		if(this.get_depleted()) {
+			return other;
+		} else {
+			return tink_streams__$Stream_CompoundStream.of([this,other]);
+		}
+	}
+	prepend(other) {
+		if(this.get_depleted()) {
+			return other;
+		} else {
+			return tink_streams__$Stream_CompoundStream.of([other,this]);
+		}
+	}
+	blend(other) {
+		if(this.get_depleted()) {
+			return other;
+		} else {
+			return new tink_streams_BlendStream(this,other);
+		}
+	}
+	decompose(into) {
+		if(!this.get_depleted()) {
+			into.push(this);
+		}
+	}
+	idealize(rescue) {
+		if(this.get_depleted()) {
+			return tink_streams_Empty.inst;
+		} else {
+			return new tink_streams_IdealizeStream(this,rescue);
+		}
+	}
+	reduce(initial,reducer) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			_gthis.forEach(tink_streams_Handler.ofUnknown(function(item) {
+				return tink_core_Future.map(reducer(initial,item),function(o) {
+					switch(o._hx_index) {
+					case 0:
+						let v = o.result;
+						initial = v;
+						return tink_streams_Handled.Resume;
+					case 1:
+						let e = o.e;
+						return tink_streams_Handled.Clog(e);
+					}
+				});
+			})).handle(function(c) {
+				switch(c._hx_index) {
+				case 0:
+					let _g = c.rest;
+					throw haxe_Exception.thrown("assert");
+				case 1:
+					let e = c.error;
+					let rest = c.at;
+					cb(tink_streams_Reduction.Crashed(e,rest));
+					break;
+				case 2:
+					let e1 = c.error;
+					cb(tink_streams_Reduction.Failed(e1));
+					break;
+				case 3:
+					cb(tink_streams_Reduction.Reduced(initial));
+					break;
+				}
+			});
+		});
+	}
+	forEach(handler) {
+		throw haxe_Exception.thrown("not implemented");
+	}
+}
+tink_streams_StreamBase.__name__ = "tink.streams.StreamBase";
+tink_streams_StreamBase.__interfaces__ = [tink_streams_StreamObject];
+Object.assign(tink_streams_StreamBase.prototype, {
+	__class__: tink_streams_StreamBase
+});
+class tink_streams_Empty extends tink_streams_StreamBase {
+	constructor() {
+		super();
+	}
+	get_depleted() {
+		return true;
+	}
+	next() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.End));
+	}
+	forEach(handler) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Conclusion.Depleted));
+	}
+	static make() {
+		return tink_streams_Empty.inst;
+	}
+}
+tink_streams_Empty.__name__ = "tink.streams.Empty";
+tink_streams_Empty.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_Empty.prototype, {
+	__class__: tink_streams_Empty
+});
+class tink_io_Source {
+	static dirty(this1) {
+		return this1;
+	}
+	static get_depleted(this1) {
+		return this1.get_depleted();
+	}
+	static ofNodeStream(name,r,options) {
+		if(options == null) {
+			options = { };
+		}
+		return tink_io_nodejs_NodejsSource.wrap(name,r,options.chunkSize,options.onEnd);
+	}
+	static toNodeStream(this1) {
+		let native = new js_node_stream_PassThrough();
+		let source = tink_io_Source.chunked(this1);
+		let write = null;
+		write = function() {
+			source.forEach(tink_streams_Handler.ofSafeSync(function(chunk) {
+				let native1 = native;
+				let b = chunk.toBytes();
+				let data = b.b;
+				let ok = native1.write(js_node_buffer_Buffer.from(data.buffer,data.byteOffset,b.length));
+				if(ok) {
+					return tink_streams_Handled.Resume;
+				} else {
+					return tink_streams_Handled.Finish;
+				}
+			})).handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let rest = o.rest;
+					source = rest;
+					break;
+				case 2:
+					let e = o.error;
+					native.emit("error",new Error(e.message));
+					break;
+				case 3:
+					native.removeListener("drain",write);
+					native.end();
+					break;
+				}
+			});
+		};
+		let f = write;
+		let time_ms = 1;
+		let tmp = function() {
+			return haxe_Timer.delay(f,time_ms);
+		};
+		native.on("drain",tmp);
+		write();
+		return native;
+	}
+	static ofJsFile(name,file,options) {
+		let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+		return new tink_io_js_BlobSource(name,file,0,chunkSize);
+	}
+	static ofJsBlob(name,blob,options) {
+		let chunkSize = options == null || options.chunkSize == null ? 16777216 : options.chunkSize;
+		return new tink_io_js_BlobSource(name,blob,0,chunkSize);
+	}
+	static ofInput(name,input,options) {
+		if(options == null) {
+			options = { };
+		}
+		let tmp = tink_io_Worker.ensure(options.worker);
+		let length;
+		let _g = options.chunkSize;
+		if(_g == null) {
+			length = 65536;
+		} else {
+			let v = _g;
+			length = v;
+		}
+		return new tink_io_std_InputSource(name,input,tmp,new haxe_io_Bytes(new ArrayBuffer(length)),0);
+	}
+	static chunked(this1) {
+		return this1;
+	}
+	static concatAll(s) {
+		return s.reduce(tink_Chunk.EMPTY,tink_streams_Reducer.ofSafeSync(function(res,cur) {
+			return tink_streams_ReductionStep.Progress(tink_Chunk.concat(res,cur));
+		}));
+	}
+	static pipeTo(this1,target,options) {
+		return target.consume(this1,options);
+	}
+	static append(this1,that) {
+		return this1.append(that);
+	}
+	static prepend(this1,that) {
+		return this1.prepend(that);
+	}
+	static transform(this1,transformer) {
+		return transformer.transform(this1);
+	}
+	static skip(this1,len) {
+		return this1.regroup(tink_streams_Regrouper.ofIgnoranceSync(function(chunks) {
+			let chunk = chunks[0];
+			if(len <= 0) {
+				return tink_streams_RegroupResult.Converted(tink_streams_Stream.single(chunk));
+			}
+			let length = chunk.getLength();
+			let out = tink_streams_RegroupResult.Converted(len < length ? tink_streams_Stream.single(chunk.slice(len,length)) : tink_streams_Empty.inst);
+			len -= length;
+			return out;
+		}));
+	}
+	static limit(this1,len) {
+		if(len == 0) {
+			return tink_io_Source.EMPTY;
+		}
+		return this1.regroup(tink_streams_Regrouper.ofIgnoranceSync(function(chunks) {
+			if(len <= 0) {
+				return tink_streams_RegroupResult.Terminated(haxe_ds_Option.None);
+			}
+			let chunk = chunks[0];
+			let length = chunk.getLength();
+			let out = len == length ? tink_streams_RegroupResult.Terminated(haxe_ds_Option.Some(tink_streams_Stream.single(chunk))) : tink_streams_RegroupResult.Converted(tink_streams_Stream.single(len < length ? chunk.slice(0,len) : chunk));
+			len -= length;
+			return out;
+		}));
+	}
+	static ofError(e) {
+		return tink_streams_Stream.ofError(e);
+	}
+	static ofFuture(f) {
+		return tink_streams_Stream.future(f);
+	}
+	static ofPromised(p) {
+		return tink_streams_Stream.future(tink_core_Future.map(p,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let s = o.data;
+				return s;
+			case 1:
+				let e = o.failure;
+				return tink_io_Source.ofError(e);
+			}
+		}));
+	}
+	static ofChunk(chunk) {
+		return new tink_streams_Single(new tink_core__$Lazy_LazyConst(chunk));
+	}
+	static ofString(s) {
+		return new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(s))));
+	}
+	static ofBytes(b) {
+		return new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_chunk_ByteChunk.of(b)));
+	}
+	static ofFutureChunk(chunk) {
+		return tink_io_Source.ofFuture(tink_core_Future.map(chunk,tink_io_Source.ofChunk));
+	}
+	static ofFutureString(s) {
+		return tink_io_Source.ofFuture(tink_core_Future.map(s,tink_io_Source.ofString));
+	}
+	static ofFutureBytes(b) {
+		return tink_io_Source.ofFuture(tink_core_Future.map(b,tink_io_Source.ofBytes));
+	}
+	static ofPromiseChunk(chunk) {
+		return tink_io_Source.ofPromised(tink_core_Promise.next(chunk,tink_core_Next.ofSafeSync(tink_io_Source.ofChunk)));
+	}
+	static ofPromiseString(s) {
+		return tink_io_Source.ofPromised(tink_core_Promise.next(s,tink_core_Next.ofSafeSync(tink_io_Source.ofString)));
+	}
+	static ofPromiseBytes(b) {
+		return tink_io_Source.ofPromised(tink_core_Promise.next(b,tink_core_Next.ofSafeSync(tink_io_Source.ofBytes)));
+	}
+}
+class tink_io_RealSourceTools {
+	static all(s) {
+		return tink_core_Future.map(tink_io_Source.concatAll(s),function(o) {
+			switch(o._hx_index) {
+			case 1:
+				let e = o.error;
+				return tink_core_Outcome.Failure(e);
+			case 2:
+				let c = o.result;
+				return tink_core_Outcome.Success(c);
+			}
+		});
+	}
+	static parse(s,p) {
+		return tink_core_Future.map(tink_io_StreamParser.parse(s,p),function(r) {
+			switch(r._hx_index) {
+			case 0:
+				let data = r.data;
+				let rest = r.rest;
+				return tink_core_Outcome.Success(new tink_core_MPair(data,rest));
+			case 1:
+				let _g = r.rest;
+				let e = r.e;
+				return tink_core_Outcome.Failure(e);
+			case 2:
+				let e1 = r.e;
+				return tink_core_Outcome.Failure(e1);
+			}
+		});
+	}
+	static split(src,delim) {
+		let s = tink_io_RealSourceTools.parse(src,new tink_io_Splitter(delim));
+		return { before : tink_streams_Stream.promise(tink_core_Promise.next(s,tink_core_Next.ofSafeSync(function(p) {
+			let _g = p.a;
+			switch(_g._hx_index) {
+			case 0:
+				let chunk = _g.v;
+				return new tink_streams_Single(new tink_core__$Lazy_LazyConst(chunk));
+			case 1:
+				return src;
+			}
+		}))), delimiter : tink_core_Promise.next(s,function(p) {
+			let _g = p.a;
+			switch(_g._hx_index) {
+			case 0:
+				let _g1 = _g.v;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(delim)));
+			case 1:
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Failure(new tink_core_TypedError(404,"Delimiter not found",{ fileName : "tink/io/Source.hx", lineNumber : 213, className : "tink.io.RealSourceTools", methodName : "split"}))));
+			}
+		}), after : tink_streams_Stream.promise(tink_core_Promise.next(s,tink_core_Next.ofSafeSync(function(p) {
+			return p.b;
+		})))};
+	}
+	static parseStream(s,p) {
+		return tink_io_StreamParser.parseStream(s,p);
+	}
+	static idealize(s,rescue) {
+		return tink_io_Source.chunked(s).idealize(rescue);
+	}
+}
+tink_io_RealSourceTools.__name__ = "tink.io.RealSourceTools";
+class tink_io_IdealSourceTools {
+	static all(s) {
+		return tink_core_Future.map(tink_io_Source.concatAll(s),function(o) {
+			let c = o.result;
+			return c;
+		});
+	}
+	static parse(s,p) {
+		return tink_core_Future.map(tink_io_StreamParser.parse(s,p),function(r) {
+			switch(r._hx_index) {
+			case 0:
+				let data = r.data;
+				let rest = r.rest;
+				return tink_core_Outcome.Success(new tink_core_MPair(data,rest));
+			case 1:
+				let _g = r.rest;
+				let e = r.e;
+				return tink_core_Outcome.Failure(e);
+			}
+		});
+	}
+	static parseStream(s,p) {
+		return tink_io_StreamParser.parseStream(s,p);
+	}
+	static split(s,delim) {
+		let s1 = tink_io_RealSourceTools.split(s,delim);
+		return { before : tink_io_RealSourceTools.idealize(s1.before,function(e) {
+			return tink_io_Source.EMPTY;
+		}), delimiter : s1.delimiter, after : tink_io_RealSourceTools.idealize(s1.after,function(e) {
+			return tink_io_Source.EMPTY;
+		})};
+	}
+}
+tink_io_IdealSourceTools.__name__ = "tink.io.IdealSourceTools";
+var tink_io_ParseResult = $hxEnums["tink.io.ParseResult"] = { __ename__:true,__constructs__:null
+	,Parsed: ($_=function(data,rest) { return {_hx_index:0,data:data,rest:rest,__enum__:"tink.io.ParseResult",toString:$estr}; },$_._hx_name="Parsed",$_.__params__ = ["data","rest"],$_)
+	,Invalid: ($_=function(e,rest) { return {_hx_index:1,e:e,rest:rest,__enum__:"tink.io.ParseResult",toString:$estr}; },$_._hx_name="Invalid",$_.__params__ = ["e","rest"],$_)
+	,Broke: ($_=function(e) { return {_hx_index:2,e:e,__enum__:"tink.io.ParseResult",toString:$estr}; },$_._hx_name="Broke",$_.__params__ = ["e"],$_)
+};
+tink_io_ParseResult.__constructs__ = [tink_io_ParseResult.Parsed,tink_io_ParseResult.Invalid,tink_io_ParseResult.Broke];
+class tink_io_StreamParser {
+	static doParse(source,p,consume,finish) {
+		let cursor = tink_Chunk.EMPTY.getCursor();
+		let resume = true;
+		let mk = function(source) {
+			if(cursor.currentPos < cursor.length) {
+				return source.prepend(new tink_streams_Single(new tink_core__$Lazy_LazyConst(cursor.right())));
+			} else {
+				return source;
+			}
+		};
+		let flush = function() {
+			let _g = cursor.flush();
+			let c = _g;
+			if(c.getLength() == 0) {
+				return tink_io_Source.EMPTY;
+			} else {
+				let c = _g;
+				return new tink_streams_Single(new tink_core__$Lazy_LazyConst(c));
+			}
+		};
+		return tink_core_Future.flatMap(source.forEach(tink_streams_Handler.ofUnknown(function(chunk) {
+			if(chunk.getLength() == 0) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Handled.Resume));
+			}
+			cursor.shift(chunk);
+			return tink_core_Future.async(function(cb) {
+				let next = null;
+				next = function() {
+					cursor.shift();
+					let lastPos = cursor.currentPos;
+					let _g = p.progress(cursor);
+					switch(_g._hx_index) {
+					case 0:
+						if(lastPos != cursor.currentPos && cursor.currentPos < cursor.length) {
+							next();
+						} else {
+							cb(tink_streams_Handled.Resume);
+						}
+						break;
+					case 1:
+						let v = _g.r;
+						consume(v).handle(function(o) {
+							resume = o.resume;
+							if(resume) {
+								if(lastPos != cursor.currentPos && cursor.currentPos < cursor.length) {
+									next();
+								} else {
+									cb(tink_streams_Handled.Resume);
+								}
+							} else {
+								cb(tink_streams_Handled.Finish);
+							}
+						});
+						break;
+					case 2:
+						let e = _g.e;
+						cb(tink_streams_Handled.Clog(e));
+						break;
+					}
+				};
+				next();
+			});
+		})),function(c) {
+			switch(c._hx_index) {
+			case 0:
+				let rest = c.rest;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Parsed(finish(),mk(rest))));
+			case 1:
+				let e = c.error;
+				let rest1 = c.at;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Invalid(e,mk(rest1))));
+			case 2:
+				let e1 = c.error;
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Broke(e1)));
+			case 3:
+				if(cursor.currentPos < cursor.length) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Parsed(finish(),mk(new tink_streams_Single(new tink_core__$Lazy_LazyConst(tink_Chunk.EMPTY))))));
+				} else if(!resume) {
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Parsed(finish(),flush())));
+				} else {
+					let _g = p.eof(cursor);
+					switch(_g._hx_index) {
+					case 0:
+						let result = _g.data;
+						return tink_core_Future.map(consume(result),function(_) {
+							return tink_io_ParseResult.Parsed(finish(),flush());
+						});
+					case 1:
+						let e = _g.failure;
+						return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_io_ParseResult.Invalid(e,flush())));
+					}
+				}
+				break;
+			}
+		});
+	}
+	static parse(s,p) {
+		let res = null;
+		let onResult = function(r) {
+			res = r;
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst({ resume : false}));
+		};
+		return tink_io_StreamParser.doParse(s,p,onResult,function() {
+			return res;
+		});
+	}
+	static parseStream(s,p) {
+		let next = null;
+		next = function(step) {
+			if(s.get_depleted()) {
+				step(tink_streams_Step.End);
+			} else {
+				tink_io_StreamParser.parse(s,p).handle(function(o) {
+					switch(o._hx_index) {
+					case 0:
+						let result = o.data;
+						let rest = o.rest;
+						s = rest;
+						step(tink_streams_Step.Link(result,tink_streams_Generator.stream(next)));
+						break;
+					case 1:
+						let _g = o.rest;
+						let e = o.e;
+						step(tink_streams_Step.Fail(e));
+						break;
+					case 2:
+						let e1 = o.e;
+						step(tink_streams_Step.Fail(e1));
+						break;
+					}
+				});
+			}
+		};
+		return tink_streams_Generator.stream(next);
+	}
+}
+class tink_io_Splitter extends tink_io_BytewiseParser {
+	constructor(delim) {
+		super();
+		this.buf = tink_Chunk.EMPTY;
+		this.delim = delim;
+	}
+	read(char) {
+		if(char == -1) {
+			return tink_io_ParseStep.Done(haxe_ds_Option.None);
+		}
+		this.buf = tink_Chunk.concat(this.buf,tink_chunk_ByteChunk.of(haxe_io_Bytes.ofString(String.fromCodePoint(char))));
+		if(this.buf.getLength() >= this.delim.getLength()) {
+			let bcursor = this.buf.getCursor();
+			let delta = this.buf.getLength() - this.delim.getLength();
+			bcursor.moveTo(bcursor.currentPos + delta);
+			let dcursor = this.delim.getCursor();
+			let _g = 0;
+			let _g1 = this.delim.getLength();
+			while(_g < _g1) {
+				let i = _g++;
+				if(bcursor.currentByte != dcursor.currentByte) {
+					return tink_io_ParseStep.Progressed;
+				} else {
+					bcursor.next();
+					dcursor.next();
+				}
+			}
+			let out = tink_io_ParseStep.Done(haxe_ds_Option.Some(this.buf.slice(0,bcursor.currentPos - this.delim.getLength())));
+			this.buf = tink_Chunk.EMPTY;
+			return out;
+		} else {
+			return tink_io_ParseStep.Progressed;
+		}
+	}
+}
+tink_io_Splitter.__name__ = "tink.io.Splitter";
+tink_io_Splitter.__super__ = tink_io_BytewiseParser;
+Object.assign(tink_io_Splitter.prototype, {
+	__class__: tink_io_Splitter
+});
+class tink_io_SimpleBytewiseParser extends tink_io_BytewiseParser {
+	constructor(f) {
+		super();
+		this._read = f;
+	}
+	read(char) {
+		return this._read(char);
+	}
+}
+tink_io_SimpleBytewiseParser.__name__ = "tink.io.SimpleBytewiseParser";
+tink_io_SimpleBytewiseParser.__super__ = tink_io_BytewiseParser;
+Object.assign(tink_io_SimpleBytewiseParser.prototype, {
+	__class__: tink_io_SimpleBytewiseParser
+});
+class tink_io_WorkerObject {
+}
+tink_io_WorkerObject.__name__ = "tink.io.WorkerObject";
+tink_io_WorkerObject.__isInterface__ = true;
+Object.assign(tink_io_WorkerObject.prototype, {
+	__class__: tink_io_WorkerObject
+});
+class tink_io__$Worker_EagerWorker {
+	constructor() {
+	}
+	work(task) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Lazy.get(task)));
+	}
+}
+tink_io__$Worker_EagerWorker.__name__ = "tink.io._Worker.EagerWorker";
+tink_io__$Worker_EagerWorker.__interfaces__ = [tink_io_WorkerObject];
+Object.assign(tink_io__$Worker_EagerWorker.prototype, {
+	__class__: tink_io__$Worker_EagerWorker
+});
+class tink_io_Worker {
+	static ensure(this1) {
+		if(this1 == null) {
+			return tink_io_Worker.get();
+		} else {
+			return this1;
+		}
+	}
+	static get() {
+		return tink_io_Worker.pool[Std.random(tink_io_Worker.pool.length)];
+	}
+	static work(this1,task) {
+		return this1.work(task);
+	}
+}
+class tink_streams_Generator extends tink_streams_StreamBase {
+	constructor(upcoming) {
+		if(tink_streams_StreamBase._hx_skip_constructor) {
+			super();
+			return;
+		}
+		tink_streams_StreamBase._hx_skip_constructor = true;
+		super();
+		tink_streams_StreamBase._hx_skip_constructor = false;
+		this._hx_constructor(upcoming);
+	}
+	_hx_constructor(upcoming) {
+		super._hx_constructor();
+		this.upcoming = upcoming;
+	}
+	next() {
+		return this.upcoming;
+	}
+	forEach(handler) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			_gthis.upcoming.handle(function(e) {
+				switch(e._hx_index) {
+				case 0:
+					let v = e.value;
+					let then = e.next;
+					handler(v).handle(function(s) {
+						switch(s._hx_index) {
+						case 0:
+							cb(tink_streams_Conclusion.Halted(_gthis));
+							break;
+						case 1:
+							cb(tink_streams_Conclusion.Halted(then));
+							break;
+						case 2:
+							then.forEach(handler).handle(cb);
+							break;
+						case 3:
+							let e = s.e;
+							cb(tink_streams_Conclusion.Clogged(e,_gthis));
+							break;
+						}
+					});
+					break;
+				case 1:
+					let e1 = e.e;
+					cb(tink_streams_Conclusion.Failed(e1));
+					break;
+				case 2:
+					cb(tink_streams_Conclusion.Depleted);
+					break;
+				}
+			});
+		});
+	}
+	static stream(step) {
+		return new tink_streams_Generator(tink_core_Future.async(step));
+	}
+}
+tink_streams_Generator.__name__ = "tink.streams.Generator";
+tink_streams_Generator.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_Generator.prototype, {
+	__class__: tink_streams_Generator
+});
+class tink_io_js_BlobSource extends tink_streams_Generator {
+	constructor(name,blob,pos,chunkSize) {
+		tink_streams_StreamBase._hx_skip_constructor = true;
+		super();
+		tink_streams_StreamBase._hx_skip_constructor = false;
+		this._hx_constructor(name,blob,pos,chunkSize);
+	}
+	_hx_constructor(name,blob,pos,chunkSize) {
+		this.name = name;
+		super._hx_constructor(tink_core_Future.async(function(cb) {
+			if(pos >= blob.size) {
+				cb(tink_streams_Step.End);
+			} else {
+				let end = pos + chunkSize;
+				if(end > blob.size) {
+					end = blob.size;
+				}
+				let reader = new FileReader();
+				reader.onload = function() {
+					let chunk = tink_chunk_ByteChunk.of(haxe_io_Bytes.ofData(reader.result));
+					cb(tink_streams_Step.Link(chunk,new tink_io_js_BlobSource(name,blob,end,chunkSize)));
+				};
+				reader.onerror = function(e) {
+					cb(tink_streams_Step.Fail(tink_core_TypedError.withData(500,e.message,e,{ fileName : "tink/io/js/BlobSource.hx", lineNumber : 29, className : "tink.io.js.BlobSource", methodName : "new"})));
+				};
+				reader.readAsArrayBuffer(blob.slice(pos,end));
+			}
+		},true));
+	}
+	static wrap(name,blob,chunkSize) {
+		return new tink_io_js_BlobSource(name,blob,0,chunkSize);
+	}
+}
+tink_io_js_BlobSource.__name__ = "tink.io.js.BlobSource";
+tink_io_js_BlobSource.__super__ = tink_streams_Generator;
+Object.assign(tink_io_js_BlobSource.prototype, {
+	__class__: tink_io_js_BlobSource
+});
+class tink_io_nodejs_NodejsSink extends tink_io_SinkBase {
+	constructor(target) {
+		super();
+		this.target = target;
+	}
+	consume(source,options) {
+		let _gthis = this;
+		let ret = source.forEach(tink_streams_Handler.ofUnknown(function(c) {
+			return tink_core_Future.map(_gthis.target.write(c),function(w) {
+				switch(w._hx_index) {
+				case 0:
+					if(w.data) {
+						return tink_streams_Handled.Resume;
+					} else {
+						return tink_streams_Handled.BackOff;
+					}
+					break;
+				case 1:
+					let e = w.failure;
+					return tink_streams_Handled.Clog(e);
+				}
+			});
+		}));
+		if(options != null && options.end) {
+			ret.handle(function(end) {
+				_gthis.target.end();
+			});
+		}
+		return tink_core_Future.map(ret,function(c) {
+			return tink_io_PipeResultTools.toResult(c,null);
+		});
+	}
+	static wrap(name,native) {
+		return new tink_io_nodejs_NodejsSink(new tink_io_nodejs_WrappedWritable(name,native));
+	}
+}
+tink_io_nodejs_NodejsSink.__name__ = "tink.io.nodejs.NodejsSink";
+tink_io_nodejs_NodejsSink.__super__ = tink_io_SinkBase;
+Object.assign(tink_io_nodejs_NodejsSink.prototype, {
+	__class__: tink_io_nodejs_NodejsSink
+});
+class tink_io_nodejs_NodejsSource extends tink_streams_Generator {
+	constructor(target) {
+		super(tink_core_Future.async(function(cb) {
+			target.read().handle(function(o) {
+				let cb1 = cb;
+				let tmp;
+				switch(o._hx_index) {
+				case 0:
+					let _g = o.data;
+					if(_g == null) {
+						tmp = tink_streams_Step.End;
+					} else {
+						let chunk = _g;
+						tmp = tink_streams_Step.Link(chunk,new tink_io_nodejs_NodejsSource(target));
+					}
+					break;
+				case 1:
+					let e = o.failure;
+					tmp = tink_streams_Step.Fail(e);
+					break;
+				}
+				cb1(tmp);
+			});
+		},true));
+	}
+	static wrap(name,native,chunkSize,onEnd) {
+		return new tink_io_nodejs_NodejsSource(new tink_io_nodejs_WrappedReadable(name,native,chunkSize,onEnd));
+	}
+}
+tink_io_nodejs_NodejsSource.__name__ = "tink.io.nodejs.NodejsSource";
+tink_io_nodejs_NodejsSource.__super__ = tink_streams_Generator;
+Object.assign(tink_io_nodejs_NodejsSource.prototype, {
+	__class__: tink_io_nodejs_NodejsSource
+});
+class tink_io_nodejs_WrappedReadable {
+	constructor(name,native,chunkSize,onEnd) {
+		this.name = name;
+		this.native = native;
+		this.chunkSize = chunkSize;
+		let this1 = tink_core_Future.async(function(cb) {
+			native.once("end",function() {
+				cb(tink_core_Outcome.Success(null));
+			});
+			native.once("error",function(e) {
+				cb(tink_core_Outcome.Failure(new tink_core_TypedError(null,"" + e.code + " - Failed reading from " + name + " because " + e.message,{ fileName : "tink/io/nodejs/WrappedReadable.hx", lineNumber : 22, className : "tink.io.nodejs.WrappedReadable", methodName : "new"})));
+			});
+		});
+		this1.eager();
+		this.end = this1;
+		if(onEnd != null) {
+			this.end.handle(function() {
+				process.nextTick(onEnd);
+			});
+		}
+	}
+	read() {
+		let _gthis = this;
+		return tink_core_Future.first(tink_core_Future.async(function(cb) {
+			let attempt = null;
+			attempt = function() {
+				try {
+					let _g = _gthis.native.read(_gthis.chunkSize);
+					if(_g == null) {
+						_gthis.native.once("readable",attempt);
+					} else {
+						let chunk = _g;
+						let buf = typeof(chunk) == "string" ? new js_node_buffer_Buffer(chunk) : chunk;
+						cb(tink_core_Outcome.Success(new tink_chunk_nodejs_BufferChunk(buf)));
+					}
+				} catch( _g ) {
+					let e = haxe_Exception.caught(_g).unwrap();
+					cb(tink_core_Outcome.Failure(tink_core_TypedError.withData(null,"Error while reading from " + _gthis.name,e,{ fileName : "tink/io/nodejs/WrappedReadable.hx", lineNumber : 48, className : "tink.io.nodejs.WrappedReadable", methodName : "read"})));
+				}
+			};
+			attempt();
+		}),this.end);
+	}
+}
+tink_io_nodejs_WrappedReadable.__name__ = "tink.io.nodejs.WrappedReadable";
+Object.assign(tink_io_nodejs_WrappedReadable.prototype, {
+	__class__: tink_io_nodejs_WrappedReadable
+});
+class tink_io_nodejs_WrappedWritable {
+	constructor(name,native) {
+		this.name = name;
+		this.native = native;
+		this.ended = tink_core_Future.async(function(cb) {
+			native.once("end",function() {
+				cb(tink_core_Outcome.Success(false));
+			});
+			native.once("finish",function() {
+				cb(tink_core_Outcome.Success(false));
+			});
+			native.once("close",function() {
+				cb(tink_core_Outcome.Success(false));
+			});
+			native.on("error",function(e) {
+				cb(tink_core_Outcome.Failure(new tink_core_TypedError(null,"" + e.code + ": " + e.message,{ fileName : "tink/io/nodejs/WrappedWritable.hx", lineNumber : 24, className : "tink.io.nodejs.WrappedWritable", methodName : "new"})));
+			});
+		});
+	}
+	end() {
+		let didEnd = false;
+		let this1 = this.ended.handle(function() {
+			didEnd = true;
+		});
+		if(this1 != null) {
+			this1.cancel();
+		}
+		if(didEnd) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(false)));
+		}
+		this.native.end();
+		return tink_core_Promise.next(this.ended,function(_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(true)));
+		});
+	}
+	write(chunk) {
+		let _gthis = this;
+		return tink_core_Future.first(tink_core_Future.async(function(cb) {
+			if(chunk.getLength() == 0) {
+				cb(tink_core_Outcome.Success(true));
+				return;
+			}
+			let buf;
+			if(js_node_buffer_Buffer.isBuffer(chunk.buffer)) {
+				buf = chunk.buffer;
+			} else {
+				let b = chunk.toBytes();
+				let data = b.b;
+				buf = js_node_buffer_Buffer.from(data.buffer,data.byteOffset,b.length);
+			}
+			let _g = cb;
+			let a1 = tink_core_Outcome.Success(true);
+			let tmp = function() {
+				_g(a1);
+			};
+			_gthis.native.write(buf,null,tmp);
+		}),this.ended);
+	}
+}
+tink_io_nodejs_WrappedWritable.__name__ = "tink.io.nodejs.WrappedWritable";
+Object.assign(tink_io_nodejs_WrappedWritable.prototype, {
+	__class__: tink_io_nodejs_WrappedWritable
+});
+class tink_io_std_InputSource extends tink_streams_Generator {
+	constructor(name,target,worker,buf,offset) {
+		let next = function(buf,offset) {
+			return new tink_io_std_InputSource(name,target,worker,buf,offset);
+		};
+		let free = buf.length - offset;
+		super(tink_core_Future.async(function(cb) {
+			tink_io_Worker.work(worker,new tink_core__$Lazy_LazyFunc(function() {
+				try {
+					let read = target.readBytes(buf,offset,free);
+					if(read == 0) {
+						return tink_streams_Step.Link(tink_Chunk.EMPTY,next(buf,offset));
+					} else {
+						let nextOffset = free - read < 1024 ? 0 : offset + read;
+						let nextBuf = nextOffset == 0 ? new haxe_io_Bytes(new ArrayBuffer(buf.length)) : buf;
+						return tink_streams_Step.Link(tink_chunk_ByteChunk.of(buf).slice(offset,offset + read),next(nextBuf,nextOffset));
+					}
+				} catch( _g ) {
+					let _g1 = haxe_Exception.caught(_g).unwrap();
+					if(((_g1) instanceof haxe_io_Eof)) {
+						return tink_streams_Step.End;
+					} else if(js_Boot.__instanceof(_g1,haxe_io_Error)) {
+						let e = _g1;
+						if(e._hx_index == 0) {
+							return tink_streams_Step.Link(tink_Chunk.EMPTY,next(buf,offset));
+						} else {
+							return tink_streams_Step.Fail(tink_core_TypedError.withData(null,"Failed to read from " + name,e,{ fileName : "tink/io/std/InputSource.hx", lineNumber : 50, className : "tink.io.std.InputSource", methodName : "new"}));
+						}
+					} else {
+						throw _g;
+					}
+				}
+			})).handle(function(step) {
+				switch(step._hx_index) {
+				case 1:
+					let _g = step.e;
+					try {
+						target.close();
+					} catch( _g ) {
+					}
+					break;
+				case 2:
+					try {
+						target.close();
+					} catch( _g ) {
+					}
+					break;
+				default:
+				}
+				cb(step);
+			});
+		},true));
+	}
+}
+tink_io_std_InputSource.__name__ = "tink.io.std.InputSource";
+tink_io_std_InputSource.__super__ = tink_streams_Generator;
+Object.assign(tink_io_std_InputSource.prototype, {
+	__class__: tink_io_std_InputSource
+});
+class tink_io_std_OutputSink extends tink_io_SinkBase {
+	constructor(name,target,worker) {
+		super();
+		this.name = name;
+		this.target = target;
+		this.worker = worker;
+	}
+	consume(source,options) {
+		let rest = tink_Chunk.EMPTY;
+		let _gthis = this;
+		let ret = source.forEach(tink_streams_Handler.ofUnknown(function(c) {
+			return tink_core_Future.async(function(cb) {
+				let pos = 0;
+				let bytes = c.toBytes();
+				let write = null;
+				write = function() {
+					if(pos == bytes.length) {
+						cb(tink_streams_Handled.Resume);
+					} else {
+						tink_io_Worker.work(_gthis.worker,new tink_core__$Lazy_LazyFunc(function() {
+							try {
+								return tink_core_Outcome.Success(_gthis.target.writeBytes(bytes,pos,bytes.length - pos));
+							} catch( _g ) {
+								let _g1 = haxe_Exception.caught(_g).unwrap();
+								if(((_g1) instanceof haxe_io_Eof)) {
+									return tink_core_Outcome.Success(-1);
+								} else if(js_Boot.__instanceof(_g1,haxe_io_Error)) {
+									let e = _g1;
+									if(e._hx_index == 0) {
+										return tink_core_Outcome.Success(0);
+									} else {
+										return tink_core_Outcome.Failure(tink_core_TypedError.withData(null,"Error writing to " + _gthis.name,e,{ fileName : "tink/io/std/OutputSink.hx", lineNumber : 40, className : "tink.io.std.OutputSink", methodName : "consume"}));
+									}
+								} else if(((_g1) instanceof tink_core_TypedError)) {
+									let e = _g1;
+									return tink_core_Outcome.Failure(e);
+								} else {
+									let e = _g1;
+									return tink_core_Outcome.Failure(tink_core_TypedError.withData(null,"Error writing to " + _gthis.name,e,{ fileName : "tink/io/std/OutputSink.hx", lineNumber : 46, className : "tink.io.std.OutputSink", methodName : "consume"}));
+								}
+							}
+						})).handle(function(o) {
+							switch(o._hx_index) {
+							case 0:
+								let _g = o.data;
+								if(_g == -1) {
+									rest = tink_chunk_ByteChunk.of(bytes).slice(pos,bytes.length);
+									cb(tink_streams_Handled.Finish);
+								} else {
+									let v = _g;
+									pos += v;
+									if(pos == bytes.length) {
+										cb(tink_streams_Handled.Resume);
+									} else {
+										write();
+									}
+								}
+								break;
+							case 1:
+								let e = o.failure;
+								cb(tink_streams_Handled.Clog(e));
+								break;
+							}
+						});
+					}
+				};
+				write();
+			});
+		}));
+		if(options != null && options.end) {
+			ret.handle(function(end) {
+				try {
+					_gthis.target.close();
+				} catch( _g ) {
+				}
+			});
+		}
+		return tink_core_Future.map(ret,function(c) {
+			return tink_io_PipeResultTools.toResult(c,null,rest);
+		});
+	}
+}
+tink_io_std_OutputSink.__name__ = "tink.io.std.OutputSink";
+tink_io_std_OutputSink.__super__ = tink_io_SinkBase;
+Object.assign(tink_io_std_OutputSink.prototype, {
+	__class__: tink_io_std_OutputSink
+});
+class tink_streams_IdealStream {
+	static promiseOfIdealStream(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static promiseOfStreamNoise(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static collect(this1) {
+		let buf = [];
+		return tink_core_Future.map(this1.forEach(tink_streams_Handler.ofSafeSync(function(x) {
+			buf.push(x);
+			return tink_streams_Handled.Resume;
+		})),function(c) {
+			return buf;
+		});
+	}
+}
+class tink_streams_IdealStreamBase extends tink_streams_StreamBase {
+	constructor() {
+		super();
+	}
+	idealize(rescue) {
+		return this;
+	}
+}
+tink_streams_IdealStreamBase.__name__ = "tink.streams.IdealStreamBase";
+tink_streams_IdealStreamBase.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_IdealStreamBase.prototype, {
+	__class__: tink_streams_IdealStreamBase
+});
+class tink_streams_RealStream {
+	static promiseOfIdealStream(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static promiseOfStreamNoise(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static promiseOfRealStream(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static promiseOfStreamError(p) {
+		return tink_streams_Stream.promise(p);
+	}
+	static collect(this1) {
+		let buf = [];
+		return tink_core_Future.map(this1.forEach(tink_streams_Handler.ofSafeSync(function(x) {
+			buf.push(x);
+			return tink_streams_Handled.Resume;
+		})),function(c) {
+			switch(c._hx_index) {
+			case 0:
+				let _g = c.rest;
+				throw haxe_Exception.thrown("unreachable");
+			case 2:
+				let e = c.error;
+				return tink_core_Outcome.Failure(e);
+			case 3:
+				return tink_core_Outcome.Success(buf);
+			}
+		});
+	}
+}
+class tink_streams_Stream {
+	static get_depleted(this1) {
+		return this1.get_depleted();
+	}
+	static dirty(this1) {
+		return this1;
+	}
+	static single(i) {
+		return new tink_streams_Single(new tink_core__$Lazy_LazyConst(i));
+	}
+	static ofIterator(i) {
+		let next = null;
+		next = function(step) {
+			step(i.hasNext() ? tink_streams_Step.Link(i.next(),tink_streams_Generator.stream(next)) : tink_streams_Step.End);
+		};
+		return tink_streams_Generator.stream(next);
+	}
+	static flatten(stream) {
+		return stream.regroup(tink_streams_Regrouper.ofIgnoranceSync(function(arr) {
+			return tink_streams_RegroupResult.Converted(arr[0]);
+		}));
+	}
+	static future(f) {
+		return new tink_streams_FutureStream(f);
+	}
+	static promiseIdeal(f) {
+		return tink_streams_Stream.promise(f);
+	}
+	static promiseReal(f) {
+		return tink_streams_Stream.promise(f);
+	}
+	static promise(f) {
+		return tink_streams_Stream.future(tink_core_Future.map(f,function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let s = o.data;
+				return tink_streams_Stream.dirty(s);
+			case 1:
+				let e = o.failure;
+				return tink_streams_Stream.ofError(e);
+			}
+		}));
+	}
+	static ofError(e) {
+		return new tink_streams__$Stream_ErrorStream(e);
+	}
+	static ofNodeStream(name,r,options) {
+		return tink_streams_nodejs_NodejsStream.wrap(name,r,options == null ? null : options.onEnd);
+	}
+}
+var tink_streams_RegroupStatus = $hxEnums["tink.streams.RegroupStatus"] = { __ename__:true,__constructs__:null
+	,Flowing: {_hx_name:"Flowing",_hx_index:0,__enum__:"tink.streams.RegroupStatus",toString:$estr}
+	,Errored: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.streams.RegroupStatus",toString:$estr}; },$_._hx_name="Errored",$_.__params__ = ["e"],$_)
+	,Ended: {_hx_name:"Ended",_hx_index:2,__enum__:"tink.streams.RegroupStatus",toString:$estr}
+};
+tink_streams_RegroupStatus.__constructs__ = [tink_streams_RegroupStatus.Flowing,tink_streams_RegroupStatus.Errored,tink_streams_RegroupStatus.Ended];
+var tink_streams_RegroupResult = $hxEnums["tink.streams.RegroupResult"] = { __ename__:true,__constructs__:null
+	,Converted: ($_=function(data,untouched) { return {_hx_index:0,data:data,untouched:untouched,__enum__:"tink.streams.RegroupResult",toString:$estr}; },$_._hx_name="Converted",$_.__params__ = ["data","untouched"],$_)
+	,Terminated: ($_=function(data) { return {_hx_index:1,data:data,__enum__:"tink.streams.RegroupResult",toString:$estr}; },$_._hx_name="Terminated",$_.__params__ = ["data"],$_)
+	,Untouched: {_hx_name:"Untouched",_hx_index:2,__enum__:"tink.streams.RegroupResult",toString:$estr}
+	,Errored: ($_=function(e) { return {_hx_index:3,e:e,__enum__:"tink.streams.RegroupResult",toString:$estr}; },$_._hx_name="Errored",$_.__params__ = ["e"],$_)
+};
+tink_streams_RegroupResult.__constructs__ = [tink_streams_RegroupResult.Converted,tink_streams_RegroupResult.Terminated,tink_streams_RegroupResult.Untouched,tink_streams_RegroupResult.Errored];
+class tink_streams_Regrouper {
+	static ofIgnorance(f) {
+		return { apply : function(i,_) {
+			return f(i);
+		}};
+	}
+	static ofIgnoranceSync(f) {
+		return { apply : function(i,_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(i)));
+		}};
+	}
+	static ofFunc(f) {
+		return { apply : f};
+	}
+	static ofFuncSync(f) {
+		return { apply : function(i,s) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(i,s)));
+		}};
+	}
+}
+class tink_streams__$Stream_CompoundStream extends tink_streams_StreamBase {
+	constructor(parts) {
+		super();
+		this.parts = parts;
+	}
+	get_depleted() {
+		switch(this.parts.length) {
+		case 0:
+			return true;
+		case 1:
+			return this.parts[0].get_depleted();
+		default:
+			return false;
+		}
+	}
+	next() {
+		let _gthis = this;
+		if(this.parts.length == 0) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.End));
+		} else {
+			return tink_core_Future.flatMap(this.parts[0].next(),function(v) {
+				switch(v._hx_index) {
+				case 0:
+					let v1 = v.value;
+					let rest = v.next;
+					let copy = _gthis.parts.slice();
+					copy[0] = rest;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.Link(v1,new tink_streams__$Stream_CompoundStream(copy))));
+				case 2:
+					if(_gthis.parts.length > 1) {
+						return _gthis.parts[1].next();
+					} else {
+						return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+					}
+					break;
+				default:
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+				}
+			});
+		}
+	}
+	decompose(into) {
+		let _g = 0;
+		let _g1 = this.parts;
+		while(_g < _g1.length) {
+			let p = _g1[_g];
+			++_g;
+			p.decompose(into);
+		}
+	}
+	forEach(handler) {
+		let parts = this.parts;
+		let handler1 = handler;
+		return tink_core_Future.async(function(cb) {
+			tink_streams__$Stream_CompoundStream.consumeParts(parts,handler1,cb);
+		});
+	}
+	static consumeParts(parts,handler,cb) {
+		if(parts.length == 0) {
+			cb(tink_streams_Conclusion.Depleted);
+		} else {
+			parts[0].forEach(handler).handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let rest = o.rest;
+					parts = parts.slice();
+					parts[0] = rest;
+					cb(tink_streams_Conclusion.Halted(new tink_streams__$Stream_CompoundStream(parts)));
+					break;
+				case 1:
+					let e = o.error;
+					let at = o.at;
+					if(at.get_depleted()) {
+						parts = parts.slice(1);
+					} else {
+						parts = parts.slice();
+						parts[0] = at;
+					}
+					cb(tink_streams_Conclusion.Clogged(e,new tink_streams__$Stream_CompoundStream(parts)));
+					break;
+				case 2:
+					let e1 = o.error;
+					cb(tink_streams_Conclusion.Failed(e1));
+					break;
+				case 3:
+					tink_streams__$Stream_CompoundStream.consumeParts(parts.slice(1),handler,cb);
+					break;
+				}
+			});
+		}
+	}
+	static of(streams) {
+		let ret = [];
+		let _g = 0;
+		while(_g < streams.length) {
+			let s = streams[_g];
+			++_g;
+			s.decompose(ret);
+		}
+		if(ret.length == 0) {
+			return tink_streams_Empty.inst;
+		} else {
+			return new tink_streams__$Stream_CompoundStream(ret);
+		}
+	}
+}
+tink_streams__$Stream_CompoundStream.__name__ = "tink.streams._Stream.CompoundStream";
+tink_streams__$Stream_CompoundStream.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams__$Stream_CompoundStream.prototype, {
+	__class__: tink_streams__$Stream_CompoundStream
+});
+class tink_streams__$Stream_RegroupStream extends tink_streams__$Stream_CompoundStream {
+	constructor(source,f,prev,buf) {
+		if(prev == null) {
+			prev = tink_streams_Empty.inst;
+		}
+		if(buf == null) {
+			buf = [];
+		}
+		let ret = null;
+		let terminated = false;
+		let next = tink_streams_Stream.future(tink_core_Future.map(source.forEach(tink_streams_Handler.ofUnknown(function(item) {
+			buf.push(item);
+			return tink_core_Future.map(f.apply(buf,tink_streams_RegroupStatus.Flowing),function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let v = o.data;
+					let untouched = o.untouched;
+					ret = v;
+					buf = untouched;
+					return tink_streams_Handled.Finish;
+				case 1:
+					let v1 = o.data;
+					let l = new tink_core__$Lazy_LazyFunc(tink_streams_Empty.make);
+					if(v1._hx_index == 0) {
+						let v = v1.v;
+						ret = v;
+					} else {
+						ret = tink_core_Lazy.get(l);
+					}
+					terminated = true;
+					return tink_streams_Handled.Finish;
+				case 2:
+					return tink_streams_Handled.Resume;
+				case 3:
+					let e = o.e;
+					return tink_streams_Handled.Clog(e);
+				}
+			});
+		})),function(o) {
+			switch(o._hx_index) {
+			case 0:
+				if(terminated) {
+					return ret;
+				} else {
+					let rest = o.rest;
+					return new tink_streams__$Stream_RegroupStream(rest,f,ret,buf);
+				}
+				break;
+			case 1:
+				let _g = o.at;
+				let e = o.error;
+				return new tink_streams__$Stream_ErrorStream(e);
+			case 2:
+				let e1 = o.error;
+				return tink_streams_Stream.ofError(e1);
+			case 3:
+				if(buf.length == 0) {
+					return tink_streams_Empty.inst;
+				} else {
+					return tink_streams_Stream.future(tink_core_Future.map(f.apply(buf,tink_streams_RegroupStatus.Ended),function(o) {
+						switch(o._hx_index) {
+						case 0:
+							let _g = o.untouched;
+							let v = o.data;
+							return v;
+						case 1:
+							let v1 = o.data;
+							let l = new tink_core__$Lazy_LazyFunc(tink_streams_Empty.make);
+							if(v1._hx_index == 0) {
+								let v = v1.v;
+								return v;
+							} else {
+								return tink_core_Lazy.get(l);
+							}
+							break;
+						case 2:
+							return tink_streams_Empty.inst;
+						case 3:
+							let e = o.e;
+							return tink_streams_Stream.ofError(e);
+						}
+					}));
+				}
+				break;
+			}
+		}));
+		super([prev,next]);
+	}
+}
+tink_streams__$Stream_RegroupStream.__name__ = "tink.streams._Stream.RegroupStream";
+tink_streams__$Stream_RegroupStream.__super__ = tink_streams__$Stream_CompoundStream;
+Object.assign(tink_streams__$Stream_RegroupStream.prototype, {
+	__class__: tink_streams__$Stream_RegroupStream
+});
+var tink_streams_Handled = $hxEnums["tink.streams.Handled"] = { __ename__:true,__constructs__:null
+	,BackOff: {_hx_name:"BackOff",_hx_index:0,__enum__:"tink.streams.Handled",toString:$estr}
+	,Finish: {_hx_name:"Finish",_hx_index:1,__enum__:"tink.streams.Handled",toString:$estr}
+	,Resume: {_hx_name:"Resume",_hx_index:2,__enum__:"tink.streams.Handled",toString:$estr}
+	,Clog: ($_=function(e) { return {_hx_index:3,e:e,__enum__:"tink.streams.Handled",toString:$estr}; },$_._hx_name="Clog",$_.__params__ = ["e"],$_)
+};
+tink_streams_Handled.__constructs__ = [tink_streams_Handled.BackOff,tink_streams_Handled.Finish,tink_streams_Handled.Resume,tink_streams_Handled.Clog];
+var tink_streams_Conclusion = $hxEnums["tink.streams.Conclusion"] = { __ename__:true,__constructs__:null
+	,Halted: ($_=function(rest) { return {_hx_index:0,rest:rest,__enum__:"tink.streams.Conclusion",toString:$estr}; },$_._hx_name="Halted",$_.__params__ = ["rest"],$_)
+	,Clogged: ($_=function(error,at) { return {_hx_index:1,error:error,at:at,__enum__:"tink.streams.Conclusion",toString:$estr}; },$_._hx_name="Clogged",$_.__params__ = ["error","at"],$_)
+	,Failed: ($_=function(error) { return {_hx_index:2,error:error,__enum__:"tink.streams.Conclusion",toString:$estr}; },$_._hx_name="Failed",$_.__params__ = ["error"],$_)
+	,Depleted: {_hx_name:"Depleted",_hx_index:3,__enum__:"tink.streams.Conclusion",toString:$estr}
+};
+tink_streams_Conclusion.__constructs__ = [tink_streams_Conclusion.Halted,tink_streams_Conclusion.Clogged,tink_streams_Conclusion.Failed,tink_streams_Conclusion.Depleted];
+var tink_streams_ReductionStep = $hxEnums["tink.streams.ReductionStep"] = { __ename__:true,__constructs__:null
+	,Progress: ($_=function(result) { return {_hx_index:0,result:result,__enum__:"tink.streams.ReductionStep",toString:$estr}; },$_._hx_name="Progress",$_.__params__ = ["result"],$_)
+	,Crash: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.streams.ReductionStep",toString:$estr}; },$_._hx_name="Crash",$_.__params__ = ["e"],$_)
+};
+tink_streams_ReductionStep.__constructs__ = [tink_streams_ReductionStep.Progress,tink_streams_ReductionStep.Crash];
+var tink_streams_Reduction = $hxEnums["tink.streams.Reduction"] = { __ename__:true,__constructs__:null
+	,Crashed: ($_=function(error,at) { return {_hx_index:0,error:error,at:at,__enum__:"tink.streams.Reduction",toString:$estr}; },$_._hx_name="Crashed",$_.__params__ = ["error","at"],$_)
+	,Failed: ($_=function(error) { return {_hx_index:1,error:error,__enum__:"tink.streams.Reduction",toString:$estr}; },$_._hx_name="Failed",$_.__params__ = ["error"],$_)
+	,Reduced: ($_=function(result) { return {_hx_index:2,result:result,__enum__:"tink.streams.Reduction",toString:$estr}; },$_._hx_name="Reduced",$_.__params__ = ["result"],$_)
+};
+tink_streams_Reduction.__constructs__ = [tink_streams_Reduction.Crashed,tink_streams_Reduction.Failed,tink_streams_Reduction.Reduced];
+class tink_streams__$Stream_CloggedStream extends tink_streams_StreamBase {
+	constructor(rest,error) {
+		super();
+		this.rest = rest;
+		this.error = error;
+	}
+	next() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.Fail(this.error)));
+	}
+	forEach(handler) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Conclusion.Clogged(this.error,this.rest)));
+	}
+}
+tink_streams__$Stream_CloggedStream.__name__ = "tink.streams._Stream.CloggedStream";
+tink_streams__$Stream_CloggedStream.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams__$Stream_CloggedStream.prototype, {
+	__class__: tink_streams__$Stream_CloggedStream
+});
+class tink_streams__$Stream_ErrorStream extends tink_streams_StreamBase {
+	constructor(error) {
+		super();
+		this.error = error;
+	}
+	next() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.Fail(this.error)));
+	}
+	forEach(handler) {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Conclusion.Failed(this.error)));
+	}
+}
+tink_streams__$Stream_ErrorStream.__name__ = "tink.streams._Stream.ErrorStream";
+tink_streams__$Stream_ErrorStream.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams__$Stream_ErrorStream.prototype, {
+	__class__: tink_streams__$Stream_ErrorStream
+});
+class tink_streams_Mapping {
+	static _new(o) {
+		return o;
+	}
+	static ofNext(n) {
+		return { apply : function(i,_) {
+			let this1 = tink_core_Promise.next(n(i[0]),function(o) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(tink_streams_RegroupResult.Converted(tink_streams_Stream.single(o)))));
+			});
+			let f = tink_core_Recover.ofSync(tink_streams_RegroupResult.Errored);
+			return tink_core_Future.flatMap(this1,function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let d = o.data;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(d));
+				case 1:
+					let e = o.failure;
+					return f(e);
+				}
+			});
+		}};
+	}
+	static ofAsync(f) {
+		return { apply : function(i,_) {
+			return tink_core_Future.map(f(i[0]),function(o) {
+				return tink_streams_RegroupResult.Converted(tink_streams_Stream.single(o));
+			});
+		}};
+	}
+	static ofSync(f) {
+		return { apply : function(i,_) {
+			let v;
+			let _g = f(i[0]);
+			switch(_g._hx_index) {
+			case 0:
+				let v1 = _g.data;
+				v = tink_streams_RegroupResult.Converted(tink_streams_Stream.single(v1));
+				break;
+			case 1:
+				let e = _g.failure;
+				v = tink_streams_RegroupResult.Errored(e);
+				break;
+			}
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+		}};
+	}
+	static ofPlain(f) {
+		return { apply : function(i,_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_RegroupResult.Converted(tink_streams_Stream.single(f(i[0])))));
+		}};
+	}
+}
+class tink_streams_Filter {
+	static _new(o) {
+		return o;
+	}
+	static ofNext(n) {
+		return { apply : function(i,_) {
+			let this1 = tink_core_Promise.next(n(i[0]),function(matched) {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(tink_streams_RegroupResult.Converted(matched ? tink_streams_Stream.single(i[0]) : tink_streams_Empty.inst))));
+			});
+			let f = tink_core_Recover.ofSync(tink_streams_RegroupResult.Errored);
+			return tink_core_Future.flatMap(this1,function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let d = o.data;
+					return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(d));
+				case 1:
+					let e = o.failure;
+					return f(e);
+				}
+			});
+		}};
+	}
+	static ofAsync(f) {
+		return { apply : function(i,_) {
+			return tink_core_Future.map(f(i[0]),function(matched) {
+				return tink_streams_RegroupResult.Converted(matched ? tink_streams_Stream.single(i[0]) : tink_streams_Empty.inst);
+			});
+		}};
+	}
+	static ofSync(f) {
+		return { apply : function(i,_) {
+			let v;
+			let _g = f(i[0]);
+			switch(_g._hx_index) {
+			case 0:
+				let v1 = _g.data;
+				v = tink_streams_RegroupResult.Converted(v1 ? tink_streams_Stream.single(i[0]) : tink_streams_Empty.inst);
+				break;
+			case 1:
+				let e = _g.failure;
+				v = tink_streams_RegroupResult.Errored(e);
+				break;
+			}
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+		}};
+	}
+	static ofPlain(f) {
+		return { apply : function(i,_) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_RegroupResult.Converted(f(i[0]) ? tink_streams_Stream.single(i[0]) : tink_streams_Empty.inst)));
+		}};
+	}
+}
+class tink_streams_IdealizeStream extends tink_streams_IdealStreamBase {
+	constructor(target,rescue) {
+		super();
+		this.target = target;
+		this.rescue = rescue;
+	}
+	get_depleted() {
+		return this.target.get_depleted();
+	}
+	next() {
+		let _gthis = this;
+		return tink_core_Future.flatMap(this.target.next(),function(v) {
+			if(v._hx_index == 1) {
+				let e = v.e;
+				return _gthis.rescue(e).idealize(_gthis.rescue).next();
+			} else {
+				return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(v));
+			}
+		});
+	}
+	forEach(handler) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			_gthis.target.forEach(handler).handle(function(end) {
+				switch(end._hx_index) {
+				case 0:
+					let rest = end.rest;
+					cb(tink_streams_Conclusion.Halted(rest.idealize(_gthis.rescue)));
+					break;
+				case 1:
+					let e = end.error;
+					let at = end.at;
+					cb(tink_streams_Conclusion.Clogged(e,at.idealize(_gthis.rescue)));
+					break;
+				case 2:
+					let e1 = end.error;
+					_gthis.rescue(e1).idealize(_gthis.rescue).forEach(handler).handle(cb);
+					break;
+				case 3:
+					cb(tink_streams_Conclusion.Depleted);
+					break;
+				}
+			});
+		});
+	}
+}
+tink_streams_IdealizeStream.__name__ = "tink.streams.IdealizeStream";
+tink_streams_IdealizeStream.__super__ = tink_streams_IdealStreamBase;
+Object.assign(tink_streams_IdealizeStream.prototype, {
+	__class__: tink_streams_IdealizeStream
+});
+class tink_streams_Single extends tink_streams_StreamBase {
+	constructor(value) {
+		super();
+		this.value = value;
+	}
+	next() {
+		return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_Step.Link(tink_core_Lazy.get(this.value),tink_streams_Empty.inst)));
+	}
+	forEach(handle) {
+		let _gthis = this;
+		return tink_core_Future.map(handle(tink_core_Lazy.get(this.value)),function(step) {
+			switch(step._hx_index) {
+			case 0:
+				return tink_streams_Conclusion.Halted(_gthis);
+			case 1:
+				return tink_streams_Conclusion.Halted(tink_streams_Empty.inst);
+			case 2:
+				return tink_streams_Conclusion.Depleted;
+			case 3:
+				let e = step.e;
+				return tink_streams_Conclusion.Clogged(e,_gthis);
+			}
+		});
+	}
+}
+tink_streams_Single.__name__ = "tink.streams.Single";
+tink_streams_Single.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_Single.prototype, {
+	__class__: tink_streams_Single
+});
+class tink_streams_Handler {
+	static _new(f) {
+		return f;
+	}
+	static apply(this1,item) {
+		return this1(item);
+	}
+	static ofSafeSync(f) {
+		return function(i) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(i)));
+		};
+	}
+	static ofUnknownSync(f) {
+		return function(i) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(i)));
+		};
+	}
+	static ofSafe(f) {
+		return f;
+	}
+	static ofUnknown(f) {
+		return f;
+	}
+}
+class tink_streams_Reducer {
+	static _new(f) {
+		return f;
+	}
+	static apply(this1,res,item) {
+		return this1(res,item);
+	}
+	static ofSafeSync(f) {
+		return function(res,cur) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(res,cur)));
+		};
+	}
+	static ofUnknownSync(f) {
+		return function(res,cur) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(f(res,cur)));
+		};
+	}
+	static ofSafe(f) {
+		return f;
+	}
+	static ofPlainSync(f) {
+		return function(res,cur) {
+			return new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_streams_ReductionStep.Progress(f(res,cur))));
+		};
+	}
+	static ofUnknown(f) {
+		return f;
+	}
+	static ofPromiseBased(f) {
+		return function(res,cur) {
+			return tink_core_Future.map(f(res,cur),function(s) {
+				switch(s._hx_index) {
+				case 0:
+					let r = s.data;
+					return tink_streams_ReductionStep.Progress(r);
+				case 1:
+					let e = s.failure;
+					return tink_streams_ReductionStep.Crash(e);
+				}
+			});
+		};
+	}
+}
+class tink_streams_FutureStream extends tink_streams_StreamBase {
+	constructor(f) {
+		super();
+		this.f = f;
+	}
+	next() {
+		return tink_core_Future.flatMap(this.f,function(s) {
+			return s.next();
+		});
+	}
+	forEach(handler) {
+		let _gthis = this;
+		return tink_core_Future.async(function(cb) {
+			_gthis.f.handle(function(s) {
+				s.forEach(handler).handle(cb);
+			});
+		});
+	}
+}
+tink_streams_FutureStream.__name__ = "tink.streams.FutureStream";
+tink_streams_FutureStream.__super__ = tink_streams_StreamBase;
+Object.assign(tink_streams_FutureStream.prototype, {
+	__class__: tink_streams_FutureStream
+});
+class tink_streams_BlendStream extends tink_streams_Generator {
+	constructor(a,b) {
+		let first = null;
+		let wait = function(s) {
+			return tink_core_Future.map(s.next(),function(o) {
+				if(first == null) {
+					first = s;
+				}
+				return o;
+			});
+		};
+		let n1 = wait(a);
+		let n2 = wait(b);
+		super(tink_core_Future.async(function(cb) {
+			tink_core_Future.first(n1,n2).handle(function(o) {
+				switch(o._hx_index) {
+				case 0:
+					let item = o.value;
+					let rest = o.next;
+					cb(tink_streams_Step.Link(item,new tink_streams_BlendStream(rest,first == a ? b : a)));
+					break;
+				case 1:
+					let e = o.e;
+					cb(tink_streams_Step.Fail(e));
+					break;
+				case 2:
+					(first == a ? n2 : n1).handle(cb);
+					break;
+				}
+			});
+		}));
+	}
+}
+tink_streams_BlendStream.__name__ = "tink.streams.BlendStream";
+tink_streams_BlendStream.__super__ = tink_streams_Generator;
+Object.assign(tink_streams_BlendStream.prototype, {
+	__class__: tink_streams_BlendStream
+});
+var tink_streams_Step = $hxEnums["tink.streams.Step"] = { __ename__:true,__constructs__:null
+	,Link: ($_=function(value,next) { return {_hx_index:0,value:value,next:next,__enum__:"tink.streams.Step",toString:$estr}; },$_._hx_name="Link",$_.__params__ = ["value","next"],$_)
+	,Fail: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.streams.Step",toString:$estr}; },$_._hx_name="Fail",$_.__params__ = ["e"],$_)
+	,End: {_hx_name:"End",_hx_index:2,__enum__:"tink.streams.Step",toString:$estr}
+};
+tink_streams_Step.__constructs__ = [tink_streams_Step.Link,tink_streams_Step.Fail,tink_streams_Step.End];
+class tink_streams_SignalStream extends tink_streams_Generator {
+	constructor(signal) {
+		let this1 = tink_core_Future.map(tink_core_Signal.nextTime(signal),function(o) {
+			switch(o._hx_index) {
+			case 0:
+				let data = o.data;
+				return tink_streams_Step.Link(data,new tink_streams_SignalStream(signal));
+			case 1:
+				let e = o.e;
+				return tink_streams_Step.Fail(e);
+			case 2:
+				return tink_streams_Step.End;
+			}
+		});
+		this1.eager();
+		super(this1);
+	}
+}
+tink_streams_SignalStream.__name__ = "tink.streams.SignalStream";
+tink_streams_SignalStream.__super__ = tink_streams_Generator;
+Object.assign(tink_streams_SignalStream.prototype, {
+	__class__: tink_streams_SignalStream
+});
+var tink_streams_Yield = $hxEnums["tink.streams.Yield"] = { __ename__:true,__constructs__:null
+	,Data: ($_=function(data) { return {_hx_index:0,data:data,__enum__:"tink.streams.Yield",toString:$estr}; },$_._hx_name="Data",$_.__params__ = ["data"],$_)
+	,Fail: ($_=function(e) { return {_hx_index:1,e:e,__enum__:"tink.streams.Yield",toString:$estr}; },$_._hx_name="Fail",$_.__params__ = ["e"],$_)
+	,End: {_hx_name:"End",_hx_index:2,__enum__:"tink.streams.Yield",toString:$estr}
+};
+tink_streams_Yield.__constructs__ = [tink_streams_Yield.Data,tink_streams_Yield.Fail,tink_streams_Yield.End];
+class tink_streams_nodejs_NodejsStream extends tink_streams_Generator {
+	constructor(target) {
+		super(tink_core_Future.async(function(cb) {
+			target.read().handle(function(o) {
+				let cb1 = cb;
+				let tmp;
+				switch(o._hx_index) {
+				case 0:
+					let _g = o.data;
+					if(_g == null) {
+						tmp = tink_streams_Step.End;
+					} else {
+						let data = _g;
+						tmp = tink_streams_Step.Link(data,new tink_streams_nodejs_NodejsStream(target));
+					}
+					break;
+				case 1:
+					let e = o.failure;
+					tmp = tink_streams_Step.Fail(e);
+					break;
+				}
+				cb1(tmp);
+			});
+		}));
+	}
+	static wrap(name,native,onEnd) {
+		return new tink_streams_nodejs_NodejsStream(new tink_streams_nodejs_WrappedReadable(name,native,onEnd));
+	}
+}
+tink_streams_nodejs_NodejsStream.__name__ = "tink.streams.nodejs.NodejsStream";
+tink_streams_nodejs_NodejsStream.__super__ = tink_streams_Generator;
+Object.assign(tink_streams_nodejs_NodejsStream.prototype, {
+	__class__: tink_streams_nodejs_NodejsStream
+});
+class tink_streams_nodejs_WrappedReadable {
+	constructor(name,native,onEnd) {
+		this.name = name;
+		this.native = native;
+		let this1 = tink_core_Future.async(function(cb) {
+			native.once("end",function() {
+				cb(tink_core_Outcome.Success(null));
+			});
+			native.once("close",function() {
+				cb(tink_core_Outcome.Success(null));
+			});
+			native.once("error",function(e) {
+				cb(tink_core_Outcome.Failure(new tink_core_TypedError(null,"" + e.code + " - Failed reading from " + name + " because " + e.message,{ fileName : "tink/streams/nodejs/WrappedReadable.hx", lineNumber : 21, className : "tink.streams.nodejs.WrappedReadable", methodName : "new"})));
+			});
+		});
+		this1.eager();
+		this.end = this1;
+		if(onEnd != null) {
+			this.end.handle(function() {
+				process.nextTick(onEnd);
+			});
+		}
+	}
+	read() {
+		let _gthis = this;
+		return tink_core_Future.first(tink_core_Future.async(function(cb) {
+			let attempt = null;
+			attempt = function() {
+				try {
+					let _g = _gthis.native.read();
+					if(_g == null) {
+						_gthis.native.once("readable",attempt);
+					} else {
+						let object = _g;
+						cb(tink_core_Outcome.Success(object));
+					}
+				} catch( _g ) {
+					let e = haxe_Exception.caught(_g).unwrap();
+					cb(tink_core_Outcome.Failure(tink_core_TypedError.withData(null,"Error while reading from " + _gthis.name,e,{ fileName : "tink/streams/nodejs/WrappedReadable.hx", lineNumber : 41, className : "tink.streams.nodejs.WrappedReadable", methodName : "read"})));
+				}
+			};
+			attempt();
+		}),this.end);
+	}
+}
+tink_streams_nodejs_WrappedReadable.__name__ = "tink.streams.nodejs.WrappedReadable";
+Object.assign(tink_streams_nodejs_WrappedReadable.prototype, {
+	__class__: tink_streams_nodejs_WrappedReadable
+});
+class tink_url_Auth {
+	static _new(user,password) {
+		return "" + user + ":" + password;
+	}
+	static get_user(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			return this1.split(":")[0];
+		}
+	}
+	static get_password(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			return this1.split(":")[1];
+		}
+	}
+	static toString(this1) {
+		if(this1 == null) {
+			return "";
+		} else {
+			return "" + this1 + "@";
+		}
+	}
+}
+class tink_url_Host {
+	static _new(name,port) {
+		let this1;
+		if(port == null) {
+			this1 = name;
+		} else if(port > 65535 || port <= 0) {
+			throw haxe_Exception.thrown("Invalid port");
+		} else {
+			this1 = "" + name + ":" + port;
+		}
+		return this1;
+	}
+	static get_name(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			let _g = this1.split("]");
+			switch(_g.length) {
+			case 1:
+				let v = _g[0];
+				return v.split(":")[0];
+			case 2:
+				let _g1 = _g[1];
+				let v1 = _g[0];
+				return v1 + "]";
+			default:
+				throw haxe_Exception.thrown("assert");
+			}
+		}
+	}
+	static get_port(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			let _g = this1.split("]");
+			switch(_g.length) {
+			case 1:
+				let v = _g[0];
+				let _g1 = v.split(":")[1];
+				if(_g1 == null) {
+					return null;
+				} else {
+					let p = _g1;
+					return Std.parseInt(p);
+				}
+				break;
+			case 2:
+				let _g2 = _g[0];
+				let v1 = _g[1];
+				let _g3 = v1.split(":")[1];
+				if(_g3 == null) {
+					return null;
+				} else {
+					let p = _g3;
+					return Std.parseInt(p);
+				}
+				break;
+			default:
+				throw haxe_Exception.thrown("assert");
+			}
+		}
+	}
+	static toString(this1) {
+		return this1;
+	}
+}
+class tink_url_Path {
+	static parts(this1) {
+		let _g = [];
+		let _g1 = 0;
+		let _g2 = this1.split("/");
+		while(_g1 < _g2.length) {
+			let p = _g2[_g1];
+			++_g1;
+			if(p != "") {
+				_g.push(p);
+			}
+		}
+		return _g;
+	}
+	static get_absolute(this1) {
+		return this1.charAt(0) == "/";
+	}
+	static get_isDir(this1) {
+		return this1.charAt(this1.length - 1) == "/";
+	}
+	static _new(s) {
+		return s;
+	}
+	static join(this1,that) {
+		if(that == "") {
+			return this1;
+		} else if(that.charAt(0) == "/") {
+			return that;
+		} else if(this1.charAt(this1.length - 1) == "/") {
+			return tink_url_Path.ofString(this1 + that);
+		} else {
+			let _g = this1.lastIndexOf("/");
+			if(_g == -1) {
+				return that;
+			} else {
+				let v = _g;
+				return tink_url_Path.ofString(HxOverrides.substr(this1,0,v + 1) + (that == null ? "null" : that));
+			}
+		}
+	}
+	static ofString(s) {
+		return tink_url_Path.normalize(s);
+	}
+	static normalize(s) {
+		s = StringTools.trim(StringTools.replace(s,"\\","/"));
+		if(s == ".") {
+			return "./";
+		}
+		let isDir = s.endsWith("/..") || s.endsWith("/") || s.endsWith("/.");
+		let parts = [];
+		let isAbsolute = s.startsWith("/");
+		let up = 0;
+		let _g = 0;
+		let _g1 = s.split("/");
+		while(_g < _g1.length) {
+			let part = _g1[_g];
+			++_g;
+			let _g2 = StringTools.trim(part);
+			switch(_g2) {
+			case "":
+				break;
+			case ".":
+				break;
+			case "..":
+				if(parts.pop() == null) {
+					++up;
+				}
+				break;
+			default:
+				let v = _g2;
+				parts.push(v);
+			}
+		}
+		if(isAbsolute) {
+			parts.unshift("");
+		} else {
+			let _g = 0;
+			let _g1 = up;
+			while(_g < _g1) {
+				let i = _g++;
+				parts.unshift("..");
+			}
+		}
+		if(isDir) {
+			parts.push("");
+		}
+		return parts.join("/");
+	}
+	static toString(this1) {
+		return this1;
+	}
+}
+class tink_url_Portion {
+	static get_raw(this1) {
+		return this1;
+	}
+	static isValid(this1) {
+		if(this1 != null) {
+			try {
+				decodeURIComponent(this1.split("+").join(" "));
+				return true;
+			} catch( _g ) {
+				return false;
+			}
+		} else {
+			return true;
+		}
+	}
+	static _new(v) {
+		return v;
+	}
+	static stringly(this1) {
+		return tink_url_Portion.toString(this1);
+	}
+	static toString(this1) {
+		if(this1 == null) {
+			return null;
+		} else {
+			try {
+				return decodeURIComponent(this1.split("+").join(" "));
+			} catch( _g ) {
+				return "";
+			}
+		}
+	}
+	static ofString(s) {
+		return s == null ? "" : encodeURIComponent(s);
+	}
+}
+class tink_url_PortionArray {
+	static toStringArray(this1) {
+		let _g = [];
+		let _g1 = 0;
+		while(_g1 < this1.length) {
+			let p = this1[_g1];
+			++_g1;
+			_g.push(tink_url_Portion.toString(p));
+		}
+		return _g;
+	}
+}
+class tink_url_Query {
+	static parse(this1) {
+		return new tink_url__$Query_QueryStringParser(this1,"&","=",0);
+	}
+	static with(this1,values) {
+		let ret = [];
+		let _g = [];
+		let key = new haxe_ds__$StringMap_StringMapKeyIterator(values.h);
+		while(key.hasNext()) {
+			let key1 = key.next();
+			_g.push(key1);
+		}
+		let insert = _g;
+		let p = new tink_url__$Query_QueryStringParser(this1,"&","=",0);
+		while(p.hasNext()) {
+			let p1 = p.next();
+			let key = tink_url_Portion.ofString(p1.name);
+			if(Object.prototype.hasOwnProperty.call(values.h,key)) {
+				let name = tink_url_Portion.ofString(p1.name);
+				let key = tink_url_Portion.ofString(p1.name);
+				ret.push(name + "=" + values.h[key]);
+				HxOverrides.remove(insert,tink_url_Portion.ofString(p1.name));
+			} else {
+				ret.push(tink_url_Portion.ofString(p1.name) + "=" + p1.value);
+			}
+		}
+		let _g1 = 0;
+		while(_g1 < insert.length) {
+			let name = insert[_g1];
+			++_g1;
+			ret.push(name + "=" + values.h[name]);
+		}
+		return ret.join("&");
+	}
+	static iterator(this1) {
+		return new tink_url__$Query_QueryStringParser(this1,"&","=",0);
+	}
+	static toMap(this1) {
+		let _g = new haxe_ds_StringMap();
+		let p = new tink_url__$Query_QueryStringParser(this1,"&","=",0);
+		while(p.hasNext()) {
+			let p1 = p.next();
+			_g.h[p1.name.toString()] = p1.value;
+		}
+		return _g;
+	}
+	static ofObj(v) {
+		let ret = [];
+		let v1 = v;
+		let _g = 0;
+		let _g1 = Reflect.fields(v1);
+		while(_g < _g1.length) {
+			let k = _g1[_g];
+			++_g;
+			ret.push(tink_url_Portion.ofString(k) + "=" + tink_url_Portion.ofString(v1[k]));
+		}
+		return ret.join("&");
+	}
+	static toString(this1) {
+		return this1;
+	}
+	static build() {
+		return [];
+	}
+	static parseString(s,sep,set,pos) {
+		if(pos == null) {
+			pos = 0;
+		}
+		if(set == null) {
+			set = "=";
+		}
+		if(sep == null) {
+			sep = "&";
+		}
+		return new tink_url__$Query_QueryStringParser(s,sep,set,pos);
+	}
+}
+class tink_url_QueryStringBuilder {
+	static _new() {
+		return [];
+	}
+	static add(this1,name,value) {
+		this1.push(name + "=" + value);
+		return this1;
+	}
+	static toString(this1,sep) {
+		if(sep == null) {
+			sep = "&";
+		}
+		return this1.join(sep);
+	}
+	static copy(this1) {
+		return this1.slice();
+	}
+}
+class tink_url__$Query_QueryStringParser {
+	constructor(s,sep,set,pos) {
+		this.s = s == null ? "" : s;
+		this.sep = sep;
+		this.set = set;
+		this.pos = pos;
+	}
+	hasNext() {
+		return this.pos < this.s.length;
+	}
+	next() {
+		let next = this.s.indexOf(this.sep,this.pos);
+		if(next == -1) {
+			next = this.s.length;
+		}
+		let split = this.s.indexOf(this.set,this.pos);
+		let start = this.pos;
+		this.pos = next + this.sep.length;
+		if(split == -1 || split > next) {
+			return new tink_core_NamedWith(tink_url_Portion.toString(tink_url__$Query_QueryStringParser.trimmedSub(this.s,start,next)),tink_url_Portion.ofString(""));
+		} else {
+			return new tink_core_NamedWith(tink_url_Portion.toString(tink_url__$Query_QueryStringParser.trimmedSub(this.s,start,split)),tink_url__$Query_QueryStringParser.trimmedSub(this.s,split + this.set.length,next));
+		}
+	}
+	static trimmedSub(s,start,end) {
+		if(start >= s.length) {
+			return "";
+		}
+		while(s.charCodeAt(start) < 33) ++start;
+		if(end < s.length - 1) {
+			while(s.charCodeAt(end - 1) < 33) --end;
+		}
+		return s.substring(start,end);
+	}
+}
+tink_url__$Query_QueryStringParser.__name__ = "tink.url._Query.QueryStringParser";
+Object.assign(tink_url__$Query_QueryStringParser.prototype, {
+	__class__: tink_url__$Query_QueryStringParser
+});
+function $getIterator(o) { if( o instanceof Array ) return new haxe_iterators_ArrayIterator(o); else return o.iterator(); }
+function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $global.$haxeUID++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = m.bind(o); o.hx__closures__[m.__id__] = f; } return f; }
+$global.$haxeUID |= 0;
+if(typeof(performance) != "undefined" ? typeof(performance.now) == "function" : false) {
+	HxOverrides.now = performance.now.bind(performance);
+}
+if( String.fromCodePoint == null ) String.fromCodePoint = function(c) { return c < 0x10000 ? String.fromCharCode(c) : String.fromCharCode((c>>10)+0xD7C0)+String.fromCharCode((c&0x3FF)+0xDC00); }
+{
+	Object.defineProperty(String.prototype,"__class__",{ value : String, enumerable : false, writable : true});
+	String.__name__ = "String";
+	Array.__name__ = "Array";
+	Date.prototype.__class__ = Date;
+	Date.__name__ = "Date";
+	var Int = { };
+	var Dynamic = { };
+	var Float = Number;
+	var Bool = Boolean;
+	var Class = { };
+	var Enum = { };
+}
+js_Boot.__toStr = ({ }).toString;
+DateTools.DAY_SHORT_NAMES = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
+DateTools.DAY_NAMES = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
+DateTools.MONTH_SHORT_NAMES = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
+DateTools.MONTH_NAMES = ["January","February","March","April","May","June","July","August","September","October","November","December"];
+Xml.Element = 0;
+Xml.PCData = 1;
+Xml.CData = 2;
+Xml.Comment = 3;
+Xml.DocType = 4;
+Xml.ProcessingInstruction = 5;
+Xml.Document = 6;
+datetime_DateTime.UNIX_EPOCH_DIFF = 62135596800.0;
+datetime_DateTime.SECONDS_IN_MINUTE = 60;
+datetime_DateTime.SECONDS_IN_HOUR = 3600;
+datetime_DateTime.SECONDS_IN_DAY = 86400;
+datetime_DateTime.SECONDS_IN_WEEK = 604800;
+datetime_DateTime.SECONDS_IN_YEAR = 31536000;
+datetime_DateTime.SECONDS_IN_LEAP_YEAR = 31622400;
+datetime_DateTime.SECONDS_IN_3_YEARS = 94608000;
+datetime_DateTime.SECONDS_IN_QUAD = 126230400.0;
+datetime_DateTime.SECONDS_IN_HALF_QUAD = 63072000.0;
+datetime_DateTime.SECONDS_IN_HALF_QUAD_LEAP = 63158400.0;
+datetime_DateTime.SECONDS_IN_3_PART_QUAD = 94694400.0;
+datetime_DateTime.SECONDS_IN_CQUAD = 12622780800.0;
+datetime_DateTime.SECONDS_IN_CENTURY = 3155673600.0;
+datetime_DateTime.SECONDS_IN_LEAP_CENTURY = 3155760000.0;
+haxe_crypto_Base64.CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+haxe_crypto_Base64.BYTES = haxe_io_Bytes.ofString(haxe_crypto_Base64.CHARS);
+haxe_crypto_Base64.URL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+haxe_crypto_Base64.URL_BYTES = haxe_io_Bytes.ofString(haxe_crypto_Base64.URL_CHARS);
+haxe_io_FPHelper.i64tmp = new haxe__$Int64__$_$_$Int64(0,0);
+haxe_io_FPHelper.helper = new DataView(new ArrayBuffer(8));
+haxe_xml_Parser.escapes = (function($this) {
+	var $r;
+	let h = new haxe_ds_StringMap();
+	h.h["lt"] = "<";
+	h.h["gt"] = ">";
+	h.h["amp"] = "&";
+	h.h["quot"] = "\"";
+	h.h["apos"] = "'";
+	$r = h;
+	return $r;
+}(this));
+hsluv_Hsluv.hexChars = "0123456789abcdef";
+hsluv_Hsluv.refY = 1.0;
+hsluv_Hsluv.refU = 0.19783000664283;
+hsluv_Hsluv.refV = 0.46831999493879;
+hsluv_Hsluv.kappa = 903.2962962;
+hsluv_Hsluv.epsilon = 0.0088564516;
+hsluv_Hsluv.m_r0 = 3.240969941904521;
+hsluv_Hsluv.m_r1 = -1.537383177570093;
+hsluv_Hsluv.m_r2 = -0.498610760293;
+hsluv_Hsluv.m_g0 = -0.96924363628087;
+hsluv_Hsluv.m_g1 = 1.87596750150772;
+hsluv_Hsluv.m_g2 = 0.041555057407175;
+hsluv_Hsluv.m_b0 = 0.055630079696993;
+hsluv_Hsluv.m_b1 = -0.20397695888897;
+hsluv_Hsluv.m_b2 = 1.056971514242878;
+htmlparser_CssSelector.reID = "[a-z](?:-?[_a-z0-9])*";
+htmlparser_CssSelector.reNamespacedID = htmlparser_CssSelector.reID + "(?::" + htmlparser_CssSelector.reID + ")?";
+htmlparser_CssSelector.reSelector = "(\\s*)((?:[>]\\s*)?)([.#]?)(" + htmlparser_CssSelector.reNamespacedID + "|[*])((?:\\[\\d+\\])?)";
+htmlparser_HtmlParser.SELF_CLOSING_TAGS_HTML = { img : 1, br : 1, input : 1, meta : 1, link : 1, hr : 1, base : 1, embed : 1, spacer : 1, source : 1, param : 1};
+htmlparser_HtmlParser.reID = "[a-z](?:-?[_a-z0-9])*";
+htmlparser_HtmlParser.reNamespacedID = htmlparser_HtmlParser.reID + "(?::" + htmlparser_HtmlParser.reID + ")?";
+htmlparser_HtmlParser.reCDATA = "[<]!\\[CDATA\\[[\\s\\S]*?\\]\\][>]";
+htmlparser_HtmlParser.reScript = "[<]\\s*script\\s*([^>]*)>([\\s\\S]*?)<\\s*/\\s*script\\s*>";
+htmlparser_HtmlParser.reStyle = "<\\s*style\\s*([^>]*)>([\\s\\S]*?)<\\s*/\\s*style\\s*>";
+htmlparser_HtmlParser.reElementOpen = "<\\s*(" + htmlparser_HtmlParser.reNamespacedID + ")";
+htmlparser_HtmlParser.reAttr = htmlparser_HtmlParser.reNamespacedID + "(?:\\s*=\\s*(?:'[^']*?'|\"[^\"]*?\"|[-_a-z0-9]+))?";
+htmlparser_HtmlParser.reElementEnd = "(/)?\\s*>";
+htmlparser_HtmlParser.reElementClose = "<\\s*/\\s*(" + htmlparser_HtmlParser.reNamespacedID + ")\\s*>";
+htmlparser_HtmlParser.reComment = "<!--[\\s\\S]*?-->";
+htmlparser_HtmlParser.reMain = new EReg("(" + htmlparser_HtmlParser.reCDATA + ")|(" + htmlparser_HtmlParser.reScript + ")|(" + htmlparser_HtmlParser.reStyle + ")|(" + htmlparser_HtmlParser.reElementOpen + "((?:\\s+" + htmlparser_HtmlParser.reAttr + ")*)\\s*" + htmlparser_HtmlParser.reElementEnd + ")|(" + htmlparser_HtmlParser.reElementClose + ")|(" + htmlparser_HtmlParser.reComment + ")","ig");
+htmlparser_HtmlParser.reParseAttrs = new EReg("(" + htmlparser_HtmlParser.reNamespacedID + ")(?:\\s*=\\s*('[^']*'|\"[^\"]*\"|[-_a-z0-9]+))?","ig");
+httpstatus_HttpStatusCode.Continue = 100;
+httpstatus_HttpStatusCode.SwitchingProtocols = 101;
+httpstatus_HttpStatusCode.Processing = 102;
+httpstatus_HttpStatusCode.OK = 200;
+httpstatus_HttpStatusCode.Created = 201;
+httpstatus_HttpStatusCode.Accepted = 202;
+httpstatus_HttpStatusCode.NonAuthoritativeInformation = 203;
+httpstatus_HttpStatusCode.NoContent = 204;
+httpstatus_HttpStatusCode.ResetContent = 205;
+httpstatus_HttpStatusCode.PartialContent = 206;
+httpstatus_HttpStatusCode.MultiStatus = 207;
+httpstatus_HttpStatusCode.AlreadyReported = 208;
+httpstatus_HttpStatusCode.IMUsed = 226;
+httpstatus_HttpStatusCode.MultipleChoices = 300;
+httpstatus_HttpStatusCode.MovedPermanently = 301;
+httpstatus_HttpStatusCode.Found = 302;
+httpstatus_HttpStatusCode.SeeOther = 303;
+httpstatus_HttpStatusCode.NotModified = 304;
+httpstatus_HttpStatusCode.UseProxy = 305;
+httpstatus_HttpStatusCode.SwitchProxy = 306;
+httpstatus_HttpStatusCode.TemporaryRedirect = 307;
+httpstatus_HttpStatusCode.PermanentRedirect = 308;
+httpstatus_HttpStatusCode.BadRequest = 400;
+httpstatus_HttpStatusCode.Unauthorized = 401;
+httpstatus_HttpStatusCode.PaymentRequired = 402;
+httpstatus_HttpStatusCode.Forbidden = 403;
+httpstatus_HttpStatusCode.NotFound = 404;
+httpstatus_HttpStatusCode.MethodNotAllowed = 405;
+httpstatus_HttpStatusCode.NotAcceptable = 406;
+httpstatus_HttpStatusCode.ProxyAuthenticationRequired = 407;
+httpstatus_HttpStatusCode.RequestTimeout = 408;
+httpstatus_HttpStatusCode.Conflict = 409;
+httpstatus_HttpStatusCode.Gone = 410;
+httpstatus_HttpStatusCode.LengthRequired = 411;
+httpstatus_HttpStatusCode.PreconditionFailed = 412;
+httpstatus_HttpStatusCode.PayloadTooLarge = 413;
+httpstatus_HttpStatusCode.URITooLong = 414;
+httpstatus_HttpStatusCode.UnsupportedMediaType = 415;
+httpstatus_HttpStatusCode.RangeNotSatisfiable = 416;
+httpstatus_HttpStatusCode.ExpectationFailed = 417;
+httpstatus_HttpStatusCode.ImATeapot = 418;
+httpstatus_HttpStatusCode.MisdirectedRequest = 421;
+httpstatus_HttpStatusCode.UnprocessableEntity = 422;
+httpstatus_HttpStatusCode.Locked = 423;
+httpstatus_HttpStatusCode.FailedDependency = 424;
+httpstatus_HttpStatusCode.UpgradeRequired = 426;
+httpstatus_HttpStatusCode.PreconditionRequired = 428;
+httpstatus_HttpStatusCode.TooManyRequests = 429;
+httpstatus_HttpStatusCode.RequestHeaderFieldsTooLarge = 431;
+httpstatus_HttpStatusCode.UnavailableForLegalReasons = 451;
+httpstatus_HttpStatusCode.InternalServerError = 500;
+httpstatus_HttpStatusCode.NotImplemented = 501;
+httpstatus_HttpStatusCode.BadGateway = 502;
+httpstatus_HttpStatusCode.ServiceUnavailable = 503;
+httpstatus_HttpStatusCode.GatewayTimeout = 504;
+httpstatus_HttpStatusCode.HTTPVersionNotSupported = 505;
+httpstatus_HttpStatusCode.VariantAlsoNegotiates = 506;
+httpstatus_HttpStatusCode.InsufficientStorage = 507;
+httpstatus_HttpStatusCode.LoopDetected = 508;
+httpstatus_HttpStatusCode.NotExtended = 510;
+httpstatus_HttpStatusCode.NetworkAuthenticationRequired = 511;
+hx_strings_Char.CHAR_CASE_MAPPER = new hx_strings__$Char_CharCaseMapper();
+hx_strings_Char.BACKSPACE = 8;
+hx_strings_Char.TAB = 9;
+hx_strings_Char.LF = 10;
+hx_strings_Char.CR = 13;
+hx_strings_Char.ESC = 27;
+hx_strings_Char.SPACE = 32;
+hx_strings_Char.EXCLAMATION_MARK = 33;
+hx_strings_Char.DOUBLE_QUOTE = 34;
+hx_strings_Char.HASH = 35;
+hx_strings_Char.DOLLAR = 36;
+hx_strings_Char.AMPERSAND = 38;
+hx_strings_Char.SINGLE_QUOTE = 39;
+hx_strings_Char.BRACKET_ROUND_LEFT = 40;
+hx_strings_Char.BRACKET_ROUND_RIGHT = 41;
+hx_strings_Char.ASTERISK = 42;
+hx_strings_Char.PLUS = 43;
+hx_strings_Char.COMMA = 44;
+hx_strings_Char.MINUS = 45;
+hx_strings_Char.DOT = 46;
+hx_strings_Char.SLASH = 47;
+hx_strings_Char.ZERO = 48;
+hx_strings_Char.ONE = 49;
+hx_strings_Char.TWO = 50;
+hx_strings_Char.TRHEE = 51;
+hx_strings_Char.FOUR = 52;
+hx_strings_Char.FIVE = 53;
+hx_strings_Char.SIX = 54;
+hx_strings_Char.SEVEN = 55;
+hx_strings_Char.EIGHT = 56;
+hx_strings_Char.NINE = 57;
+hx_strings_Char.COLON = 58;
+hx_strings_Char.SEMICOLON = 59;
+hx_strings_Char.LOWER_THAN = 60;
+hx_strings_Char.EQUALS = 61;
+hx_strings_Char.GREATER_THAN = 62;
+hx_strings_Char.QUESTION_MARK = 63;
+hx_strings_Char.BRACKET_SQUARE_LEFT = 91;
+hx_strings_Char.BACKSLASH = 92;
+hx_strings_Char.BRACKET_SQUARE_RIGHT = 93;
+hx_strings_Char.CARET = 94;
+hx_strings_Char.UNDERSCORE = 95;
+hx_strings_Char.BRACKET_CURLY_LEFT = 123;
+hx_strings_Char.PIPE = 124;
+hx_strings_Char.BRACKET_CURLY_RIGHT = 125;
+hx_strings_CharIterator._hx_skip_constructor = false;
+hx_strings__$CharIterator_NullCharIterator.INSTANCE = new hx_strings__$CharIterator_NullCharIterator();
+hx_strings_Pattern.__meta__ = { obj : { immutable : null, threadSafe : null}};
+hx_strings_Matcher.__meta__ = { obj : { notThreadSafe : null}};
+hx_strings_internal_OS.isNodeJS = (typeof process !== 'undefined') && (typeof process.release !== 'undefined') && (process.release.name === 'node');
+hx_strings_internal_OS.isWindows = (function($this) {
+	var $r;
+	let os = hx_strings_internal_OS.isNodeJS ? process.platform : $global.navigator.platform;
+	$r = new EReg("win","i").match(os);
+	return $r;
+}(this));
+hx_strings_Strings.REGEX_ANSI_ESC = hx_strings_Pattern.compile(String.fromCodePoint(27) + "\\[[;\\d]*m",hx_strings_internal__$Either3__$Either3.b("g"));
+hx_strings_Strings.REGEX_HTML_UNESCAPE = hx_strings_Pattern.compile("&(#\\d+|amp|nbsp|apos|lt|gt|quot);",hx_strings_internal__$Either3__$Either3.b("g"));
+hx_strings_Strings.REGEX_SPLIT_LINES = hx_strings_Pattern.compile("\\r?\\n",hx_strings_internal__$Either3__$Either3.b("g"));
+hx_strings_Strings.REGEX_REMOVE_XML_TAGS = hx_strings_Pattern.compile("<[!a-zA-Z\\/][^>]*>",hx_strings_internal__$Either3__$Either3.b("g"));
+hx_strings_Strings.POS_NOT_FOUND = -1;
+hx_strings_Strings.NEW_LINE_NIX = "\n";
+hx_strings_Strings.NEW_LINE_WIN = "\r\n";
+hx_strings_Strings.NEW_LINE = hx_strings_internal_OS.isWindows ? "\r\n" : "\n";
+hx_strings_RandomStrings.DIGITS = hx_strings_Strings.toChars("0123456789");
+hx_strings_RandomStrings.ASCII_ALPHA = hx_strings_RandomStrings._genAsciiAlpha();
+hx_strings_RandomStrings.ASCII_ALPHA_NUMERIC = hx_strings_RandomStrings.DIGITS.concat(hx_strings_RandomStrings.ASCII_ALPHA);
+hx_strings_RandomStrings.MAX_INT = 2147483647;
+hx_strings_StringBuilder.__meta__ = { obj : { notThreadSafe : null}};
+sha_Hash._hx_skip_constructor = false;
+var sha_SHA256_K = [1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998];
+snikket_Autolink.__meta__ = { statics : { GOOD_IRI_CHAR : { Deprecated : null}}};
+snikket_Autolink.IANA_TOP_LEVEL_DOMAINS = "(?:" + "(?:aaa|aarp|abb|abbott|abogado|academy|accenture|accountant|accountants|aco|active" + "|actor|ads|adult|aeg|aero|afl|agency|aig|airforce|airtel|allfinanz|alsace|amica|amsterdam" + "|android|apartments|app|apple|aquarelle|aramco|archi|army|arpa|arte|asia|associates" + "|attorney|auction|audio|auto|autos|axa|azure|a[cdefgilmoqrstuwxz])" + "|(?:band|bank|bar|barcelona|barclaycard|barclays|bargains|bauhaus|bayern|bbc|bbva" + "|bcn|beats|beer|bentley|berlin|best|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black" + "|blackfriday|bloomberg|blue|bms|bmw|bnl|bnpparibas|boats|bom|bond|boo|boots|boutique" + "|bradesco|bridgestone|broadway|broker|brother|brussels|budapest|build|builders|business" + "|buzz|bzh|b[abdefghijmnorstvwyz])" + "|(?:cab|cafe|cal|camera|camp|cancerresearch|canon|capetown|capital|car|caravan|cards" + "|care|career|careers|cars|cartier|casa|cash|casino|cat|catering|cba|cbn|ceb|center|ceo" + "|cern|cfa|cfd|chanel|channel|chat|cheap|chloe|christmas|chrome|church|cipriani|cisco" + "|citic|city|cityeats|claims|cleaning|click|clinic|clothing|cloud|club|clubmed|coach" + "|codes|coffee|college|cologne|com|commbank|community|company|computer|comsec|condos" + "|construction|consulting|contractors|cooking|cool|coop|corsica|country|coupons|courses" + "|credit|creditcard|creditunion|cricket|crown|crs|cruises|csc|cuisinella|cymru|cyou|c[acdfghiklmnoruvwxyz])" + "|(?:dabur|dad|dance|date|dating|datsun|day|dclk|deals|degree|delivery|dell|delta" + "|democrat|dental|dentist|desi|design|dev|diamonds|diet|digital|direct|directory|discount" + "|dnp|docs|dog|doha|domains|doosan|download|drive|durban|dvag|d[ejkmoz])" + "|(?:earth|eat|edu|education|email|emerck|energy|engineer|engineering|enterprises" + "|epson|equipment|erni|esq|estate|eurovision|eus|events|everbank|exchange|expert|exposed" + "|express|e[cegrstu])" + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|fashion|feedback|ferrero|film" + "|final|finance|financial|firmdale|fish|fishing|fit|fitness|flights|florist|flowers|flsmidth" + "|fly|foo|football|forex|forsale|forum|foundation|frl|frogans|fund|furniture|futbol|fyi" + "|f[ijkmor])" + "|(?:gal|gallery|game|garden|gbiz|gdn|gea|gent|genting|ggee|gift|gifts|gives|giving" + "|glass|gle|global|globo|gmail|gmo|gmx|gold|goldpoint|golf|goo|goog|google|gop|gov|grainger" + "|graphics|gratis|green|gripe|group|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])" + "|(?:hamburg|hangout|haus|healthcare|help|here|hermes|hiphop|hitachi|hiv|hockey|holdings" + "|holiday|homedepot|homes|honda|horse|host|hosting|hoteles|hotmail|house|how|hsbc|hyundai" + "|h[kmnrtu])" + "|(?:ibm|icbc|ice|icu|ifm|iinet|immo|immobilien|industries|infiniti|info|ing|ink|institute" + "|insure|int|international|investments|ipiranga|irish|ist|istanbul|itau|iwc|i[delmnoqrst])" + "|(?:jaguar|java|jcb|jetzt|jewelry|jlc|jll|jobs|joburg|jprs|juegos|j[emop])" + "|(?:kaufen|kddi|kia|kim|kinder|kitchen|kiwi|koeln|komatsu|krd|kred|kyoto|k[eghimnprwyz])" + "|(?:lacaixa|lancaster|land|landrover|lasalle|lat|latrobe|law|lawyer|lds|lease|leclerc" + "|legal|lexus|lgbt|liaison|lidl|life|lifestyle|lighting|limited|limo|linde|link|live" + "|lixil|loan|loans|lol|london|lotte|lotto|love|ltd|ltda|lupin|luxe|luxury|l[abcikrstuvy])" + "|(?:madrid|maif|maison|man|management|mango|market|marketing|markets|marriott|mba" + "|media|meet|melbourne|meme|memorial|men|menu|meo|miami|microsoft|mil|mini|mma|mobi|moda" + "|moe|moi|mom|monash|money|montblanc|mormon|mortgage|moscow|motorcycles|mov|movie|movistar" + "|mtn|mtpc|mtr|museum|mutuelle|m[acdeghklmnopqrstuvwxyz])" + "|(?:nadex|nagoya|name|navy|nec|net|netbank|network|neustar|new|news|nexus|ngo|nhk" + "|nico|ninja|nissan|nokia|nra|nrw|ntt|nyc|n[acefgilopruz])" + "|(?:obi|office|okinawa|omega|one|ong|onl|online|ooo|oracle|orange|org|organic|osaka" + "|otsuka|ovh|om)" + "|(?:page|panerai|paris|partners|parts|party|pet|pharmacy|philips|photo|photography" + "|photos|physio|piaget|pics|pictet|pictures|ping|pink|pizza|place|play|playstation|plumbing" + "|plus|pohl|poker|porn|post|praxi|press|pro|prod|productions|prof|properties|property" + "|protection|pub|p[aefghklmnrstwy])" + "|(?:qpon|quebec|qa)" + "|(?:racing|realtor|realty|recipes|red|redstone|rehab|reise|reisen|reit|ren|rent|rentals" + "|repair|report|republican|rest|restaurant|review|reviews|rich|ricoh|rio|rip|rocher|rocks" + "|rodeo|rsvp|ruhr|run|rwe|ryukyu|r[eosuw])" + "|(?:saarland|sakura|sale|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|saxo" + "|sbs|sca|scb|schmidt|scholarships|school|schule|schwarz|science|scor|scot|seat|security" + "|seek|sener|services|seven|sew|sex|sexy|shiksha|shoes|show|shriram|singles|site|ski" + "|sky|skype|sncf|soccer|social|software|sohu|solar|solutions|sony|soy|space|spiegel|spreadbetting" + "|srl|stada|starhub|statoil|stc|stcgroup|stockholm|studio|study|style|sucks|supplies" + "|supply|support|surf|surgery|suzuki|swatch|swiss|sydney|systems|s[abcdeghijklmnortuvxyz])" + "|(?:tab|taipei|tatamotors|tatar|tattoo|tax|taxi|team|tech|technology|tel|telefonica" + "|temasek|tennis|thd|theater|theatre|tickets|tienda|tips|tires|tirol|today|tokyo|tools" + "|top|toray|toshiba|tours|town|toyota|toys|trade|trading|training|travel|trust|tui|t[cdfghjklmnortvwz])" + "|(?:ubs|university|uno|uol|u[agksyz])" + "|(?:vacations|vana|vegas|ventures|versicherung|vet|viajes|video|villas|vin|virgin" + "|vision|vista|vistaprint|viva|vlaanderen|vodka|vote|voting|voto|voyage|v[aceginu])" + "|(?:wales|walter|wang|watch|webcam|website|wed|wedding|weir|whoswho|wien|wiki|williamhill" + "|win|windows|wine|wme|work|works|world|wtc|wtf|w[fs])" + "|(?:ελ|бел|дети|ком|мкд" + "|мон|москва|онлайн" + "|орг|рус|рф|сайт|срб" + "|укр|қаз|հայ|קום|ارامكو" + "|الاردن|الجزائر|السعودية" + "|المغرب|امارات|ایران" + "|بازار|بھارت|تونس" + "|سودان|سورية|شبكة" + "|عراق|عمان|فلسطين" + "|قطر|كوم|مصر|مليسيا" + "|موقع|कॉम|नेट|भारत" + "|संगठन|ভারত|ਭਾਰਤ|ભારત" + "|இந்தியா|இலங்கை|சிங்கப்பூர்" + "|భారత్|ලංකා|คอม|ไทย" + "|გე|みんな|グーグル|コム|世界" + "|中信|中国|中國|中文网|企业|佛山" + "|信息|健康|八卦|公司|公益|台湾|台灣" + "|商城|商店|商标|在线|大拿|娱乐|工行" + "|广东|慈善|我爱你|手机|政务|政府" + "|新加坡|新闻|时尚|机构|淡马锡|游戏" + "|点看|移动|组织机构|网址|网店|网络" + "|谷歌|集团|飞利浦|餐厅|香港|닷넷" + "|닷컴|삼성|한국|xbox" + "|xerox|xin|xn\\-\\-11b4c3d|xn\\-\\-1qqw23a|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g" + "|xn\\-\\-3e0b707e|xn\\-\\-3pxu8k|xn\\-\\-42c2d9a|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4gbrim" + "|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks" + "|xn\\-\\-80ao21a|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-90a3ac|xn\\-\\-90ais|xn\\-\\-9dbq2a" + "|xn\\-\\-9et52u|xn\\-\\-b4w605ferd|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd" + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-efvy88h" + "|xn\\-\\-estv75g|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s" + "|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-gecrj9c" + "|xn\\-\\-h2brj9c|xn\\-\\-hxt814e|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i" + "|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d" + "|xn\\-\\-kput3i|xn\\-\\-l1acc|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgb9awbf|xn\\-\\-mgba3a3ejt" + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e" + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbpl2fh|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab" + "|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema" + "|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh" + "|xn\\-\\-pssy2u|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-s9brj9c" + "|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb" + "|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv|xn\\-\\-vuq861b|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a" + "|xn\\-\\-xhq521b|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-y9a3aq|xn\\-\\-yfro4i67o" + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xperia|xxx|xyz)" + "|(?:yachts|yamaxun|yandex|yodobashi|yoga|yokohama|youtube|y[et])" + "|(?:zara|zip|zone|zuerich|z[amw]))";
+snikket_Autolink.GOOD_IRI_CHAR = "a-zA-Z0-9 -퟿豈-﷏ﷰ-￯";
+snikket_Autolink.IP_ADDRESS = "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + "|[1-9][0-9]|[0-9]))";
+snikket_Autolink.IP6_ADDRESS = "\\[" + "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|" + "([0-9a-fA-F]{1,4}:){1,7}:|" + "([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|" + "([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|" + "([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|" + "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|" + "([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|" + "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|" + ":((:[0-9a-fA-F]{1,4}){1,7}|:)|" + "fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|" + "::(ffff(:0{1,4}){0,1}:){0,1}" + "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}" + "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|" + "([0-9a-fA-F]{1,4}:){1,4}:" + "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}" + "(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))" + "\\]";
+snikket_Autolink.UCS_CHAR = "[" + "\\u00A0-\\uD7FF" + "\\uF900-\\uFDCF" + "\\uFDF0-\\uFFEF";
+snikket_Autolink.LABEL_CHAR = "a-zA-Z0-9" + snikket_Autolink.UCS_CHAR;
+snikket_Autolink.TLD_CHAR = "a-zA-Z" + snikket_Autolink.UCS_CHAR;
+snikket_Autolink.IRI_LABEL = "[" + snikket_Autolink.LABEL_CHAR + "](?:[" + snikket_Autolink.LABEL_CHAR + "\\-]{0,61}[" + snikket_Autolink.LABEL_CHAR + "]){0,1}";
+snikket_Autolink.PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w";
+snikket_Autolink.TLD = "(" + snikket_Autolink.PUNYCODE_TLD + "|" + "[" + snikket_Autolink.TLD_CHAR + "]{2,63}" + ")";
+snikket_Autolink.HOST_NAME = "(" + snikket_Autolink.IRI_LABEL + "\\.)+" + snikket_Autolink.TLD;
+snikket_Autolink.PROTOCOL = "(?:http|https|rtsp):\\/\\/";
+snikket_Autolink.WORD_BOUNDARY = "(?:\\b|$|^)";
+snikket_Autolink.USER_INFO = "(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@";
+snikket_Autolink.PORT_NUMBER = "\\:\\d{1,5}";
+snikket_Autolink.PATH_CHAR = "(?:(?:[" + snikket_Autolink.LABEL_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_\\$])|(?:\\%[a-fA-F0-9]{2}))";
+snikket_Autolink.PATH_AND_QUERY = "\\/" + snikket_Autolink.PATH_CHAR + "*";
+snikket_Autolink.STRICT_TLD = "(?:" + snikket_Autolink.IANA_TOP_LEVEL_DOMAINS + "|" + snikket_Autolink.PUNYCODE_TLD + ")";
+snikket_Autolink.STRICT_HOST_NAME = "(?:(?:" + snikket_Autolink.IRI_LABEL + "\\.)+" + snikket_Autolink.STRICT_TLD + ")";
+snikket_Autolink.STRICT_DOMAIN_NAME = "(?:" + snikket_Autolink.STRICT_HOST_NAME + "|" + snikket_Autolink.IP_ADDRESS + "|" + snikket_Autolink.IP6_ADDRESS + ")";
+snikket_Autolink.RELAXED_DOMAIN_NAME = "(?:" + "(?:" + snikket_Autolink.IRI_LABEL + "(?:\\.(?=\\S))" + "?)+" + "|" + snikket_Autolink.IP_ADDRESS + "|" + snikket_Autolink.IP6_ADDRESS + ")";
+snikket_Autolink.WEB_URL_WITHOUT_PROTOCOL = "(" + snikket_Autolink.WORD_BOUNDARY + "(?<!:\\/\\/)" + "(" + "(?:" + snikket_Autolink.STRICT_DOMAIN_NAME + ")" + "(?:" + snikket_Autolink.PORT_NUMBER + ")?" + ")" + "(?:" + snikket_Autolink.PATH_AND_QUERY + ")?" + ")";
+snikket_Autolink.WEB_URL_WITH_PROTOCOL = "(" + snikket_Autolink.WORD_BOUNDARY + "(?:" + "(?:" + snikket_Autolink.PROTOCOL + "(?:" + snikket_Autolink.USER_INFO + ")?" + ")" + "(?:" + snikket_Autolink.RELAXED_DOMAIN_NAME + ")?" + "(?:" + snikket_Autolink.PORT_NUMBER + ")?" + ")" + "(?:" + snikket_Autolink.PATH_AND_QUERY + ")?" + ")";
+snikket_Autolink.AUTOLINK_WEB_URL = "(" + snikket_Autolink.WEB_URL_WITH_PROTOCOL + "|" + snikket_Autolink.WEB_URL_WITHOUT_PROTOCOL + ")" + snikket_Autolink.WORD_BOUNDARY;
+snikket_Autolink.TEL_URI = "tel:(?:(?:\\+\\d+)|(?:\\d+;phone-context=" + snikket_Autolink.PATH_CHAR + "+))";
+snikket_Autolink.SMS_URI = "sms:(?:(?:\\+\\d+)|(?:\\d+;phone-context=" + snikket_Autolink.PATH_CHAR + "+))";
+snikket_Autolink.XMPP_URI = "xmpp\\:(?:(?:[" + snikket_Autolink.GOOD_IRI_CHAR + "\\;\\/\\?\\@\\&\\=\\#\\~\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])" + "|(?:\\%[a-fA-F0-9]{2}))+";
+snikket_Chat._hx_skip_constructor = false;
+snikket_Chat.__meta__ = { fields : { addMedia : { 'HaxeCBridge.noemit' : null}}};
+snikket_DirectChat.__meta__ = { fields : { getParticipants : { 'HaxeCBridge.noemit' : null}, getParticipantDetails : { 'HaxeCBridge.noemit' : null}, getMessagesBefore : { 'HaxeCBridge.noemit' : null}, getMessagesAfter : { 'HaxeCBridge.noemit' : null}, getMessagesAround : { 'HaxeCBridge.noemit' : null}, correctMessage : { 'HaxeCBridge.noemit' : null}, sendMessage : { 'HaxeCBridge.noemit' : null}, removeReaction : { 'HaxeCBridge.noemit' : null}, lastMessageId : { 'HaxeCBridge.noemit' : null}, markReadUpTo : { 'HaxeCBridge.noemit' : null}, bookmark : { 'HaxeCBridge.noemit' : null}, close : { 'HaxeCBridge.noemit' : null}}};
+snikket_Channel.__meta__ = { fields : { getParticipants : { 'HaxeCBridge.noemit' : null}, getParticipantDetails : { 'HaxeCBridge.noemit' : null}, getMessagesBefore : { 'HaxeCBridge.noemit' : null}, getMessagesAfter : { 'HaxeCBridge.noemit' : null}, getMessagesAround : { 'HaxeCBridge.noemit' : null}, correctMessage : { 'HaxeCBridge.noemit' : null}, sendMessage : { 'HaxeCBridge.noemit' : null}, removeReaction : { 'HaxeCBridge.noemit' : null}, lastMessageId : { 'HaxeCBridge.noemit' : null}, markReadUpTo : { 'HaxeCBridge.noemit' : null}, bookmark : { 'HaxeCBridge.noemit' : null}, close : { 'HaxeCBridge.noemit' : null}}};
+snikket_ChatMessage.__meta__ = { fields : { reactions : { 'HaxeCBridge.noemit' : null}}};
+snikket_ChatMessageBuilder.__meta__ = { fields : { reactions : { 'HaxeCBridge.noemit' : null}}};
+snikket_EventEmitter._hx_skip_constructor = false;
+snikket_Config.relativeHashUri = false;
+snikket_EmojiUtil.MISC_SYMBOLS_AND_PICTOGRAPHS = new snikket_UnicodeRange(127744,128511);
+snikket_EmojiUtil.SUPPLEMENTAL_SYMBOLS = new snikket_UnicodeRange(129280,129535);
+snikket_EmojiUtil.EMOTICONS = new snikket_UnicodeRange(128512,129782);
+snikket_EmojiUtil.MISC_SYMBOLS = new snikket_UnicodeRange(9728,9983);
+snikket_EmojiUtil.DINGBATS = new snikket_UnicodeRange(9984,10175);
+snikket_EmojiUtil.ENCLOSED_ALPHANUMERIC_SUPPLEMENT = new snikket_UnicodeRange(127232,127487);
+snikket_EmojiUtil.ENCLOSED_IDEOGRAPHIC_SUPPLEMENT = new snikket_UnicodeRange(127488,127743);
+snikket_EmojiUtil.REGIONAL_INDICATORS = new snikket_UnicodeRange(127462,127487);
+snikket_EmojiUtil.GEOMETRIC_SHAPES = new snikket_UnicodeRange(9632,9727);
+snikket_EmojiUtil.LATIN_SUPPLEMENT = new snikket_UnicodeRange(128,255);
+snikket_EmojiUtil.MISC_TECHNICAL = new snikket_UnicodeRange(8960,9215);
+snikket_EmojiUtil.TAGS = new snikket_UnicodeRange(917536,917631);
+snikket_EmojiUtil.CYK_SYMBOLS_AND_PUNCTUATION = new snikket_UnicodeList(12336,12349);
+snikket_EmojiUtil.LETTERLIKE_SYMBOLS = new snikket_UnicodeList(8482,8505);
+snikket_EmojiUtil.KEYCAP_COMBINEABLE = new snikket_UnicodeBlocks(new snikket_UnicodeList(35),new snikket_UnicodeList(42),new snikket_UnicodeRange(48,57));
+snikket_EmojiUtil.SYMBOLIZE = new snikket_UnicodeBlocks(snikket_EmojiUtil.GEOMETRIC_SHAPES,snikket_EmojiUtil.LATIN_SUPPLEMENT,snikket_EmojiUtil.CYK_SYMBOLS_AND_PUNCTUATION,snikket_EmojiUtil.LETTERLIKE_SYMBOLS,snikket_EmojiUtil.KEYCAP_COMBINEABLE);
+snikket_EmojiUtil.EMOJIS = new snikket_UnicodeBlocks(snikket_EmojiUtil.MISC_SYMBOLS_AND_PICTOGRAPHS,snikket_EmojiUtil.SUPPLEMENTAL_SYMBOLS,snikket_EmojiUtil.EMOTICONS,snikket_EmojiUtil.MISC_SYMBOLS,snikket_EmojiUtil.DINGBATS,snikket_EmojiUtil.ENCLOSED_ALPHANUMERIC_SUPPLEMENT,snikket_EmojiUtil.ENCLOSED_IDEOGRAPHIC_SUPPLEMENT,snikket_EmojiUtil.MISC_TECHNICAL);
+snikket_EmojiUtil.MAX_EMOIJS = 42;
+snikket_EmojiUtil.ZWJ = 8205;
+snikket_EmojiUtil.VARIATION_16 = 65039;
+snikket_EmojiUtil.COMBINING_ENCLOSING_KEYCAP = 8419;
+snikket_EmojiUtil.BLACK_FLAG = 127988;
+snikket_EmojiUtil.FITZPATRICK = new snikket_UnicodeRange(127995,127999);
+snikket_Persistence.__meta__ = { fields : { getChatsUnreadDetails : { 'HaxeCBridge.noemit' : null}, findServicesWithFeature : { 'HaxeCBridge.noemit' : null}}};
+snikket_Version.HUMAN = "cf378ac";
+snikket_persistence_Dummy.__meta__ = { fields : { lastId : { 'HaxeCBridge.noemit' : null}, storeChats : { 'HaxeCBridge.noemit' : null}, getChats : { 'HaxeCBridge.noemit' : null}, storeMessages : { 'HaxeCBridge.noemit' : null}, updateMessage : { 'HaxeCBridge.noemit' : null}, getMessage : { 'HaxeCBridge.noemit' : null}, getMessagesBefore : { 'HaxeCBridge.noemit' : null}, getMessagesAfter : { 'HaxeCBridge.noemit' : null}, getMessagesAround : { 'HaxeCBridge.noemit' : null}, getChatsUnreadDetails : { 'HaxeCBridge.noemit' : null}, storeReaction : { 'HaxeCBridge.noemit' : null}, updateMessageStatus : { 'HaxeCBridge.noemit' : null}, getMediaUri : { 'HaxeCBridge.noemit' : null}, hasMedia : { 'HaxeCBridge.noemit' : null}, storeMedia : { 'HaxeCBridge.noemit' : null}, removeMedia : { 'HaxeCBridge.noemit' : null}, storeCaps : { 'HaxeCBridge.noemit' : null}, getCaps : { 'HaxeCBridge.noemit' : null}, storeLogin : { 'HaxeCBridge.noemit' : null}, getLogin : { 'HaxeCBridge.noemit' : null}, removeAccount : { 'HaxeCBridge.noemit' : null}, storeStreamManagement : { 'HaxeCBridge.noemit' : null}, getStreamManagement : { 'HaxeCBridge.noemit' : null}, storeService : { 'HaxeCBridge.noemit' : null}, findServicesWithFeature : { 'HaxeCBridge.noemit' : null}}};
+snikket_persistence_Sqlite.__meta__ = { fields : { get : { 'HaxeCBridge.noemit' : null}, set : { 'HaxeCBridge.noemit' : null}, lastId : { 'HaxeCBridge.noemit' : null}, storeChats : { 'HaxeCBridge.noemit' : null}, getChats : { 'HaxeCBridge.noemit' : null}, storeMessages : { 'HaxeCBridge.noemit' : null}, updateMessage : { 'HaxeCBridge.noemit' : null}, getMessagesBefore : { 'HaxeCBridge.noemit' : null}, getMessagesAfter : { 'HaxeCBridge.noemit' : null}, getMessagesAround : { 'HaxeCBridge.noemit' : null}, getChatsUnreadDetails : { 'HaxeCBridge.noemit' : null}, storeReaction : { 'HaxeCBridge.noemit' : null}, updateMessageStatus : { 'HaxeCBridge.noemit' : null}, hasMedia : { 'HaxeCBridge.noemit' : null}, removeMedia : { 'HaxeCBridge.noemit' : null}, storeMedia : { 'HaxeCBridge.noemit' : null}, storeCaps : { 'HaxeCBridge.noemit' : null}, getCaps : { 'HaxeCBridge.noemit' : null}, storeLogin : { 'HaxeCBridge.noemit' : null}, getLogin : { 'HaxeCBridge.noemit' : null}, removeAccount : { 'HaxeCBridge.noemit' : null}, storeStreamManagement : { 'HaxeCBridge.noemit' : null}, getStreamManagement : { 'HaxeCBridge.noemit' : null}, storeService : { 'HaxeCBridge.noemit' : null}, findServicesWithFeature : { 'HaxeCBridge.noemit' : null}}};
+snikket_queries_GenericQuery._hx_skip_constructor = false;
+thenshim_Promise.factory = new thenshim_js_JSPromiseFactory();
+tink__$Chunk_EmptyChunk.EMPTY = new haxe_io_Bytes(new ArrayBuffer(0));
+tink_Chunk.EMPTY = new tink__$Chunk_EmptyChunk();
+tink_Stringly.SUPPORTED_DATE_REGEX = new EReg("^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})(\\.\\d{3})?(Z|[\\+-]\\d{2}:\\d{2})$","");
+tink_Url.SCHEME = 2;
+tink_Url.PAYLOAD = 3;
+tink_Url.AUTH = 6;
+tink_Url.HOSTNAMES = 7;
+tink_Url.PATH = 8;
+tink_Url.QUERY = 10;
+tink_Url.HASH = 12;
+tink_core_Callback.depth = 0;
+tink_core_Callback.MAX_DEPTH = 500;
+tink_core_SimpleDisposable._hx_skip_constructor = false;
+tink_core_AlreadyDisposed.INST = new tink_core_AlreadyDisposed();
+tink_core__$Future_FutureObject._hx_skip_constructor = false;
+tink_core_Future.NOISE = new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(null));
+tink_core_Future.NEVER_INST = new tink_core__$Future_FutureObject();
+tink_core_Future.NEVER = tink_core_Future.NEVER_INST;
+tink_core_Lazy.NOISE = new tink_core__$Lazy_LazyConst(null);
+tink_core_Lazy.NULL = tink_core_Lazy.NOISE;
+tink_core_Noise.Noise = null;
+tink_core_ProgressValue.ZERO = new tink_core_MPair(0,haxe_ds_Option.None);
+tink_core_Progress.INIT = tink_core_ProgressValue.ZERO;
+tink_core__$Progress_ProgressObject._hx_skip_constructor = false;
+tink_core_Promise.NOISE = new tink_core__$Future_SyncFuture(new tink_core__$Lazy_LazyConst(tink_core_Outcome.Success(null)));
+tink_core_Promise.NEVER = tink_core_Promise.never();
+tink_core__$Signal_Disposed.INST = new tink_core__$Signal_Disposed();
+tink_http_ChunkedParser.LINEBREAK = tink_chunk_Seekable.ofBytes(haxe_io_Bytes.ofString("\r\n"));
+tink_http_Fetch.cache = new haxe_ds_EnumValueMap();
+tink_http_Header._hx_skip_constructor = false;
+tink_http_HeaderValue.DAYS = "Sun,Mon,Tue,Wen,Thu,Fri,Sat".split(",");
+tink_http_HeaderValue.MONTHS = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(",");
+tink_http_HeaderName.REFERER = "referer";
+tink_http_HeaderName.HOST = "host";
+tink_http_HeaderName.SET_COOKIE = "set-cookie";
+tink_http_HeaderName.COOKIE = "cookie";
+tink_http_HeaderName.CONTENT_TYPE = "content-type";
+tink_http_HeaderName.CONTENT_LENGTH = "content-length";
+tink_http_HeaderName.CONTENT_DISPOSITION = "content-disposition";
+tink_http_HeaderName.CONTENT_RANGE = "content-range";
+tink_http_HeaderName.ACCEPT = "accept";
+tink_http_HeaderName.ACCEPT_ENCODING = "accept-encoding";
+tink_http_HeaderName.TRANSFER_ENCODING = "transfer-encoding";
+tink_http_HeaderName.RANGE = "range";
+tink_http_HeaderName.LOCATION = "location";
+tink_http_HeaderName.AUTHORIZATION = "authorization";
+tink_http_HeaderName.ORIGIN = "origin";
+tink_http_HeaderName.VARY = "vary";
+tink_http_HeaderName.CACHE_CONTROL = "cache-control";
+tink_http_HeaderName.EXPIRES = "expires";
+tink_http_HeaderName.ACCESS_CONTROL_REQUEST_METHOD = "access-control-request-method";
+tink_http_HeaderName.ACCESS_CONTROL_REQUEST_HEADERS = "access-control-request-headers";
+tink_http_HeaderName.ACCESS_CONTROL_ALLOW_ORIGIN = "access-control-allow-origin";
+tink_http_HeaderName.ACCESS_CONTROL_ALLOW_CREDENTIALS = "access-control-allow-credentials";
+tink_http_HeaderName.ACCESS_CONTROL_EXPOSE_HEADERS = "access-control-expose-headers";
+tink_http_HeaderName.ACCESS_CONTROL_MAX_AGE = "access-control-max-age";
+tink_http_HeaderName.ACCESS_CONTROL_ALLOW_METHODS = "access-control-allow-methods";
+tink_http_HeaderName.ACCESS_CONTROL_ALLOW_HEADERS = "access-control-allow-headers";
+tink_http_HeaderParser.INVALID = tink_io_ParseStep.Failed(new tink_core_TypedError(422,"Invalid HTTP header",{ fileName : "tink/http/Header.hx", lineNumber : 310, className : "tink.http.HeaderParser", methodName : "INVALID"}));
+tink_http_Message._hx_skip_constructor = false;
+tink_http_Method.GET = "GET";
+tink_http_Method.HEAD = "HEAD";
+tink_http_Method.OPTIONS = "OPTIONS";
+tink_http_Method.POST = "POST";
+tink_http_Method.PUT = "PUT";
+tink_http_Method.PATCH = "PATCH";
+tink_http_Method.DELETE = "DELETE";
+tink_io__$Sink_Blackhole.inst = new tink_io__$Sink_Blackhole();
+tink_io_SinkYielding.BLACKHOLE = tink_io__$Sink_Blackhole.inst;
+tink_streams_StreamBase._hx_skip_constructor = false;
+tink_streams_Empty.inst = new tink_streams_Empty();
+tink_io_Source.EMPTY = tink_streams_Empty.inst;
+tink_io_Worker.EAGER = new tink_io__$Worker_EagerWorker();
+tink_io_Worker.pool = [tink_io_Worker.EAGER];
+tink_url_Path.root = "/";
+})(typeof exports != "undefined" ? exports : typeof window != "undefined" ? window : typeof self != "undefined" ? self : this, typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this);
+export const snikket = exports.snikket;
diff --git a/npm/sqlite-worker1.mjs b/npm/sqlite-worker1.mjs
new file mode 100644
index 0000000..b894a75
--- /dev/null
+++ b/npm/sqlite-worker1.mjs
@@ -0,0 +1,38 @@
+/*
+  2022-05-23
+
+  The author disclaims copyright to this source code.  In place of a
+  legal notice, here is a blessing:
+
+  *   May you do good and not evil.
+  *   May you find forgiveness for yourself and forgive others.
+  *   May you share freely, never taking more than you give.
+
+  ***********************************************************************
+
+  This is a JS Worker file for the main sqlite3 api. It loads
+  sqlite3.js, initializes the module, and postMessage()'s a message
+  after the module is initialized:
+
+  {type: 'sqlite3-api', result: 'worker1-ready'}
+
+  This seemingly superfluous level of indirection is necessary when
+  loading sqlite3.js via a Worker. Instantiating a worker with new
+  Worker("sqlite.js") will not (cannot) call sqlite3InitModule() to
+  initialize the module due to a timing/order-of-operations conflict
+  (and that symbol is not exported in a way that a Worker loading it
+  that way can see it).  Thus JS code wanting to load the sqlite3
+  Worker-specific API needs to pass _this_ file (or equivalent) to the
+  Worker constructor and then listen for an event in the form shown
+  above in order to know when the module has completed initialization.
+
+  This file accepts a URL arguments to adjust how it loads sqlite3.js:
+
+  - `sqlite3.dir`, if set, treats the given directory name as the
+    directory from which `sqlite3.js` will be loaded.
+*/
+import { default as sqlite3InitModule } from '@sqlite.org/sqlite-wasm';
+sqlite3InitModule().then(async (sqlite3) => {
+	await sqlite3.installOpfsSAHPoolVfs(); // enable opfs-sahpool
+	await sqlite3.initWorker1API();
+});