// File: /workspace/github_cpp_makefile_star2_O2/Computer-Kids-Club[P]screenshare-pro-backend/server.cpp
// Function: main
int main(int argc, char *argv[]) {
    int opt = TRUE;
    int master_socket, addrlen, new_socket,
        max_clients = 30, activity, i, valread, sd;
    int max_sd;
    struct sockaddr_in address;

    bool doPrintSocketFrame = false;
    bool doPrintSocketFrameStats = false;

    // yes
    for (int i = 0; i < argc; i++) {
        if (argv[i][0] == '-') {
            if (strcmp(argv[i], "-pf") == 0) {
                doPrintSocketFrame = true;
            } else if (strcmp(argv[i], "-pfs") == 0) {
                doPrintSocketFrameStats = true;
            }
        }
    }

    unsigned long long totalFramesRecieved = 1;
    unsigned long long totalFramesSent = 1;
    unsigned long long lastFrameLength = 0;
    unsigned long long totalFrameLength = 0;

    std::unordered_map<std::string, int> urlToSocketDesc;
    std::unordered_map<int, std::vector<Client>> socketDescToClients;
    std::unordered_map<int, int> clientSocketDescToStreamerSocketDesc;
    std::unordered_map<int, Client> clients;

    char buffer[BUFFER_SIZE + 1];       //data buffer of 1K
    char send_buffer[BUFFER_SIZE + 1];  //data buffer of 1K

    //set of socket descriptors
    fd_set readfds;

    //create a master socket
    if ((master_socket = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    //set master socket to allow multiple connections ,
    //this is just a good habit, it will work without this
    if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
                   sizeof(opt)) < 0) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    //type of socket created
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    //bind the socket to localhost port 4004
    if (0 > bind(master_socket, (struct sockaddr *)&address, sizeof(address))) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    printf(COLOR_RESET "Listener on port %d \n", PORT);

    //try to specify maximum of 3 pending connections for the master socket
    if (listen(master_socket, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    //accept the incoming connection
    addrlen = sizeof(address);
    puts("Waiting for connections ...");

    while (TRUE) {
        //clear the socket set
        FD_ZERO(&readfds);

        //add master socket to set
        FD_SET(master_socket, &readfds);
        max_sd = master_socket;

        //add child sockets to set
        for (auto &clientFromClients : clients) {
            Client client = clientFromClients.second;
            //socket descriptor
            sd = client.socket_descriptor;

            //if valid socket descriptor then add to read list
            if (sd > 0)
                FD_SET(sd, &readfds);

            //highest file descriptor number, need it for the select function
            if (sd > max_sd)
                max_sd = sd;

            if (client.last_ping != -1) {
                if (client.last_ping != -1) {
                }
            }
        }

        //wait for an activity on one of the sockets , timeout is NULL ,
        //so wait indefinitely
        activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);

        if ((activity < 0) && (errno != EINTR)) {
            printf("select error");
        }

        //If something happened on the master socket ,
        //then its an incoming connection
        if (FD_ISSET(master_socket, &readfds)) {
            if (0 > (new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t *)&addrlen))) {
                perror("accept");
                exit(EXIT_FAILURE);
            }

            //inform user of socket number - used in send and receive commands
            printf(GREEN("New connection , socket fd is %d , ip is : %s , port : %d  \n"), new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));

            //puts("Welcome message sent successfully");

            clients[new_socket] = {new_socket, 0, "", -1};
            // clients.push_back({new_socket, 0});
            //printf("Adding to list of sockets as %d\n", i);
        }

        //else its some IO operation on some other socket
        // for (auto socketClientPair = clients.begin(); socketClientPair != clients.end(); ++socketClientPair) { //&socketClientPair : clients)
        auto it = clients.begin();
        while (it != clients.end()) {
            if (doPrintSocketFrameStats) {
                printf(COLOR_RESET "Total frames recieved: %llu\n", totalFramesRecieved);
                printf(COLOR_RESET "Total frames sent: %llu\n", totalFramesSent);
                printf(COLOR_RESET "Last frame length: %llu\n", lastFrameLength);
                printf(COLOR_RESET "Average frame length: %llu\n\n", totalFrameLength / totalFramesRecieved);
            }

            Client client = it->second;
            auto previous_it = it;
            ++it;
            //socket descriptor
            sd = client.socket_descriptor;
            if (FD_ISSET(sd, &readfds)) {
                //Check if it was for closing , and also read the
                //incoming message
                memset(buffer, 0, sizeof(buffer));

                int read_size = BUFFER_SIZE;

                if (client.startedWS == 1) {
                    read_size = 10;
                }
                if ((valread = read(sd, buffer, read_size)) == 0) {
                    //Somebody disconnected , get his details and print
                    getpeername(sd, (struct sockaddr *)&address, (socklen_t *)&addrlen);
                    printf(MAGENTA("Host disconnected , ip %s , port %d \n"), inet_ntoa(address.sin_addr), ntohs(address.sin_port));

                    //Close the socket and mark as 0 in list for reuse
                    close(sd);
                    //socketDescToClients[sd].erase(std::remove(socketDescToClients[sd].begin(), socketDescToClients[sd].end(), clients[sd]), socketDescToClients[sd].end());
                    it = clients.erase(previous_it);
                    continue;
                } else {
                    //set the string terminating NULL byte on the end
                    //of the data read
                    buffer[valread] = '\0';

                    if (client.startedWS == 1) {
                        unsigned int fin = (unsigned int)(buffer[0] & 0b10000000) == 0b10000000;
                        unsigned int opcode = (unsigned int)(buffer[0] & 0b00001111);
                        if (opcode > 2) {
                            //printf(BACK_YELLOW(RED("Something is very wrong: 1.") "\n=============================================================\n"));
                            //continue;
                        } else if (fin == 0 || opcode == 0) {
                            //printf(BACK_YELLOW(RED("Something is very wrong: 2.") "\n=============================================================\n"));
                            continue;
                        }
                        unsigned long payload_length = (unsigned int)(buffer[1] & 0b01111111);
                        unsigned int bit_offset = 2;
                        if (payload_length == 126) {
                            bit_offset += 2;
                            payload_length = (unsigned int)(buffer[2] & 0b11111111);
                            payload_length = payload_length << 8;
                            payload_length += (unsigned int)(buffer[3] & 0b11111111);
                        } else if (payload_length == 127) {
                            bit_offset += 8;
                            payload_length = (unsigned int)(buffer[2] & 0b11111111);
                            for (int shift_i = 0; shift_i < 7; shift_i++) {
                                payload_length = payload_length << 8;
                                payload_length += (unsigned int)(buffer[3 + shift_i] & 0b11111111);
                            }
                        }
                        if (doPrintSocketFrame) {
                            printf(BACK_YELLOW("================= Recieved websocket Frame ==================") ".");
                            printf("\n" BACK_YELLOW(" ") " Fin: %x ", fin);
                            printf(("Opcode: %x "), opcode);
                            printf(("Is masked: %d "), (unsigned int)((buffer[1] & 0b10000000) == 0b10000000));
                            printf(("Payload length: %lu"), payload_length);
                            printf(("\n" BACK_YELLOW(" ") " Mask: %x %x %x %x "),
                                   (unsigned int)(buffer[bit_offset + 0] & 0b11111111),
                                   (unsigned int)(buffer[bit_offset + 1] & 0b11111111),
                                   (unsigned int)(buffer[bit_offset + 2] & 0b11111111),
                                   (unsigned int)(buffer[bit_offset + 3] & 0b11111111));
                        }

                        bit_offset += 4;

                        totalFramesRecieved++;

                        int totalread = valread;
                        if (payload_length + bit_offset + 1 > BUFFER_SIZE) {
                            while (totalread < payload_length + bit_offset && (valread = read(sd, buffer, payload_length + bit_offset - totalread)) != 0) {
                                totalread += valread;
                            }
                            lastFrameLength = totalread;
                            totalFrameLength += totalread;
                            printf(BACK_YELLOW(RED("Dropped frame.")) " (Frame size is greater than %d bytes)\n", BUFFER_SIZE);
                            continue;
                        };
                        while (totalread < payload_length + bit_offset) {
                            valread = read(sd, buffer + totalread, payload_length + bit_offset - totalread);
                            totalread += valread;
                        }
                        lastFrameLength = totalread;
                        totalFrameLength += totalread;
                        buffer[totalread] = '\0';
                        if (doPrintSocketFrame) {
                            printf(("Total read length: %d\n"), totalread);
                            printf(BACK_YELLOW("=============================================================\n"));
                        }

                        //printf("Unmasked payload: \n>");
                        for (int payload_i = 0; payload_i < payload_length; payload_i++) {
                            buffer[bit_offset + payload_i] = buffer[bit_offset + payload_i] ^ buffer[bit_offset - 4 + payload_i % 4];
                            //printf("%c", buffer[bit_offset + payload_i]);
                        }

                        if (payload_length > 7 && buffer[bit_offset + 2] == 'h' && buffer[bit_offset + 3] == 'r' && buffer[bit_offset + 4] == 'e' && buffer[bit_offset + 5] == 'f') {
                            std::string url = std::string(buffer + bit_offset + 9, buffer + bit_offset - 2 + payload_length);
                            printf("%s\n", url.c_str());
                            if (url.compare(baseUrl) == 0) {
                                std::string stream_url = url + std::to_string(sd);
                                urlToSocketDesc[stream_url] = sd;
                                socketDescToClients[sd] = std::vector<Client>();

                                int send_len = generate_ws_frame(send_buffer, "{\"url\":\"" + stream_url + "\",\"streamer\":" + std::to_string(sd) + "}");

                                if (send(sd, send_buffer, send_len, 0) != send_len) {
                                    perror("send");
                                }

                                continue;
                            } else {
                                previous_it->second.url = url;
                                clientSocketDescToStreamerSocketDesc[sd] = urlToSocketDesc[url];
                                socketDescToClients[urlToSocketDesc[url]].push_back(previous_it->second);

                                int send_len = generate_ws_frame(send_buffer, "{\"watcher\":" + std::to_string(sd) + ",\"streamer\":" + std::to_string(urlToSocketDesc[url]) + "}");

                                if (send(sd, send_buffer, send_len, 0) != send_len) {
                                    perror("send");
                                }
                            }
                            continue;
                        }

                        if (opcode != 1 && opcode != 2) {
                            continue;
                        }

                        //printf("Bit offset: %d\n", bit_offset);

                        for (int payload_i = 0; payload_i < payload_length; payload_i++) {
                            buffer[bit_offset - 4 + payload_i] = buffer[bit_offset + payload_i];
                        }

                        buffer[0] = buffer[0] & 0b10001111;
                        buffer[1] = buffer[1] & 0b01111111;

                        opcode = (unsigned int)(buffer[0] & 0b00001111);

                        buffer[bit_offset - 4 + payload_length] = '\0';
                        buffer[bit_offset - 3 + payload_length] = '\0';
                        buffer[bit_offset - 2 + payload_length] = '\0';
                        buffer[bit_offset - 1 + payload_length] = '\0';

                        int target_sd_bit_offset = bit_offset - 4;
                        if (buffer[target_sd_bit_offset] == 't' && buffer[target_sd_bit_offset + 1] == 'o') {
                            int target_sd = 0;
                            target_sd_bit_offset += 2;
                            while (buffer[target_sd_bit_offset] != '{') {
                                target_sd = target_sd * 10 + buffer[target_sd_bit_offset++] - '0';
                            }
                            if (send(target_sd, buffer, bit_offset - 4 + payload_length, 0) != bit_offset - 4 + payload_length) {
                                perror("send");
                            } else {
                                totalFramesSent++;
                            }
                        } else if (clientSocketDescToStreamerSocketDesc[sd] && clientSocketDescToStreamerSocketDesc[sd] != sd) {
                            if (send(clientSocketDescToStreamerSocketDesc[sd], buffer, bit_offset - 4 + payload_length, 0) != bit_offset - 4 + payload_length) {
                                perror("send");
                            } else {
                                totalFramesSent++;
                            }
                        } else {
                            for (auto clientForSocket = socketDescToClients[sd].begin(); clientForSocket != socketDescToClients[sd].end();) {
                                if (send(clientForSocket->socket_descriptor, buffer, bit_offset - 4 + payload_length, 0) != bit_offset - 4 + payload_length) {
                                    perror("send");
                                    clientForSocket = socketDescToClients[sd].erase(clientForSocket);
                                } else {
                                    totalFramesSent++;
                                    clientForSocket++;
                                }
                            }
                        }

                        continue;
                    }

                    std::unordered_map<std::string, std::string> headerMap = parse_header(buffer, buffer + valread);

                    if (headerMap.count("Sec-WebSocket-Key") == 1) {
                        printf(GREEN("Recieved ws request\n"));
                        printf(CYAN("%s\n"), buffer);

                        char sha1_handshake[40];
                        size_t handshake_sz;

                        memset(sha1_handshake, 0, sizeof(sha1_handshake));
                        if (ws_compute_handshake(headerMap["Sec-WebSocket-Key"].c_str(), sha1_handshake, &handshake_sz) != 0) {
                            /* failed to compute handshake. */
                            printf("failed to compute handshake\n");
                            continue;
                        }

                        //printf("%s\n", sha1_handshake);

                        std::string strWSResponse = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\n";
                        strWSResponse += "Sec-WebSocket-Accept: ";
                        strWSResponse += sha1_handshake;
                        strWSResponse += "\r\n";
                        const char *strWSResponseMsg = strWSResponse.c_str();

                        //send websocket response
                        if (send(sd, strWSResponseMsg, strlen(strWSResponseMsg), 0) != strlen(strWSResponseMsg)) {
                            perror("send");
                        }

                        previous_it->second.startedWS = 1;

                    } else {
                        printf(GREEN("Recieved http request\n"));
                        printf(RED("%s\n"), buffer);
                    }

                    /*for (auto x : headerMap)
                    {
                        //cout << x.first << " " << x.second << endl;
                        printf(">%s< -> >%s<\n", x.first.c_str(), x.second.c_str());
                    }*/
                    //send(sd, buffer, strlen(buffer), 0);
                }
            }
        }
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x20348, %rsp          # imm = 0x20348
movq %rsi, %rbx
movl %edi, %r14d
movl $0x1, -0x8c(%rbp)
xorl %r12d, %r12d
testl %edi, %edi
cmovlel %r12d, %r14d
leaq 0x4a30(%rip), %r15      # 0x7020
movq $0x0, -0x38(%rbp)
movq $0x0, -0x88(%rbp)
cmpq %r12, %r14
je 0x2650
movq (%rbx,%r12,8), %r13
cmpb $0x2d, (%r13)
jne 0x264b
movq %r13, %rdi
movq %r15, %rsi
callq 0x22e0
testl %eax, %eax
je 0x2642
movq %r13, %rdi
leaq 0x49f8(%rip), %rsi      # 0x7024
callq 0x22e0
testl %eax, %eax
sete %al
movq -0x38(%rbp), %rcx
orb %al, %cl
movq %rcx, -0x38(%rbp)
jmp 0x264b
movb $0x1, %al
movq %rax, -0x88(%rbp)
incq %r12
jmp 0x2603
leaq -0x2a0(%rbp), %rax
movq %rax, -0x30(%rax)
pushq $0x1
popq %rdx
movq %rdx, -0x28(%rax)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, %ecx       # imm = 0x3F800000
movl %ecx, -0x10(%rax)
movups %xmm0, -0x8(%rax)
leaq -0x1f8(%rbp), %rax
movq %rax, -0x30(%rax)
movq %rdx, -0x28(%rax)
movups %xmm0, -0x20(%rax)
movl %ecx, -0x10(%rax)
movups %xmm0, -0x8(%rax)
leaq -0x268(%rbp), %rax
movq %rax, -0x30(%rax)
movq %rdx, -0x28(%rax)
movups %xmm0, -0x20(%rax)
movl %ecx, -0x10(%rax)
movups %xmm0, -0x8(%rax)
leaq -0x230(%rbp), %rax
movq %rax, -0x30(%rax)
movq %rdx, -0x28(%rax)
movups %xmm0, -0x20(%rax)
movl %ecx, -0x10(%rax)
movups %xmm0, -0x8(%rax)
pushq $0x2
popq %rdi
pushq $0x1
popq %rsi
xorl %edx, %edx
callq 0x2080
testl %eax, %eax
jne 0x26dd
leaq 0x494e(%rip), %rdi      # 0x7029
jmp 0x2752
movl %eax, %ebx
pushq $0x1
popq %rsi
pushq $0x2
popq %rdx
leaq -0x8c(%rbp), %rcx
pushq $0x4
popq %r8
movl %eax, %edi
callq 0x2390
testl %eax, %eax
jns 0x2704
leaq 0x4935(%rip), %rdi      # 0x7037
jmp 0x2752
movl $0xa40f0002, %eax       # imm = 0xA40F0002
leaq -0xd8(%rbp), %rsi
movq %rax, (%rsi)
pushq $0x10
popq %rdx
movl %ebx, %edi
callq 0x2060
testl %eax, %eax
jns 0x272a
leaq 0x491a(%rip), %rdi      # 0x7042
jmp 0x2752
leaq 0x491d(%rip), %rdi      # 0x704e
movl $0xfa4, %esi            # imm = 0xFA4
xorl %eax, %eax
callq 0x2040
pushq $0x3
popq %rsi
movl %ebx, %edi
callq 0x2250
testl %eax, %eax
jns 0x275f
leaq 0x4916(%rip), %rdi      # 0x7068
callq 0x21f0
pushq $0x1
popq %rdi
callq 0x2280
leaq -0x48(%rbp), %rax
movl $0x10, (%rax)
leaq 0x48ff(%rip), %rdi      # 0x706f
callq 0x2330
pushq $0x40
popq %rcx
movl %ebx, %eax
cltd
idivl %ecx
movslq %eax, %rcx
movq %rcx, -0xe8(%rbp)
shll $0x6, %eax
movl %ebx, -0x3c(%rbp)
subl %eax, %ebx
pushq $0x1
popq %rdx
movq %rdx, %rax
movl %ebx, %ecx
shlq %cl, %rax
movq %rax, -0xe0(%rbp)
leaq -0x158(%rbp), %r12
movq $0x0, -0xf8(%rbp)
xorl %ebx, %ebx
movq %rdx, -0x78(%rbp)
movq %rdx, -0xf0(%rbp)
xorl %eax, %eax
cmpq $0x10, %rax
je 0x27d6
andq $0x0, -0x370(%rbp,%rax,8)
incq %rax
jmp 0x27c2
movq -0xe8(%rbp), %rax
movq -0xe0(%rbp), %rcx
orq %rcx, -0x370(%rbp,%rax,8)
leaq -0x250(%rbp), %r15
movl -0x3c(%rbp), %r14d
movq (%r15), %r15
testq %r15, %r15
je 0x2844
leaq 0x10(%r15), %rsi
leaq -0xc8(%rbp), %rdi
callq 0x35da
movl -0xc8(%rbp), %ecx
movl %ecx, -0x2c(%rbp)
testl %ecx, %ecx
jle 0x282f
pushq $0x1
popq %rax
shlq %cl, %rax
movl %ecx, %edx
shrl $0x6, %edx
orq %rax, -0x370(%rbp,%rdx,8)
cmpl %r14d, %ecx
cmovgl %ecx, %r14d
leaq -0xc0(%rbp), %rdi
callq 0x2130
jmp 0x27f7
incl %r14d
movl %r14d, %edi
leaq -0x370(%rbp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x2210
movq -0x38(%rbp), %r15
testl %eax, %eax
jns 0x287d
callq 0x2030
cmpl $0x4, (%rax)
je 0x287d
leaq 0x4815(%rip), %rdi      # 0x708b
xorl %eax, %eax
callq 0x2040
movq -0xe8(%rbp), %rax
movq -0xe0(%rbp), %rcx
testq %rcx, -0x370(%rbp,%rax,8)
je 0x2943
movl -0x3c(%rbp), %edi
leaq -0xd8(%rbp), %rsi
leaq -0x48(%rbp), %rdx
callq 0x20d0
movl %eax, %r14d
movl %eax, -0x44(%rbp)
testl %eax, %eax
js 0x341e
movl -0xd4(%rbp), %edi
callq 0x2110
movzwl -0xd6(%rbp), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
leaq 0x47c5(%rip), %rdi      # 0x709f
movl %r14d, %esi
movq %rax, %rdx
xorl %eax, %eax
callq 0x2040
movl -0x44(%rbp), %eax
movl %eax, -0xc8(%rbp)
andl $0x0, -0xc4(%rbp)
leaq -0xc0(%rbp), %rdi
leaq 0x485b(%rip), %rsi      # 0x7160
leaq -0x160(%rbp), %rdx
callq 0x3606
orl $-0x1, -0xa0(%rbp)
leaq -0x260(%rbp), %rdi
leaq -0x44(%rbp), %rsi
callq 0x3e5a
movq %rax, %rdi
leaq -0xc8(%rbp), %rsi
callq 0x3642
leaq -0xc0(%rbp), %rdi
callq 0x2130
movq -0x250(%rbp), %r14
testq %r14, %r14
je 0x27c0
testb $0x1, %r15b
je 0x29b7
leaq 0x4785(%rip), %rdi      # 0x70e5
movq %r14, %r13
movq -0xf0(%rbp), %r14
movq %r14, %rsi
xorl %eax, %eax
callq 0x2040
leaq 0x478b(%rip), %rdi      # 0x7106
movq -0x78(%rbp), %rsi
xorl %eax, %eax
callq 0x2040
leaq 0x4796(%rip), %rdi      # 0x7123
movq %rbx, %rsi
xorl %eax, %eax
callq 0x2040
movq -0xf8(%rbp), %rax
xorl %edx, %edx
divq %r14
movq %r13, %r14
leaq 0x4793(%rip), %rdi      # 0x7140
movq %rax, %rsi
xorl %eax, %eax
callq 0x2040
leaq 0x10(%r14), %r13
leaq -0x160(%rbp), %rdi
movq %r13, %rsi
callq 0x35da
movq %r14, -0x80(%rbp)
movq (%r14), %rax
movq %rax, -0x100(%rbp)
movl -0x160(%rbp), %r14d
movl %r14d, -0x2c(%rbp)
movl %r14d, %eax
cltd
pushq $0x40
popq %rcx
idivl %ecx
cltq
movq -0x370(%rbp,%rax,8), %rax
btq %rdx, %rax
jae 0x3248
movq %r13, -0x170(%rbp)
movl $0x10000, %edx          # imm = 0x10000
leaq -0x10370(%rbp), %r13
movq %r13, %rdi
xorl %esi, %esi
callq 0x2190
cmpl $0x1, -0x15c(%rbp)
movl $0xffff, %edx           # imm = 0xFFFF
pushq $0xa
popq %rax
cmoveq %rax, %rdx
movl %r14d, %edi
movq %r13, %rsi
callq 0x22f0
movq %rax, %r14
testl %r14d, %r14d
je 0x2aab
movslq %r14d, %rax
movb $0x0, -0x10370(%rbp,%rax)
cmpl $0x1, -0x15c(%rbp)
jne 0x2b0c
movzbl -0x10370(%rbp), %esi
movl %esi, %edx
andl $0xf, %edx
cmpl $0x2, %edx
ja 0x2a7f
testb %sil, %sil
setns %al
testl %edx, %edx
sete %cl
orb %al, %cl
jne 0x3248
movzbl -0x1036f(%rbp), %r13d
andl $0x7f, %r13d
cmpq $0x7e, %r13
jne 0x2c34
movzwl -0x1036e(%rbp), %eax
rolw $0x8, %ax
movzwl %ax, %r13d
pushq $0x4
jmp 0x2c63
movl -0x2c(%rbp), %edi
leaq -0xd8(%rbp), %rsi
leaq -0x48(%rbp), %rdx
callq 0x21c0
movl -0xd4(%rbp), %edi
callq 0x2110
movzwl -0xd6(%rbp), %ecx
rolw $0x8, %cx
movzwl %cx, %edx
leaq 0x4683(%rip), %rdi      # 0x7161
movq %rax, %rsi
xorl %eax, %eax
callq 0x2040
movl -0x2c(%rbp), %edi
callq 0x23e0
leaq -0x260(%rbp), %rdi
movq -0x80(%rbp), %rsi
callq 0x42c8
movq %rax, -0x100(%rbp)
jmp 0x3248
leaq (%rax,%rbp), %rdx
addq $-0x10370, %rdx         # imm = 0xFFFEFC90
leaq -0xc8(%rbp), %rdi
leaq -0x10370(%rbp), %rsi
callq 0x59f8
leaq -0x130(%rbp), %r13
movq %r13, %rdi
leaq 0x4817(%rip), %rsi      # 0x7352
leaq -0x70(%rbp), %rdx
callq 0x3606
leaq -0xc8(%rbp), %rdi
movq %r13, %rsi
callq 0x5374
movq %rax, %r14
movq %r13, %rdi
callq 0x2130
cmpq $0x1, %r14
jne 0x2c0c
leaq 0x47f5(%rip), %rdi      # 0x7364
xorl %eax, %eax
callq 0x2040
leaq 0x4805(%rip), %rdi      # 0x7382
leaq -0x10370(%rbp), %rsi
xorl %eax, %eax
callq 0x2040
xorps %xmm0, %xmm0
movaps %xmm0, -0x130(%rbp)
movaps %xmm0, -0x120(%rbp)
andq $0x0, -0x110(%rbp)
leaq -0x70(%rbp), %r14
movq %r14, %rdi
leaq 0x47a0(%rip), %rsi      # 0x7352
leaq -0x190(%rbp), %rdx
callq 0x3606
leaq -0xc8(%rbp), %rdi
movq %r14, %rsi
callq 0x5468
movq (%rax), %rdi
leaq -0x130(%rbp), %rsi
leaq -0x1b0(%rbp), %rdx
callq 0x62d4
movl %eax, %r14d
leaq -0x70(%rbp), %r13
movq %r13, %rdi
callq 0x2130
testl %r14d, %r14d
je 0x3030
leaq 0x4861(%rip), %rdi      # 0x7463
callq 0x2330
jmp 0x30bf
leaq 0x47df(%rip), %rdi      # 0x73f2
xorl %eax, %eax
callq 0x2040
leaq 0x47f1(%rip), %rdi      # 0x7412
leaq -0x10370(%rbp), %rsi
xorl %eax, %eax
callq 0x2040
jmp 0x30bf
pushq $0x2
popq %rax
cmpb $0x7f, %r13b
jne 0x2c64
movzbl -0x1036e(%rbp), %r13d
pushq $-0x7
popq %rax
testq %rax, %rax
je 0x2c61
shlq $0x8, %r13
movzbl -0x10366(%rbp,%rax), %ecx
orq %rcx, %r13
incq %rax
jmp 0x2c48
pushq $0xa
popq %rax
movl %edx, -0x40(%rbp)
movl %eax, %r12d
testb $0x1, -0x88(%rbp)
je 0x2d00
shrl $0x7, %esi
leaq 0x450f(%rip), %rdi      # 0x7190
xorl %eax, %eax
movl %esi, %ebx
callq 0x2040
leaq 0x4550(%rip), %rdi      # 0x71e1
movl %ebx, %esi
xorl %eax, %eax
callq 0x2040
leaq 0x455e(%rip), %rdi      # 0x71ff
movl -0x40(%rbp), %esi
xorl %eax, %eax
callq 0x2040
movzbl -0x1036f(%rbp), %esi
shrl $0x7, %esi
leaq 0x454f(%rip), %rdi      # 0x720b
xorl %eax, %eax
callq 0x2040
leaq 0x4550(%rip), %rdi      # 0x721a
movq %r13, %rsi
xorl %eax, %eax
callq 0x2040
leaq -0x10370(%rbp), %rax
movzbl (%r12,%rax), %esi
movzbl 0x1(%r12,%rax), %edx
movzbl 0x2(%r12,%rax), %ecx
movzbl 0x3(%r12,%rax), %r8d
leaq 0x4535(%rip), %rdi      # 0x722e
xorl %eax, %eax
callq 0x2040
leaq (%r12,%r13), %r15
addq $0x4, %r15
leaq (%r12,%r13), %rax
addq $-0xfffb, %rax          # imm = 0xFFFF0005
cmpq $-0x10000, %rax         # imm = 0xFFFF0000
jae 0x2d5e
leaq -0x158(%rbp), %r12
movslq %r14d, %rbx
movq %r15, %rdx
subq %rbx, %rdx
jbe 0x2d42
movl -0x2c(%rbp), %edi
leaq -0x10370(%rbp), %rsi
callq 0x22f0
addl %eax, %r14d
testl %eax, %eax
jne 0x2d21
leaq 0x450d(%rip), %rdi      # 0x7256
movl $0xffff, %esi           # imm = 0xFFFF
xorl %eax, %eax
callq 0x2040
movq -0x38(%rbp), %r15
jmp 0x323a
leaq 0x4(%r12), %rax
movq %rax, -0x168(%rbp)
movslq %r14d, %rbx
movq %r15, %rdx
subq %rbx, %rdx
jbe 0x2d8d
movl -0x2c(%rbp), %edi
leaq (%rbx,%rbp), %rsi
addq $-0x10370, %rsi         # imm = 0xFFFEFC90
callq 0x22f0
addl %eax, %r14d
jmp 0x2d6a
movb $0x0, -0x10370(%rbp,%rbx)
testb $0x1, -0x88(%rbp)
je 0x2dbd
leaq 0x4502(%rip), %rdi      # 0x72a7
movl %r14d, %esi
xorl %eax, %eax
callq 0x2040
leaq 0x4508(%rip), %rdi      # 0x72be
xorl %eax, %eax
callq 0x2040
leaq -0x1036c(%rbp), %rax
addq %r12, %rax
xorl %ecx, %ecx
movq -0x38(%rbp), %r15
cmpq %rcx, %r13
je 0x2de9
movl %ecx, %edx
andl $0x3, %edx
addq %r12, %rdx
movb -0x10370(%rbp,%rdx), %dl
xorb %dl, (%rax,%rcx)
incq %rcx
jmp 0x2dcd
cmpq $0x7, %r13
jbe 0x3015
leaq -0x10370(%rbp), %rax
cmpb $0x68, 0x6(%r12,%rax)
jne 0x3015
cmpb $0x72, 0x7(%r12,%rax)
jne 0x3015
cmpb $0x65, 0x8(%r12,%rax)
jne 0x3015
cmpb $0x66, 0x9(%r12,%rax)
jne 0x3015
movq -0x168(%rbp), %rcx
leaq (%rcx,%rbp), %rax
addq $-0x10370, %rax         # imm = 0xFFFEFC90
leaq -0x10367(%rbp,%rcx), %rsi
leaq -0x2(%r13,%rax), %rdx
leaq -0xb8(%rbp), %rax
movq %rax, -0xc8(%rbp)
leaq -0xc8(%rbp), %r14
movq %r14, %rdi
callq 0x38b0
movq -0xc8(%rbp), %rdi
callq 0x2330
movq %r14, %rdi
leaq 0x4494(%rip), %rsi      # 0x730f
callq 0x20c0
testl %eax, %eax
leaq -0x158(%rbp), %r12
movq -0x170(%rbp), %r13
je 0x32a3
movq -0x80(%rbp), %rdi
addq $0x18, %rdi
movq %r14, %rsi
callq 0x2180
leaq -0x2d0(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
callq 0x43de
movl (%rax), %r14d
leaq -0x298(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0x4d0a
movl %r14d, (%rax)
leaq -0x2d0(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
callq 0x43de
leaq -0x228(%rbp), %rdi
movq %rax, %rsi
callq 0x489a
movq %rax, %rdi
movq %r13, %rsi
callq 0x383c
movl -0x2c(%rbp), %esi
leaq -0x190(%rbp), %r14
movq %r14, %rdi
callq 0x369f
leaq -0x1b0(%rbp), %r13
movq %r13, %rdi
leaq 0x4427(%rip), %rsi      # 0x7346
movq %r14, %rdx
callq 0x3877
leaq -0x70(%rbp), %rdi
movq %r13, %rsi
leaq 0x43fd(%rip), %rdx      # 0x7332
callq 0x372b
leaq -0x2d0(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
callq 0x43de
leaq -0x1d0(%rbp), %r13
movl (%rax), %esi
movq %r13, %rdi
callq 0x369f
leaq -0x130(%rbp), %r14
movq %r14, %rdi
leaq -0x70(%rbp), %rsi
movq %r13, %rdx
callq 0x3754
leaq -0x1f0(%rbp), %rdi
movq %r14, %rsi
leaq 0x43ba(%rip), %rdx      # 0x733f
callq 0x372b
leaq -0x20370(%rbp), %r13
movq %r13, %rdi
leaq -0x1f0(%rbp), %rsi
callq 0x6405
movl %eax, %r14d
leaq -0x1f0(%rbp), %rdi
callq 0x2130
leaq -0x130(%rbp), %rdi
callq 0x2130
leaq -0x1d0(%rbp), %rdi
callq 0x2130
leaq -0x70(%rbp), %rdi
callq 0x2130
leaq -0x1b0(%rbp), %rdi
callq 0x2130
leaq -0x190(%rbp), %rdi
callq 0x2130
movl -0x2c(%rbp), %edi
movslq %r14d, %r14
movq %r13, %rsi
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x2150
cmpq %r14, %rax
je 0x33ff
leaq 0x4336(%rip), %rdi      # 0x7341
callq 0x21f0
jmp 0x33ff
movl -0x40(%rbp), %eax
addl $-0x3, %eax
cmpl $-0x2, %eax
jae 0x30d0
leaq -0x158(%rbp), %r12
jmp 0x323a
movq %r13, %rdi
leaq 0x4355(%rip), %rsi      # 0x738f
leaq -0x190(%rbp), %rdx
callq 0x3606
movq %r13, %rdi
leaq 0x438b(%rip), %rsi      # 0x73db
callq 0x23c0
leaq -0x130(%rbp), %rsi
movq %r13, %rdi
callq 0x23c0
movq %r13, %rdi
leaq 0x436a(%rip), %rsi      # 0x73d8
callq 0x23c0
movq -0x70(%rbp), %r14
movl -0x2c(%rbp), %r15d
movq %r14, %rdi
callq 0x2100
movl %r15d, %edi
movq %r14, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x2150
movq %rax, %r15
movq %r14, %rdi
callq 0x2100
cmpq %rax, %r15
jne 0x3292
movq -0x80(%rbp), %rax
movl $0x1, 0x14(%rax)
leaq -0x70(%rbp), %rdi
callq 0x2130
movq -0x38(%rbp), %r15
leaq -0xc8(%rbp), %rdi
callq 0x3a04
jmp 0x3248
leaq -0x1036c(%rbp), %rax
addq %r12, %rax
xorl %ecx, %ecx
cmpq %rcx, %r13
je 0x30ed
movb (%rax,%rcx), %dl
movb %dl, -0x4(%rax,%rcx)
incq %rcx
jmp 0x30dc
andb $-0x71, -0x10370(%rbp)
andb $0x7f, -0x1036f(%rbp)
leaq (%r12,%r13), %r14
xorl %ecx, %ecx
movb %cl, -0x10370(%rbp,%r14)
leaq (%r12,%r13), %rax
incq %rax
movb %cl, -0x10370(%rbp,%rax)
addq %r12, %r13
andw $0x0, -0x1036e(%rbp,%r13)
cmpb $0x74, -0x10370(%rbp,%r12)
jne 0x3166
movq %r12, %rax
orq $0x1, %rax
cmpb $0x6f, -0x10370(%rbp,%rax)
jne 0x3166
leaq -0x1036e(%rbp), %rax
addq %r12, %rax
xorl %edi, %edi
movsbl (%rax), %ecx
cmpl $0x7b, %ecx
je 0x3219
imull $0xa, %edi, %edx
leal (%rdx,%rcx), %edi
addl $-0x30, %edi
incq %rax
jmp 0x314c
leaq -0x298(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
leaq -0x158(%rbp), %r12
callq 0x4d0a
cmpl $0x0, (%rax)
je 0x319d
leaq -0x298(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0x4d0a
movl (%rax), %eax
cmpl -0x2c(%rbp), %eax
jne 0x325c
leaq -0x228(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0x489a
movq (%rax), %r15
leaq -0x228(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0x489a
cmpq 0x8(%rax), %r15
je 0x2d55
movl (%r15), %edi
leaq -0x10370(%rbp), %rsi
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x2150
cmpq %r14, %rax
je 0x320f
leaq 0x4157(%rip), %rdi      # 0x7341
callq 0x21f0
leaq -0x228(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0x489a
movq %rax, %rdi
movq %r15, %rsi
callq 0x38a6
movq %rax, %r15
jmp 0x31b0
incq -0x78(%rbp)
addq $0x30, %r15
jmp 0x31b0
leaq -0x10370(%rbp), %rsi
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x2150
cmpq %r14, %rax
leaq -0x158(%rbp), %r12
jne 0x3284
incq -0x78(%rbp)
incq -0xf0(%rbp)
addq %rbx, -0xf8(%rbp)
movq %r12, %rdi
callq 0x2130
movq -0x100(%rbp), %r14
jmp 0x294a
leaq -0x298(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0x4d0a
movl (%rax), %edi
leaq -0x10370(%rbp), %rsi
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x2150
cmpq %r14, %rax
je 0x3236
leaq 0x40b6(%rip), %rdi      # 0x7341
callq 0x21f0
jmp 0x323a
leaq 0x40a8(%rip), %rdi      # 0x7341
callq 0x21f0
jmp 0x30a7
movl -0x2c(%rbp), %esi
leaq -0x70(%rbp), %r14
movq %r14, %rdi
callq 0x369f
leaq -0x130(%rbp), %r13
movq %r13, %rdi
leaq -0xc8(%rbp), %rsi
movq %r14, %rdx
callq 0x3671
movq %r14, %rdi
callq 0x2130
movl -0x2c(%rbp), %r14d
leaq -0x2d0(%rbp), %rdi
movq %r13, %rsi
callq 0x43de
movl %r14d, (%rax)
xorps %xmm0, %xmm0
movaps %xmm0, -0x70(%rbp)
andq $0x0, -0x60(%rbp)
leaq -0x228(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0x489a
movq %rax, %rdi
leaq -0x70(%rbp), %r14
movq %r14, %rsi
callq 0x4c9e
movq %r14, %rdi
callq 0x3700
leaq -0x190(%rbp), %r14
movq %r14, %rdi
leaq 0x3ffb(%rip), %rsi      # 0x7328
leaq -0x130(%rbp), %rdx
callq 0x37c5
leaq -0x1b0(%rbp), %rdi
movq %r14, %rsi
leaq 0x3fe7(%rip), %rdx      # 0x7331
callq 0x372b
movl -0x2c(%rbp), %esi
leaq -0x1d0(%rbp), %r13
movq %r13, %rdi
callq 0x369f
leaq -0x70(%rbp), %r14
movq %r14, %rdi
leaq -0x1b0(%rbp), %rsi
movq %r13, %rdx
callq 0x3754
leaq -0x2f0(%rbp), %r13
movq %r13, %rdi
movq %r14, %rsi
leaq 0x3fb4(%rip), %rdx      # 0x733f
callq 0x372b
leaq -0x20370(%rbp), %rdi
movq %r13, %rsi
callq 0x6405
movl %eax, %r14d
movq %r13, %rdi
callq 0x2130
leaq -0x70(%rbp), %rdi
callq 0x2130
leaq -0x1d0(%rbp), %rdi
callq 0x2130
leaq -0x1b0(%rbp), %rdi
callq 0x2130
leaq -0x190(%rbp), %rdi
callq 0x2130
movl -0x2c(%rbp), %edi
movslq %r14d, %r14
leaq -0x20370(%rbp), %rsi
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x2150
cmpq %r14, %rax
jne 0x3410
leaq -0x130(%rbp), %rdi
callq 0x2130
leaq -0xc8(%rbp), %rdi
callq 0x2130
jmp 0x323a
leaq 0x3f2a(%rip), %rdi      # 0x7341
callq 0x21f0
jmp 0x33f3
leaq 0x3c73(%rip), %rdi      # 0x7098
jmp 0x2752
jmp 0x348e
movq %rax, %rbx
leaq -0x2f0(%rbp), %rdi
callq 0x2130
jmp 0x3440
movq %rax, %rbx
leaq -0x70(%rbp), %rdi
callq 0x2130
jmp 0x344e
movq %rax, %rbx
leaq -0x1d0(%rbp), %rdi
callq 0x2130
jmp 0x345f
movq %rax, %rbx
leaq -0x1b0(%rbp), %rdi
callq 0x2130
leaq -0x190(%rbp), %rdi
callq 0x2130
jmp 0x3491
movq %rax, %rbx
jmp 0x346b
jmp 0x348e
movq %rax, %rbx
leaq -0x70(%rbp), %rdi
callq 0x3700
jmp 0x3491
movq %rax, %rbx
leaq -0x130(%rbp), %rdi
jmp 0x350f
movq %rax, %rbx
leaq -0x70(%rbp), %rdi
callq 0x2130
jmp 0x3520
jmp 0x351d
jmp 0x351d
movq %rax, %rbx
leaq -0x1f0(%rbp), %rdi
callq 0x2130
jmp 0x34c7
movq %rax, %rbx
jmp 0x34fc
jmp 0x351d
movq %rax, %rbx
leaq -0x130(%rbp), %rdi
callq 0x2130
jmp 0x34d8
movq %rax, %rbx
leaq -0x1d0(%rbp), %rdi
callq 0x2130
jmp 0x34f3
movq %rax, %rbx
jmp 0x3508
jmp 0x358f
movq %rax, %rbx
leaq -0x70(%rbp), %rdi
callq 0x2130
leaq -0x1b0(%rbp), %rdi
callq 0x2130
leaq -0x190(%rbp), %rdi
callq 0x2130
leaq -0x158(%rbp), %r12
jmp 0x3520
movq %rax, %rbx
leaq -0xc8(%rbp), %rdi
callq 0x2130
jmp 0x3599
jmp 0x358f
jmp 0x358a
movq %rax, %rbx
leaq -0xc0(%rbp), %rdi
jmp 0x359c
jmp 0x3585
jmp 0x354c
jmp 0x3566
jmp 0x3585
jmp 0x358a
jmp 0x3566
jmp 0x354c
movq %rax, %rbx
leaq -0x70(%rbp), %rdi
jmp 0x355f
movq %rax, %rbx
leaq -0x130(%rbp), %rdi
callq 0x2130
jmp 0x3569
movq %rax, %rbx
leaq -0xc8(%rbp), %rdi
callq 0x3a04
jmp 0x3599
jmp 0x358a
jmp 0x358a
jmp 0x358a
jmp 0x358a
jmp 0x358a
jmp 0x358a
jmp 0x3585
movq %rax, %rbx
jmp 0x35a1
movq %rax, %rbx
jmp 0x3599
movq %rax, %rbx
leaq -0x158(%rbp), %r12
movq %r12, %rdi
callq 0x2130
leaq -0x260(%rbp), %rdi
callq 0x3b02
leaq -0x298(%rbp), %rdi
callq 0x3be0
leaq -0x228(%rbp), %rdi
callq 0x3c9e
leaq -0x2d0(%rbp), %rdi
callq 0x3d7c
movq %rbx, %rdi
callq 0x2380
nop