<commit_before>// This module performs low-level WASM manipulations, such as linking several
// modules together and inspecting the debug zone at the bottom of the memory.
// This module is aware of the compilation strategy of kreMLin. It can be
// included from either a browser or a shell context, as long as my_print is
// defined in scope.

"use strict";

var my_print;

// When loaded "as is" via d8 or ch, we inherit the caller's scope. When loaded
// via node, we don't.
if (typeof process !== "undefined")
  my_print = console.log

/******************************************************************************/
/* Some printing helpers                                                      */
/******************************************************************************/

function p8(n) {
  return ("0"+Number(n).toString(16)).slice(-2);
}

function hex(m8, start, len) {
  let s = "";
  for (let i = 0; i < len; ++i)
    s += p8(m8[start + i]);
  return s;
}

function hexle(m8, i, m) {
  let buf = "";
  let n = m - 1;
  while (n >= 0) {
    buf += p8(m8[i+n]);
    n--;
  }
  return buf;
}

function hex32(m8, start) {
  return hexle(m8, start, 4);
}

function hex64(m8, start) {
  return hexle(m8, start, 8);
}

function p32(n) {
  return p8((n >>> 24) & 255) + p8((n >>> 16) & 255) + p8((n >>> 8) & 255) + p8(n & 255);
}

function dump(mem, size) {
  let m8 = new Uint8Array(mem.buffer);
  let i = 0;
  let buf = "";
  while (i < size) {
    buf += p32(i) + "    ";
    for (let j = 0; j < 32; ++j) {
      buf += p8(m8[i+j]);
      if (j % 4 == 3)
        buf += " ";
    }
    buf += "    ";
    for (let j = 0; j < 32; ++j) {
      let c = m8[i+j];
      if (32 <= c && c < 128)
        buf += String.fromCharCode(c);
      else
        buf += ".";
    }
    buf += "\n";
    i += 32;
  }
  my_print(buf);
}

/******************************************************************************/
/* Implementations of the kremlin runtime support library                     */
/******************************************************************************/

function stringAtAddr(mem, addr) {
  let m8 = new Uint8Array(mem.buffer);
  let buf = "";
  while (m8[addr] != 0) {
    buf += String.fromCharCode(m8[addr++]);
  }
  return buf;
}

function readLeAtAddr(mem, addr, bytes) {
  let m8 = new Uint8Array(mem.buffer);
  let i = 0;
  while (bytes-- > 0)
    i = (i << 8) + m8[addr + bytes];
  return i;
}

function writeLeAtAddr(mem, addr, n, bytes) {
  let m8 = new Uint8Array(mem.buffer);
  for (let i = 0; i < bytes; ++i) {
    m8[addr + i] = n & 255;
    n >>>= 8;
  }
}

function writeBeAtAddr(mem, addr, n, bytes) {
  let m8 = new Uint8Array(mem.buffer);
  while (bytes > 0) {
    m8[addr + bytes - 1] = n & 255;
    bytes--;
    n >>>= 8;
  }
}

function dummyModule(funcs, globals) {
  let module = {};
  for (let f of funcs)
    module[f] = () => {
      my_print("Not implemented: " + s);
      throw new Error();
    };
  for (let g of globals)
    module[g] = 0;
  return module;
}

let mkWasmSupport = (mem) => ({
  WasmSupport_trap: () => {
    dump(mem, 2*1024);
    my_print("Run-time trap, e.g. zero-sized array or abort.");
    throw new Error();
  }
});

let mkFStar = () => dummyModule(
  [ "FStar_UInt128_constant_time_carry_ok", "FStar_PropositionalExtensionality_axiom" ],
  [ "FStar_Monotonic_Heap_lemma_mref_injectivity" ]);

let mkC = (mem) => ({
  srand: () => { throw new Error("todo: srand") },
  rand: () => { throw new Error("todo: rand") },
  exit: () => { throw new Error("todo: exit") },
  print_bytes: () => { throw new Error("todo: print_bytes") },
  htole16: (x) => { throw new Error("todo: htole16") },
  le16toh: (x) => { throw new Error("todo: le16toh") },
  htole32: (x) => { throw new Error("todo: htole32") },
  le32toh: (x) => { throw new Error("todo: le32toh") },
  htole64: (x) => { throw new Error("todo: htole64") },
  le64toh: (x) => { throw new Error("todo: le64toh") },
  htobe16: (x) => { throw new Error("todo: htobe16") },
  be16toh: (x) => { throw new Error("todo: be16toh") },
  htobe32: (x) => { throw new Error("todo: htobe32") },
  be32toh: (x) => { throw new Error("todo: be32toh") },
  htobe64: (x) => { throw new Error("todo: htobe64") },
  be64toh: (x) => { throw new Error("todo: be64toh") },
  store16_le: (addr, n) => { throw new Error("todo: store16_le") },
  load16_le: (addr) => { throw new Error("todo: load16_le") },
  store16_be: (addr, n) => { throw new Error("todo: store16_be") },
  load16_be: (addr) => { throw new Error("todo: load16_be") },
  store32_le: (addr, n) => {
    writeLeAtAddr(mem, addr, n, 4);
  },
  // load32_le: implemented natively
  store32_be: (addr, n) => { throw new Error("todo: store32_be") },
  load32_be: (addr) => { throw new Error("todo: load32_be") },
  store64_le: (addr, n) => { throw new Error("todo: store64_le") },
  load64_le: (addr) => { throw new Error("todo: load64_le") },
  store64_be: (addr, n) => { throw new Error("todo: store64_be") },
  load64_be: (addr) => { throw new Error("todo: load64_be") },
  store128_le: (addr, n) => { throw new Error("todo: store128_le") },
  load128_le: (addr) => { throw new Error("todo: load128_le") },
  store128_be: (addr, n) => { throw new Error("todo: store128_be") },
  load128_be: (addr) => { throw new Error("todo: load128_be") },

  char_uint8: () => { throw new Error("todo: char_uint8") },
  uint8_char: () => { throw new Error("todo: uint8_char") },
  char_of_uint8: (x) => { throw new Error("todo: char_of_uint8") },
  uint8_of_char: (x) => { throw new Error("todo: uint8_of_char") },

  // A Prims_string generates a literal allocated in the data segment;
  // string_of_literal is just a typing trick.
  string_of_literal: (x) => x,
  print_string: (addr) => my_print(stringAtAddr(mem, addr)),

  // Truncated
  clock: () => Date.now(),
});

let mkCNullity = (mem) => ({
  C_Nullity_is_null: () => { throw new Error("todo: is_null") }
});

function checkEq(mem, name) {
  return (x1, x2) => {
    if (x1 != x2) {
      dump(mem, 2*1024);
      my_print(name + ": equality failure, "+x1+" != "+x2);
      throw new Error();
    }
    return 0;
  };
}

let mkTestLib = (mem) => ({
  TestLib_touch: () => 0,
  TestLib_check8: checkEq(mem, "TestLib_check8"),
  TestLib_check16: checkEq(mem, "TestLib_check16"),
  TestLib_check32: checkEq(mem, "TestLib_check32"),
  TestLib_check64: checkEq(mem, "TestLib_check64"),
  TestLib_checku8: checkEq(mem, "TestLib_checku8"),
  TestLib_checku16: checkEq(mem, "TestLib_checku16"),
  TestLib_checku32: checkEq(mem, "TestLib_checku32"),
  TestLib_checku64: checkEq(mem, "TestLib_checku64"),
  TestLib_check: (b) => {
    if (!b) {
      dump(mem, 2*1024);
      my_print("TestLib_check: assertion failure");
      throw new Error();
    }
    return 0;
  },
  TestLib_unsafe_malloc: () => { throw new Error("todo: unsafe_malloc") },
  TestLib_perr: (err) => {
    my_print("Got error code "+err);
    return 0;
  },
  TestLib_uint8_p_null: 0,
  TestLib_uint32_p_null: 0,
  TestLib_uint64_p_null: 0,
  TestLib_compare_and_print: (addr, b1, b2, len) => {
    let m8 = new Uint8Array(mem.buffer);
    let str = stringAtAddr(m8, addr);
    let hex1 = hex(m8, b1, len);
    let hex2 = hex(m8, b2, len);
    my_print("[test] expected output "+str+" is "+hex1);
    my_print("[test] computed output "+str+" is "+hex2);
    for (let i = 0; i < len; ++i) {
      if (m8[b1+i] != m8[b2+i]) {
        my_print("[test] reference "+str+" and expected "+str+" differ at byte "+i);
        my_print("b1="+p32(b1)+",b2="+p32(b2));
        dump(mem, 4*1024);
        throw new Error("test failure");
      }
    }
    my_print("[test] "+str+" is a success\n");
  },
  TestLib_print_clock_diff: (t1, t2) => {
    my_print("[benchmark] took: " + (t2 - t1) + "ms\n");
  },
});

/******************************************************************************/
/* Memory layout                                                              */
/******************************************************************************/

// mem[0..3] = top-of-the-stack pointer (I32);
// mem[4..127] = scratch space for debugging.
// Conventions for debugging and "debugging format" (lolz) are in WasmDebug.ml
const header_size = 128;

// this sets up the base data pointer and the debug entry point for the WASM
// context; WASM-generated code expects to have these defined.
function init() {
  let mem = new WebAssembly.Memory({ initial: 16 });
  let m8 = new Uint8Array(mem.buffer);
  let nest = 0;

  let debug = () => {
    let i = 0;
    let buf = "";
    let string = () => {
      let ptr = m8[i] + (m8[i+1] << 8) + (m8[i+2] << 16) + (m8[i+3] << 24);
      i += 4;
      while (m8[ptr] != 0) {
        buf += String.fromCharCode(m8[ptr]);
        ptr++;
      }
    };
    let int32 = () => {
      buf += "0x";
      buf += hex32(m8, i);
      i += 4;
    };
    let int64 = () => {
      buf += "0x";
      buf += hex64(m8, i);
      i += 8;
    };
    // Dump the stack pointer
    int32();
    buf += " | ";
    buf += " ".repeat(nest);
    while (m8[i] != 0 && i < 128) {
      let c = m8[i];
      i++;
      switch (c) {
        case 1:
          string();
          break;
        case 2:
          int32();
          break;
        case 3:
          int64();
          break;
        case 4:
          nest++;
          break;
        case 5:
          nest--;
          break;
        default:
          my_print(hex(m8, 0, 128));
          throw "unrecognized debug format:\n  buf="+buf+"\n  c=0x"+p8(c)+"\n  i="+i;
      }
      buf += " ";
    }
    my_print(buf);
  };

  // Initialize the highwater mark.
  new Uint32Array(mem.buffer)[0] = header_size;

  // Base stuff that appears as requirement, because they're exposed in TestLib
  // and/or C.
  let imports = {
    Kremlin: {
      mem: mem,
      debug: debug,
      data_start: header_size
    },
    WasmSupport: mkWasmSupport(mem),
    FStar: mkFStar(mem),
    C: mkC(mem),
    C_Nullity: mkCNullity(mem),
    TestLib: mkTestLib(mem)
  };
  return imports;
}

// One MUST call this function after loading a module.
function propagate(module_name, imports, instance) {
  my_print("Module", module_name, "successfully loaded");
  my_print("Adding exports into global import table:\n ", Object.keys(instance.exports));
  if (!(module_name in imports))
    imports[module_name] = {};
  for (let o of Object.keys(instance.exports)) {
    imports[module_name][o] = instance.exports[o];
  }
  my_print("This module has a data segment of size: ", instance.exports.data_size);
  imports.Kremlin.data_start += instance.exports.data_size;
  my_print("Next data segment will start at: ", imports.Kremlin.data_start);
  // Set the highwater mark right after the data segment
  new Uint32Array(imports.Kremlin.mem.buffer)[0] = imports.Kremlin.data_start;
  my_print();
}

// One MAY only call this function after all modules have been loaded and
// suitable calls to propagate have been performed.
function reserve(mem, size) {
  let m32 = new Uint32Array(mem.buffer);
  let p = m32[0];
  m32[0] += size;
  my_print("Reserved memory area 0x"+p32(p)+"..0x"+p32(m32[0]));
  return p;
}

function link(modules) {
  let fold = async (imports, modules) => {
    if (!modules.length)
      return imports;

    let [{ name, buf }, ...ms] = modules;
    let { module, instance } = await WebAssembly.instantiate(buf, imports);
    propagate(name, imports, instance);
    return fold(imports, ms);
  };

  return fold(init(), modules);
}

if (typeof module !== "undefined")
  module.exports = {
    link: link,
    reserve: reserve
  };
<commit_msg>Move things around per the move of endianness-conversion functions from C to C.Endianness<commit_after>// This module performs low-level WASM manipulations, such as linking several
// modules together and inspecting the debug zone at the bottom of the memory.
// This module is aware of the compilation strategy of kreMLin. It can be
// included from either a browser or a shell context, as long as my_print is
// defined in scope.

"use strict";

var my_print;

// When loaded "as is" via d8 or ch, we inherit the caller's scope. When loaded
// via node, we don't.
if (typeof process !== "undefined")
  my_print = console.log

/******************************************************************************/
/* Some printing helpers                                                      */
/******************************************************************************/

function p8(n) {
  return ("0"+Number(n).toString(16)).slice(-2);
}

function hex(m8, start, len) {
  let s = "";
  for (let i = 0; i < len; ++i)
    s += p8(m8[start + i]);
  return s;
}

function hexle(m8, i, m) {
  let buf = "";
  let n = m - 1;
  while (n >= 0) {
    buf += p8(m8[i+n]);
    n--;
  }
  return buf;
}

function hex32(m8, start) {
  return hexle(m8, start, 4);
}

function hex64(m8, start) {
  return hexle(m8, start, 8);
}

function p32(n) {
  return p8((n >>> 24) & 255) + p8((n >>> 16) & 255) + p8((n >>> 8) & 255) + p8(n & 255);
}

function dump(mem, size) {
  let m8 = new Uint8Array(mem.buffer);
  let i = 0;
  let buf = "";
  while (i < size) {
    buf += p32(i) + "    ";
    for (let j = 0; j < 32; ++j) {
      buf += p8(m8[i+j]);
      if (j % 4 == 3)
        buf += " ";
    }
    buf += "    ";
    for (let j = 0; j < 32; ++j) {
      let c = m8[i+j];
      if (32 <= c && c < 128)
        buf += String.fromCharCode(c);
      else
        buf += ".";
    }
    buf += "\n";
    i += 32;
  }
  my_print(buf);
}

/******************************************************************************/
/* Implementations of the kremlin runtime support library                     */
/******************************************************************************/

function stringAtAddr(mem, addr) {
  let m8 = new Uint8Array(mem.buffer);
  let buf = "";
  while (m8[addr] != 0) {
    buf += String.fromCharCode(m8[addr++]);
  }
  return buf;
}

function readLeAtAddr(mem, addr, bytes) {
  let m8 = new Uint8Array(mem.buffer);
  let i = 0;
  while (bytes-- > 0)
    i = (i << 8) + m8[addr + bytes];
  return i;
}

function writeLeAtAddr(mem, addr, n, bytes) {
  let m8 = new Uint8Array(mem.buffer);
  for (let i = 0; i < bytes; ++i) {
    m8[addr + i] = n & 255;
    n >>>= 8;
  }
}

function writeBeAtAddr(mem, addr, n, bytes) {
  let m8 = new Uint8Array(mem.buffer);
  while (bytes > 0) {
    m8[addr + bytes - 1] = n & 255;
    bytes--;
    n >>>= 8;
  }
}

function dummyModule(funcs, globals) {
  let module = {};
  for (let f of funcs)
    module[f] = () => {
      my_print("Not implemented: " + s);
      throw new Error();
    };
  for (let g of globals)
    module[g] = 0;
  return module;
}

let mkWasmSupport = (mem) => ({
  WasmSupport_trap: () => {
    dump(mem, 2*1024);
    my_print("Run-time trap, e.g. zero-sized array or abort.");
    throw new Error();
  }
});

let mkFStar = () => dummyModule(
  [ "FStar_UInt128_constant_time_carry_ok", "FStar_PropositionalExtensionality_axiom" ],
  [ "FStar_Monotonic_Heap_lemma_mref_injectivity" ]);

let mkPrims = (mem) => ({
  Prims_op_Addition: (x, y) => { return x + y; }
});

let mkC = (mem) => ({
  srand: () => { throw new Error("todo: srand") },
  rand: () => { throw new Error("todo: rand") },
  exit: () => { throw new Error("todo: exit") },
  print_bytes: () => { throw new Error("todo: print_bytes") },

  char_uint8: () => { throw new Error("todo: char_uint8") },
  uint8_char: () => { throw new Error("todo: uint8_char") },
  char_of_uint8: (x) => { throw new Error("todo: char_of_uint8") },
  uint8_of_char: (x) => { throw new Error("todo: uint8_of_char") },

  // A Prims_string generates a literal allocated in the data segment;
  // string_of_literal is just a typing trick.
  string_of_literal: (x) => x,
  print_string: (addr) => my_print(stringAtAddr(mem, addr)),

  // Truncated
  clock: () => Date.now(),
});

let mkCEndianness = (mem) => ({
  htole16: (x) => { throw new Error("todo: htole16") },
  le16toh: (x) => { throw new Error("todo: le16toh") },
  htole32: (x) => { throw new Error("todo: htole32") },
  le32toh: (x) => { throw new Error("todo: le32toh") },
  htole64: (x) => { throw new Error("todo: htole64") },
  le64toh: (x) => { throw new Error("todo: le64toh") },
  htobe16: (x) => { throw new Error("todo: htobe16") },
  be16toh: (x) => { throw new Error("todo: be16toh") },
  htobe32: (x) => { throw new Error("todo: htobe32") },
  be32toh: (x) => { throw new Error("todo: be32toh") },
  htobe64: (x) => { throw new Error("todo: htobe64") },
  be64toh: (x) => { throw new Error("todo: be64toh") },
  store16_le: (addr, n) => { throw new Error("todo: store16_le") },
  load16_le: (addr) => { throw new Error("todo: load16_le") },
  store16_be: (addr, n) => { throw new Error("todo: store16_be") },
  load16_be: (addr) => { throw new Error("todo: load16_be") },
  store32_le: (addr, n) => {
    writeLeAtAddr(mem, addr, n, 4);
  },
  // load32_le: implemented natively
  store32_be: (addr, n) => { throw new Error("todo: store32_be") },
  load32_be: (addr) => { throw new Error("todo: load32_be") },
  store64_le: (addr, n) => { throw new Error("todo: store64_le") },
  load64_le: (addr) => { throw new Error("todo: load64_le") },
  store64_be: (addr, n) => { throw new Error("todo: store64_be") },
  load64_be: (addr) => { throw new Error("todo: load64_be") },
  store128_le: (addr, n) => { throw new Error("todo: store128_le") },
  load128_le: (addr) => { throw new Error("todo: load128_le") },
  store128_be: (addr, n) => { throw new Error("todo: store128_be") },
  load128_be: (addr) => { throw new Error("todo: load128_be") }
});

let mkCNullity = (mem) => ({
  C_Nullity_is_null: () => { throw new Error("todo: is_null") }
});

function checkEq(mem, name) {
  return (x1, x2) => {
    if (x1 != x2) {
      dump(mem, 2*1024);
      my_print(name + ": equality failure, "+x1+" != "+x2);
      throw new Error();
    }
    return 0;
  };
}

let mkTestLib = (mem) => ({
  TestLib_touch: () => 0,
  TestLib_check8: checkEq(mem, "TestLib_check8"),
  TestLib_check16: checkEq(mem, "TestLib_check16"),
  TestLib_check32: checkEq(mem, "TestLib_check32"),
  TestLib_check64: checkEq(mem, "TestLib_check64"),
  TestLib_checku8: checkEq(mem, "TestLib_checku8"),
  TestLib_checku16: checkEq(mem, "TestLib_checku16"),
  TestLib_checku32: checkEq(mem, "TestLib_checku32"),
  TestLib_checku64: checkEq(mem, "TestLib_checku64"),
  TestLib_check: (b) => {
    if (!b) {
      dump(mem, 2*1024);
      my_print("TestLib_check: assertion failure");
      throw new Error();
    }
    return 0;
  },
  TestLib_unsafe_malloc: () => { throw new Error("todo: unsafe_malloc") },
  TestLib_perr: (err) => {
    my_print("Got error code "+err);
    return 0;
  },
  TestLib_uint8_p_null: 0,
  TestLib_uint32_p_null: 0,
  TestLib_uint64_p_null: 0,
  TestLib_compare_and_print: (addr, b1, b2, len) => {
    let m8 = new Uint8Array(mem.buffer);
    let str = stringAtAddr(m8, addr);
    let hex1 = hex(m8, b1, len);
    let hex2 = hex(m8, b2, len);
    my_print("[test] expected output "+str+" is "+hex1);
    my_print("[test] computed output "+str+" is "+hex2);
    for (let i = 0; i < len; ++i) {
      if (m8[b1+i] != m8[b2+i]) {
        my_print("[test] reference "+str+" and expected "+str+" differ at byte "+i);
        my_print("b1="+p32(b1)+",b2="+p32(b2));
        dump(mem, 4*1024);
        throw new Error("test failure");
      }
    }
    my_print("[test] "+str+" is a success\n");
  },
  TestLib_print_clock_diff: (t1, t2) => {
    my_print("[benchmark] took: " + (t2 - t1) + "ms\n");
  },
});

/******************************************************************************/
/* Memory layout                                                              */
/******************************************************************************/

// mem[0..3] = top-of-the-stack pointer (I32);
// mem[4..127] = scratch space for debugging.
// Conventions for debugging and "debugging format" (lolz) are in WasmDebug.ml
const header_size = 128;

// this sets up the base data pointer and the debug entry point for the WASM
// context; WASM-generated code expects to have these defined.
function init() {
  let mem = new WebAssembly.Memory({ initial: 16 });
  let m8 = new Uint8Array(mem.buffer);
  let nest = 0;

  let debug = () => {
    let i = 0;
    let buf = "";
    let string = () => {
      let ptr = m8[i] + (m8[i+1] << 8) + (m8[i+2] << 16) + (m8[i+3] << 24);
      i += 4;
      while (m8[ptr] != 0) {
        buf += String.fromCharCode(m8[ptr]);
        ptr++;
      }
    };
    let int32 = () => {
      buf += "0x";
      buf += hex32(m8, i);
      i += 4;
    };
    let int64 = () => {
      buf += "0x";
      buf += hex64(m8, i);
      i += 8;
    };
    // Dump the stack pointer
    int32();
    buf += " | ";
    buf += " ".repeat(nest);
    while (m8[i] != 0 && i < 128) {
      let c = m8[i];
      i++;
      switch (c) {
        case 1:
          string();
          break;
        case 2:
          int32();
          break;
        case 3:
          int64();
          break;
        case 4:
          nest++;
          break;
        case 5:
          nest--;
          break;
        default:
          my_print(hex(m8, 0, 128));
          throw "unrecognized debug format:\n  buf="+buf+"\n  c=0x"+p8(c)+"\n  i="+i;
      }
      buf += " ";
    }
    my_print(buf);
  };

  // Initialize the highwater mark.
  new Uint32Array(mem.buffer)[0] = header_size;

  // Base stuff that appears as requirement, because they're exposed in TestLib
  // and/or C.
  let imports = {
    Kremlin: {
      mem: mem,
      debug: debug,
      data_start: header_size
    },
    WasmSupport: mkWasmSupport(mem),
    FStar: mkFStar(mem),
    Prims: mkPrims(mem),
    C: mkC(mem),
    C_Endianness: mkCEndianness(mem),
    C_Nullity: mkCNullity(mem),
    TestLib: mkTestLib(mem)
  };
  return imports;
}

// One MUST call this function after loading a module.
function propagate(module_name, imports, instance) {
  my_print("Module", module_name, "successfully loaded");
  my_print("Adding exports into global import table:\n ", Object.keys(instance.exports));
  if (!(module_name in imports))
    imports[module_name] = {};
  for (let o of Object.keys(instance.exports)) {
    imports[module_name][o] = instance.exports[o];
  }
  my_print("This module has a data segment of size: ", instance.exports.data_size);
  imports.Kremlin.data_start += instance.exports.data_size;
  my_print("Next data segment will start at: ", imports.Kremlin.data_start);
  // Set the highwater mark right after the data segment
  new Uint32Array(imports.Kremlin.mem.buffer)[0] = imports.Kremlin.data_start;
  my_print();
}

// One MAY only call this function after all modules have been loaded and
// suitable calls to propagate have been performed.
function reserve(mem, size) {
  let m32 = new Uint32Array(mem.buffer);
  let p = m32[0];
  m32[0] += size;
  my_print("Reserved memory area 0x"+p32(p)+"..0x"+p32(m32[0]));
  return p;
}

function link(modules) {
  let fold = async (imports, modules) => {
    if (!modules.length)
      return imports;

    let [{ name, buf }, ...ms] = modules;
    let { module, instance } = await WebAssembly.instantiate(buf, imports);
    propagate(name, imports, instance);
    return fold(imports, ms);
  };

  return fold(init(), modules);
}

if (typeof module !== "undefined")
  module.exports = {
    link: link,
    reserve: reserve
  };
<|endoftext|>


<commit_before>import React from 'react'
import { Link } from 'react-router'
import { prefixLink } from 'gatsby-helpers'
import Helmet from 'react-helmet'
import { config } from 'config'
import { Modal, Button } from 'react-bootstrap'

import Footer from './public/components/Footer.js'
import ReactDOM from 'react-dom'
import {Icon} from 'react-fa'

class Index extends React.Component {
  constructor(props) {
    super(props);
    this.handleChangeDisplay = this.handleChangeDisplay.bind(this);
    this.handleFacebookLink = this.handleFacebookLink.bind(this);
    this.handleInstagramLink = this.handleInstagramLink.bind(this);
    this.handleTwitterLink = this.handleTwitterLink.bind(this);
    this.handleEmail = this.handleEmail.bind(this);
    this.handleSelect = this.handleSelect.bind(this);
    this.state = {
      videoDisplay: 'inline',
      siteDisplay: 'none',

    }
  }

  handleChangeDisplay(event) {
    if (typeof window === 'undefined') {
      global.window = {}
    }

    const changeDisplay = () => {
      this.setState({
        videoDisplay: 'none',
        siteDisplay: 'inline'
      })
    }
    if (window.innerWidth > 768) {
    setTimeout(changeDisplay, 5500)
  }
    else {
      changeDisplay()
    }

  }

  componentDidMount(){
    this.handleChangeDisplay()
  }

  handleFacebookLink() {
    window.open('https://www.facebook.com/MBeltranini/')
  }

  handleInstagramLink(){
    window.open('https://www.instagram.com/magic_mark_show/')
  }

  handleTwitterLink(){
    window.open('https://twitter.com/Beltranini')
  }

  handleEmail(){
    window.location.assign('mailto:marklbeltran@gmail.com')
  }
  handleSelect(selectedIndex, event) {
    console.log(event)
    console.log(selectedIndex)
    this.setState({
      index: selectedIndex,
      direction: e.direction
    });
  }

  render() {
    const divstyle = {
      display: this.state.videoDisplay,
    }
    const sitestyle = {
      display: this.state.siteDisplay,

    }
    return (

              <Icon name="facebook-official"  size="2x" className="icon" onClick={this.handleFacebookLink}/>
              <Icon name="instagram" size="2x" className="icon" onClick={this.handleInstagramLink}/>
              <Icon name="twitter" size="2x" className="icon" onClick={this.handleTwitterLink}/>
              <Icon name="envelope" size="2x" className="icon" onClick={this.handleEmail}/>

    )

  }
}

export default Index<commit_msg>corrected intro code so video does not show up on mobile<commit_after>import React from 'react'
import { Link } from 'react-router'
import { prefixLink } from 'gatsby-helpers'
import Helmet from 'react-helmet'
import { config } from 'config'
import { Modal, Button } from 'react-bootstrap'

import Footer from './public/components/Footer.js'
import ReactDOM from 'react-dom'
import {Icon} from 'react-fa'

class Index extends React.Component {
  constructor(props) {
    super(props);
    this.handleChangeDisplay = this.handleChangeDisplay.bind(this);
    this.handleFacebookLink = this.handleFacebookLink.bind(this);
    this.handleInstagramLink = this.handleInstagramLink.bind(this);
    this.handleTwitterLink = this.handleTwitterLink.bind(this);
    this.handleEmail = this.handleEmail.bind(this);
    this.handleSelect = this.handleSelect.bind(this);
    this.state = {
      videoDisplay: 'none',
      siteDisplay: 'inline',

    }
  }

  handleChangeDisplay(event) {
    if (typeof window === 'undefined') {
      global.window = {}
    }

    const changeDisplay = () => {
      this.setState({
        videoDisplay: 'none',
        siteDisplay: 'inline'
      })
    }

    if (window.innerWidth >= 768) {
      this.setState({
        videoDisplay: 'inline',
        siteDisplay: 'none'
      })
    setTimeout(changeDisplay, 5500)
  }

  }

  componentDidMount(){
    this.handleChangeDisplay()
  }

  handleFacebookLink() {
    window.open('https://www.facebook.com/MBeltranini/')
  }

  handleInstagramLink(){
    window.open('https://www.instagram.com/magic_mark_show/')
  }

  handleTwitterLink(){
    window.open('https://twitter.com/Beltranini')
  }

  handleEmail(){
    window.location.assign('mailto:marklbeltran@gmail.com')
  }
  handleSelect(selectedIndex, event) {
    console.log(event)
    console.log(selectedIndex)
    this.setState({
      index: selectedIndex,
      direction: e.direction
    });
  }

  render() {
    const divstyle = {
      display: this.state.videoDisplay,
    }
    const sitestyle = {
      display: this.state.siteDisplay,

    }
    return (

              <Icon name="facebook-official"  size="2x" className="icon" onClick={this.handleFacebookLink}/>
              <Icon name="instagram" size="2x" className="icon" onClick={this.handleInstagramLink}/>
              <Icon name="twitter" size="2x" className="icon" onClick={this.handleTwitterLink}/>
              <Icon name="envelope" size="2x" className="icon" onClick={this.handleEmail}/>

    )

  }
}

export default Index<|endoftext|>


<commit_before>import React from 'react';
import { Link } from 'react-router';
import { prefixLink } from 'gatsby-helpers';
import DocumentTitle from 'react-document-title';
import Header from '../components/header';
import Footer from '../components/footer';
import { config } from 'config';

export default class Index extends React.Component {
  render () {
    return (
      <DocumentTitle title={config.siteTitle}>

{config.tagLine}

                <Link to={prefixLink(config.docsLink)}>Get started</Link>

                npm i -g waigo

                  Changelog

                  Twitter

                  Github

                  Discuss

Build data-driven APIs, apps and reactive websites.
Uses Koa and RethinkDB.

Koa and RethinkDB

                    Waigo builds on Koa, the ES6-based spiritual successor to Express.
                    Elegantly compose complex middleware patterns.
                    Use RethinkDB to build fully end-to-end
                    reactive applications.

Plugin architecture

                    Extend or override any part of the core framework as you
                    see fit. Only use what you need. Publish your
                    customizations as plugins (NPM modules) to re-use across
                    your other Waigo projects.

Form handling

                    Declaratively build
                    forms with automatic sanitization and validation. Initialize
                    and submit forms from any part of your application. Output a
                    form's configuration as JSON. CSRF-prevention comes built-in.

Routing and APIs

                    Powerful route configuration with intelligent nesting and
                    per-route and per-HTTP-method middleware customization.
                    All routes double-up as JSON API endpoints.
                    Control the output format of any route using query
                    parameters. Easily add your own custom output formats.

Frontend is yours

                    Effortlessly build basic HTML
                    using Pug templating
                    and the built-in template helpers. Use
                    whatever Javascript frameworks
                    (e.g. Angular/React) and CSS languages you want the rest of the way.

Users and Roles

                    Built-in user accounts. Authenticate
                    users via password, OAuth or custom mechanisms.
                    Assign roles to users, and elegantly control who gets
                    access to what via the Access Control
                    List (ACL).

Email notifications

                    Built-in configurable notifications via email and Slack.
                    Target notifications to specific users or roles and trigger
                    them asynchronously. Send emails to console,
                    using SMTP or a provider (e.g. Mailgun).

Scheduled Tasks

                    Built-in Cron system for task scheduling.
                    Tasks run within the full application context, giving you
                    access to all your data and other parts of the app.
                    Programmatically start, stop and run tasks.

Quick Setup

                    Create and run a skeleton app in seconds using the command-line client.
                    Generate gulp scripts to enable live-reload in the browser during development.
                    Install the <Link to="https://github.com/waigo/admin">Admin interface</Link> for
                    easy data management.

Quick start

{`$ npm init
$ waigo init
$ waigo init-gulp
$ gulp`}

Visit <Link to="http://localhost:3000 ">http://localhost:3000</Link> in your browser to see it.

Now start editing files and the browser page will auto-reload!

                <Link to={prefixLink(config.docsLink)}>Read the docs »</Link>

Get an in-depth introduction to Waigo and how to use it.

                View the code »

Check out upcoming features and contribute.

                Discuss and share »

Provide feedback, ask questions and share with the community.

      </DocumentTitle>
    )
  }

  componentDidMount () {
    if (window.twttr) {
      window.twttr.widgets.load();
    }
  }
}
<commit_msg>replace getting started link<commit_after>import React from 'react';
import { Link } from 'react-router';
import { prefixLink } from 'gatsby-helpers';
import DocumentTitle from 'react-document-title';
import Header from '../components/header';
import Footer from '../components/footer';
import { config } from 'config';

export default class Index extends React.Component {
  render () {
    return (
      <DocumentTitle title={config.siteTitle}>

{config.tagLine}

                <Link to={prefixLink(config.gettingStartedLink)}>Get started</Link>

                npm i -g waigo

                  Changelog

                  Twitter

                  Github

                  Discuss

Build data-driven APIs, apps and reactive websites.
Uses Koa and RethinkDB.

Koa and RethinkDB

                    Waigo builds on Koa, the ES6-based spiritual successor to Express.
                    Elegantly compose complex middleware patterns.
                    Use RethinkDB to build fully end-to-end
                    reactive applications.

Plugin architecture

                    Extend or override any part of the core framework as you
                    see fit. Only use what you need. Publish your
                    customizations as plugins (NPM modules) to re-use across
                    your other Waigo projects.

Form handling

                    Declaratively build
                    forms with automatic sanitization and validation. Initialize
                    and submit forms from any part of your application. Output a
                    form's configuration as JSON. CSRF-prevention comes built-in.

Routing and APIs

                    Powerful route configuration with intelligent nesting and
                    per-route and per-HTTP-method middleware customization.
                    All routes double-up as JSON API endpoints.
                    Control the output format of any route using query
                    parameters. Easily add your own custom output formats.

Frontend is yours

                    Effortlessly build basic HTML
                    using Pug templating
                    and the built-in template helpers. Use
                    whatever Javascript frameworks
                    (e.g. Angular/React) and CSS languages you want the rest of the way.

Users and Roles

                    Built-in user accounts. Authenticate
                    users via password, OAuth or custom mechanisms.
                    Assign roles to users, and elegantly control who gets
                    access to what via the Access Control
                    List (ACL).

Email notifications

                    Built-in configurable notifications via email and Slack.
                    Target notifications to specific users or roles and trigger
                    them asynchronously. Send emails to console,
                    using SMTP or a provider (e.g. Mailgun).

Scheduled Tasks

                    Built-in Cron system for task scheduling.
                    Tasks run within the full application context, giving you
                    access to all your data and other parts of the app.
                    Programmatically start, stop and run tasks.

Quick Setup

                    Create and run a skeleton app in seconds using the command-line client.
                    Generate gulp scripts to enable live-reload in the browser during development.
                    Install the <Link to="https://github.com/waigo/admin">Admin interface</Link> for
                    easy data management.

Quick start

{`$ npm init
$ waigo init
$ waigo init-gulp
$ gulp`}

Visit <Link to="http://localhost:3000 ">http://localhost:3000</Link> in your browser to see it.

Now start editing files and the browser page will auto-reload!

                <Link to={prefixLink(config.docsLink)}>Read the docs »</Link>

Get an in-depth introduction to Waigo and how to use it.

                View the code »

Check out upcoming features and contribute.

                Discuss and share »

Provide feedback, ask questions and share with the community.

      </DocumentTitle>
    )
  }

  componentDidMount () {
    if (window.twttr) {
      window.twttr.widgets.load();
    }
  }
}
<|endoftext|>


<commit_before>import Head from "next/head";
import Link from "next/link";
import React from "react";
import { DateTime } from "luxon";
import {
  Container,
  Section,
  SingleColumn,
  IntraNav,
} from "foundation-design-system";
import Header from "../components/Header";
import Footer from "../components/Footer";
import Contact from "../components/Contact";
import PostPreview from "../components/PostPreview";
import EventPreview from "../components/EventPreview";
import TwoUp from "../components/TwoUp";
import { getAllPosts, getAllEvents, generateRealtimeDate } from "../lib/lib";
import { eventKeys } from "../lib/constants";

export default function Home({ posts, events, grantNumbers, search }) {
  return (
    <Container>

        <title>urbit.org</title>

      <IntraNav ourSite="https://urbit.org" search={search} />
      <SingleColumn>

        {
          // Hero Statement
        }

A clean-slate OS and network for the 21st century.

        {
          // Hero
        }

Assembly 2022

                Assembly 2022 is the second ever Urbit conference coming to you
                this year from Miami Beach. Grab a towel and get ready.

                September 22nd–25th • Miami Beach, Florida

              <Link href="https://assembly.urbit.org" passHref>

                  Learn More

              </Link>

            Urbit is a{" "}
            new kind of computer that you
            can own completely in ways
            that matter:{" "}

              networking, identity, and data

            .

            We realized that in order to fix the internet, we had to build a new
            computer from scratch. Good thing we started over a decade ago.

            Today, Urbit a real system with thousands of users that are building
            all kinds of communities, software, DAOs, and more. And it’s getting
            better every day.{" "}

          <Link href="/overview" passHref>

              Read the Overview

          </Link>

        {
          // Grants
        }

Grants

{grantNumbers?.starsAwarded}

                Urbit stars awarded

{grantNumbers?.contributors}

                Different Contributors

{grantNumbers?.active}

                Active Projects

              We regularly grant address space to give motivated contributors
              real ownership and authority over the network.

              <Link href="/grants" passHref>

                  Learn More

              </Link>
              <Link href="/grants#view-grants" passHref>

                  View Grants

              </Link>

        {
          // Build on Urbit Developer CTA
        }

Build on Urbit

              Urbit is a personal OS designed from scratch to run peer-to-peer
              applications.

              It solves the hard problems of implementing a peer-to-peer network
              (including identity, NAT traversal, and exactly-once delivery) in
              the kernel so app developers can focus on business logic.

              The entire OS is a{" "}
              <Link href="https://urbit.org/docs/nock/definition/" passHref>
                single pure function
              </Link>{" "}
              that provides application developers with strong guarantees:
              automated persistence and memory management, repeatable builds,
              and support for hot code reloading.

              You can get started learning how to{" "}
              <Link href="https://urbit.org/docs/development/develop/" passHref>
                contribute to the project
              </Link>
              , or view a variety of{" "}
              <Link
                href="https://github.com/urbit/awesome-urbit#http-apis-airlock"
                passHref
              >
                libraries
              </Link>{" "}
              for building on Urbit using the languages you already know.

            <Link href="https://developers.urbit.org" passHref>

                Visit Urbit Developers

            </Link>

        {
          // Blog Posts
        }

Blog

          <TwoUp>
            <PostPreview post={posts[0]} key={posts[0].slug} />
            <PostPreview post={posts[1]} key={posts[1].slug} />
          </TwoUp>

          <Link href="/blog" passHref>

              See More

          </Link>

        {
          // Events Posts
        }

Events

          <TwoUp>
            <EventPreview event={events[0]} key={events[0].slug} />
            <EventPreview event={events[1]} key={events[1].slug} />
          </TwoUp>

          <Link href="/events" passHref>

              More Events

          </Link>

        {
          // Newsletter and social media
        }

          <Contact emphasize />

      </SingleColumn>

    </Container>
  );
}

export async function getStaticProps() {
  const posts = getAllPosts(
    ["title", "slug", "date", "description", "extra"],
    "blog",
    "date"
  );

  const events = getAllEvents(eventKeys, "events");

  const grants = getAllPosts(["extra", "taxonomies"], "grants", "date");

  const grantNumbers = {
    starsAwarded: Math.floor(
      grants.reduce(
        (total, a) =>
          total + (Number(a?.extra?.reward.replace(/ star[s]?/, "")) || 0),
        0
      )
    ),
    contributors: [
      ...new Set(...[grants.map((e) => e.extra.assignee.split(","))]),
    ].length,
    active: grants.filter(
      (e) =>
        !e.extra.canceled &&
        !e.extra.completed &&
        e.extra.assignee &&
        e.extra.assignee.length > 0
    ).length,
  };

  const now = DateTime.now();

  const pastEvents = events.filter((event) => {
    const ends = generateRealtimeDate(event.ends);
    return ends < now;
  });

  const futureEvents = events
    .filter((event) => {
      const starts = generateRealtimeDate(event.starts);
      return starts > now;
    })
    .sort((a, b) => {
      const aStarts = generateRealtimeDate(a.starts).ts;
      const bStarts = generateRealtimeDate(b.starts).ts;
      if (aStarts > bStarts) {
        return 1;
      } else if (aStarts === bStarts) {
        return 0;
      }
      return -1;
    });

  const happeningNow = events.filter((event) => {
    const starts = generateRealtimeDate(event.starts);
    const ends = generateRealtimeDate(event.ends);
    return starts > DateTime.now() && ends < now;
  });

  return {
    props: {
      posts,
      grantNumbers,
      events: happeningNow.concat(futureEvents).concat(pastEvents),
    },
  };
}
<commit_msg>index: bolden accent text<commit_after>import Head from "next/head";
import Link from "next/link";
import React from "react";
import { DateTime } from "luxon";
import {
  Container,
  Section,
  SingleColumn,
  IntraNav,
} from "foundation-design-system";
import Header from "../components/Header";
import Footer from "../components/Footer";
import Contact from "../components/Contact";
import PostPreview from "../components/PostPreview";
import EventPreview from "../components/EventPreview";
import TwoUp from "../components/TwoUp";
import { getAllPosts, getAllEvents, generateRealtimeDate } from "../lib/lib";
import { eventKeys } from "../lib/constants";

export default function Home({ posts, events, grantNumbers, search }) {
  return (
    <Container>

        <title>urbit.org</title>

      <IntraNav ourSite="https://urbit.org" search={search} />
      <SingleColumn>

        {
          // Hero Statement
        }

A clean-slate OS and network for the 21st century.

        {
          // Hero
        }

Assembly 2022

                Assembly 2022 is the second ever Urbit conference coming to you
                this year from Miami Beach. Grab a towel and get ready.

                September 22nd–25th • Miami Beach, Florida

              <Link href="https://assembly.urbit.org" passHref>

                  Learn More

              </Link>

            Urbit is a new kind of computer{" "}
            that you can own completely in
            ways that matter:{" "}
            networking, identity, and data.

            We realized that in order to fix the internet, we had to build a new
            computer from scratch. Good thing we started over a decade ago.

            Today, Urbit a real system with thousands of users that are building
            all kinds of communities, software, DAOs, and more. And it’s getting
            better every day.{" "}

          <Link href="/overview" passHref>

              Read the Overview

          </Link>

        {
          // Grants
        }

Grants

{grantNumbers?.starsAwarded}

                Urbit stars awarded

{grantNumbers?.contributors}

                Different Contributors

{grantNumbers?.active}

                Active Projects

              We regularly grant address space to give motivated contributors
              real ownership and authority over the network.

              <Link href="/grants" passHref>

                  Learn More

              </Link>
              <Link href="/grants#view-grants" passHref>

                  View Grants

              </Link>

        {
          // Build on Urbit Developer CTA
        }

Build on Urbit

              Urbit is a personal OS designed from scratch to run peer-to-peer
              applications.

              It solves the hard problems of implementing a peer-to-peer network
              (including identity, NAT traversal, and exactly-once delivery) in
              the kernel so app developers can focus on business logic.

              The entire OS is a{" "}
              <Link href="https://urbit.org/docs/nock/definition/" passHref>
                single pure function
              </Link>{" "}
              that provides application developers with strong guarantees:
              automated persistence and memory management, repeatable builds,
              and support for hot code reloading.

              You can get started learning how to{" "}
              <Link href="https://urbit.org/docs/development/develop/" passHref>
                contribute to the project
              </Link>
              , or view a variety of{" "}
              <Link
                href="https://github.com/urbit/awesome-urbit#http-apis-airlock"
                passHref
              >
                libraries
              </Link>{" "}
              for building on Urbit using the languages you already know.

            <Link href="https://developers.urbit.org" passHref>

                Visit Urbit Developers

            </Link>

        {
          // Blog Posts
        }

Blog

          <TwoUp>
            <PostPreview post={posts[0]} key={posts[0].slug} />
            <PostPreview post={posts[1]} key={posts[1].slug} />
          </TwoUp>

          <Link href="/blog" passHref>

              See More

          </Link>

        {
          // Events Posts
        }

Events

          <TwoUp>
            <EventPreview event={events[0]} key={events[0].slug} />
            <EventPreview event={events[1]} key={events[1].slug} />
          </TwoUp>

          <Link href="/events" passHref>

              More Events

          </Link>

        {
          // Newsletter and social media
        }

          <Contact emphasize />

      </SingleColumn>

    </Container>
  );
}

export async function getStaticProps() {
  const posts = getAllPosts(
    ["title", "slug", "date", "description", "extra"],
    "blog",
    "date"
  );

  const events = getAllEvents(eventKeys, "events");

  const grants = getAllPosts(["extra", "taxonomies"], "grants", "date");

  const grantNumbers = {
    starsAwarded: Math.floor(
      grants.reduce(
        (total, a) =>
          total + (Number(a?.extra?.reward.replace(/ star[s]?/, "")) || 0),
        0
      )
    ),
    contributors: [
      ...new Set(...[grants.map((e) => e.extra.assignee.split(","))]),
    ].length,
    active: grants.filter(
      (e) =>
        !e.extra.canceled &&
        !e.extra.completed &&
        e.extra.assignee &&
        e.extra.assignee.length > 0
    ).length,
  };

  const now = DateTime.now();

  const pastEvents = events.filter((event) => {
    const ends = generateRealtimeDate(event.ends);
    return ends < now;
  });

  const futureEvents = events
    .filter((event) => {
      const starts = generateRealtimeDate(event.starts);
      return starts > now;
    })
    .sort((a, b) => {
      const aStarts = generateRealtimeDate(a.starts).ts;
      const bStarts = generateRealtimeDate(b.starts).ts;
      if (aStarts > bStarts) {
        return 1;
      } else if (aStarts === bStarts) {
        return 0;
      }
      return -1;
    });

  const happeningNow = events.filter((event) => {
    const starts = generateRealtimeDate(event.starts);
    const ends = generateRealtimeDate(event.ends);
    return starts > DateTime.now() && ends < now;
  });

  return {
    props: {
      posts,
      grantNumbers,
      events: happeningNow.concat(futureEvents).concat(pastEvents),
    },
  };
}
<|endoftext|>


<commit_before>import React from 'react';
import styled from 'react-emotion';
import { space } from 'styled-system';
import FaCalender from 'react-icons/lib/fa/calendar';
import { Box } from 'grid-emotion';
import { Timeline, TimelineEvent } from 'react-event-timeline'; // eslint-disable-line import/no-unresolved
import Layout from '../components/common/layout';
import BannerSection from '../components/common/banner';
import { Container, Title, breakpoints, SubTitle, Button } from '../utils/base.styles';
import { spaceMapUrl } from '../utils/urls';

const ForWhomSection = styled.section`
  ${space};
  background: #fff;
  color: #222;
  text-align: center;
  & ul {
    text-align: left;
    max-width: 900px;
    margin-left: auto;
    margin-right: auto;
    font-size: 1.1rem;
    line-height: 2rem;
    ${breakpoints.md} {
      font-size: 1rem;
    }
    ${breakpoints.sm} {
      font-size: 1rem;
    }
    ${breakpoints.xs} {
      font-size: 0.9rem;
    }
  }
`;

const ActivitySection = styled.section`
  ${space};
  background: #fbfbfb;
  color: #222;
  text-align: center;
`;

const ActivityTimeline = styled(Timeline)`
  max-width: 600px;
  text-align: left;
`;

const ActiviteEvent = styled(TimelineEvent)`
  font-size: 1.5rem;
  ${breakpoints.sm} {
    font-size: 1.2rem;
  }
  ${breakpoints.xs} {
    font-size: 1rem;
  }
`;

const PricingSection = styled.section`
  ${space};
  background: #fff;
  text-align: center;
  position: relative;
`;

const MapSection = styled.section`
  ${space};
  background: #fbfbfb;
  text-align: center;
  position: relative;
`;

const forWhomPoints = [
  'People who are genuinely passionate about tech, who get excited about learning new skills, building, solving and discussing problems in latest tech.',
  'Graduates who are struggling to get a job, who want to build their expertise in modern technologies and are willing to invest a significant amount of their time self-learning',
  'Students who are willing to learn outside of their college curriculum, would like to become professional developers down the line and get exposure to the real world',
  'Experienced developers, who want to interact with other developers, contribute to open source, expand their horizons and learn new technologies.',
  'Professionals from non-tech background, who want to get started with tech or switch their careers.',
];

const activities = [
  {
    day: 'Daily',
    task: 'You will engage in daily code review and pair programming exercises with other members.',
  },
  {
    day: 'Wednesday',
    task:
      'We will have an Open Source Evening, where everyone will be encouraged to find open source projects and contribute to them.',
  },
  {
    day: 'Thursday',
    task:
      'We will have a casual coding competition, where members will participate to solve coding challenges together.',
  },
  {
    day: 'Friday',
    task: 'We will have casual hackathons, where everyone will participate to build a project, big or small.',
  },
  {
    day: 'Saturday',
    task: 'In the evening, we will screen a tech-related documentary, movie or TV show.',
  },
  {
    day: 'Sunday',
    task: 'Members will present their work i.e. projects or new topics they have made or learned in the past week',
  },
];

export default () => (
  <Layout>
    <BannerSection title="Offline Co-Learning Spaces" subTitle="Physical spaces for peer-learning and collaboration" />
    <ForWhomSection py={[3, 5]} px={[3, 2]}>
      <Container>
        <Title inverted color="#222">
          Who Is This For?
        </Title>

{forWhomPoints.map(point =>
{point}
)}

      </Container>
    </ForWhomSection>
    <ActivitySection py={[3, 5]} px={[3, 2]}>
      <Container>
        <Title inverted color="#222">
          Activites and Schedule
        </Title>
        <SubTitle inverted>
          We will help you pick a technology and provide you with learning guides to learn and build something on a
          daily basis.
        </SubTitle>
        <ActivityTimeline>
          {activities.map(activity => (
            <ActiviteEvent key={activity.day} title={activity.day} icon={<FaCalender />} iconColor="#222">
              {activity.task}
            </ActiviteEvent>
          ))}
        </ActivityTimeline>
      </Container>
    </ActivitySection>
    <PricingSection py={[3, 5]} px={[3, 2]}>
      <Container>
        <Title inverted color="#222">
          Pricing
        </Title>
        <SubTitle inverted>₹1000 or More Per Month</SubTitle>
        <Box pt={[3]} pb={[3]}>
          <Button
            href="https://docs.google.com/forms/d/e/1FAIpQLSfTV7VcaZuc9a1XH3I2hXNWVr1ILOl8TRNE8Rz7Qc9Pxdca7w/viewform"
            rel="noopener noreferrer"
            target="_blank"
            inverted
            large>
            Apply for Membership
          </Button>
        </Box>
      </Container>
    </PricingSection>
    <MapSection py={[3, 5]} px={[3, 2]}>
      <Container>
        <Title inverted color="#222">
          Location
        </Title>
        <SubTitle inverted>
          91SpringBoard, Kavuri Hills
Hyderbad, India
        </SubTitle>
      </Container>

    </MapSection>
  </Layout>
);
<commit_msg>fix typo grid-emotion -> grid-styled<commit_after>import React from 'react';
import styled from 'react-emotion';
import { space } from 'styled-system';
import FaCalender from 'react-icons/lib/fa/calendar';
import { Box } from 'grid-styled';
import { Timeline, TimelineEvent } from 'react-event-timeline'; // eslint-disable-line import/no-unresolved
import Layout from '../components/common/layout';
import BannerSection from '../components/common/banner';
import { Container, Title, breakpoints, SubTitle, Button } from '../utils/base.styles';
import { spaceMapUrl } from '../utils/urls';

const ForWhomSection = styled.section`
  ${space};
  background: #fff;
  color: #222;
  text-align: center;
  & ul {
    text-align: left;
    max-width: 900px;
    margin-left: auto;
    margin-right: auto;
    font-size: 1.1rem;
    line-height: 2rem;
    ${breakpoints.md} {
      font-size: 1rem;
    }
    ${breakpoints.sm} {
      font-size: 1rem;
    }
    ${breakpoints.xs} {
      font-size: 0.9rem;
    }
  }
`;

const ActivitySection = styled.section`
  ${space};
  background: #fbfbfb;
  color: #222;
  text-align: center;
`;

const ActivityTimeline = styled(Timeline)`
  max-width: 600px;
  text-align: left;
`;

const ActiviteEvent = styled(TimelineEvent)`
  font-size: 1.5rem;
  ${breakpoints.sm} {
    font-size: 1.2rem;
  }
  ${breakpoints.xs} {
    font-size: 1rem;
  }
`;

const PricingSection = styled.section`
  ${space};
  background: #fff;
  text-align: center;
  position: relative;
`;

const MapSection = styled.section`
  ${space};
  background: #fbfbfb;
  text-align: center;
  position: relative;
`;

const forWhomPoints = [
  'People who are genuinely passionate about tech, who get excited about learning new skills, building, solving and discussing problems in latest tech.',
  'Graduates who are struggling to get a job, who want to build their expertise in modern technologies and are willing to invest a significant amount of their time self-learning',
  'Students who are willing to learn outside of their college curriculum, would like to become professional developers down the line and get exposure to the real world',
  'Experienced developers, who want to interact with other developers, contribute to open source, expand their horizons and learn new technologies.',
  'Professionals from non-tech background, who want to get started with tech or switch their careers.',
];

const activities = [
  {
    day: 'Daily',
    task: 'You will engage in daily code review and pair programming exercises with other members.',
  },
  {
    day: 'Wednesday',
    task:
      'We will have an Open Source Evening, where everyone will be encouraged to find open source projects and contribute to them.',
  },
  {
    day: 'Thursday',
    task:
      'We will have a casual coding competition, where members will participate to solve coding challenges together.',
  },
  {
    day: 'Friday',
    task: 'We will have casual hackathons, where everyone will participate to build a project, big or small.',
  },
  {
    day: 'Saturday',
    task: 'In the evening, we will screen a tech-related documentary, movie or TV show.',
  },
  {
    day: 'Sunday',
    task: 'Members will present their work i.e. projects or new topics they have made or learned in the past week',
  },
];

export default () => (
  <Layout>
    <BannerSection title="Offline Co-Learning Spaces" subTitle="Physical spaces for peer-learning and collaboration" />
    <ForWhomSection py={[3, 5]} px={[3, 2]}>
      <Container>
        <Title inverted color="#222">
          Who Is This For?
        </Title>

{forWhomPoints.map(point =>
{point}
)}

      </Container>
    </ForWhomSection>
    <ActivitySection py={[3, 5]} px={[3, 2]}>
      <Container>
        <Title inverted color="#222">
          Activites and Schedule
        </Title>
        <SubTitle inverted>
          We will help you pick a technology and provide you with learning guides to learn and build something on a
          daily basis.
        </SubTitle>
        <ActivityTimeline>
          {activities.map(activity => (
            <ActiviteEvent key={activity.day} title={activity.day} icon={<FaCalender />} iconColor="#222">
              {activity.task}
            </ActiviteEvent>
          ))}
        </ActivityTimeline>
      </Container>
    </ActivitySection>
    <PricingSection py={[3, 5]} px={[3, 2]}>
      <Container>
        <Title inverted color="#222">
          Pricing
        </Title>
        <SubTitle inverted>₹1000 or More Per Month</SubTitle>
        <Box pt={[3]} pb={[3]}>
          <Button
            href="https://docs.google.com/forms/d/e/1FAIpQLSfTV7VcaZuc9a1XH3I2hXNWVr1ILOl8TRNE8Rz7Qc9Pxdca7w/viewform"
            rel="noopener noreferrer"
            target="_blank"
            inverted
            large>
            Apply for Membership
          </Button>
        </Box>
      </Container>
    </PricingSection>
    <MapSection py={[3, 5]} px={[3, 2]}>
      <Container>
        <Title inverted color="#222">
          Location
        </Title>
        <SubTitle inverted>
          91SpringBoard, Kavuri Hills
Hyderbad, India
        </SubTitle>
      </Container>

    </MapSection>
  </Layout>
);
<|endoftext|>


<commit_before>'use strict';

const NorthstarClient = require('@dosomething/northstar-js');

/**
 * Nortstar client service.
 */
module.exports = {

  getClient() {
    if (!this.client) {
      this.client = new NorthstarClient({
        baseURI: sails.config.northstar.apiBaseURI,
        apiKey: sails.config.northstar.apiKey,
      });
    }
    return this.client;
  },

  getUserFor(model) {
    const options = this.resolveRequestId(model);
    return this.getClient().getUser(options.type, options.id);
  },

  resolveRequestId(model) {
    let id;
    let type;

    if (model.user_id) {
      type = 'id';
      id = model.user_id;
    } else if (model.email) {
      type = 'email';
      id = model.email;
    } else if (model.mobile) {
      type = 'mobile';
      id = model.mobile;
    }

    return { type, id };
  },

  isOneOfFieldSet(submission) {
    return ['user_id', 'email', 'mobile'].every(userField => !submission[userField]);
  },

};
<commit_msg>Cleanout NorthstarService logic - should have not added to repo first<commit_after>'use strict';

/**
 * Helpers services. A collection of services to be used throughout the application.
 */
module.exports = {

  isOneOfFieldSet(submission) {
    return ['user_id', 'email', 'mobile'].every(userField => !submission[userField]);
  },

};
<|endoftext|>


<commit_before>var ent = require('ent');
var Promise = require('bluebird');

var ForbiddenError = require('../errors/ForbiddenError');
var InvalidInputError = require('../errors/InvalidInputError');

module.exports.createMessage = function (roomMember, text) {

	text = ent.encode(text);

	if (!text || !text.length) {
		throw new InvalidInputError(); // block the trolls
	}
	else if (/^\/nick\s+/i.test(text)) {
		return setUserNick(roomMember, text); // Change the current user's nick
	}
	else if (/^\/(away|afk|busy)/i.test(text)) {
		return setUserBusy(roomMember, text); // away, afk, busy (with optional message)
	}
	else if (/^\/help/i.test(text)) {
		return getHelp(roomMember, text);
	}
	else if (/^\/topic/i.test(text)) { // Change room topic
		return setRoomTopic(roomMember, text);
	}
	else if (/^\/room\s+topic/i.test(text)) {
		return setRoomTopic(roomMember, text)
	}
	else if (/^\/room\s+name\s+\w/i.test(text)) {
		return setRoomName(roomMember, text)
	}
	else if (/^\/magic8ball/i.test(text)) {
		return magic8ball(roomMember, text); // Jordan's Magic 8 Ball, Bitches
	}
	else if (/^\/roll/i.test(text)) {
		return roll(roomMember, text);
	}
	else if (/^\/me\s+/i.test(text)) {
		return me(roomMember, text);
	}
	else {
		return message(roomMember, text, 'standard');
	}
};

module.exports.broadcastMessage = broadcastMessage;

function getHelp(roomMember, text) {
	return helpService.getHelp(text).then(function (helpMessage) {
		RoomService.messageUserInRoom(roomMember.user.id, roomMember.room, helpMessage, 'help');
	});
}

function setUserNick(roomMember, text) {
	var nickMatches = text.match(/^\/nick\s+(\w[\w\s\-\.]{0,19})/i);
	if (!nickMatches) throw new InvalidInputError('Invalid nick');

	var user = roomMember.user;
	var newNick = nickMatches[1];
	if (user.nick == newNick) throw new InvalidInputError('Nick is already set');

	return Promise.all([
		User.update(user.id, {nick: newNick}),
		RoomMember.find({user: user.id})
	])
		.spread(function (updatedUser, memberships) {
			updatedUser = updatedUser[0];
			User.publishUpdate(user.id, {nick: updatedUser.nick});
			RoomService.messageRooms(_.pluck(memberships, 'room'), user.nick + ' changed their handle to ' + updatedUser.nick);
		});
}

function setUserBusy(roomMember, text) {
	return RoomMember.find({user: roomMember.user.id})
		.then(function (memberships) {

			var user = roomMember.user;
			var busy = !user.busy; // Flip busy status
			var busyMessageMatches = text.match(/^\/(?:away|afk|busy)\s*(.+)/i);
			var busyMessage = busy && busyMessageMatches ? busyMessageMatches[1] : null;

			return [User.update(user.id, {busy: busy, busyMessage: busyMessage}), memberships];
		})
		.spread(function (user, memberships) {
			user = user[0];

			var message = [];
			message.push(user.nick);
			message.push(user.busy ? 'is now away' : 'is back');
			if (user.busy && user.busyMessage) {
				message.push(': ' + user.busyMessage);
			}

			RoomService.messageRooms(_.pluck(memberships, 'room'), message.join(' '));
			User.publishUpdate(user.id, {busy: user.busy, busyMessage: user.busyMessage});
		});
}

function setRoomTopic(roomMember, text) {

	if (roomMember.role == 'member') {
		throw new ForbiddenError('Must be an administrator to change topic');
	}

	var user = roomMember.user;
	var roomId = roomMember.room;
	var topicMatches = text.match(/topic\s+(.+)/i);
	var topic = topicMatches ? topicMatches[1].substr(0, 200) : null;

	return Room.update(roomId, {topic: topic}).then(function (room) {
		room = room[0];
		var message = user.nick + (room.topic ? ' changed the topic to "' + room.topic + '"' : ' cleared the topic');

		Room.publishUpdate(roomId, {topic: room.topic});
		RoomService.messageRoom(roomId, message);
	});
}

function setRoomName(roomMember, text) {

	if (roomMember.role == 'member') {
		throw new ForbiddenError('Must be an administrator to change room name');
	}

	var user = roomMember.user;
	var roomId = roomMember.room;

	var nameMatches = text.match(/\/room\s+name\s+([\w\s]+)/i);
	if (!nameMatches) throw new InvalidInputError('Invalid room name');

	var name = nameMatches[1].substr(0, 50);

	return Room.update(roomId, {name: name}).then(function (room) {
		room = room[0];
		var message = user.nick + ' changed the room name to "' + room.name + '"';

		Room.publishUpdate(roomId, {name: room.name});
		RoomService.messageRoom(roomId, message);
	});
}

function magic8ball(roomMember, text) {
	var ballResponse = _.sample([
		"It is certain", "It is decidedly so", "Yes definitely",
		"You may rely on it", "As I see it, yes",
		"Most likely", "Outlook good", "Yes", "Signs point to yes", "Without a doubt",
		"Ask again later", "Better not tell you now",
		"Cannot predict now", "Concentrate and ask again", "Reply hazy, try again",
		"Don't count on it", "My reply is no",
		"My sources say no", "Outlook not so good", "Very doubtful"
	]);

	setTimeout(function () {
		return Message.create({
			room: roomMember.room,
			author: null,
			type: '8ball',
			text: ':magic8ball: ' + ballResponse
		}).then(broadcastMessage);
	}, 3000);

	var question = ' shakes the magic 8 ball...';
	var questionMatch = text.match(/\/magic8ball\s+(.+)/i);
	if (questionMatch) {
		question = ' shakes the magic 8 ball and asks "' + questionMatch[1] + '"';
	}

	return message(roomMember, roomMember.user.nick + question, 'room');
}

function roll(roomMember, text) {
	var matches = text.match(/\/roll\s+(.+)/i);
	var roll = matches ? matches[1] : null;

	// Determine outcome
	var rollOutcome;

	if (_.isNumber(+roll) && !_.isNaN(+roll)) {
		var max = +roll;
		rollOutcome = 'rolled ' + Math.ceil(Math.random() * max) + ' out of ' + max;
	}
	// d20 case for D&D nerds
	//else if(/^d\d{1,4}/i.test(roll)) { // a dice roll
	//	rollOutcome = 'rolled a ' + roll + ' for ' + 100;
	//}
	else { // Doesn't fit any of our cases
		return;
	}

	return message(roomMember, roomMember.user.nick + ' ' + rollOutcome, 'roll');
}

function me(roomMember, text) {
	return message(roomMember, roomMember.user.nick + text.substring(3), 'emote');
}

function message(roomMember, text, type) {

	type = type || 'standard';

	return Message.create({
		room: roomMember.room,
		type: type,
		author: type == 'standard' ? roomMember.user : null,
		text: text
	}).then(function (message) {
		broadcastMessage(message);
		saveInMentionedInboxes(message);
		return message;
	});
}

function broadcastMessage(message) {
	// now that message has been created, get the populated version
	return Message.findOne(message.id).populateAll().exec(function (error, message) {
		Room.message(message.room, message); // message all subscribers of the room that with the new message as data
	});
}

function saveInMentionedInboxes(message) {
	if(!message.author) return;

	// Check if this message mentions anyone
	// Completely async process that shouldn't disrupt the normal message flow
	return Promise.all([
		User.findOne(message.author),
		RoomMember.find({room: message.room}).populate('user')
	])
		.spread(function (author, roomMembers) {
			return Promise.each(roomMembers, function (roomMember) {
				var regex = new RegExp(roomMember.user.nick + '\\b|@[Aa]ll', 'i');
				if (regex.test(message.text)) {
					return InboxMessage.create({user: roomMember.user.id, message: message.id})
						.then(function (inboxMessage) {
							return InboxMessage.findOne(inboxMessage.id).populateAll();
						})
						.then(function (inboxMessage) {
							inboxMessage.message.author = author; // Attach populated author data
							InboxMessage.message(roomMember.user.id, inboxMessage);
						});
				}
			})
		});
}
<commit_msg>improve /roll<commit_after>var ent = require('ent');
var Promise = require('bluebird');

var ForbiddenError = require('../errors/ForbiddenError');
var InvalidInputError = require('../errors/InvalidInputError');

module.exports.createMessage = function (roomMember, text) {

	text = ent.encode(text);

	if (!text || !text.length) {
		throw new InvalidInputError(); // block the trolls
	}
	else if (/^\/nick\s+/i.test(text)) {
		return setUserNick(roomMember, text); // Change the current user's nick
	}
	else if (/^\/(away|afk|busy)/i.test(text)) {
		return setUserBusy(roomMember, text); // away, afk, busy (with optional message)
	}
	else if (/^\/help/i.test(text)) {
		return getHelp(roomMember, text);
	}
	else if (/^\/topic/i.test(text)) { // Change room topic
		return setRoomTopic(roomMember, text);
	}
	else if (/^\/room\s+topic/i.test(text)) {
		return setRoomTopic(roomMember, text)
	}
	else if (/^\/room\s+name\s+\w/i.test(text)) {
		return setRoomName(roomMember, text)
	}
	else if (/^\/magic8ball/i.test(text)) {
		return magic8ball(roomMember, text); // Jordan's Magic 8 Ball, Bitches
	}
	else if (/^\/roll/i.test(text)) {
		return roll(roomMember, text);
	}
	else if (/^\/me\s+/i.test(text)) {
		return me(roomMember, text);
	}
	else {
		return message(roomMember, text, 'standard');
	}
};

module.exports.broadcastMessage = broadcastMessage;

function getHelp(roomMember, text) {
	return helpService.getHelp(text).then(function (helpMessage) {
		RoomService.messageUserInRoom(roomMember.user.id, roomMember.room, helpMessage, 'help');
	});
}

function setUserNick(roomMember, text) {
	var nickMatches = text.match(/^\/nick\s+(\w[\w\s\-\.]{0,19})/i);
	if (!nickMatches) throw new InvalidInputError('Invalid nick');

	var user = roomMember.user;
	var newNick = nickMatches[1];
	if (user.nick == newNick) throw new InvalidInputError('Nick is already set');

	return Promise.all([
		User.update(user.id, {nick: newNick}),
		RoomMember.find({user: user.id})
	])
		.spread(function (updatedUser, memberships) {
			updatedUser = updatedUser[0];
			User.publishUpdate(user.id, {nick: updatedUser.nick});
			RoomService.messageRooms(_.pluck(memberships, 'room'), user.nick + ' changed their handle to ' + updatedUser.nick);
		});
}

function setUserBusy(roomMember, text) {
	return RoomMember.find({user: roomMember.user.id})
		.then(function (memberships) {

			var user = roomMember.user;
			var busy = !user.busy; // Flip busy status
			var busyMessageMatches = text.match(/^\/(?:away|afk|busy)\s*(.+)/i);
			var busyMessage = busy && busyMessageMatches ? busyMessageMatches[1] : null;

			return [User.update(user.id, {busy: busy, busyMessage: busyMessage}), memberships];
		})
		.spread(function (user, memberships) {
			user = user[0];

			var message = [];
			message.push(user.nick);
			message.push(user.busy ? 'is now away' : 'is back');
			if (user.busy && user.busyMessage) {
				message.push(': ' + user.busyMessage);
			}

			RoomService.messageRooms(_.pluck(memberships, 'room'), message.join(' '));
			User.publishUpdate(user.id, {busy: user.busy, busyMessage: user.busyMessage});
		});
}

function setRoomTopic(roomMember, text) {

	if (roomMember.role == 'member') {
		throw new ForbiddenError('Must be an administrator to change topic');
	}

	var user = roomMember.user;
	var roomId = roomMember.room;
	var topicMatches = text.match(/topic\s+(.+)/i);
	var topic = topicMatches ? topicMatches[1].substr(0, 200) : null;

	return Room.update(roomId, {topic: topic}).then(function (room) {
		room = room[0];
		var message = user.nick + (room.topic ? ' changed the topic to "' + room.topic + '"' : ' cleared the topic');

		Room.publishUpdate(roomId, {topic: room.topic});
		RoomService.messageRoom(roomId, message);
	});
}

function setRoomName(roomMember, text) {

	if (roomMember.role == 'member') {
		throw new ForbiddenError('Must be an administrator to change room name');
	}

	var user = roomMember.user;
	var roomId = roomMember.room;

	var nameMatches = text.match(/\/room\s+name\s+([\w\s]+)/i);
	if (!nameMatches) throw new InvalidInputError('Invalid room name');

	var name = nameMatches[1].substr(0, 50);

	return Room.update(roomId, {name: name}).then(function (room) {
		room = room[0];
		var message = user.nick + ' changed the room name to "' + room.name + '"';

		Room.publishUpdate(roomId, {name: room.name});
		RoomService.messageRoom(roomId, message);
	});
}

function magic8ball(roomMember, text) {
	var ballResponse = _.sample([
		"It is certain", "It is decidedly so", "Yes definitely",
		"You may rely on it", "As I see it, yes",
		"Most likely", "Outlook good", "Yes", "Signs point to yes", "Without a doubt",
		"Ask again later", "Better not tell you now",
		"Cannot predict now", "Concentrate and ask again", "Reply hazy, try again",
		"Don't count on it", "My reply is no",
		"My sources say no", "Outlook not so good", "Very doubtful"
	]);

	setTimeout(function () {
		return Message.create({
			room: roomMember.room,
			author: null,
			type: '8ball',
			text: ':magic8ball: ' + ballResponse
		}).then(broadcastMessage);
	}, 3000);

	var question = ' shakes the magic 8 ball...';
	var questionMatch = text.match(/\/magic8ball\s+(.+)/i);
	if (questionMatch) {
		question = ' shakes the magic 8 ball and asks "' + questionMatch[1] + '"';
	}

	return message(roomMember, roomMember.user.nick + question, 'room');
}

function roll(roomMember, text) {
	var matches = text.match(/\/roll\s+(.+)/i);
	var roll = matches ? matches[1] : null;
	var rollOutcome;

	// Generic number roll
	if (/^\d+$/.test(roll)) {
		var max = Math.round(+roll);
		rollOutcome = 'rolled ' + Math.ceil(Math.random() * max) + ' out of ' + max;
	}
	// d20 case for D&D nerds
	else if (/^\d*d\d+$/i.test(roll)) { // a dice roll
		var textParse = /(\d*)d(\d+)/.exec(roll);
		var diceCount = parseInt(textParse[1]) || 1;
		var dieSides = parseInt(textParse[2]);

		var total = 0;
		for (var i = 0; i < diceCount; i++) {
			total += Math.ceil(Math.random() * dieSides);
		}

		rollOutcome = 'rolled ' + roll + ' for ' + total;
	}
	else { // Doesn't fit any of our cases
		return;
	}

	return message(roomMember, ':rolldice: ' + roomMember.user.nick + ' ' + rollOutcome, 'roll');
}

function me(roomMember, text) {
	return message(roomMember, roomMember.user.nick + text.substring(3), 'emote');
}

function message(roomMember, text, type) {

	type = type || 'standard';

	return Message.create({
		room: roomMember.room,
		type: type,
		author: type == 'standard' ? roomMember.user : null,
		text: text
	}).then(function (message) {
		broadcastMessage(message);
		saveInMentionedInboxes(message);
		return message;
	});
}

function broadcastMessage(message) {
	// now that message has been created, get the populated version
	return Message.findOne(message.id).populateAll().exec(function (error, message) {
		Room.message(message.room, message); // message all subscribers of the room that with the new message as data
	});
}

function saveInMentionedInboxes(message) {
	if (!message.author) return;

	// Check if this message mentions anyone
	// Completely async process that shouldn't disrupt the normal message flow
	return Promise.all([
		User.findOne(message.author),
		RoomMember.find({room: message.room}).populate('user')
	])
		.spread(function (author, roomMembers) {
			return Promise.each(roomMembers, function (roomMember) {
				var regex = new RegExp(roomMember.user.nick + '\\b|@[Aa]ll', 'i');
				if (regex.test(message.text)) {
					return InboxMessage.create({user: roomMember.user.id, message: message.id})
						.then(function (inboxMessage) {
							return InboxMessage.findOne(inboxMessage.id).populateAll();
						})
						.then(function (inboxMessage) {
							inboxMessage.message.author = author; // Attach populated author data
							InboxMessage.message(roomMember.user.id, inboxMessage);
						});
				}
			})
		});
}
<|endoftext|>


<commit_before>import decode from 'jwt-decode'
import { Forbidden } from '@feathersjs/errors'
import { Ability, AbilityBuilder } from '@casl/ability'
import _ from 'lodash'

Ability.addAlias('update', 'patch')
Ability.addAlias('read', ['get', 'find'])
Ability.addAlias('delete', 'remove')

// hardcoded roles that must match roles defined in database (for now)
const ROLE_USER = 'user'
const ROLE_ADMIN = 'admin'
const ROLE_SUPERADMIN = 'superadmin'

const subjectName = subject =>
  !subject || typeof subject === 'string' ? subject : subject.type()

const extractRolesFromJwtToken = ctx =>
  ctx.params.headers && ctx.params.headers.authorization
    ? decode(ctx.params.headers.authorization).roles
    : []

const defineAbilities = ctx => {
  const roles = extractRolesFromJwtToken(ctx)

  if (!ctx.params.user) {
    ctx.params.user = {
      id: -1,
      name: 'guest'
    }
  }

  const userId = ctx.params.user.id

  ctx.app.debug(
    roles.length > 0 ? roles.map(r => r.name) : 'none',
    `authorized user ${userId} ${ctx.params.user.name} with roles`
  )

  const hasRole = role => roles.find(r => r.name === role)

  const { rules, can } = AbilityBuilder.extract()

  // admin backend
  if (hasRole(ROLE_SUPERADMIN)) {
    // TODO: can manage everything in admin backend
  } else if (hasRole(ROLE_ADMIN)) {
    // TODO: can manage entities in admin backend, but no user accounts/roles
  }

  // app
  if (hasRole(ROLE_USER)) {
    can('create', 'autocomplete')
    can('create', 'geocoder')
    can('read', 'entries')
    can(['read', 'create'], 'farms')
    can(['update', 'delete'], 'farms', { ownerships: userId })
    can(['read', 'create'], 'depots')
    can(['update', 'delete'], 'depots', { ownerships: userId })
    can(['read', 'create'], 'initiatives')
    can(['update', 'delete'], 'initiatives', { ownerships: userId })
    can('read', 'products')
    can('read', 'goals')
  } else {
    // guest
    can('create', 'autocomplete')
    can('create', 'geocoder')
    can('read', 'entries')
    can('read', 'farms')
    can('read', 'depots')
    can('read', 'initiatives')
    can('read', 'products')
    can('read', 'goals')
  }

  // login
  can('create', 'authentication')
  // confirm email
  can('create', 'authManagement')
  // sign up
  can('create', 'users')
  // edit user account
  can('patch', 'users', { id: userId })

  return new Ability(rules, { subjectName })
}

const filterFor = condition => {
  switch (condition) {
    case 'ownerships':
      return (resource, value) =>
        resource.ownerships.some(o => o.id === value.toString())
    default:
      return (resource, value) => resource[condition] === value
  }
}

const checkConditions = (id, resource, conditions) =>
  _.keys(conditions).every(name => filterFor(name)(resource, conditions[name]))

const authorize = async ctx => {
  const { method: action, service, path: serviceName } = ctx
  const ability = defineAbilities(ctx)

  const throwUnlessCan = (a, resource) => {
    if (ability.cannot(a, resource)) {
      throw new Forbidden(`You are not allowed to ${a} ${resource}.`)
    }
  }

  // collection request (read, create)
  if (!ctx.id) {
    throwUnlessCan(action, serviceName)
    // TODO also implement condition filter for collections?
    return ctx
  }

  // resource request (update, delete)
  const conditions = Object.assign(
    {},
    ...ability.rulesFor(action, serviceName).map(r => r.conditions)
  )

  const eager = _.keys(conditions).filter(name => name === 'ownerships')

  const resource = await service.get(ctx.id, {
    query: { $eager: `[${eager.join(',')}]` },
    provider: null
  })

  if (!checkConditions(ctx.id, resource, conditions)) {
    throw new Forbidden(
      `You are not allowed to ${action} ${resource.type()} ${resource.id}.`
    )
  }

  return ctx
}

export default authorize
<commit_msg>Bug: Check authorization for all actions (resource and collection).<commit_after>import decode from 'jwt-decode'
import { Forbidden } from '@feathersjs/errors'
import { Ability, AbilityBuilder } from '@casl/ability'
import _ from 'lodash'

Ability.addAlias('update', 'patch')
Ability.addAlias('read', ['get', 'find'])
Ability.addAlias('delete', 'remove')

// hardcoded roles that must match roles defined in database (for now)
const ROLE_USER = 'user'
const ROLE_ADMIN = 'admin'
const ROLE_SUPERADMIN = 'superadmin'

const subjectName = subject =>
  !subject || typeof subject === 'string' ? subject : subject.type()

const extractRolesFromJwtToken = ctx =>
  ctx.params.headers && ctx.params.headers.authorization
    ? decode(ctx.params.headers.authorization).roles
    : []

const defineAbilities = ctx => {
  const roles = extractRolesFromJwtToken(ctx)

  if (!ctx.params.user) {
    ctx.params.user = {
      id: -1,
      name: 'guest'
    }
  }

  const userId = ctx.params.user.id

  ctx.app.debug(
    roles.length > 0 ? roles.map(r => r.name) : 'none',
    `authorized user ${userId} ${ctx.params.user.name} with roles`
  )

  const hasRole = role => roles.find(r => r.name === role)

  const { rules, can } = AbilityBuilder.extract()

  // admin backend
  if (hasRole(ROLE_SUPERADMIN)) {
    // TODO: can manage everything in admin backend
  } else if (hasRole(ROLE_ADMIN)) {
    // TODO: can manage entities in admin backend, but no user accounts/roles
  }

  // app
  if (hasRole(ROLE_USER)) {
    can('create', 'autocomplete')
    can('create', 'geocoder')
    can('read', 'entries')
    can(['read', 'create'], 'farms')
    can(['update', 'delete'], 'farms', { ownerships: userId })
    can(['read', 'create'], 'depots')
    can(['update', 'delete'], 'depots', { ownerships: userId })
    can(['read', 'create'], 'initiatives')
    can(['update', 'delete'], 'initiatives', { ownerships: userId })
    can('read', 'products')
    can('read', 'goals')
  } else {
    // guest
    can('create', 'autocomplete')
    can('create', 'geocoder')
    can('read', 'entries')
    can('read', 'farms')
    can('read', 'depots')
    can('read', 'initiatives')
    can('read', 'products')
    can('read', 'goals')
  }

  // login
  can('create', 'authentication')
  // confirm email
  can('create', 'authManagement')
  // sign up
  can('create', 'users')
  // edit user account
  can('patch', 'users', { id: userId })

  return new Ability(rules, { subjectName })
}

const filterFor = condition => {
  switch (condition) {
    case 'ownerships':
      return (resource, value) =>
        resource.ownerships.some(o => o.id === value.toString())
    default:
      return (resource, value) => resource[condition] === value
  }
}

const checkConditions = (id, resource, conditions) =>
  _.keys(conditions).every(name => filterFor(name)(resource, conditions[name]))

const authorize = async ctx => {
  const { method: action, service, path: serviceName } = ctx
  const ability = defineAbilities(ctx)

  const throwUnlessCan = (a, resource) => {
    if (ability.cannot(a, resource)) {
      throw new Forbidden(`You are not allowed to ${a} ${resource}.`)
    }
  }

  throwUnlessCan(action, serviceName)

  // collection request (read, create)
  if (!ctx.id) {
    // TODO also implement condition filter for collections?
    return ctx
  }

  // resource request (update, delete)
  const conditions = Object.assign(
    {},
    ...ability.rulesFor(action, serviceName).map(r => r.conditions)
  )

  const eager = _.keys(conditions).filter(name => name === 'ownerships')

  const resource = await service.get(ctx.id, {
    query: { $eager: `[${eager.join(',')}]` },
    provider: null
  })

  if (!checkConditions(ctx.id, resource, conditions)) {
    throw new Forbidden(
      `You are not allowed to ${action} ${resource.type()} ${resource.id}.`
    )
  }

  return ctx
}

export default authorize
<|endoftext|>