text:
<repo_name>zhengqmark/deltafs-nexus<file_sep>/tests/nexus-test.cc
/*
 * Copyright (c) 2017 Carnegie Mellon University.
 * <NAME> <<EMAIL>>
 *
 * All rights reserved.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file. See the AUTHORS file for names of contributors.
 */

#include <cstdio>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <mpi.h>
#include <string.h>

#include "deltafs-nexus_api.h"

struct test_ctx {
    int myrank;
    int ranksize;

    int count;
    char subnet[16];
    char proto[8];

    /* Nexus context */
    nexus_ctx_t nctx;
};

char *me;
struct test_ctx tctx;

/*
 * usage: prints usage information and exits
 */
static void usage(int ret)
{
    printf("usage: %s [options]\n"
           "\n"
           "options:\n"
           " -c count       number of RPCs to perform\n"
           " -p baseport    base port number\n"
           " -t proto       transport protocol\n"
           " -s subnet      subnet for Mercury instances\n"
           " -h             this usage info\n"
           "\n", me);

    exit(ret);
}

/*
 * msg_abort: abort with a message
 */
static inline void nx_fatal(const char *msg)
{
    if (errno != 0) {
        fprintf(stderr, "Error: %s (%s)\n", msg, strerror(errno));
    } else {
        fprintf(stderr, "Error: %s\n", msg);
    }

    abort();
}

#if 0
void print_hg_addr(hg_class_t *hgcl, int rank, const char *str)
{
    char *addr_str = NULL;
    hg_size_t addr_size = 0;
    hg_addr_t hgaddr;
    hg_return_t hret;

    if (nexus_get_addr(rank, &hgaddr))
        msg_abort("nexus_get_addr failed");

    hret = HG_Addr_to_string(hgcl, NULL, &addr_size, hgaddr);
    if (hgaddr == NULL)
        msg_abort("HG_Addr_to_string failed");

    addr_str = (char *)malloc(addr_size);
    if (addr_str == NULL)
        msg_abort("malloc failed");

    hret = HG_Addr_to_string(hgcl, addr_str, &addr_size, hgaddr);
    if (hret != HG_SUCCESS)
        msg_abort("HG_Addr_to_string failed");

    fprintf(stdout, "[r%d] %s addr: %s\n", rank, str, addr_str);
}
#endif

int main(int argc, char **argv)
{
    int c;
    char *end;

    me = argv[0];

    /* set random data generator seed */
    srandom(getpid());

    /* set default parameter values */
    tctx.count = 2;

    if (snprintf(tctx.subnet, sizeof(tctx.subnet), "127.0.0.1") <= 0)
      nx_fatal("sprintf for subnet failed");

    if (snprintf(tctx.proto, sizeof(tctx.proto), "bmi+tcp") <= 0)
      nx_fatal("sprintf for proto failed");

    while ((c = getopt(argc, argv, "c:t:s:h")) != -1) {
        switch(c) {
        case 'h': /* print help */
            usage(0);
        case 'c': /* number of RPCs to transport */
            tctx.count = strtol(optarg, &end, 10);
            if (*end) {
                perror("Error: invalid RPC count");
                usage(1);
            }
            break;
        case 't': /* transport protocol */
            if (!strncpy(tctx.proto, optarg, sizeof(tctx.proto))) {
                perror("Error: invalid proto");
                usage(1);
            }
            break;
        case 's': /* subnet to pick IP from */
            if (!strncpy(tctx.subnet, optarg, sizeof(tctx.subnet))) {
                perror("Error: invalid subnet");
                usage(1);
            }
            break;
        default:
            usage(1);
        }
    }

    if (MPI_Init(&argc, &argv) != MPI_SUCCESS) {
        perror("Error: MPI_Init failed");
        exit(1);
    }

    MPI_Comm_size(MPI_COMM_WORLD, &(tctx.ranksize));
    MPI_Comm_rank(MPI_COMM_WORLD, &(tctx.myrank));

    /* Output test configuration */
    if (!tctx.myrank) {
        printf("\n%s options:\n", me);
        printf("\tTrials = %d\n", tctx.count);
        printf("\tSubnet = %s\n", tctx.subnet);
        printf("\tProtocol = %s\n", tctx.proto);
    }

    if (!(tctx.nctx = nexus_bootstrap(tctx.subnet, tctx.proto))) {
        fprintf(stderr, "Error: nexus_bootstrap failed\n");
        goto error;
    }

    for (int i = 1; i <= tctx.count; i++) {
        int srcrep = -1, dstrep = -1, dest = -1;
        int src = tctx.myrank;
        int dst = rand() % tctx.ranksize; /* not uniform, but ok */
        hg_addr_t sr_addr, dr_addr, d_addr;
        nexus_ret_t nret;

        fprintf(stdout, "[r%d,i%d] Trying to route: src=%d -> ... -> dst=%d\n",
                src, i, src, dst);

        /* Get srcrep */
        nret = nexus_next_hop(tctx.nctx, dst, &srcrep, &sr_addr);
#if 0
        if (nret == NX_DONE) {
            fprintf(stdout, "[r%d,i%d] Route: src (%d) and dst (%d) overlap\n",
                    src, i, src, dst);
            continue;
        } else if (nret == NX_ISLOCAL) {
            fprintf(stdout, "[r%d,i%d] Route src (%d) and dst (%d) is local\n",
                    src, i, src, dst);
            continue;
        } else if (nret == NX_SRCREP) {
            /* Get dstrep */
            fprintf(stdout, "[r%d,i%d] got srcrep = %d\n", src, i, srcrep);
            tctx.nctx.grank = srcrep; /* Trick Nexus to think we advanced */
            nret = nexus_next_hop(&(tctx.nctx), dst, &dstrep, &dr_addr);

            /* Don't look for dest because we only have rep addresses at src */
            if (nret == NX_DESTREP || nret == NX_SUCCESS)
                goto done;
            else
                msg_abort("nexus_next_hop for destrep failed");
        } else if (nret == NX_DESTREP) {
            goto done;
        } else if (nret != NX_SUCCESS) {
            msg_abort("nexus_next_hop for srcrep failed");
        }
#endif

#if 0
        print_hg_addr(tctx.hgcl, srcrep, "srcrep");
#endif
done:
        nexus_set_grank(tctx.nctx, src);
        fprintf(stdout, "[r%d,i%d] Route: src=%d -> src_rep=%d"
                        " -> dst_rep=%d -> dst=%d\n",
                src, i, src, srcrep, dstrep, dst);
    }

    nexus_destroy(tctx.nctx);
    MPI_Finalize();
    exit(0);

error:
    MPI_Finalize();
    exit(1);
}
<file_sep>/include/deltafs-nexus_api.h
/*
 * Copyright (c) 2017-2019, Carnegie Mellon University and
 *     Los Alamos National Laboratory.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#pragma once

#include <mercury.h>
#include <map>

typedef struct nexus_ctx* nexus_ctx_t;
typedef struct nexus_iter* nexus_iter_t;

/* error codes */
typedef enum {
  NX_SUCCESS = 0, /* operation succeeded */
  NX_ERROR,       /* operation resulted in error */
  NX_NOTFOUND,    /* address not found */
  NX_ISLOCAL,     /* dest is local */
  NX_SRCREP,      /* dest is srcrep */
  NX_DESTREP,     /* dest is dstrep */
  NX_INVAL,       /* invalid parameter */
  NX_DONE,        /* already at destination */
} nexus_ret_t;

/**
 * nexus_bootstrap: bootstraps the Nexus library
 * @param string of the network subnet to be preferred for Mercury endpoints
 * @param string of the Mercury protocol plugin to be preferred
 * @return nexus context or NULL on error
 */
nexus_ctx_t nexus_bootstrap(char* subnet, char* proto);

/**
 * nexus_bootstrap_uri: bootstraps the nx library using a specific server uri
 * @param uri mercury server uri for remote forwarding
 * @return nexus context or NULL on errors
 */
nexus_ctx_t nexus_bootstrap_uri(char* uri);

/**
 * Destroys the Nexus library freeing all allocated resources
 * @param nexus context
 */
void nexus_destroy(nexus_ctx_t nctx);

/**
 * Returns next Mercury address in route to dest or error
 * @param nexus context
 * @param MPI rank of destination
 * @param MPI rank of next hop (returned)
 * @param Mercury address of next hop (returned)
 * @return NX_SUCCESS or an error code
 */
nexus_ret_t nexus_next_hop(nexus_ctx_t nctx, int dest, int* rank,
                           hg_addr_t* addr);

/**
 * Blocks until all processes in the global communicator have reached this
 * routine.
 * @param nctx context
 * @return NX_SUCCESS or an error code
 */
nexus_ret_t nexus_global_barrier(nexus_ctx_t nctx);

/**
 * Return global rank of this process (assumes nexus is up)
 * @param nctx context
 * @return global rank
 */
int nexus_global_rank(nexus_ctx_t nctx);

/**
 * Return size of the global communicator (assumes nexus is up)
 * @param nctx context
 * @return size of the global communicator
 */
int nexus_global_size(nexus_ctx_t nctx);

/**
 * Blocks until all processes in the local communicator have reached this
 * routine.
 * @param nctx context
 * @return NX_SUCCESS or an error code
 */
nexus_ret_t nexus_local_barrier(nexus_ctx_t nctx);

/**
 * Return local rank of this process (assumes nexus is up)
 * @param nctx context
 * @return local rank
 */
int nexus_local_rank(nexus_ctx_t nctx);

/**
 * Return size of the local communicator (assumes nexus is up)
 * @param nctx context
 * @return size of the global communicator
 */
int nexus_local_size(nexus_ctx_t nctx);

/**
 * Sets the global rank of the process (for debug purposes)
 * @param nexus context
 * @param new MPI rank
 * @return NX_SUCCESS or an error code
 */
nexus_ret_t nexus_set_grank(nexus_ctx_t nctx, int rank);

/**
 * Return mercury class for local (na+sm)
 *
 * @param nctx context
 */
hg_class_t* nexus_hgclass_local(nexus_ctx_t nctx);

/**
 * Return mercury class for remote (bmi+tcp or something like that)
 *
 * @param nctx context
 */
hg_class_t* nexus_hgclass_remote(nexus_ctx_t nctx);

/**
 * Return mercury context for local (bmi+tcp or something like that)
 *
 * @param nctx context
 */
hg_context_t* nexus_hgcontext_local(nexus_ctx_t nctx);

/**
 * Return mercury context for remote (bmi+tcp or something like that)
 *
 * @param nctx context
 */
hg_context_t* nexus_hgcontext_remote(nexus_ctx_t nctx);

/**
 * Allocate a new iterator.  nctx must remain active while iter is
 * allocated.  must free iterator when done.
 *
 * @param nctx context
 * @param local set non-zero if you want a local map iterator
 */
nexus_iter_t nexus_iter(nexus_ctx_t nctx, int local);

/**
 * Free a previously allocated iterator
 *
 * @param nitp pointer to iterator handle (we set to null)
 */
void nexus_iter_free(nexus_iter_t* nitp);

/**
 * Return non-zero if we are at the end of the map.
 *
 * @param nit iterator handle
 */
int nexus_iter_atend(nexus_iter_t nit);

/**
 * Advance the iterator
 *
 * @param nit iterator handle
 */
void nexus_iter_advance(nexus_iter_t nit);

/**
 * Return current hgaddr of iterator
 *
 * @param nit iterator handle
 */
hg_addr_t nexus_iter_addr(nexus_iter_t nit);

/**
 * Return current global rank of iterator
 *
 * @param nit iterator handle
 */
int nexus_iter_globalrank(nexus_iter_t nit);

/**
 * Return current subrank of iterator.  subrank is 0 for local
 * maps and node number for remote maps.
 *
 * @param nit iterator handle
 */
int nexus_iter_subrank(nexus_iter_t nit);
<file_sep>/README.md
**library managing process communication information for deltafs.**

[![GitHub release](https://img.shields.io/github/release/pdlfs/deltafs-nexus.svg)](https://github.com/pdlfs/deltafs-nexus/releases)
[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](LICENSE.txt)

deltafs-nexus
=============

```
xxxxxxxx           xxxx xxxx        xxx
xxxx xxxx          xxxx  xxxx      xxx
xxxx  xxxx         xxxx   xxxx    xxx
xxxx   xxxx        xxxx    xxxx  xxx
xxxx    xxxx       xxxx     xxxxxx
xxxx     xxxx      xxxx      xxxx
xxxx      xxxx     xxxx      xxxxx
xxxx       xxxx    xxxx     xxxxxxx
xxxx        xxxx   xxxx    xxx  xxxx
xxxx         xxxx  xxxx   xxx    xxxx
xxxx          xxxx xxxx  xxx      xxxx
xxxx           xxxxxxxx xxx        xxxx
```

Please see the accompanying LICENSE file for licensing details.

# Software requirements

First, if on a Ubuntu box, do the following:

```bash
sudo apt-get install -y gcc g++ make
sudo apt-get install -y pkg-config
sudo apt-get install -y autoconf automake libtool
sudo apt-get install -y cmake
sudo apt-get install -y libmpich-dev
sudo apt-get install -y mpich
```

If on a Mac machine with `brew`, do the following:

```bash
brew install gcc
brew install pkg-config
brew install autoconf automake libtool
brew install cmake
env \
CC=/usr/local/bin/gcc-<n> \
CXX=/usr/local/bin/g++-<n> \
brew install --build-from-source \
mpich
```

Next, we need to install `mercury`. This can be done as follows:

```bash
git clone <EMAIL>:mercury-hpc/mercury.git
cd mercury
mkdir build
cd build
cmake \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INSTALL_PREFIX=</tmp/mercury-prefix> \
-DNA_USE_SM=ON \
..
```

# Building

After installing dependencies, we can build `deltafs-nexus` as follows:

```bash
git clone git@github.com:pdlfs/deltafs-nexus.git
cd deltafs-nexus
mkdir build
cd build
cmake \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INSTALL_PREFIX=</tmp/deltafs-nexus-prefix> \
-DCMAKE_PREFIX_PATH=</tmp/mercury-prefix> \
..
```
<file_sep>/src/nexus_internal.cc
/*
 * Copyright (c) 2017-2019, Carnegie Mellon University and
 *     Los Alamos National Laboratory.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <arpa/inet.h>
#include <assert.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <pthread.h>
#include <sys/socket.h>

#include "nexus_internal.h"

#define DEFAULT_NX_LIMIT 4
#define TMPADDRSZ 64

namespace {
typedef struct {
  int grank;
  int idx;
  char addr[];
} xchg_dat_t;

/* nx_fatal: abort with a message */
void nx_fatal(const char* msg) {
  if (errno != 0)
    fprintf(stderr, "NX FATAL: %s (%s)\n", msg, strerror(errno));
  else
    fprintf(stderr, "NX FATAL: %s\n", msg);

  abort();
}

/* nx_is_envset: check if a given env is set */
bool nx_is_envset(const char* name) {
  char* env = getenv(name);
  if (env == NULL || env[0] == 0) return false;
  return strcmp(env, "0") != 0;
}

struct bgthread_dat {
  hg_context_t* hgctx;
  nexus_ctx_t nctx;
  int bgdone;
};

/*
 * network support pthread. Need to call progress to push the network and then
 * trigger to run the callback.
 */
void* nx_bgthread(void* arg) {
  struct bgthread_dat* const bgdat = (struct bgthread_dat*)arg;
  hg_return_t hret;
  int r = bgdat->nctx->grank;
#ifdef NEXUS_DEBUG
  fprintf(stderr, "NX-%d: BG UP\n", r);
#endif

  while (!bgdat->bgdone) {
    unsigned int count = 0;
    do {
      hret = HG_Trigger(bgdat->hgctx, 0, 1, &count);
    } while (hret == HG_SUCCESS && count);

    if (hret != HG_SUCCESS && hret != HG_TIMEOUT) {
      nx_fatal("bg:HG_Trigger");
    }
    hret = HG_Progress(bgdat->hgctx, 100);
    if (hret != HG_SUCCESS && hret != HG_TIMEOUT) {
      nx_fatal("bg:HG_Progress");
    }
  }

#ifdef NEXUS_DEBUG
  fprintf(stderr, "NX-%d: BG DOWN\n", r);
#endif
  return NULL;
}

/*
 * nx_get_ipmatch: look at our interfaces and find an IP address that
 * matches our spec...  aborts on failure.
 */
void nx_get_ipmatch(char* subnet, char* i, int ilen) {
  struct ifaddrs *ifaddr, *cur;
  int family;

  /* Query local socket layer to get our IP addr */
  if (getifaddrs(&ifaddr) == -1) nx_fatal("getifaddrs failed");

  for (cur = ifaddr; cur != NULL; cur = cur->ifa_next) {
    if (cur->ifa_addr != NULL) {
      family = cur->ifa_addr->sa_family;

      if (family == AF_INET) {
        if (getnameinfo(cur->ifa_addr, sizeof(struct sockaddr_in), i, ilen,
                        NULL, 0, NI_NUMERICHOST) == -1)
          nx_fatal("getnameinfo failed");

        if (strncmp(subnet, i, strlen(subnet)) == 0) break;
      }
    }
  }

  if (cur == NULL) nx_fatal("no ip addr");

  freeifaddrs(ifaddr);
}

/*
 * Put together the remote Mercury endpoint address from bootstrap parameters.
 * Writes the server URI into *uri on success. Aborts on error.
 */
void nx_prepare_addr(nexus_ctx_t nctx, char* subnet, char* proto, char* uri) {
  char ip[16];
  int lcv, port, so, n;
  struct sockaddr_in addr;
  socklen_t addr_len = sizeof(addr);

  nx_get_ipmatch(subnet, ip, sizeof(ip)); /* fill ip w/req'd local IP */

  if (strcmp(proto, "bmi+tcp") == 0) {
    /*
     * XXX: bmi+tcp HG_Addr_to_string() is broken.  if we request
     * port 0 (to let OS fill in) and later use HG_Addr_to_string()
     * to request the actual port number allocated, it still returns
     * 0 as the port number...   here's an attempt to hack around
     * this bug.
     */
    so = socket(PF_INET, SOCK_STREAM, 0);
    if (so < 0) nx_fatal("bmi:socket1");
    n = 1;
    setsockopt(so, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
    for (lcv = 0; lcv < 1024; lcv++) {
      /* have each local rank try a different set of ports */
      port = 10000 + (lcv * nctx->lsize) + nctx->lrank;
      addr.sin_family = AF_INET;
      addr.sin_addr.s_addr = INADDR_ANY;
      addr.sin_port = htons(port);
      n = bind(so, (struct sockaddr*)&addr, addr_len);
      if (n == 0) break;
    }
    close(so);
    if (n != 0) nx_fatal("bmi:socket2");

    sprintf(uri, "%s://%s:%d", proto, ip, port);

  } else {
    /* set port 0, let OS fill it, collect later w/HG_Addr_to_string */
    sprintf(uri, "%s://%s:0", proto, ip);
  }
}

struct nx_lookup_ctx {
  /* the address map we'll be updating */
  nexus_map_t* nx_map;
  /* num of ops done */
  int done;

  pthread_mutex_t cb_mutex;
  pthread_cond_t cb_cv;
};

struct nx_lookup_out {
  struct nx_lookup_ctx* ctx;
  hg_return_t hret;
  int idx;
};

hg_return_t nx_lookup_cb(const struct hg_cb_info* info) {
  struct nx_lookup_out* const out = (struct nx_lookup_out*)info->arg;
  out->hret = info->ret;

  pthread_mutex_lock(&out->ctx->cb_mutex);

  if (out->hret == HG_SUCCESS)
    (*(out->ctx->nx_map))[out->idx] = info->info.lookup.addr;
  out->ctx->done += 1;

  pthread_cond_signal(&out->ctx->cb_cv);
  pthread_mutex_unlock(&out->ctx->cb_mutex);

  return HG_SUCCESS;
}

hg_return_t nx_lookup_addrs(nexus_ctx_t nctx, nexus_hg_t* hg, xchg_dat_t* xarr,
                            int xsize, int addrsz, nexus_map_t* map) {
  struct nx_lookup_out* out;
  hg_addr_t self_addr;
  hg_return_t hret;

  struct nx_lookup_ctx ctx;
  out = (struct nx_lookup_out*)malloc(sizeof(*out) * xsize);
  if (out == NULL) return HG_NOMEM_ERROR;

  hret = HG_SUCCESS;
  pthread_mutex_init(&ctx.cb_mutex, NULL);
  pthread_cond_init(&ctx.cb_cv, NULL);
  ctx.nx_map = map;
  ctx.done = 0;

  /* determine if we are local, use my rank as starting point */
  const int local = (hg == nctx->hg_local);
  int eff_offset = (local) ? nctx->lrank : nctx->grank;
  int i = 0;

  pthread_mutex_lock(&ctx.cb_mutex);

  while (hret == HG_SUCCESS && i < xsize) {
    int remain = xsize - i;
    int cando = remain < nctx->nx_limit ? remain : nctx->nx_limit;

    /* start as many as we can */
    while (hret == HG_SUCCESS && cando-- > 0) {
      const int eff_i = (i + eff_offset) % xsize;

      xchg_dat_t* const xi =
          (xchg_dat_t*)(((char*)xarr) + eff_i * (sizeof(*xi) + addrsz));

      out[eff_i].hret = HG_SUCCESS;
      out[eff_i].idx = xi->idx;
      out[eff_i].ctx = &ctx;

      if (xi->grank != nctx->grank) {
        pthread_mutex_unlock(&ctx.cb_mutex);

        hret = HG_Addr_lookup(hg->hg_ctx, &nx_lookup_cb, &out[eff_i], xi->addr,
                              HG_OP_ID_IGNORE);

        pthread_mutex_lock(&ctx.cb_mutex);
      } else {
        hret = HG_Addr_self(hg->hg_cl, &self_addr);

        if (hret == HG_SUCCESS) { /* directly add address to map */
          (*(ctx.nx_map))[xi->idx] = self_addr;

          ctx.done += 1;
        }
      }

      if (hret != HG_SUCCESS) {
        out[eff_i].hret = hret;
        ctx.done += 1;
      }

      i++;
    }

    while (ctx.done < i) { /* XXX: ok to break out if just one slot is free? */
      pthread_cond_wait(&ctx.cb_cv, &ctx.cb_mutex);
    }
  }

  pthread_mutex_unlock(&ctx.cb_mutex);

  hret = HG_SUCCESS;
  for (int j = 0; j < i; j++) {
    const int eff_j = (j + eff_offset) % xsize;
    if (out[eff_j].hret != HG_SUCCESS) {
      hret = out[eff_j].hret;
      break;
    }
  }

  free(out);

  pthread_cond_destroy(&ctx.cb_cv);
  pthread_mutex_destroy(&ctx.cb_mutex);
  return hret;
}

/*
 * nx_dump_addrs: dump a given map to stderr.
 */
void nx_dump_addrs(nexus_ctx_t nctx, nexus_hg_t* hg, nexus_map_t* map) {
  char addr[TMPADDRSZ];
  hg_return_t hret;

  const char* map_name = (map == &nctx->lmap) ? "lmap" : "rmap";
  nexus_map_t::iterator it = map->begin();

  for (; it != map->end(); ++it) {
    hg_size_t addr_sz = sizeof(addr);
    hret = HG_Addr_to_string(hg->hg_cl, addr, &addr_sz, it->second);
    if (hret != HG_SUCCESS) strcpy(addr, "n/a");
    fprintf(stderr, "NX-%d: %s[%d]=%s\n", nctx->grank, map_name, it->first,
            addr);
  }
}

void nx_init_localcomm(nexus_ctx_t nctx) {
  if (MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, 0,
                          MPI_INFO_NULL, &nctx->localcomm) != MPI_SUCCESS)
    nx_fatal("MPI_Comm_split_type");
  if (MPI_Comm_rank(nctx->localcomm, &nctx->lrank) != MPI_SUCCESS)
    nx_fatal("MPI_Comm_rank");
  if (MPI_Comm_size(nctx->localcomm, &nctx->lsize) != MPI_SUCCESS)
    nx_fatal("MPI_Comm_size");
}

void nx_init_repcomm(nexus_ctx_t nctx) {
  int color = (nctx->grank == nctx->lroot) ? 1 : MPI_UNDEFINED;
  if (MPI_Comm_split(MPI_COMM_WORLD, color, nctx->grank, &nctx->repcomm) !=
      MPI_SUCCESS)
    nx_fatal("MPI_Comm_split");
  if (nctx->repcomm != MPI_COMM_NULL) {
    if (MPI_Comm_rank(nctx->repcomm, &nctx->nodeid) != MPI_SUCCESS)
      nx_fatal("MPI_Comm_rank");
    if (MPI_Comm_size(nctx->repcomm, &nctx->nnodes) != MPI_SUCCESS)
      nx_fatal("MPI_Comm_size");
  }
}

/*
 * nx_setup_local_via_remote: setup the local network substrate by reusing the
 * remote substrate. must be called after nx_setup_local and nx_discover_remote.
 */
void nx_setup_local_via_remote(nexus_ctx_t nctx) {
  hg_addr_t addr_self;
  hg_size_t addr_sz;
  int ret, my_sz, xchg_sz;
  char addr[TMPADDRSZ];
  xchg_dat_t *xitm, *xarr;
  pthread_t bgthread; /* network bg thread */
  struct bgthread_dat bgarg;
  hg_return_t hret;

  assert(nctx->hg_remote != NULL);
  assert(nctx->hg_local == NULL);
  nctx->hg_local = nctx->hg_remote;
  nctx->hg_local->refs++;

  /* fetch self-address */
  hret = HG_Addr_self(nctx->hg_local->hg_cl, &addr_self);
  if (hret != HG_SUCCESS) {
    nx_fatal("lo:HG_Addr_self");
  }
  addr_sz = sizeof(addr);
  hret = HG_Addr_to_string(nctx->hg_local->hg_cl, addr, &addr_sz, addr_self);
  if (hret != HG_SUCCESS) {
    nx_fatal("lo:HG_Addr_to_string");
  }
  HG_Addr_free(nctx->hg_local->hg_cl, addr_self);
  my_sz = strlen(addr) + 1;

  /* determine the max address size for local comm */
  MPI_Allreduce(&my_sz, &nctx->laddrsz, 1, MPI_INT, MPI_MAX, nctx->localcomm);
  xchg_sz = sizeof(xchg_dat_t) + nctx->laddrsz;

  /* exchange address and rank info within the local comm */
  xitm = (xchg_dat_t*)malloc(xchg_sz);
  if (!xitm) nx_fatal("malloc failed");
  xitm->grank = nctx->grank;
  xitm->idx = xitm->grank; /* use granks as address indexes */
  strcpy(xitm->addr, addr);

  xarr = (xchg_dat_t*)malloc(nctx->lsize * xchg_sz);
  if (!xarr) nx_fatal("malloc failed");

  MPI_Allgather(xitm, xchg_sz, MPI_BYTE, xarr, xchg_sz, MPI_BYTE,
                nctx->localcomm);

  /* lookup and store all mercury addresses */
  bgarg.hgctx = nctx->hg_local->hg_ctx;
  bgarg.bgdone = 0;
  bgarg.nctx = nctx;

  ret = pthread_create(&bgthread, NULL, nx_bgthread, (void*)&bgarg);
  if (ret != 0) nx_fatal("pthread_create");

  MPI_Barrier(nctx->localcomm);

  hret = nx_lookup_addrs(nctx, nctx->hg_local, xarr, nctx->lsize, nctx->laddrsz,
                         &nctx->lmap);
  if (hret != HG_SUCCESS) {
    nx_fatal("lo:HG_Addr_lookup");
  }

#ifdef NEXUS_DEBUG
  nx_dump_addrs(nctx, nctx->hg_local, &nctx->lmap);
#endif

  MPI_Barrier(nctx->localcomm);

  bgarg.bgdone = 1;
  pthread_join(bgthread, NULL);

  free(xarr);
  free(xitm);
}

/*
 * nx_setup_local: setup the local network substrate with a local-optimized
 * communication mechanism (e.g. shared memory). if the local mechanism if
 * bypassed (NEXUS_BYPASS_LOCAL), the local substrate will be built on top of
 * the remote substrate and will only be initialized partially at this point. as
 * a result, nx_setup_local_via_remote must be called later to finish the
 * remaining work after nx_discover_remote is done.
 */
void nx_setup_local(nexus_ctx_t nctx) {
  char* nx_alt_proto;
  int ret, my_sz, xchg_sz;
  char addr[TMPADDRSZ];
  xchg_dat_t *xitm, *xarr;
  pthread_t bgthread; /* network bg thread */
  struct bgthread_dat bgarg;
  hg_return_t hret;

  nx_init_localcomm(nctx);
  memset(addr, 0, sizeof(addr));
  nctx->hg_local = NULL;

  /* first, we map each local rank to its global rank */
  nctx->local2global = (int*)malloc(sizeof(int) * nctx->lsize);
  if (!nctx->local2global) nx_fatal("malloc failed");

  MPI_Allgather(&nctx->grank, 1, MPI_INT, nctx->local2global, 1, MPI_INT,
                nctx->localcomm);

  /* set the local root */
  nctx->lroot = nctx->local2global[0];

  /* next, we build the local network */
  if (nx_is_envset("NEXUS_BYPASS_LOCAL")) return;
  snprintf(addr, sizeof(addr), "na+sm://%d/0", getpid());

  /* switch to an alternate local protocol if requested */
  nx_alt_proto = getenv("NEXUS_ALT_LOCAL");
  if (nx_alt_proto && strcmp(nx_alt_proto, "na+sm") != 0)
    snprintf(addr, sizeof(addr), "%s://127.0.0.1:%d", nx_alt_proto,
             19000 + nctx->lrank);

#ifdef NEXUS_DEBUG
  fprintf(stderr, "NX-%d: LOCAL %s\n", nctx->grank, addr);
#endif

  my_sz = strlen(addr) + 1;
  nctx->hg_local = (nexus_hg_t*)malloc(sizeof(nexus_hg_t));
  memset(nctx->hg_local, 0, sizeof(nexus_hg_t));
  nctx->hg_local->refs = 1;
  nctx->hg_local->hg_cl = HG_Init(addr, HG_TRUE);
  if (!nctx->hg_local->hg_cl) {
    nx_fatal("lo:HG_Init");
  }
  nctx->hg_local->hg_ctx = HG_Context_create(nctx->hg_local->hg_cl);
  if (!nctx->hg_local->hg_ctx) {
    nx_fatal("lo:HG_Context_create");
  }

  /* determine the max address size for local comm */
  MPI_Allreduce(&my_sz, &nctx->laddrsz, 1, MPI_INT, MPI_MAX, nctx->localcomm);
  xchg_sz = sizeof(xchg_dat_t) + nctx->laddrsz;

  /* exchange address and rank info within the local comm */
  xitm = (xchg_dat_t*)malloc(xchg_sz);
  if (!xitm) nx_fatal("malloc failed");
  xitm->grank = nctx->grank;
  xitm->idx = xitm->grank; /* use granks as address indexes */
  strcpy(xitm->addr, addr);

  xarr = (xchg_dat_t*)malloc(nctx->lsize * xchg_sz);
  if (!xarr) nx_fatal("malloc failed");

  MPI_Allgather(xitm, xchg_sz, MPI_BYTE, xarr, xchg_sz, MPI_BYTE,
                nctx->localcomm);

  /* lookup and store all mercury addresses */
  bgarg.hgctx = nctx->hg_local->hg_ctx;
  bgarg.bgdone = 0;
  bgarg.nctx = nctx;

  ret = pthread_create(&bgthread, NULL, nx_bgthread, (void*)&bgarg);
  if (ret != 0) nx_fatal("pthread_create");

  MPI_Barrier(nctx->localcomm);

  hret = nx_lookup_addrs(nctx, nctx->hg_local, xarr, nctx->lsize, nctx->laddrsz,
                         &nctx->lmap);
  if (hret != HG_SUCCESS) {
    nx_fatal("lo:HG_Addr_lookup");
  }

#ifdef NEXUS_DEBUG
  nx_dump_addrs(nctx, nctx->hg_local, &nctx->lmap);
#endif

  MPI_Barrier(nctx->localcomm);

  bgarg.bgdone = 1;
  pthread_join(bgthread, NULL);

  free(xarr);
  free(xitm);
}

void nx_find_remote_addrs(nexus_ctx_t nctx, char* myaddr) {
  int my_sz, i, j, M, c, P;
  int *myinfo, *nodeinfo;
  char* rank2addr;
  xchg_dat_t *xitm, *xarr;
  hg_return_t hret;

  /* if we're alone stop here */
  if (nctx->nnodes == 1) return;

  /*
   * to setup the remote network, we need to know a) which remote peers we
   * should connect to, and b) what are their addresses. but to accomplish a,
   * we need to first prepare two auxiliary arrays: rank2addr which maps each
   * rank to its remote address, and nodeinfo which is going to contain the
   * manifest information for each remote node.
   *
   * our first step is to prepare the rank2addr array.
   */
  my_sz = strlen(myaddr) + 1;

  /* determine the max address size for the global comm */
  MPI_Allreduce(&my_sz, &nctx->gaddrsz, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);

  /* map each rank to its address */
  rank2addr = (char*)malloc(nctx->gsize * nctx->gaddrsz);
  if (!rank2addr) nx_fatal("malloc failed");

  MPI_Allgather(myaddr, nctx->gaddrsz, MPI_BYTE, rank2addr, nctx->gaddrsz,
                MPI_BYTE, MPI_COMM_WORLD);
#ifdef NEXUS_DEBUG
  for (i = 0; i < nctx->gsize; i++)
    fprintf(stderr, "NX-%d: rank2addr[%d]=%s\n", nctx->grank, i,
            NADDR(rank2addr, i, nctx->gaddrsz));
#endif

  /*
   * we now prepare the nodeinfo array and this is done in 4 steps: 1) we find
   * the max number of ranks per node, M, 2) have each node rep construct a
   * (M+1)-sized array containing (# ranks, r0, r1, ...), 3) have node reps
   * all-gather their (M+1)-sized arrays (on repcomm), and 4) have each node rep
   * broadcasts the finished array (on localcomm)
   */

  /* find the max number of ranks per node (i.e., max PPN) */
  MPI_Allreduce(&nctx->lsize, &M, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
  /* XXX: we could replace the MPI_Allreduce() above with a smaller
   * MPI_Allreduce() followed by an MPI_Bcast(), but we think MPI itself will do
   * this internally */
  nodeinfo = (int*)malloc(sizeof(int) * (M + 1) * nctx->nnodes);
  if (!nodeinfo) nx_fatal("malloc failed");

  /* prepare my info (node representatives only) */
  if (nctx->repcomm != MPI_COMM_NULL) {
    myinfo = (int*)malloc(sizeof(int) * (M + 1));
    if (!myinfo) nx_fatal("malloc failed");

    for (i = 0; i < M; i++)
      myinfo[i + 1] = (i < nctx->lsize) ? nctx->local2global[i] : -1;
    myinfo[0] = nctx->lsize;

    /* exchange node information */
    MPI_Allgather(myinfo, M + 1, MPI_INT, nodeinfo, M + 1, MPI_INT,
                  nctx->repcomm);

    free(myinfo);
  }

  /* broadcast so everyone knows it */
  MPI_Bcast(nodeinfo, (M + 1) * nctx->nnodes * sizeof(int), MPI_BYTE, 0,
            nctx->localcomm);
#ifdef NEXUS_DEBUG
  for (j = 0; j < nctx->nnodes; j++)
    for (i = 1; i < M + 1; i++)
      fprintf(stderr, "NX-%d: nodeinfo[%d][%d]=%d\n", nctx->grank, j, i - 1,
              nodeinfo[j * (M + 1) + i]);
#endif

  /* before we go figure out who's our peers, let's first use the nodeinfo array
   * to construct a corresponding node2rep array. this array maps each node to
   * its node representative.
   */
  nctx->node2rep = (int*)malloc(sizeof(int) * nctx->nnodes);
  if (!nctx->node2rep) nx_fatal("malloc failed");

  /*
   * the representative for a node is one whose local rank is equal to our
   * node's id modulo the remote node's lsize.
   */
  for (i = 0; i < nctx->nnodes; i++) {
#define IDX(i) (i * (M + 1))
    nctx->node2rep[i] =
        nodeinfo[IDX(i) + 1 + (nctx->nodeid % nodeinfo[IDX(i)])];

#undef IDX
  }

  free(nodeinfo);

  /*
   * with rank2addr and node2rep both done, the next step is to determine
   * who's indeed our peers. but let's first determine the max possible number
   * of peers that we can be responsible for.
   */
  P = (nctx->nnodes / nctx->lsize) + ((nctx->nnodes % nctx->lsize) ? 1 : 0);

  xarr = (xchg_dat_t*)malloc(P * (sizeof(*xarr) + nctx->gaddrsz));
  if (!xarr) nx_fatal("malloc failed");

  /*
   * a node (node, not a rank) is a peer iff its node id modulo our node's
   * lsize is equal to our lrank.
   */
  i = nctx->lrank;
  c = 0;
  while (i < nctx->nnodes) {
#define NADDR(x, y, s) (&x[y * s])
    char* raddr;

    /* skip ourselves */
    if (i == nctx->nodeid) {
      i += nctx->lsize;
      continue;
    }

    raddr = NADDR(rank2addr, nctx->node2rep[i], nctx->gaddrsz);

    xitm = (xchg_dat_t*)(((char*)xarr) + c * (sizeof(*xitm) + nctx->gaddrsz));
    xitm->idx = i; /* use node id as address indexes */
    xitm->grank = nctx->node2rep[i];
    strcpy(xitm->addr, raddr);

    i += nctx->lsize;
    c++;

#undef NADDR
  }

  free(rank2addr);

  /* lookup addresses */
  if (c != 0) {
#ifdef NEXUS_DEBUG
    for (i = 0; i < c; i++) {
      xchg_dat_t* xi =
          (xchg_dat_t*)(((char*)xarr) + i * (sizeof(*xi) + nctx->gaddrsz));
      fprintf(stderr, "NX-%d: remote-peer[%d]=%d (addr=%s)\n", nctx->grank,
              xi->idx, xi->grank, xi->addr);
    }
#endif

    hret = nx_lookup_addrs(nctx, nctx->hg_remote, xarr, c, nctx->gaddrsz,
                           &nctx->rmap);
    if (hret != HG_SUCCESS) {
      nx_fatal("net:HG_Addr_lookup");
    }
  }

  free(xarr);
}

/*
 * nx_discover_remote: detect remote peers and setup the remote network
 * substrate for multi-hop routing.
 */
void nx_discover_remote(nexus_ctx_t nctx, char* hgaddr_in) {
  hg_addr_t addr_self;
  hg_size_t addr_sz;
  char addr[TMPADDRSZ];
  pthread_t bgthread; /* network bg thread */
  struct bgthread_dat bgarg;
  hg_return_t hret;
  int ret;

  nx_init_repcomm(nctx);
  MPI_Bcast(&nctx->nodeid, 1, MPI_INT, 0, nctx->localcomm);
  MPI_Bcast(&nctx->nnodes, 1, MPI_INT, 0, nctx->localcomm);

  /* build the map of global rank to node id */
  nctx->rank2node = (int*)malloc(sizeof(int) * nctx->gsize);
  if (!nctx->rank2node) nx_fatal("malloc failed");

  MPI_Allgather(&nctx->nodeid, 1, MPI_INT, nctx->rank2node, 1, MPI_INT,
                MPI_COMM_WORLD);

#ifdef NEXUS_DEBUG
  fprintf(stderr, "NX-%d: REMOTE %s\n", nctx->grank, hgaddr_in);
#endif

  nctx->hg_remote = (nexus_hg_t*)malloc(sizeof(nexus_hg_t));
  memset(nctx->hg_remote, 0, sizeof(nexus_hg_t));
  nctx->hg_remote->refs = 1;
  nctx->hg_remote->hg_cl = HG_Init(hgaddr_in, HG_TRUE);
  if (!nctx->hg_remote->hg_cl) {
    nx_fatal("net:HG_Init");
  }
  nctx->hg_remote->hg_ctx = HG_Context_create(nctx->hg_remote->hg_cl);
  if (!nctx->hg_remote->hg_ctx) {
    nx_fatal("net:HG_Context_create");
  }

  /* fetch self-address */
  hret = HG_Addr_self(nctx->hg_remote->hg_cl, &addr_self);
  if (hret != HG_SUCCESS) {
    nx_fatal("net:HG_Addr_self");
  }
  addr_sz = sizeof(addr);
  hret = HG_Addr_to_string(nctx->hg_remote->hg_cl, addr, &addr_sz, addr_self);
  if (hret != HG_SUCCESS) {
    nx_fatal("net:HG_Addr_to_string");
  }
  HG_Addr_free(nctx->hg_remote->hg_cl, addr_self);

  /* lookup and store mercury addresses */
  if (nctx->nnodes != 1) { /* only do it when we aren't alone */
    bgarg.hgctx = nctx->hg_remote->hg_ctx;
    bgarg.bgdone = 0;
    bgarg.nctx = nctx;

    ret = pthread_create(&bgthread, NULL, nx_bgthread, (void*)&bgarg);
    if (ret != 0) nx_fatal("pthread_create");

    MPI_Barrier(MPI_COMM_WORLD);

    nx_find_remote_addrs(nctx, addr);
#ifdef NEXUS_DEBUG
    nx_dump_addrs(nctx, nctx->hg_remote, &nctx->rmap);
#endif

    MPI_Barrier(MPI_COMM_WORLD);
    bgarg.bgdone = 1;

    pthread_join(bgthread, NULL);
  }
}

nexus_ctx_t nx_bootstrap_internal(char* uri, char* subnet, char* proto) {
  nexus_ctx_t nctx;
  char addr[TMPADDRSZ]; /* server uri buffer */
  char* env;

  nctx = new nexus_ctx;

  env = getenv("NEXUS_LOOKUP_LIMIT");
  if (env == NULL || env[0] == 0) {
    nctx->nx_limit = DEFAULT_NX_LIMIT;
  } else {
    nctx->nx_limit = atoi(env);
    if (nctx->nx_limit <= 0) {
      nctx->nx_limit = 1;
    }
  }

  nctx->localcomm = MPI_COMM_NULL;
  nctx->repcomm = MPI_COMM_NULL;
  nctx->rank2node = NULL;
  nctx->local2global = NULL;
  nctx->node2rep = NULL;

  MPI_Comm_rank(MPI_COMM_WORLD, &nctx->grank);
  MPI_Comm_size(MPI_COMM_WORLD, &nctx->gsize);

  nx_setup_local(nctx);

  if (!nctx->grank)
    fprintf(stdout, "NX: LOCAL %s (NX-LIMIT=%d)\n",
            nctx->hg_local ? "DONE" : "VIA REMOTE", nctx->nx_limit);

  if (!uri) {
    nx_prepare_addr(nctx, subnet, proto, addr);
    uri = addr;
  }
  nx_discover_remote(nctx, uri);
  if (!nctx->hg_local) {
    nx_setup_local_via_remote(nctx);
  }

  if (!nctx->grank) fprintf(stdout, "NX: REMOTE DONE\n");

#ifdef NEXUS_DEBUG
  fprintf(stderr, "NX-%d: ALL DONE\n", nctx->grank);
#endif

  return nctx;
}
}  // namespace

nexus_ctx_t nexus_bootstrap_uri(char* uri) {
  return nx_bootstrap_internal(uri, NULL, NULL);
}

nexus_ctx_t nexus_bootstrap(char* subnet, char* proto) {
  return nx_bootstrap_internal(NULL, subnet, proto);
}

void nexus_destroy(nexus_ctx_t nctx) {
  nexus_map_t::iterator it;

  for (it = nctx->lmap.begin(); it != nctx->lmap.end(); ++it) {
    if (it->second != HG_ADDR_NULL) {
      HG_Addr_free(nctx->hg_local->hg_cl, it->second);
    }
  }

  MPI_Barrier(nctx->localcomm);
  MPI_Comm_free(&nctx->localcomm);
  assert(nctx->hg_local->refs > 0);
  nctx->hg_local->refs--;
  if (nctx->hg_local->refs == 0) {
    HG_Context_destroy(nctx->hg_local->hg_ctx);
    HG_Finalize(nctx->hg_local->hg_cl);
    free(nctx->hg_local);
  }

  for (it = nctx->rmap.begin(); it != nctx->rmap.end(); ++it) {
    if (it->second != HG_ADDR_NULL) {
      HG_Addr_free(nctx->hg_remote->hg_cl, it->second);
    }
  }

  MPI_Barrier(MPI_COMM_WORLD);
  if (nctx->repcomm != MPI_COMM_NULL) {
    MPI_Comm_free(&nctx->repcomm);
  }
  assert(nctx->hg_remote->refs > 0);
  nctx->hg_remote->refs--;
  if (nctx->hg_remote->refs == 0) {
    HG_Context_destroy(nctx->hg_remote->hg_ctx);
    HG_Finalize(nctx->hg_remote->hg_cl);
    free(nctx->hg_remote);
  }

  if (nctx->node2rep) free(nctx->node2rep);
  free(nctx->local2global);
  free(nctx->rank2node);
  delete nctx;
}

hg_context_t* nexus_hgcontext_local(nexus_ctx_t nctx) {
  return nctx->hg_local->hg_ctx;
}

hg_class_t* nexus_hgclass_local(nexus_ctx_t nctx) {
  return nctx->hg_local->hg_cl;
}

hg_context_t* nexus_hgcontext_remote(nexus_ctx_t nctx) {
  return nctx->hg_remote->hg_ctx;
}

hg_class_t* nexus_hgclass_remote(nexus_ctx_t nctx) {
  return nctx->hg_remote->hg_cl;
}
<file_sep>/src/nexus.cc
/*
 * Copyright (c) 2017-2019, Carnegie Mellon University and
 *     Los Alamos National Laboratory.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "nexus_internal.h"

#include <assert.h>

/*
 * utility function
 */
namespace {
/* nx_addr_get: retrieve address from a given nexus map. return HG_ADDR_NULL if
 * no such address if found */
hg_addr_t nx_addr_get(nexus_map_t* map, int key) {
  nexus_map_t::iterator it = map->find(key);
  return (it == map->end()) ? HG_ADDR_NULL : it->second;
}
}  // namespace

nexus_ret_t nexus_next_hop(nexus_ctx_t nctx, int dest, int* rank,
                           hg_addr_t* addr) {
  int srcrep, destrep;
  int destn;
  assert(nctx != NULL);

  /* stop here if we are the final hop */
  if (nctx->grank == dest) return NX_DONE;

  /* if dest is local we return its local address */
  if ((*addr = nx_addr_get(&nctx->lmap, dest)) != HG_ADDR_NULL) {
    *rank = dest; /* the next stop is the final dest */
    /* we are either the original src, or a dest rep */
    return NX_ISLOCAL;
  }

  /* dest >> dest node */
  destn = nctx->rank2node[dest];
  /* dest node >> src rep's global rank */
  srcrep = nctx->local2global[(destn % nctx->lsize)];
  /* dest node >> dest rep's global rank */
  destrep = nctx->node2rep[destn];
#ifdef NEXUS_DEBUG
  fprintf(stderr, "NX-%d: dest=%d, destnode=%d, srcrep=%d, destrep=%d\n",
          nctx->grank, dest, destn, srcrep, destrep);
#endif

  if (nctx->grank != srcrep) {
    *addr = nx_addr_get(&nctx->lmap, srcrep);
    if (*addr == HG_ADDR_NULL) return NX_NOTFOUND;
    *rank = srcrep; /* the next stop is src rep */
    /* we are the original src */
    return NX_SRCREP;
  } else {
    *addr = nx_addr_get(&nctx->rmap, destn);
    if (*addr == HG_ADDR_NULL) return NX_NOTFOUND;
    *rank = destrep; /* the next stop is dest rep */
    /* we are the src rep */
    return NX_DESTREP;
  }
}

nexus_ret_t nexus_set_grank(nexus_ctx_t nctx, int rank) {
  nctx->grank = rank;
  return NX_SUCCESS;
}

int nexus_global_rank(nexus_ctx_t nctx) {
  assert(nctx != NULL);
  return nctx->grank;
}

int nexus_global_size(nexus_ctx_t nctx) {
  assert(nctx != NULL);
  return nctx->gsize;
}

int nexus_local_rank(nexus_ctx_t nctx) {
  assert(nctx != NULL);
  return nctx->lrank;
}

int nexus_local_size(nexus_ctx_t nctx) {
  assert(nctx != NULL);
  return nctx->lsize;
}

nexus_ret_t nexus_global_barrier(nexus_ctx_t nctx) {
  assert(nctx != NULL);
  int rv = MPI_Barrier(MPI_COMM_WORLD);
  if (rv != MPI_SUCCESS) return NX_ERROR;
  return NX_SUCCESS;
}

nexus_ret_t nexus_local_barrier(nexus_ctx_t nctx) {
  assert(nctx != NULL);
  int rv = MPI_Barrier(nctx->localcomm);
  if (rv != MPI_SUCCESS) return NX_ERROR;
  return NX_SUCCESS;
}

languages: Markdown C++

repo_name: zhengqmark/deltafs-nexus


text:
<file_sep># fromvktoytm

Adds your VK audios to YouTube Music.

### Input format

The only supported input for now is raw copied list of tracks in the following format in a text file:
```
Track title (track title)
Devil In My Veins (artist name)
3:58 (duration)

Glass Animals
The Other Side Of Paradise
5:20

A Tribe Called Quest
Jazz (We've Got)
4:10

...
```
### YouTube Music authentication

The app uses [this unofficial API](https://github.com/sigma67/ytmusicapi) to communicate with YouTube Music.
Follow [this](https://github.com/sigma67/ytmusicapi/blob/master/docs/source/setup.rst#copy-authentication-headers) this instructions to copy your authentication headers
and then provide them in a text file the first time you use the app. A new file called `ytmheaders.json` will be created and then used.
<file_sep>from ytmusicapi import YTMusic
import re

def check_search_result(search_result, song):
    for result in search_result:
        if result['resultType'] == 'song' and result['title'] == song['title']:
            for artist in result['artists']:
                if artist['name'] in song['artist']:
                    return result['videoId']

def __main__ ():
    songlist_filepath = input('Audios list filepath: ')
    songlist = open(songlist_filepath, 'r').read()
    matches = re.finditer('(.*?)\n(.*?)\n([0-9]*?:[0-9]*?)\n', songlist, )
    songs = [{
        'artist': match.group(1),
        'title': match.group(2),
        'duration': match.group(3)
    } for index, match in enumerate(matches, start=1)]
    print('Found ' + str(len(songs)) + ' songs.')
    raw_headers = input('YTMusic raw headers (leave blank to skip this step): ')
    if raw_headers:
        YTMusic.setup(filepath='ytmheaders.json', headers_raw=raw_headers)
    ytm = YTMusic('ytmheaders.json')
    playlist = ytm.create_playlist('Imported from VK', 'Contains songs automatically imported from VK')
    if 'error' in playlist and '401' in playlist:
        print('[!] Error while creating playlist. Aborting...')
        return
    print('Created playlist with Id: ' + str(playlist))
    unfound = []
    found_count = 0
    for song in songs:
        query = song['artist'] + ' ' + song['title']
        try:
            search_result = ytm.search(query)
            videoId = check_search_result(search_result, song)
            if videoId:
                ytm.add_playlist_items(playlist, [videoId])
                print('Added ' + song['title'] + ' by ' + song['artist'])
                found_count += 1
            else:
                unfound.append(song)
        except:
            print('[!] Error searching for ' + query)
            unfound.append(song)
    print('Added ' + str(found_count) + ' of ' + str(len(songs)) + '. Exporting remaining to "unfound.txt"')
    unfound_list = ''.join([song['artist'] + ' - ' + song['title'] + '\n' for song in unfound])
    print(unfound_list)
    f = open('unfound.txt', 'w')
    f.write(unfound_list)
    f.close()

__main__()

branch_name: refs/heads/main

languages: Markdown Python

repo_language: Markdown

repo_name: darginyegor/fromvktoytm


text:
<file_sep>// <NAME>, <NAME>, <NAME>
/* Questions
1. ForwardElimination fails to provide a solution to the given system because after it iterates through the second row of the matrix, the pivot position's
value becomes 0. When the algorithm tries to iterate through the third row, it will divide its elements by the pivot position value of 0, which will result
in a divide by 0 error and the algorithm will terminate.
BetterForwardElimination remedies this by swapping the pivot row with the row with the greatest value for a pivot position, preventing divide by 0 errors
in the case where the system has a solution.
2. BetterForwardElimination fails to provide a solution for the given system because it continues to iterate through the matrix when the solution is reached,
preventing a correct answer from being reached. The way to remedy this is to check if there is a combination of 0 elements in the first n positions in each
row such that the rows can be ordered to form an upper triangular matrix.
*/

// Applies Guass-Jordan elimination on a matrix
// A: The matrix of coefficients
// b: The system's right-hand side values
// Returns the solved matrix
using namespace std;
#include <malloc.h>
#include <vector>
#include <iostream>
vector< vector<double> > Elimination (vector<vector<double> > A, vector<double> b) {
	double n = A.size(); // The rows of the matrix
	for (int i = 0; i < n; i++) {
		A.at(i).push_back(b.at(i));
	}
	for (int i = 0; i < n - 1; i++) { // Forwards elimination
		bool solved = false;
		int count = 0;
		for (int j = n - 1; j > 0; j--) {
			if (A[j][i] == 0) {
				count++;
			}
			else break;
		}
		if (count > n - 2) solved = true;
		if (!solved) {
			double pivotrow = i;
			for (int j = i + 1; j < n; j++) {
				if (A[j][i] > A[pivotrow][i]) pivotrow = j;
			}
			for (int k = i; k < n + 1; k++) {
				double temp1 = A[i][k];
				double temp2 = A[pivotrow][k];
				A[i][k] = temp2;
				A[pivotrow][k] = temp1;
			}
			for (int j = i + 1; j < n; j++) {
				double temp = (double)A[j][i] / (double)A[i][i];
				for (double k = i; k < n + 1; k++) {
					A[j][k] = A[j][k] - (double)A[i][k] * temp;
				}
			}
		}
	}

	for (int i = n - 1; i > 0; i--) { // Backwards elimination
		double diagonal = A[i][i];
		if (diagonal != 0) {
			for (int j = 0; j < i; j++) {
				double ratio = A[j][i] / A[i][i];
				A[j][i] = A[j][i] - ratio * A[i][i];
				A[j][n] = A[j][n] - ratio * A[i][n];
			}
		}
	}

	for (int i = 0; i < n; i++) {
		double diagonal = A[i][i];
		if (diagonal != 0) {
			for (int j = 0; j < n + 1; j++) {
				if (A[i][j] != 0) A[i][j] /= diagonal;
			}
		}
	}
	return A;
}

// Performs guass-jordan elimination on a given matrix and prints the result
// A: The matrix of coefficients
// b: The system's right-hand side values
void elimAndPrint(vector<vector<double>> A, vector<double> b) {
	int n = A.size();
	cout << "Original matrix:" << endl;
	for (int j = 0; j < n; j++) { // print original matrix
		for (int k = 0; k < n + 1; k++) {
			if (k < n) {
				cout << A[j][k] << " ";
			}
			else cout << b[j] << " ";

		}
		cout << endl;
	}
	cout << endl;
	vector<vector<double>> result = Elimination(A, b);
	cout << "Solved matrix:" << endl;
	for (int j = 0; j < n; j++) { // print solved matrix
		for (int k = 0; k < n + 1; k++) {
			cout << result[j][k] << " ";
		}
		cout << endl;
	}
}

vector<vector<int>> board = { {79, 71, 18, 20, 34, 51, 93, 65}, {73, 38, 24, 49, 18, 6, 40, 74}, {31, 5, 63, 10, 32, 40, 14, 13}, {13, 78, 48, 19, 78, 11, 90, 94}, {22, 93, 68, 11, 56, 63, 49, 35}, {85, 52, 27, 5, 94, 91, 82, 62}, {46, 23, 99, 77, 10, 42, 1, 72}, {89, 70, 73, 83, 90, 22, 44, 92} };
vector<vector<int>> vals = { {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}  ,{0,0,0,0,0,0,0,0},  {0,0,0,0,0,0,0,0} }; // Matrix of calculated values

// Calculates the value at a given row and column
// r: The row
// c: The column
int calcVal(int r, int c) {
		if (r == 7) vals[r][c] = board[r][c]; // base case for top row
		else if (vals[r][c] == 0) { // not yet calculated
			int up = 0;
			int right = 0;
			int left = 0;
			switch (c) { // checking for if on left/right
			case(0): // left wall
				up = calcVal(r + 1, c);
				right = calcVal(r + 1, c + 1);
				vals[r][c] = board[r][c] + fmax(up, right);
				break;
			case(7): // right wall
				up = calcVal(r + 1, c);
				left = calcVal(r + 1, c - 1);
				vals[r][c] = board[r][c] + fmax(up, left);
				break;
			default: // otherwise
				up = calcVal(r + 1, c);
				left = calcVal(r + 1, c - 1);
				right = calcVal(r + 1, c + 1);
				vals[r][c] = board[r][c] + fmax(fmax(up, left), fmax(up, right));
				break;
			}
		}
		return vals[r][c];
}

// Calculates the optimal path for a starting node
// r: The starting row
// c: The starting column
vector<int> calcPath(int r, int c) {
	vector<int> output = { board[r][c] };
	if (r == 7) { // base case
		return output;
	}
	else {
		int up = 0;
		int right = 0;
		int left = 0;
		vector<int> path;
		switch (c) { // checking for if on left/right
		case(0): // left wall
			up = calcVal(r + 1, c);
			right = calcVal(r + 1, c + 1);
			if (up > right) {
				path = calcPath(r + 1, c);
			}
			else path = calcPath(r + 1, c + 1);
			break;
		case(7): // right wall
			up = calcVal(r + 1, c);
			left = calcVal(r + 1, c - 1);
			if (up > left) {
				path = calcPath(r + 1, c);
			}
			else path = calcPath(r + 1, c - 1);
			break;
		default: // otherwise
			up = calcVal(r + 1, c);
			left = calcVal(r + 1, c - 1);
			right = calcVal(r + 1, c + 1);
			int max = fmax(fmax(up, left), fmax(up, right));
			if (max == up) path = calcPath(r + 1, c);
			else if (max == left) path = calcPath(r + 1, c - 1);
			else if (max == right) path = calcPath(r + 1, c + 1);
			break;
		}
		output.insert(output.begin(), path.begin(), path.end());
		return output;
	}
}

// Calculates the path for question 4
void pathCalculator() {
	vector<vector<int>> paths = { {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}  ,{0,0,0,0,0,0,0,0},  {0,0,0,0,0,0,0,0} };// the paths for each vault index
	vector<int> totals = { 0,0,0,0,0,0,0,0 };
	for (int i = 0; i < 8; i++) { // Calculate path for each starting node

		totals[i] = calcVal(0, i);
		paths[i] = calcPath(0, i);
	}
	cout << "Starting square: Row 1 vault 7" << endl;
	cout << "Bilbo's path: ";
	for (int i = 7; i >= 0; i--) {
		cout << paths[6][i] << " ";
	}
	cout << endl;
	cout << "Total gems collected: " << totals[6] << endl;
	cout << "Arkenstone vault: Row 8 vault 5";
}

int main() {
	vector<vector<double>> A1 = { {1, 1, -1}, {0, 1, 3}, {-1, 0, 2} };
	vector<double> b1 = { 9, 3, 2 };
	vector<vector<double>> A2 = { {1, 1, 1}, {1, 1, 2}, {2, 2, 3} };
	vector<double> b2 = { 6, 9, 15 };
	vector<vector<double>> A3 = { {1,1,1,1,1,1,1,1}, {1,2,1,1,1,1,2,1}, {1,1,3,1,1,3,1,1}, {1,1,1,4,4,1,1,1}, {11,1,1,1,1,1,1,1}, {1,1,1,1,-1,-1,-1,-1}, {1,2,3,4,5,6,7,8}, {1,-1,1,-1,1,-1,1,-1} };
	vector<double> b3 = { 0,0,0,0,20,34,-51,-6 };
	elimAndPrint(A3, b3);
	cout << endl;
	pathCalculator();
}

branch_name: refs/heads/master


text:
<file_sep>-- phpMyAdmin SQL Dump
-- version 5.0.2
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1
-- Generation Time: Oct 12, 2020 at 04:40 AM
-- Server version: 10.4.14-MariaDB
-- PHP Version: 7.4.10

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `eproject`
--

-- --------------------------------------------------------

--
-- Table structure for table `categories`
--

CREATE TABLE `categories` (
  `cat_id` int(11) NOT NULL,
  `cat_title` varchar(255) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `categories`
--

INSERT INTO `categories` (`cat_id`, `cat_title`) VALUES
(1, 'Panasonic'),
(2, 'Daikin'),
(3, 'Samsung'),
(4, 'Toshiba'),
(5, 'Beko');

-- --------------------------------------------------------

--
-- Table structure for table `products`
--

CREATE TABLE `products` (
  `product_id` int(11) NOT NULL,
  `product_title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `cat_id` int(11) NOT NULL,
  `product_price` float NOT NULL,
  `product_quantity` int(11) NOT NULL,
  `product_description` text COLLATE utf8_unicode_ci NOT NULL,
  `product_image` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `product_word` text COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `products`
--

INSERT INTO `products` (`product_id`, `product_title`, `cat_id`, `product_price`, `product_quantity`, `product_description`, `product_image`, `product_word`) VALUES
(1, 'Panasonic 1', 1, 29.99, 3, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum', 'panasonic.png', 'description.docx'),
(2, 'Panasonic 2', 1, 15.19, 2, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum', 'panasonic.png', 'description.docx'),
(3, 'Panasonic 3', 1, 99.99, 4, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\r\n\r\n', 'panasonic.png', 'description.docx'),
(4, 'Panasonic 4', 1, 79.99, 1, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\r\n\r\n', 'panasonic.png', 'description.docx'),
(6, '<NAME>', 2, 19.99, 5, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', 'daikin.jpg', 'description.docx'),
(7, '<NAME>', 2, 29.99, 5, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', 'daikin.jpg', 'description.docx'),
(8, 'Daikin 4', 2, 39.99, 12, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', 'daikin.jpg', 'description.docx'),
(9, 'Samsung 1', 3, 99.99, 45, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', 'samsung.jpg', 'description.docx'),
(10, 'Samsung 2', 3, 199.99, 3, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', 'samsung.jpg', 'description.docx'),
(11, 'Samsung 3', 3, 145, 5, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', 'samsung.jpg', 'description.docx'),
(12, 'Samsung 4', 3, 200, 6, 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.', 'samsung.jpg', 'description.docx'),
(32, '1', 1, 1, 1, 'Công nghệ lọc không khí Nanoe-G cho bầu không khí sạch bụi bẩn, bụi mịn PM2.5.\r\nSử dụng như một chiếc máy lọc không khí với hệ thống lọc khí hoạt động độc lập.\r\nCông nghệ Inverter và Eco tích hợp AI giúp tiết kiệm điện tối đa.\r\nLàm lạnh nhanh tức thì với chế độ Powerful.\r\nKhông khí thoáng đãng, khô ráo khi thời tiết ẩm ướt với chế độ hút ẩm.\r\nTiện lợi hơn với chế độ hẹn giờ bật/tắt máy.', 'dieuhoa.jpg', 'description.docx'),
(34, 'TEST', 1, 100, 100, '100', 'panasonic.png', 'description.docx'),
(35, 'TEST 1', 1, 100, 100, '100', 'panasonic.png', 'description.docx'),
(36, 'TESTTTTTTTTTTT', 1, 1, 1, '1', 'panasonic.png', 'description.docx');

-- --------------------------------------------------------

--
-- Table structure for table `users`
--

CREATE TABLE `users` (
  `user_id` int(11) NOT NULL,
  `username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `phonenumber` int(11) NOT NULL,
  `level` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `users`
--

INSERT INTO `users` (`user_id`, `username`, `password`, `email`, `phonenumber`, `level`) VALUES
(1, 'admin', 'admin', '<EMAIL>', 333374982, 1),
(2, 'user1', '123456', '<EMAIL>', 333374982, 0);

--
-- Indexes for dumped tables
--

--
-- Indexes for table `categories`
--
ALTER TABLE `categories`
  ADD PRIMARY KEY (`cat_id`);

--
-- Indexes for table `products`
--
ALTER TABLE `products`
  ADD PRIMARY KEY (`product_id`);

--
-- Indexes for table `users`
--
ALTER TABLE `users`
  ADD PRIMARY KEY (`user_id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `categories`
--
ALTER TABLE `categories`
  MODIFY `cat_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=50;

--
-- AUTO_INCREMENT for table `products`
--
ALTER TABLE `products`
  MODIFY `product_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=37;

--
-- AUTO_INCREMENT for table `users`
--
ALTER TABLE `users`
  MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
COMMIT;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
<file_sep><?php

    function redirect($location){
        header("Location: $location");
    }

    function query($sql){

        global $connection;
        return mysqli_query($connection,$sql);
    }

    function confirm($result){
        global $connection;
        if(!$result){
            die("QUERY FAILED" . mysqli_error($connection));
        }
    }

    function escape_string($string){
        global $connection;
        return mysqli_real_escape_string($connection,$string);
    }

    function fetch_array($result){
        return mysqli_fetch_array($result);
    }

/*--------------------------------------------FRONT END -----------------------------------------------------*/
/*--------------------------------------------FRONT END -----------------------------------------------------*/
/*--------------------------------------------FRONT END -----------------------------------------------------*/

	function login_user(){
		if(isset($_POST['submit'])){
		$username = escape_string($_POST['username']);
		$password = escape_string($_POST['pass']);
		$query = query("SELECT * FROM users WHERE username = '{$username}' and password = '{$<PASSWORD>}'");
			confirm($query);
			if(mysqli_num_rows($query)==1){
				$_SESSION['username'] = $username;
				$row=fetch_array($query);
				if ($row['level']==1){
					redirect('../public/admin/index.php');
			}
				if($row['level']==0) {
						redirect('../public/index.php');
			}
			}
			else{
				redirect('login.php');
			}
		}
			}

	function signup_user(){
		if(isset($_POST['submit'])){

			$username = escape_string($_POST['username']);
			$password = escape_string($_POST['password']);
			$email = escape_string($_POST['email']);
			$phonenumber = escape_string($_POST['phonenumber']);
			$confirmpassword = escape_string($_POST['confirmpassword']);
		if($confirmpassword==$password)
		{
		$query = query("INSERT INTO `users`(`username`, `password`, `email`, `phonenumber`) VALUES ('$username','$password','$email','$phonenumber'");
		confirm($query);
	}
	}
	}

    function get_products(){
        $query = query("SELECT * FROM products");
        confirm($query);

        while( $row = fetch_array($query)){
				$product = <<<DELIMETER

New

{$row['product_title']}

${$row['product_price']}

				DELIMETER;

            echo $product;
        }
	}
	function get_products_4(){
        $query = query("SELECT * FROM products limit 4");
        confirm($query);

        while( $row = fetch_array($query)){
				$product = <<<DELIMETER

New

{$row['product_title']}

${$row['product_price']}

				DELIMETER;

            echo $product;
        }
	}

    function get_categories(){
        $query = query("SELECT * FROM categories");
        confirm($query);

        while($row = fetch_array($query)){
		$category_links = <<<DELIMETER

{$row['cat_title']}

			DELIMETER;

						echo $category_links;
					}
		}

		function get_all_products_in_cat_page(){
			$query = query("SELECT * FROM products");
			confirm($query);

			while( $row = fetch_array($query)){
				$product = <<<DELIMETER

New

{$row['product_title']}

${$row['product_price']}

				DELIMETER;
			echo $product;
			}
		}
    function get_products_in_cat_page(){
        $query = query("SELECT * FROM products WHERE cat_id = ". escape_string($_GET['id']) . "");
        confirm($query);
        while( $row = fetch_array($query)){
			$product = <<<DELIMETER

New

{$row['product_title']}

${$row['product_price']}

			DELIMETER;
        echo $product;
        }
	}
	function get_products_in_cat_page1(){
        $query = query("SELECT * FROM products");
        confirm($query);
        while( $row = fetch_array($query)){
			$product = <<<DELIMETER

New

{$row['product_title']}

${$row['product_price']}

			DELIMETER;
        echo $product;
        }
	}
	function relate_product(){
        $query = query("SELECT * FROM products WHERE cat_id = ". escape_string($_GET['cat_id']) .  " limit 4 ");
        confirm($query);

        while( $row = fetch_array($query)){
			$product = <<<DELIMETER

New

{$row['product_title']}

${$row['product_price']}

			DELIMETER;
        echo $product;
        }
    }

    function show_total_product(){
        $query = query("SELECT COUNT(product_id) FROM products WHERE cat_id = ". escape_string($_GET['id']) . "");
        confirm($query);

        while( $row = fetch_array($query)){
			$total = <<<DELIMETER

Showing {$row['COUNT(product_id)']} results

			DELIMETER;

						echo $total;
					}
				}
    function show_total_product1(){
        $query = query("SELECT COUNT(product_id) FROM products");
        confirm($query);

        while( $row = fetch_array($query)){
			$total = <<<DELIMETER

Showing {$row['COUNT(product_id)']} results

			DELIMETER;

						echo $total;
					}
				}
/*---------------------------------------------------BACK END -----------------------------------------------------*/
/*---------------------------------------------------BACK END -----------------------------------------------------*/
/*---------------------------------------------------BACK END -----------------------------------------------------*/

		function show_categories_in_admin(){
			$query = "SELECT * FROM `categories`";
			$category_query = query($query);
			confirm($query);

			while($row = fetch_array($category_query)){
				$cat_id = $row['cat_id'];
				$cat_title = $row['cat_title'];

					$categories = <<<DELIMETER

							{$cat_id}
							{$cat_title}

								Delete
								Update

					DELIMETER;
									echo $categories;
								}
							}

		function add_category(){
			if(isset($_POST['add_category'])){

				$cat_title = escape_string($_POST['cat_title']);
				if(empty($cat_title) || $cat_title == ""){
					echo '';
				}
				else{
					$insert_cat = query("INSERT INTO `categories`(`cat_title`) VALUES ('{$cat_title}') ");
					echo'';

					confirm($insert_cat);

				}

			}
		}
		function update_category(){
			if(isset($_POST['update_category'])){

				$cat_title = escape_string($_POST['cat_title']);
				if(empty($cat_title) || $cat_title == ""){
					echo "Category is not empty";
				}
				else{
					$insert_cat = query("UPDATE `categories` SET `cat_title`= '{$cat_title}' WHERE cat_id = ". escape_string($_GET['id']) . "");
					confirm($insert_cat);
					redirect("categories.php");
				}

			}
		}
		function show_categories_in_add_product(){
			$query = query("SELECT DISTINCT cat_id FROM `categories`");
			confirm($query);

			while($row = fetch_array($query)){
				$product = <<<DELIMETER
				<option value="{$row['cat_id']}">{$row['cat_id']}</option>
			DELIMETER;
							echo $product;
						}
					}

		function get_products_in_admin(){
			$query = query("SELECT * FROM products");
			confirm($query);

			while( $row = fetch_array($query)){
					$product = <<<DELIMETER

						{$row['product_id']}
						{$row['cat_id']}
						{$row['product_title']}
						{$row['product_price']}
						{$row['product_quantity']}

							Delete
							 Update

					DELIMETER;

				echo $product;
			}
		}
		function add_product(){
			if(isset($_POST['add_product'])){

				$product_title = escape_string($_POST['product_title']);
				$cat_id = escape_string($_POST['cat_id']);
				$product_price = escape_string($_POST['product_price']);
				$product_quantity = escape_string($_POST['product_quantity']);
				$product_description = escape_string($_POST['product_description']);
				$product_image = escape_string($_FILES['file']['name']);
				$image_temp_location = escape_string($_FILES['file']['tmp_name']);

				$product_word = escape_string($_FILES['file1']['name']);
				$word_temp_location = escape_string($_FILES['file1']['tmp_name']);

				move_uploaded_file($image_temp_location,UPLOAD_DIRECTORY . DS .$product_image);
				move_uploaded_file($word_temp_location,UPLOAD_DIRECTORY . DS .$product_word);
				$insert_product = query("INSERT INTO `products`(`product_title`, `cat_id`, `product_price`, `product_quantity`, `product_description`, `product_image`,`product_word`) VALUES ('{$product_title}','{$cat_id}','{$product_price}','{$product_quantity}','{$product_description}','{$product_image}','{$product_word}') ");
					confirm($insert_product);
					redirect("add_product.php");
				}

			}
			function update_product(){
				if(isset($_POST['update_product'])){

					$product_title = escape_string($_POST['product_title']);
					$cat_id = escape_string($_POST['cat_id']);
					$product_price = escape_string($_POST['product_price']);
					$product_quantity = escape_string($_POST['product_quantity']);
					$product_description = escape_string($_POST['product_description']);
					$product_image = escape_string($_FILES['file']['name']);
					$image_temp_location = escape_string($_FILES['file']['tmp_name']);

					move_uploaded_file($image_temp_location,UPLOAD_DIRECTORY . DS .$product_image);
					$insert_product = query("UPDATE `products` SET `product_title`='{$product_title}',`cat_id`='{$cat_id}',`product_price`='{$product_price}',`product_quantity`='{$product_quantity}',`product_description`='{$product_description}',`product_image`='{$product_image}' WHERE product_id = ". escape_string($_GET['id']) . " ");
						confirm($insert_product);
						redirect("view_product.php");
					}

				}
				function get_users_in_admin(){
					$query = query("SELECT * FROM users");
					confirm($query);

					while( $row = fetch_array($query)){
							$product = <<<DELIMETER

								{$row['user_id']}
								{$row['username']}
								{$row['email']}
								{$row['phonenumber']}
								{$row['level']}

									Delete
									Update

							DELIMETER;

						echo $product;
					}
				}

?><file_sep>
<?php require_once("../resources/config.php"); ?>
<?php include(TEMPLATE_FRONT . DS . "header.php"); ?>
<?php include(TEMPLATE_FRONT . DS . "footer.php"); ?>

<!DOCTYPE html>

<title>Checkout</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="Sublime project">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="styles/bootstrap4/bootstrap.min.css">
<link href="plugins/font-awesome-4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" type="text/css" href="styles/checkout.css">
<link rel="stylesheet" type="text/css" href="styles/checkout_responsive.css">

Home

Shopping Cart

Checkout

Billing Address

Enter your address info

							<form action="#" id="checkout_form" class="checkout_form">

										First Name*
										<input type="text" id="checkout_name" class="checkout_input" required="required">

										Last Name*
										<input type="text" id="checkout_last_name" class="checkout_input" required="required">

									Address*
									<input type="text" id="checkout_address" class="checkout_input" required="required">
									<input type="text" id="checkout_address_2" class="checkout_input checkout_address_2" required="required">

									Phone no*
									<input type="phone" id="checkout_phone" class="checkout_input" required="required">

									Email Address*
									<input type="phone" id="checkout_email" class="checkout_input" required="required">

										<input type="checkbox" id="checkbox_terms" name="regular_checkbox" class="regular_checkbox" checked="checked">

										Terms and conditions

							</form>

Your order

Order details

Product

Total

Cocktail Yellow dress

$59.90

Subtotal

$59.90

Shipping

Free

Total

$59.90

								Cach on delivery
									<input type="radio" name="radio">

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin pharetra temp or so dales. Phasellus sagittis auctor gravida. Integ er bibendum sodales arcu id te mpus. Ut consectetur lacus.

Place Order

<file_sep><?php require_once("../resources/config.php"); ?>

<?php include(TEMPLATE_FRONT . DS . "footer.php"); ?>

<?php
	if(isset($_GET['action']) && $_GET['action']=="add"){
		$id=$_GET['id'];
		$sql=("SELECT * FROM products WHERE product_id='{$id}'");
			$query=mysqli_query($connection,$sql);
			if(mysqli_num_rows($query)!=0){
				$row=mysqli_fetch_array($query);
				$_SESSION['cart'][$row['product_id']]=array(
					"product_image" => $row['product_image'],
					"product_title" => $row['product_title'],
					"product_price" => $row['product_price'],
					"product_quantity" => 1,
					);
			}else{
				$message="This product id it's invalid!";
			}
		}

	if(isset($_GET['action']) && $_GET['action']=="clear"){
		if(isset($_SESSION['cart']))
		{
			unset($_SESSION['cart']);
		}

	}
?>

<?php
	if(isset($_GET['action']) && $_GET['action']=="increase"){
			$id=$_GET['id'];
			$_SESSION['cart'][$id]['product_quantity']++;
		}

	if(isset($_GET['action']) && $_GET['action']=="decrease"){
			$id=$_GET['id'];
			$_SESSION['cart'][$id]['product_quantity']--;
		}

?>

<?php include(TEMPLATE_FRONT . DS . "header.php"); ?>
	<link rel="stylesheet" type="text/css" href="styles/cart_responsive.css">
<!DOCTYPE html>

	<title>Cart</title>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="description" content="Sublime project">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" type="text/css" href="styles/bootstrap4/bootstrap.min.css">
	<link href="plugins/font-awesome-4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css">
	<link rel="stylesheet" type="text/css" href="styles/cart.css">

Home

Categories

Shopping Cart

Product

Price

Quantity

Total

					<?php
							// Add item to cart
							if(isset($_SESSION['cart'])&&$cartCount > 0){
								$sql = "SELECT * FROM products WHERE product_id IN (";
									foreach($_SESSION['cart'] as $id => $value) {
										$sql .= "'" . $id. "'" . ",";
									}
								$sql = substr($sql, 0, -1).")";
								$query = mysqli_query($connection,$sql);
								$totalprice = 0;
								$finaltotal = 0;
								while($row = mysqli_fetch_array($query)){
									$subtotal = $_SESSION['cart'][$row['product_id']]['product_quantity']*$row['product_price'];

									$totalprice+= $subtotal;
							?>

<img src="../resources/uploads/<?php echo $row['product_image']?>" alt="">

<?php echo $row['product_title']?>

							<div class="cart_item_price" id="cartItemPrice<?php echo $row['product_id']?>">$<?php echo $row['product_price']?>

										Qty
										<input name="quantity[<?php echo $row['product_id'] ?>]" value="<?php echo $_SESSION['cart'][$row['product_id']]['product_quantity'] ?>">

												<a href="cart.php?id=<?php echo $row['product_id']?>&action=increase">

												<a href="cart.php?id=<?php echo $row['product_id']?>&action=decrease">

$
							<?php
							if(isset($_SESSION['cart'])&&$cartCount > 0){
								echo $subtotal;
							} else
							echo 0;
						?>

						<?php }} ?>

Continue shopping

Clear cart

Update cart

Shipping method

Select the one you want

								Personal pickup
									<input type="radio" checked="checked" name="radio">

									Free

Cart total

Final info

Subtotal

														$<?php
											if(isset($_SESSION['cart'])&&$cartCount > 0){
												echo $totalprice;
											} else
											echo 0;
											?>

Shipping

Free

Total

											$<?php
											if(isset($_SESSION['cart'])&&$cartCount > 0){
												echo $totalprice;
											} else
											echo 0;
											?>

Proceed to checkout

languages: SQL PHP

repo_language: SQL


text:
<file_sep>
public class Metodos extends Thread{
	private int soma;
	private int i;

	public Metodos(int soma, int i) {
		this.soma = soma;
		this.i= i;
		start();
	}

	public void run() {
		System.out.println("Soma da linha #" + i +": " + soma);
	}

}
<file_sep>import java.util.Random;

public class Principal {

	public static void main(String[] args) {

		int soma = 0;
		int[][] Mat = new int[3][5];
		Random random = new Random();
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 5; j++) {
				Mat[i][j] = random.nextInt(10);
			}
		}

		for (int i = 0; i < 1; i++) {
			for (int j = 0; j < 5; j++) {
				soma = soma + Mat[i][j];
			}
			Metodos metodos = new Metodos(soma, i);
		}
		soma=0;
		for (int i = 1; i < 2; i++) {
			for (int j = 0; j < 5; j++) {
				soma = soma + Mat[i][j];
			}
			Metodos metodos2 = new Metodos(soma, i);
		}
		soma=0;
		for (int i = 2; i < 3; i++) {
			for (int j = 0; j < 5; j++) {
				soma = soma + Mat[i][j];
			}
			Metodos metodos3 = new Metodos(soma, i);
		}
		soma=0;

	}
}

repo_language: Java