<commit_before>// @flow

import type Transport from "@ledgerhq/hw-transport";
import { hashPublicKey } from "./hashPublicKey";
import { getWalletPublicKey } from "./getWalletPublicKey";
import type { AddressFormat } from "./getWalletPublicKey";
import { getTrustedInput } from "./getTrustedInput";
import { startUntrustedHashTransactionInput } from "./startUntrustedHashTransactionInput";
import { serializeTransaction } from "./serializeTransaction";
import { getTrustedInputBIP143 } from "./getTrustedInputBIP143";
import { compressPublicKey } from "./compressPublicKey";
import { signTransaction } from "./signTransaction";
import { hashOutputFull, provideOutputFullChangePath } from "./finalizeInput";
import type { TransactionOutput, Transaction } from "./types";
import {
  DEFAULT_LOCKTIME,
  DEFAULT_SEQUENCE,
  SIGHASH_ALL,
  OP_DUP,
  OP_HASH160,
  HASH_SIZE,
  OP_EQUALVERIFY,
  OP_CHECKSIG
} from "./constants";

export type { AddressFormat };

const defaultsSignTransaction = {
  lockTime: DEFAULT_LOCKTIME,
  sigHashType: SIGHASH_ALL,
  segwit: false,
  additionals: [],
  onDeviceStreaming: _progress => {},
  onDeviceSignatureGranted: () => {},
  onDeviceSignatureRequested: () => {}
};

export type CreateTransactionArg = {
  inputs: Array<[Transaction, number, ?string, ?number]>,
  associatedKeysets: string[],
  changePath?: string,
  outputScriptHex: string,
  lockTime?: number,
  sigHashType?: number,
  segwit?: boolean,
  initialTimestamp?: number,
  additionals: Array<string>,
  expiryHeight?: Buffer,
  onDeviceStreaming?: ({
    progress: number,
    total: number,
    index: number
  }) => void,
  onDeviceSignatureRequested?: () => void,
  onDeviceSignatureGranted?: () => void
};

export async function createTransaction(
  transport: Transport<*>,
  arg: CreateTransactionArg
) {
  const {
    inputs,
    associatedKeysets,
    changePath,
    outputScriptHex,
    lockTime,
    sigHashType,
    segwit,
    initialTimestamp,
    additionals,
    expiryHeight,
    onDeviceStreaming,
    onDeviceSignatureGranted,
    onDeviceSignatureRequested
  } = {
    ...defaultsSignTransaction,
    ...arg
  };

  const isDecred = additionals.includes("decred");
  const isXST = additionals.includes("stealthcoin");
  const hasTimestamp = initialTimestamp !== undefined;
  let startTime = Date.now();
  const sapling = additionals.includes("sapling");
  const bech32 = segwit && additionals.includes("bech32");
  let useBip143 =
    segwit ||
    (!!additionals &&
      (additionals.includes("abc") ||
        additionals.includes("gold") ||
        additionals.includes("bip143"))) ||
    (!!expiryHeight && !isDecred);
  // Inputs are provided as arrays of [transaction, output_index, optional redeem script, optional sequence]
  // associatedKeysets are provided as arrays of [path]
  const nullScript = Buffer.alloc(0);
  const nullPrevout = Buffer.alloc(0);
  const defaultVersion = Buffer.alloc(4);
  !!expiryHeight && !isDecred
    ? defaultVersion.writeUInt32LE(sapling ? 0x80000004 : 0x80000003, 0)
    : isXST
    ? defaultVersion.writeUInt32LE(2, 0)
    : defaultVersion.writeUInt32LE(1, 0); // Default version to 2 for XST not to have timestamp
  const trustedInputs: Array<*> = [];
  const regularOutputs: Array<TransactionOutput> = [];
  const signatures = [];
  const publicKeys = [];
  let firstRun = true;
  const resuming = false;
  const targetTransaction: Transaction = {
    inputs: [],
    version: defaultVersion,
    timestamp: Buffer.alloc(0)
  };
  const getTrustedInputCall = useBip143
    ? getTrustedInputBIP143
    : getTrustedInput;
  const outputScript = Buffer.from(outputScriptHex, "hex");

  onDeviceStreaming({ progress: 0, index: 0, total: inputs.length });

  // first pass on inputs to get trusted inputs
  for (let input of inputs) {
    if (!resuming) {
      const trustedInput = await getTrustedInputCall(
        transport,
        input[1],
        input[0],
        additionals
      );
      let sequence = Buffer.alloc(4);
      sequence.writeUInt32LE(
        input.length >= 4 && typeof input[3] === "number"
          ? input[3]
          : DEFAULT_SEQUENCE,
        0
      );
      trustedInputs.push({
        trustedInput: true,
        value: Buffer.from(trustedInput, "hex"),
        sequence
      });
    }

    const { outputs } = input[0];
    const index = input[1];
    if (outputs && index <= outputs.length - 1) {
      regularOutputs.push(outputs[index]);
    }

    if (expiryHeight && !isDecred) {
      targetTransaction.nVersionGroupId = Buffer.from(
        sapling ? [0x85, 0x20, 0x2f, 0x89] : [0x70, 0x82, 0xc4, 0x03]
      );
      targetTransaction.nExpiryHeight = expiryHeight;
      // For sapling : valueBalance (8), nShieldedSpend (1), nShieldedOutput (1), nJoinSplit (1)
      // Overwinter : use nJoinSplit (1)
      targetTransaction.extraData = Buffer.from(
        sapling
          ? [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
          : [0x00]
      );
    } else if (isDecred) {
      targetTransaction.nExpiryHeight = expiryHeight;
    }
  }

  targetTransaction.inputs = inputs.map(input => {
    let sequence = Buffer.alloc(4);
    sequence.writeUInt32LE(
      input.length >= 4 && typeof input[3] === "number"
        ? input[3]
        : DEFAULT_SEQUENCE,
      0
    );
    return {
      script: nullScript,
      prevout: nullPrevout,
      sequence
    };
  });

  if (!resuming) {
    // Collect public keys
    const result = [];
    for (let i = 0; i < inputs.length; i++) {
      const r = await getWalletPublicKey(transport, {
        path: associatedKeysets[i]
      });
      onDeviceStreaming({
        progress: (i + 1) / inputs.length,
        index: i + 1,
        total: inputs.length
      });
      result.push(r);
    }
    for (let i = 0; i < result.length; i++) {
      publicKeys.push(
        compressPublicKey(Buffer.from(result[i].publicKey, "hex"))
      );
    }
  }

  if (hasTimestamp) {
    targetTransaction.timestamp = Buffer.alloc(4);
    targetTransaction.timestamp.writeUInt32LE(
      Math.floor(initialTimestamp + (Date.now() - startTime) / 1000),
      0
    );
  }

  onDeviceSignatureRequested();

  if (useBip143) {
    // Do the first run with all inputs
    await startUntrustedHashTransactionInput(
      transport,
      true,
      targetTransaction,
      trustedInputs,
      true,
      !!expiryHeight,
      additionals
    );

    if (!resuming && changePath) {
      await provideOutputFullChangePath(transport, changePath);
    }

    await hashOutputFull(transport, outputScript);
  }

  if (!!expiryHeight && !isDecred) {
    await signTransaction(transport, "", lockTime, SIGHASH_ALL, expiryHeight);
  }

  // Do the second run with the individual transaction
  for (let i = 0; i < inputs.length; i++) {
    const input = inputs[i];
    let script =
      inputs[i].length >= 3 && typeof input[2] === "string"
        ? Buffer.from(input[2], "hex")
        : !segwit
        ? regularOutputs[i].script
        : Buffer.concat([
            Buffer.from([OP_DUP, OP_HASH160, HASH_SIZE]),
            hashPublicKey(publicKeys[i]),
            Buffer.from([OP_EQUALVERIFY, OP_CHECKSIG])
          ]);
    let pseudoTX = Object.assign({}, targetTransaction);
    let pseudoTrustedInputs = useBip143 ? [trustedInputs[i]] : trustedInputs;
    if (useBip143) {
      pseudoTX.inputs = [{ ...pseudoTX.inputs[i], script }];
    } else {
      pseudoTX.inputs[i].script = script;
    }

    await startUntrustedHashTransactionInput(
      transport,
      !useBip143 && firstRun,
      pseudoTX,
      pseudoTrustedInputs,
      useBip143,
      !!expiryHeight && !isDecred,
      additionals
    );

    if (!useBip143) {
      if (!resuming && changePath) {
        await provideOutputFullChangePath(transport, changePath);
      }
      await hashOutputFull(transport, outputScript, additionals);
    }

    if (firstRun) {
      onDeviceSignatureGranted();
      onDeviceStreaming({ progress: 0, index: 0, total: inputs.length });
    }

    const signature = await signTransaction(
      transport,
      associatedKeysets[i],
      lockTime,
      sigHashType,
      expiryHeight,
      additionals
    );
    onDeviceStreaming({
      progress: (i + 1) / inputs.length,
      index: 0,
      total: inputs.length
    });

    signatures.push(signature);
    targetTransaction.inputs[i].script = nullScript;
    if (firstRun) {
      firstRun = false;
    }
  }

  // Populate the final input scripts
  for (let i = 0; i < inputs.length; i++) {
    if (segwit) {
      targetTransaction.witness = Buffer.alloc(0);
      if (!bech32) {
        targetTransaction.inputs[i].script = Buffer.concat([
          Buffer.from("160014", "hex"),
          hashPublicKey(publicKeys[i])
        ]);
      }
    } else {
      const signatureSize = Buffer.alloc(1);
      const keySize = Buffer.alloc(1);
      signatureSize[0] = signatures[i].length;
      keySize[0] = publicKeys[i].length;
      targetTransaction.inputs[i].script = Buffer.concat([
        signatureSize,
        signatures[i],
        keySize,
        publicKeys[i]
      ]);
    }
    let offset = useBip143 ? 0 : 4;
    targetTransaction.inputs[i].prevout = trustedInputs[i].value.slice(
      offset,
      offset + 0x24
    );
  }

  const lockTimeBuffer = Buffer.alloc(4);
  lockTimeBuffer.writeUInt32LE(lockTime, 0);

  var result = Buffer.concat([
    serializeTransaction(
      targetTransaction,
      false,
      targetTransaction.timestamp,
      additionals
    ),
    outputScript
  ]);

  if (segwit && !isDecred) {
    var witness = Buffer.alloc(0);
    for (var i = 0; i < inputs.length; i++) {
      var tmpScriptData = Buffer.concat([
        Buffer.from("02", "hex"),
        Buffer.from([signatures[i].length]),
        signatures[i],
        Buffer.from([publicKeys[i].length]),
        publicKeys[i]
      ]);
      witness = Buffer.concat([witness, tmpScriptData]);
    }
    result = Buffer.concat([result, witness]);
  }

  // FIXME: In ZEC or KMD sapling lockTime is serialized before expiryHeight.
  // expiryHeight is used only in overwinter/sapling so I moved lockTimeBuffer here
  // and it should not break other coins because expiryHeight is false for them.
  // Don't know about Decred though.
  result = Buffer.concat([result, lockTimeBuffer]);

  if (expiryHeight) {
    result = Buffer.concat([
      result,
      targetTransaction.nExpiryHeight || Buffer.alloc(0),
      targetTransaction.extraData || Buffer.alloc(0)
    ]);
  }

  if (isDecred) {
    let decredWitness = Buffer.from([targetTransaction.inputs.length]);
    inputs.forEach((input, inputIndex) => {
      decredWitness = Buffer.concat([
        decredWitness,
        Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
        Buffer.from([0x00, 0x00, 0x00, 0x00]), //Block height
        Buffer.from([0xff, 0xff, 0xff, 0xff]), //Block index
        Buffer.from([targetTransaction.inputs[inputIndex].script.length]),
        targetTransaction.inputs[inputIndex].script
      ]);
    });

    result = Buffer.concat([result, decredWitness]);
  }

  return result.toString("hex");
}
<commit_msg>hw-app-btc: onDeviceStreaming: fixes index value<commit_after>// @flow

import type Transport from "@ledgerhq/hw-transport";
import { hashPublicKey } from "./hashPublicKey";
import { getWalletPublicKey } from "./getWalletPublicKey";
import type { AddressFormat } from "./getWalletPublicKey";
import { getTrustedInput } from "./getTrustedInput";
import { startUntrustedHashTransactionInput } from "./startUntrustedHashTransactionInput";
import { serializeTransaction } from "./serializeTransaction";
import { getTrustedInputBIP143 } from "./getTrustedInputBIP143";
import { compressPublicKey } from "./compressPublicKey";
import { signTransaction } from "./signTransaction";
import { hashOutputFull, provideOutputFullChangePath } from "./finalizeInput";
import type { TransactionOutput, Transaction } from "./types";
import {
  DEFAULT_LOCKTIME,
  DEFAULT_SEQUENCE,
  SIGHASH_ALL,
  OP_DUP,
  OP_HASH160,
  HASH_SIZE,
  OP_EQUALVERIFY,
  OP_CHECKSIG
} from "./constants";

export type { AddressFormat };

const defaultsSignTransaction = {
  lockTime: DEFAULT_LOCKTIME,
  sigHashType: SIGHASH_ALL,
  segwit: false,
  additionals: [],
  onDeviceStreaming: _progress => {},
  onDeviceSignatureGranted: () => {},
  onDeviceSignatureRequested: () => {}
};

export type CreateTransactionArg = {
  inputs: Array<[Transaction, number, ?string, ?number]>,
  associatedKeysets: string[],
  changePath?: string,
  outputScriptHex: string,
  lockTime?: number,
  sigHashType?: number,
  segwit?: boolean,
  initialTimestamp?: number,
  additionals: Array<string>,
  expiryHeight?: Buffer,
  onDeviceStreaming?: ({
    progress: number,
    total: number,
    index: number
  }) => void,
  onDeviceSignatureRequested?: () => void,
  onDeviceSignatureGranted?: () => void
};

export async function createTransaction(
  transport: Transport<*>,
  arg: CreateTransactionArg
) {
  const {
    inputs,
    associatedKeysets,
    changePath,
    outputScriptHex,
    lockTime,
    sigHashType,
    segwit,
    initialTimestamp,
    additionals,
    expiryHeight,
    onDeviceStreaming,
    onDeviceSignatureGranted,
    onDeviceSignatureRequested
  } = {
    ...defaultsSignTransaction,
    ...arg
  };

  const isDecred = additionals.includes("decred");
  const isXST = additionals.includes("stealthcoin");
  const hasTimestamp = initialTimestamp !== undefined;
  let startTime = Date.now();
  const sapling = additionals.includes("sapling");
  const bech32 = segwit && additionals.includes("bech32");
  let useBip143 =
    segwit ||
    (!!additionals &&
      (additionals.includes("abc") ||
        additionals.includes("gold") ||
        additionals.includes("bip143"))) ||
    (!!expiryHeight && !isDecred);
  // Inputs are provided as arrays of [transaction, output_index, optional redeem script, optional sequence]
  // associatedKeysets are provided as arrays of [path]
  const nullScript = Buffer.alloc(0);
  const nullPrevout = Buffer.alloc(0);
  const defaultVersion = Buffer.alloc(4);
  !!expiryHeight && !isDecred
    ? defaultVersion.writeUInt32LE(sapling ? 0x80000004 : 0x80000003, 0)
    : isXST
    ? defaultVersion.writeUInt32LE(2, 0)
    : defaultVersion.writeUInt32LE(1, 0); // Default version to 2 for XST not to have timestamp
  const trustedInputs: Array<*> = [];
  const regularOutputs: Array<TransactionOutput> = [];
  const signatures = [];
  const publicKeys = [];
  let firstRun = true;
  const resuming = false;
  const targetTransaction: Transaction = {
    inputs: [],
    version: defaultVersion,
    timestamp: Buffer.alloc(0)
  };
  const getTrustedInputCall = useBip143
    ? getTrustedInputBIP143
    : getTrustedInput;
  const outputScript = Buffer.from(outputScriptHex, "hex");

  onDeviceStreaming({ progress: 0, index: 0, total: inputs.length });

  // first pass on inputs to get trusted inputs
  for (let input of inputs) {
    if (!resuming) {
      const trustedInput = await getTrustedInputCall(
        transport,
        input[1],
        input[0],
        additionals
      );
      let sequence = Buffer.alloc(4);
      sequence.writeUInt32LE(
        input.length >= 4 && typeof input[3] === "number"
          ? input[3]
          : DEFAULT_SEQUENCE,
        0
      );
      trustedInputs.push({
        trustedInput: true,
        value: Buffer.from(trustedInput, "hex"),
        sequence
      });
    }

    const { outputs } = input[0];
    const index = input[1];
    if (outputs && index <= outputs.length - 1) {
      regularOutputs.push(outputs[index]);
    }

    if (expiryHeight && !isDecred) {
      targetTransaction.nVersionGroupId = Buffer.from(
        sapling ? [0x85, 0x20, 0x2f, 0x89] : [0x70, 0x82, 0xc4, 0x03]
      );
      targetTransaction.nExpiryHeight = expiryHeight;
      // For sapling : valueBalance (8), nShieldedSpend (1), nShieldedOutput (1), nJoinSplit (1)
      // Overwinter : use nJoinSplit (1)
      targetTransaction.extraData = Buffer.from(
        sapling
          ? [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
          : [0x00]
      );
    } else if (isDecred) {
      targetTransaction.nExpiryHeight = expiryHeight;
    }
  }

  targetTransaction.inputs = inputs.map(input => {
    let sequence = Buffer.alloc(4);
    sequence.writeUInt32LE(
      input.length >= 4 && typeof input[3] === "number"
        ? input[3]
        : DEFAULT_SEQUENCE,
      0
    );
    return {
      script: nullScript,
      prevout: nullPrevout,
      sequence
    };
  });

  if (!resuming) {
    // Collect public keys
    const result = [];
    for (let i = 0; i < inputs.length; i++) {
      const r = await getWalletPublicKey(transport, {
        path: associatedKeysets[i]
      });
      onDeviceStreaming({
        progress: (i + 1) / inputs.length,
        index: i + 1,
        total: inputs.length
      });
      result.push(r);
    }
    for (let i = 0; i < result.length; i++) {
      publicKeys.push(
        compressPublicKey(Buffer.from(result[i].publicKey, "hex"))
      );
    }
  }

  if (hasTimestamp) {
    targetTransaction.timestamp = Buffer.alloc(4);
    targetTransaction.timestamp.writeUInt32LE(
      Math.floor(initialTimestamp + (Date.now() - startTime) / 1000),
      0
    );
  }

  onDeviceSignatureRequested();

  if (useBip143) {
    // Do the first run with all inputs
    await startUntrustedHashTransactionInput(
      transport,
      true,
      targetTransaction,
      trustedInputs,
      true,
      !!expiryHeight,
      additionals
    );

    if (!resuming && changePath) {
      await provideOutputFullChangePath(transport, changePath);
    }

    await hashOutputFull(transport, outputScript);
  }

  if (!!expiryHeight && !isDecred) {
    await signTransaction(transport, "", lockTime, SIGHASH_ALL, expiryHeight);
  }

  // Do the second run with the individual transaction
  for (let i = 0; i < inputs.length; i++) {
    const input = inputs[i];
    let script =
      inputs[i].length >= 3 && typeof input[2] === "string"
        ? Buffer.from(input[2], "hex")
        : !segwit
        ? regularOutputs[i].script
        : Buffer.concat([
            Buffer.from([OP_DUP, OP_HASH160, HASH_SIZE]),
            hashPublicKey(publicKeys[i]),
            Buffer.from([OP_EQUALVERIFY, OP_CHECKSIG])
          ]);
    let pseudoTX = Object.assign({}, targetTransaction);
    let pseudoTrustedInputs = useBip143 ? [trustedInputs[i]] : trustedInputs;
    if (useBip143) {
      pseudoTX.inputs = [{ ...pseudoTX.inputs[i], script }];
    } else {
      pseudoTX.inputs[i].script = script;
    }

    await startUntrustedHashTransactionInput(
      transport,
      !useBip143 && firstRun,
      pseudoTX,
      pseudoTrustedInputs,
      useBip143,
      !!expiryHeight && !isDecred,
      additionals
    );

    if (!useBip143) {
      if (!resuming && changePath) {
        await provideOutputFullChangePath(transport, changePath);
      }
      await hashOutputFull(transport, outputScript, additionals);
    }

    if (firstRun) {
      onDeviceSignatureGranted();
      onDeviceStreaming({ progress: 0, index: 0, total: inputs.length });
    }

    const signature = await signTransaction(
      transport,
      associatedKeysets[i],
      lockTime,
      sigHashType,
      expiryHeight,
      additionals
    );
    onDeviceStreaming({
      progress: (i + 1) / inputs.length,
      index: i + 1,
      total: inputs.length
    });

    signatures.push(signature);
    targetTransaction.inputs[i].script = nullScript;
    if (firstRun) {
      firstRun = false;
    }
  }

  // Populate the final input scripts
  for (let i = 0; i < inputs.length; i++) {
    if (segwit) {
      targetTransaction.witness = Buffer.alloc(0);
      if (!bech32) {
        targetTransaction.inputs[i].script = Buffer.concat([
          Buffer.from("160014", "hex"),
          hashPublicKey(publicKeys[i])
        ]);
      }
    } else {
      const signatureSize = Buffer.alloc(1);
      const keySize = Buffer.alloc(1);
      signatureSize[0] = signatures[i].length;
      keySize[0] = publicKeys[i].length;
      targetTransaction.inputs[i].script = Buffer.concat([
        signatureSize,
        signatures[i],
        keySize,
        publicKeys[i]
      ]);
    }
    let offset = useBip143 ? 0 : 4;
    targetTransaction.inputs[i].prevout = trustedInputs[i].value.slice(
      offset,
      offset + 0x24
    );
  }

  const lockTimeBuffer = Buffer.alloc(4);
  lockTimeBuffer.writeUInt32LE(lockTime, 0);

  var result = Buffer.concat([
    serializeTransaction(
      targetTransaction,
      false,
      targetTransaction.timestamp,
      additionals
    ),
    outputScript
  ]);

  if (segwit && !isDecred) {
    var witness = Buffer.alloc(0);
    for (var i = 0; i < inputs.length; i++) {
      var tmpScriptData = Buffer.concat([
        Buffer.from("02", "hex"),
        Buffer.from([signatures[i].length]),
        signatures[i],
        Buffer.from([publicKeys[i].length]),
        publicKeys[i]
      ]);
      witness = Buffer.concat([witness, tmpScriptData]);
    }
    result = Buffer.concat([result, witness]);
  }

  // FIXME: In ZEC or KMD sapling lockTime is serialized before expiryHeight.
  // expiryHeight is used only in overwinter/sapling so I moved lockTimeBuffer here
  // and it should not break other coins because expiryHeight is false for them.
  // Don't know about Decred though.
  result = Buffer.concat([result, lockTimeBuffer]);

  if (expiryHeight) {
    result = Buffer.concat([
      result,
      targetTransaction.nExpiryHeight || Buffer.alloc(0),
      targetTransaction.extraData || Buffer.alloc(0)
    ]);
  }

  if (isDecred) {
    let decredWitness = Buffer.from([targetTransaction.inputs.length]);
    inputs.forEach((input, inputIndex) => {
      decredWitness = Buffer.concat([
        decredWitness,
        Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
        Buffer.from([0x00, 0x00, 0x00, 0x00]), //Block height
        Buffer.from([0xff, 0xff, 0xff, 0xff]), //Block index
        Buffer.from([targetTransaction.inputs[inputIndex].script.length]),
        targetTransaction.inputs[inputIndex].script
      ]);
    });

    result = Buffer.concat([result, decredWitness]);
  }

  return result.toString("hex");
}
<|endoftext|>


<commit_before>$(document).ready(function() {
    var id = location.pathname.split('/').slice(-1)[0];
    if (id) {
        $('#paste').show();
        $.get('get/' + id, function(entry) {
            $('#paste').text(entry.content);
            $('#content').val(entry.content);
        }, 'json');
    }

    $('#entry form').bind('submit', function() {
        var entry = {
            content: $('#content').val()
        };
        $.post("post", JSON.stringify(entry), function(id) {
            location = id;
        }, 'text');
        return false;
    });
});
<commit_msg>Use jQuery chaining, you dolt.<commit_after>$(document).ready(function() {
    var id = location.pathname.split('/').slice(-1)[0];
    if (id) {
        $.get('get/' + id, function(entry) {
            $('#paste').show().text(entry.content);
            $('#content').val(entry.content);
        }, 'json');
    }

    $('#entry form').bind('submit', function() {
        var entry = {
            content: $('#content').val()
        };
        $.post("post", JSON.stringify(entry), function(id) {
            location = id;
        }, 'text');
        return false;
    });
});
<|endoftext|>


<commit_before>var applyProperties = require("./apply-properties")

var isWidget = require("vtree/is-widget")
var VPatch = require("vtree/vpatch")

var render = require("./create-element")
var updateWidget = require("./update-widget")

module.exports = applyPatch

function applyPatch(vpatch, domNode, renderOptions) {
    var type = vpatch.type
    var vNode = vpatch.vNode
    var patch = vpatch.patch

    switch (type) {
        case VPatch.REMOVE:
            return removeNode(domNode, vNode)
        case VPatch.INSERT:
            return insertNode(domNode, patch, renderOptions)
        case VPatch.VTEXT:
            return stringPatch(domNode, vNode, patch, renderOptions)
        case VPatch.WIDGET:
            return widgetPatch(domNode, vNode, patch, renderOptions)
        case VPatch.VNODE:
            return vNodePatch(domNode, vNode, patch, renderOptions)
        case VPatch.ORDER:
            reorderChildren(domNode, patch)
            return domNode
        case VPatch.PROPS:
            applyProperties(domNode, patch, vNode.propeties)
            return domNode
        default:
            return domNode
    }
}

function removeNode(domNode, vNode) {
    var parentNode = domNode.parentNode

    if (parentNode) {
        parentNode.removeChild(domNode)
    }

    destroyWidget(domNode, vNode);

    return null
}

function insertNode(parentNode, vNode, renderOptions) {
    var newNode = render(vNode, renderOptions)

    if (parentNode) {
        parentNode.appendChild(newNode)
    }

    return parentNode
}

function stringPatch(domNode, leftVNode, vText, renderOptions) {
    var newNode

    if (domNode.nodeType === 3) {
        domNode.replaceData(0, domNode.length, vText.text)
        newNode = domNode
    } else {
        var parentNode = domNode.parentNode
        newNode = render(vText, renderOptions)

        if (parentNode) {
            parentNode.replaceChild(newNode, domNode)
        }
    }

    destroyWidget(domNode, leftVNode)

    return newNode
}

function widgetPatch(domNode, leftVNode, widget, renderOptions) {
    if (updateWidget(leftVNode, widget)) {
        return widget.update(leftVNode, domNode) || domNode
    }

    var parentNode = domNode.parentNode
    var newWidget = render(widget, renderOptions)

    if (parentNode) {
        parentNode.replaceChild(newWidget, domNode)
    }

    destroyWidget(domNode, leftVNode)

    return newWidget
}

function vNodePatch(domNode, leftVNode, vNode, renderOptions) {
    var parentNode = domNode.parentNode
    var newNode = render(vNode, renderOptions)

    if (parentNode) {
        parentNode.replaceChild(newNode, domNode)
    }

    destroyWidget(domNode, leftVNode)

    return newNode
}

function destroyWidget(domNode, w) {
    if (typeof w.destroy === "function" && isWidget(w)) {
        w.destroy(domNode)
    }
}

function reorderChildren(domNode, bIndex) {
    var children = []
    var childNodes = domNode.childNodes
    var len = childNodes.length
    var i

    for (i = 0; i < len; i++) {
        children.push(domNode.childNodes[i])
    }

    for (i = 0; i < len; i++) {
        var move = bIndex[i]
        if (move !== undefined) {
            var node = children[move]
            domNode.removeChild(node)
            domNode.insertBefore(node, childNodes[i])
        }
    }
}
<commit_msg>typo applying properties<commit_after>var applyProperties = require("./apply-properties")

var isWidget = require("vtree/is-widget")
var VPatch = require("vtree/vpatch")

var render = require("./create-element")
var updateWidget = require("./update-widget")

module.exports = applyPatch

function applyPatch(vpatch, domNode, renderOptions) {
    var type = vpatch.type
    var vNode = vpatch.vNode
    var patch = vpatch.patch

    switch (type) {
        case VPatch.REMOVE:
            return removeNode(domNode, vNode)
        case VPatch.INSERT:
            return insertNode(domNode, patch, renderOptions)
        case VPatch.VTEXT:
            return stringPatch(domNode, vNode, patch, renderOptions)
        case VPatch.WIDGET:
            return widgetPatch(domNode, vNode, patch, renderOptions)
        case VPatch.VNODE:
            return vNodePatch(domNode, vNode, patch, renderOptions)
        case VPatch.ORDER:
            reorderChildren(domNode, patch)
            return domNode
        case VPatch.PROPS:
            applyProperties(domNode, patch, vNode.properties)
            return domNode
        default:
            return domNode
    }
}

function removeNode(domNode, vNode) {
    var parentNode = domNode.parentNode

    if (parentNode) {
        parentNode.removeChild(domNode)
    }

    destroyWidget(domNode, vNode);

    return null
}

function insertNode(parentNode, vNode, renderOptions) {
    var newNode = render(vNode, renderOptions)

    if (parentNode) {
        parentNode.appendChild(newNode)
    }

    return parentNode
}

function stringPatch(domNode, leftVNode, vText, renderOptions) {
    var newNode

    if (domNode.nodeType === 3) {
        domNode.replaceData(0, domNode.length, vText.text)
        newNode = domNode
    } else {
        var parentNode = domNode.parentNode
        newNode = render(vText, renderOptions)

        if (parentNode) {
            parentNode.replaceChild(newNode, domNode)
        }
    }

    destroyWidget(domNode, leftVNode)

    return newNode
}

function widgetPatch(domNode, leftVNode, widget, renderOptions) {
    if (updateWidget(leftVNode, widget)) {
        return widget.update(leftVNode, domNode) || domNode
    }

    var parentNode = domNode.parentNode
    var newWidget = render(widget, renderOptions)

    if (parentNode) {
        parentNode.replaceChild(newWidget, domNode)
    }

    destroyWidget(domNode, leftVNode)

    return newWidget
}

function vNodePatch(domNode, leftVNode, vNode, renderOptions) {
    var parentNode = domNode.parentNode
    var newNode = render(vNode, renderOptions)

    if (parentNode) {
        parentNode.replaceChild(newNode, domNode)
    }

    destroyWidget(domNode, leftVNode)

    return newNode
}

function destroyWidget(domNode, w) {
    if (typeof w.destroy === "function" && isWidget(w)) {
        w.destroy(domNode)
    }
}

function reorderChildren(domNode, bIndex) {
    var children = []
    var childNodes = domNode.childNodes
    var len = childNodes.length
    var i

    for (i = 0; i < len; i++) {
        children.push(domNode.childNodes[i])
    }

    for (i = 0; i < len; i++) {
        var move = bIndex[i]
        if (move !== undefined) {
            var node = children[move]
            domNode.removeChild(node)
            domNode.insertBefore(node, childNodes[i])
        }
    }
}
<|endoftext|>


<commit_before>/**

   Copyright 2013-2017 Cris Stringfellow / DOSAYGO CREATIVE INTANGIBLE HOLDINGS (UK) LTD

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

**/

"use strict";
{
  const utils = require('./utils.js');
  const MAX_DEPTH = 10000;
  const CLASS_MATCHER = /(\.[^#\.:]+)/g;
  const ID_MATCHER = /#([^#\.:]+)/g;
  const TAG_MATCHER = /^([^#\.:]+)/g;
  const ANY_MATCHER = /:\w+\(\s*([^\)]+)\s*\)/g;
  const NTH_MATCHER = /(:nth-of-type\([^)]*\))/g;

  let vendor;
  let current_code = 2;

  const path_lcs = {
    any_mode : false,
    get_canonical_path(node) {
      const path = [];
      const class_path = [];
      const canonical_path = [];
      let code = next_code();
      while(!!node && node.tagName != 'HTML') {
        if(!node.parentNode && !!node.host) {
          // Issue: this is only here for reference when we add in updated shadow dom support, or remove this code
          node = node.host;
          const shadow_level = {};
          shadow_level["TAG:"+node.tagName+"::shadow"] = 1;
          canonical_path.unshift(shadow_level);
        } else {
          const canonical_level = {
            tags: new Set(),
            geometry: new Set(),
            classes: new Set(),
            ids: new Set()
          };

          // make the level
            // get index_name ( like nth-of-type(n) )
              let index_name = '';
              if(!!node.parentNode) {
                let count = 0;
                const siblings = Array.from( node.parentNode.childNodes );
                for( const sibling of siblings ) {
                  if(sibling.tagName == node.tagName) {
                    count += 1;
                  }
                  if(sibling === node) {
                    index_name = `:nth-of-type(${count})`;
                    break;
                  }
                }
              }

            // add id ( if any ) to canonical level
              if(!!node.id && node.id.length > 0) {
                canonical_level.ids.add( node.id );
              }

            // get classes
              let classes;
              try {
                classes = node.getAttribute('class');
              } catch(e) {
                classes = node.className;
              }
              if(typeof classes !== 'string') {
                // fallback for SVG the className is an object.
                try {
                  classes = Array.from( node.classList );
                } catch(e) {
                  classes = []
                }
              } else {
                classes = classes.split(/\s+/);
              }

            // add class words to canonical_level
              classes.forEach( classword => {
                if(classword.length > 0) {
                  canonical_level.classes.add(`.${safe(classword)}`);
                }
              });

            // add tag and index_name to canonical level
              canonical_level.tags.add(node.tagName);
              canonical_level.geometry.add(index_name);

            // add code
              canonical_level.code = code;
              code += 1;

          canonical_path.unshift(canonical_level);
        }
        node = node.parentNode;
      }
      return {canonical:canonical_path};
    },
    path_from_sel(sel) {
      const levels = sel.split(/\s*>\s*/g);
      const path = [];
      let code = next_code();
      for( const level of levels ) {
        const canonical_level = {
          tags: new Set(),
          geometry: new Set(),
          classes: new Set(),
          ids: new Set()
        };

        const classes = new Set( run_match(CLASS_MATCHER,level).map( c => safe(c) ));
        let anys = run_match(ANY_MATCHER,level)[0];
        if ( anys ) {
          anys = new Set( anys.split(/\s*,\s*/g) );
        } else {
          anys = new Set();
        }

        const tag = run_match(TAG_MATCHER,level)[0];
        const id = safe(run_match(ID_MATCHER,level)[0] || '');
        const geometry = run_match(NTH_MATCHER,level)[0];

        canonical_level.classes = classes;
        canonical_level.tags = anys;

        if ( tag ) {
          if ( anys.size == 0 ) {
            canonical_level.tags.add( tag );
          } else if ( tag !== '*' ) {
            canonical_level.tags.add( tag );
          }
        }
        if ( id ) {
          canonical_level.ids.add(id);
        }
        if ( geometry ) {
          canonical_level.geometry.add(geometry);
        }

        canonical_level.code = code;
        code -= 1;
        path.push( canonical_level );
      }
      return path;
    },
    selector_from_canonical_path(path) {
      vendor = vendor || require('./vendor.js').get_prefix();
      path = Array.from(path);
      if ( path.length == 0 ) {
        return '';
      }
      const selector = [];

      // add direct descendent combinators
        let last_level = path[0];
        for( let i = 1; i < path.length; i++ ) {
          const level = path[i];
          const diff = get_code_diff(last_level,level);
          if ( diff == 1 ) {
            path.splice( i, 0, {'>': 1});
          }
          last_level = level;
        }

      path.forEach( levelset => {
        if(!!levelset['>']) {
          const last = selector[selector.length-1];
          if(last !== '>') {
            selector.push('>');
          }
          return;
        }
        const { tags, classes, ids, geometry } = levelset;
        let level_sel = '';

        if ( path_lcs.any_mode && tags.size > 1 ) {
          level_sel += `:-${vendor}-any(${[...tags].join(',')})`;
        } else {
          level_sel += `${[...tags].join(',')}`;
        }

        if ( ids.size ) {
          level_sel += `#${[...ids].map(i => safe(i)).join('#')}`;
        }

        if ( classes.size) {
          level_sel += `${[...classes].map(c => safe(c)).join('')}`;
        }

        if ( geometry.size ) {
          level_sel += `${[...geometry].join('')}`;
        }

        if(!!level_sel) {
          selector.push(level_sel);
        }
      });

      const selector_str = selector.join(' ');
      return selector_str;
    },
    basic_multiple_lcs_from_canonical_path_list(list) {
      if(list.length == 0) {
        return [];
      }
      let path2 = list[0];
      let path1;
      for(let i = 1; i < list.length; i+=1 ) {
        path1 = list[i];
        const lcs = lcs_from_canonical_path_pair(path1,path2);
        if(!!lcs) {
          path2 = lcs.value;
        }
      }
      return path2;
    }
  };

  // helpers
    function safe(s) {
      // CSS escapes
      if ( Number.isInteger(parseInt(s)) && parseInt(s).toString() == s) {
        s = s.split('').map( c => c.charCodeAt(0).toString(16) ).join('\\');
        return '\\'+s;
      } else {
        return s.replace(/\\\\([\[\]])/, '$1' ).replace(/([\[\]])/g, '\\$1' ).replace(/\\(\d\d)/g,'\\\\$1');
      }
    }
    function run_match(R,s) {
      const m = [];
      let match;
      while(match = R.exec(s)) {
        m.push(match[1]);
      }
      return m;
    }
    function find_max_value_index(s,x,y) {
      let value = 0;
      let max_index = s.length-1;
      for(let i = 0; i < s.length; i += 1) {
        if(s[i] >= value) {
          value = s[i];
          max_index = i;
        }
      }
      if ( y.length ) {
        const column = max_index % y.length;
        const row = (max_index-column)/y.length;
        return { row, column, value };
      } else {
        return { row: 0, column: 0, value };
      }
    }

    function lcs_read(s,x,y,i,j) {
      if ( i <= 0 || j <= 0 ) {
        return [];
      }

      let xy_intersection;
      if ( path_lcs.any_mode ) {
        xy_intersection = utils.any_intersection(x[i],y[j]);
      } else {
        xy_intersection = utils.intersection(x[i],y[j]);
      }
      const order = utils.order(xy_intersection, path_lcs.any_mode);
      if(!!order) {
        const xcode = utils.get_code(x[i]);
        const ycode = utils.get_code(y[j]);
        Object.assign( xy_intersection, {
          xcode, ycode
        });
        return lcs_read(s,x,y,i-1,j-1).concat([xy_intersection]);
      } else {
        let score_insert_y = s[i*y.length+j-1];
        let score_insert_x = s[(i-1)*y.length+j];
        if(score_insert_y > score_insert_x) {
          return lcs_read(s,x,y,i,j-1);
        } else {
          return lcs_read(s,x,y,i-1,j);
        }
      }
    }

    function next_code() {
      current_code += MAX_DEPTH;
      return current_code;
    }

    function get_code_diff(last_level, level) {
      const lcode = utils.get_code(last_level);
      const code = utils.get_code(level);
      return lcode - code;
    }

    function diffs( last_level, level ) {
      const {xcode,ycode} = last_level;
      const xdif = xcode - level.xcode;
      const ydif = ycode - level.ycode;
      return [xdif, ydif];
    }

    function isOneLevel( last_level, level ) {
      const [xdif, ydif] = [...diffs(last_level, level )];
      return xdif == 1 && ydif == 1;
    }

    function max_diff( last_level, level ) {
      return Math.max( ...diffs( last_level, level ) );
    }

    function lcs_from_canonical_path_pair(path1,path2) {
      const score_matrix = new Float32Array(new ArrayBuffer(4*path1.length*path2.length));
      const row_offset = path2.length;
      let i1,i2;
      let address;
      let path1_path2_match_score, path1_insert_score, path2_insert_score;

      for(i1 = 1; i1 < path1.length; i1 += 1 ) {
        for(i2 = 1; i2 < path2.length; i2 += 1 ) {
          const union_order = utils.order(utils.union(path1[i1],path2[i2]), path_lcs.any_mode);
          let quotient = 0;
          if ( union_order ) {
            quotient = utils.order(utils.intersection(path1[i1],path2[i2]), path_lcs.any_mode)/union_order;
          }
          address = path2.length*i1+i2;
          path1_path2_match_score = score_matrix[address-path2.length-1]+quotient;
          path1_insert_score = score_matrix[address-1];
          path2_insert_score = score_matrix[address-path2.length];
          score_matrix[address] = Math.max(path1_insert_score,path1_path2_match_score,path2_insert_score);
        }
      }

      const max_value_index = find_max_value_index(score_matrix,path1,path2);
      let last_match_i = max_value_index.row;
      let last_match_j = max_value_index.column;
      const lcs_selector = lcs_read(score_matrix,path1,path2,last_match_i, last_match_j);

      // add codes
        if ( lcs_selector.length ) {
          let code = next_code();
          let last_level = lcs_selector[0];
          last_level.code = code;
          for( let i = 1; i < lcs_selector.length; i++ ) {
            const level = lcs_selector[i];
            const is_one_level = isOneLevel( last_level, level );
            if ( is_one_level ) {
              code -= 1;
            } else {
              code -= max_diff( last_level, level );
            }
            level.code = code;
            last_level = level;
          }
        }

        lcs_selector.forEach( level => {
          delete level.xcode;
          delete level.ycode;
        });

      return {value:lcs_selector,score:max_value_index.value};
    }

  module.exports = path_lcs;
}
<commit_msg>Closes #48<commit_after>/**

   Copyright 2013-2017 Cris Stringfellow / DOSAYGO CREATIVE INTANGIBLE HOLDINGS (UK) LTD

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

**/

"use strict";
{
  const utils = require('./utils.js');
  const MAX_DEPTH = 10000;
  const CLASS_MATCHER = /(\.[^#\.:]+)/g;
  const ID_MATCHER = /#([^#\.:]+)/g;
  const TAG_MATCHER = /^([^#\.:]+)/g;
  const ANY_MATCHER = /:\w+\(\s*([^\)]+)\s*\)/g;
  const NTH_MATCHER = /(:nth-of-type\([^)]*\))/g;

  let vendor;
  let current_code = 2;

  const path_lcs = {
    any_mode : false,
    get_canonical_path(node) {
      const path = [];
      const class_path = [];
      const canonical_path = [];
      let code = next_code();
      while(!!node && node.tagName != 'HTML') {
        if(!node.parentNode && !!node.host) {
          // Issue: this is only here for reference when we add in updated shadow dom support, or remove this code
          node = node.host;
          const shadow_level = {};
          shadow_level["TAG:"+node.tagName+"::shadow"] = 1;
          canonical_path.unshift(shadow_level);
        } else {
          const canonical_level = {
            tags: new Set(),
            geometry: new Set(),
            classes: new Set(),
            ids: new Set()
          };

          // make the level
            // get index_name ( like nth-of-type(n) )
              let index_name = '';
              if(!!node.parentNode) {
                let count = 0;
                const siblings = Array.from( node.parentNode.childNodes );
                for( const sibling of siblings ) {
                  if(sibling.tagName == node.tagName) {
                    count += 1;
                  }
                  if(sibling === node) {
                    index_name = `:nth-of-type(${count})`;
                    break;
                  }
                }
              }

            // add id ( if any ) to canonical level
              if(!!node.id && node.id.length > 0) {
                canonical_level.ids.add( node.id );
              }

            // get classes
              let classes;
              try {
                classes = node.getAttribute('class');
              } catch(e) {
                classes = node.className;
              }
              if(typeof classes !== 'string') {
                // fallback for SVG the className is an object.
                try {
                  classes = Array.from( node.classList );
                } catch(e) {
                  classes = []
                }
              } else {
                classes = classes.split(/\s+/);
              }

            // add class words to canonical_level
              classes.forEach( classword => {
                if(classword.length > 0) {
                  canonical_level.classes.add(`.${safe(classword)}`);
                }
              });

            // add tag and index_name to canonical level
              canonical_level.tags.add(node.tagName);
              canonical_level.geometry.add(index_name);

            // add code
              canonical_level.code = code;
              code += 1;

          canonical_path.unshift(canonical_level);
        }
        node = node.parentNode;
      }
      return {canonical:canonical_path};
    },
    path_from_sel(sel) {
      const levels = sel.split(/\s*>\s*/g);
      const path = [];
      let code = next_code();
      for( const level of levels ) {
        const canonical_level = {
          tags: new Set(),
          geometry: new Set(),
          classes: new Set(),
          ids: new Set()
        };

        const classes = new Set( run_match(CLASS_MATCHER,level).map( c => safe(c) ));
        let anys = run_match(ANY_MATCHER,level)[0];
        if ( anys ) {
          anys = new Set( anys.split(/\s*,\s*/g) );
        } else {
          anys = new Set();
        }

        const tag = run_match(TAG_MATCHER,level)[0];
        const id = safe(run_match(ID_MATCHER,level)[0] || '');
        const geometry = run_match(NTH_MATCHER,level)[0];

        canonical_level.classes = classes;
        canonical_level.tags = anys;

        if ( tag ) {
          if ( anys.size == 0 ) {
            canonical_level.tags.add( tag );
          } else if ( tag !== '*' ) {
            canonical_level.tags.add( tag );
          }
        }
        if ( id ) {
          canonical_level.ids.add(id);
        }
        if ( geometry ) {
          canonical_level.geometry.add(geometry);
        }

        canonical_level.code = code;
        code -= 1;
        path.push( canonical_level );
      }
      return path;
    },
    selector_from_canonical_path(path) {
      vendor = vendor || require('./vendor.js').get_prefix();
      path = Array.from(path);
      if ( path.length == 0 ) {
        return '';
      }
      const selector = [];

      // add direct descendent combinators
        let last_level = path[0];
        for( let i = 1; i < path.length; i++ ) {
          const level = path[i];
          const diff = get_code_diff(last_level,level);
          if ( diff == 1 ) {
            path.splice( i, 0, {'>': 1});
          }
          last_level = level;
        }

      path.forEach( levelset => {
        if(!!levelset['>']) {
          const last = selector[selector.length-1];
          if(last !== '>') {
            selector.push('>');
          }
          return;
        }
        const { tags, classes, ids, geometry } = levelset;
        let level_sel = '';

        if ( path_lcs.any_mode && tags.size > 1 ) {
          level_sel += `:-${vendor}-any(${[...tags].join(',')})`;
        } else {
          level_sel += `${[...tags].join(',')}`;
        }

        if ( ids.size ) {
          level_sel += `#${[...ids].map(i => safe(i)).join('#')}`;
        }

        if ( classes.size) {
          level_sel += `${[...classes].map(c => safe(c)).join('')}`;
        }

        if ( geometry.size ) {
          level_sel += `${[...geometry].join('')}`;
        }

        if(!!level_sel) {
          selector.push(level_sel);
        }
      });

      const selector_str = selector.join(' ');
      return selector_str;
    },
    basic_multiple_lcs_from_canonical_path_list(list) {
      if(list.length == 0) {
        return [];
      }
      let path2 = list[0];
      let path1;
      for(let i = 1; i < list.length; i+=1 ) {
        path1 = list[i];
        const lcs = lcs_from_canonical_path_pair(path1,path2);
        if(!!lcs) {
          path2 = lcs.value;
        }
      }
      return path2;
    }
  };

  // helpers
    function safe(s) {
      // CSS escapes
      if ( Number.isInteger(parseInt(s)) && parseInt(s).toString() == s) {
        s = s.split('').map( c => c.charCodeAt(0).toString(16) ).join('\\');
        return '\\'+s;
      } else {
        return s.replace(/\\\\([\[\]])/, '$1' ).replace(/([\[\]])/g, '\\$1' ).replace(/\\(\d\d)/g,'\\\\$1');
      }
    }
    function run_match(R,s) {
      const m = [];
      let match;
      while(match = R.exec(s)) {
        m.push(match[1]);
      }
      return m;
    }
    function find_max_value_index(s,x,y) {
      let value = 0;
      let max_index = s.length-1;
      for(let i = 0; i < s.length; i += 1) {
        if(s[i] >= value) {
          value = s[i];
          max_index = i;
        }
      }
      if ( y.length ) {
        const column = max_index % y.length;
        const row = (max_index-column)/y.length;
        return { row, column, value };
      } else {
        return { row: 0, column: 0, value };
      }
    }

    function lcs_read(s,x,y,i,j) {
      if ( i < 0 || j < 0 ) {
        return [];
      }

      let xy_intersection;
      if ( path_lcs.any_mode ) {
        xy_intersection = utils.any_intersection(x[i],y[j]);
      } else {
        xy_intersection = utils.intersection(x[i],y[j]);
      }
      const order = utils.order(xy_intersection, path_lcs.any_mode);
      if(!!order) {
        const xcode = utils.get_code(x[i]);
        const ycode = utils.get_code(y[j]);
        Object.assign( xy_intersection, {
          xcode, ycode
        });
        return lcs_read(s,x,y,i-1,j-1).concat([xy_intersection]);
      } else {
        let score_insert_y = s[i*y.length+j-1];
        let score_insert_x = s[(i-1)*y.length+j];
        if(score_insert_y > score_insert_x) {
          return lcs_read(s,x,y,i,j-1);
        } else {
          return lcs_read(s,x,y,i-1,j);
        }
      }
    }

    function next_code() {
      current_code += MAX_DEPTH;
      return current_code;
    }

    function get_code_diff(last_level, level) {
      const lcode = utils.get_code(last_level);
      const code = utils.get_code(level);
      return lcode - code;
    }

    function diffs( last_level, level ) {
      const {xcode,ycode} = last_level;
      const xdif = xcode - level.xcode;
      const ydif = ycode - level.ycode;
      return [xdif, ydif];
    }

    function isOneLevel( last_level, level ) {
      const [xdif, ydif] = [...diffs(last_level, level )];
      return xdif == 1 && ydif == 1;
    }

    function max_diff( last_level, level ) {
      return Math.max( ...diffs( last_level, level ) );
    }

    function lcs_from_canonical_path_pair(path1,path2) {
      const score_matrix = new Float32Array(new ArrayBuffer(4*path1.length*path2.length));
      const row_offset = path2.length;
      let i1,i2;
      let address;
      let path1_path2_match_score, path1_insert_score, path2_insert_score;

      for(i1 = 0; i1 < path1.length; i1 += 1 ) {
        for(i2 = 0; i2 < path2.length; i2 += 1 ) {
          const union_order = utils.order(utils.union(path1[i1],path2[i2]), path_lcs.any_mode);
          let quotient = 0;
          if ( union_order ) {
            quotient = utils.order(utils.intersection(path1[i1],path2[i2]), path_lcs.any_mode)/union_order;
          }
          address = path2.length*i1+i2;
          path1_path2_match_score = score_matrix[address-path2.length-1]+quotient;
          path1_insert_score = score_matrix[address-1];
          path2_insert_score = score_matrix[address-path2.length];
          score_matrix[address] = Math.max(path1_insert_score,path1_path2_match_score,path2_insert_score);
        }
      }

      const max_value_index = find_max_value_index(score_matrix,path1,path2);
      let last_match_i = max_value_index.row;
      let last_match_j = max_value_index.column;
      const lcs_selector = lcs_read(score_matrix,path1,path2,last_match_i, last_match_j);

      // add codes
        if ( lcs_selector.length ) {
          let code = next_code();
          let last_level = lcs_selector[0];
          last_level.code = code;
          for( let i = 1; i < lcs_selector.length; i++ ) {
            const level = lcs_selector[i];
            const is_one_level = isOneLevel( last_level, level );
            if ( is_one_level ) {
              code -= 1;
            } else {
              code -= max_diff( last_level, level );
            }
            level.code = code;
            last_level = level;
          }
        }

        lcs_selector.forEach( level => {
          delete level.xcode;
          delete level.ycode;
        });

      return {value:lcs_selector,score:max_value_index.value};
    }

  module.exports = path_lcs;
}
<|endoftext|>


<commit_before>
var t = 0;
const exec = require('child_process').exec;
exec('node nodejs_app/app.js', function(error, stdout, stderr){
  if (error) {
    console.error('exec error: ${error}');
	t =1;
    return 1;
  }
 else{

  console.log('stdout: ${stdout}');
  console.log('stderr: ${stderr}');
  return 0;
 }
});

exec('node nodejs_app/app.js', function(error, stdout, stderr){
  if (error) {
    console.error('exec error: ${error}'+error);
	t =1;
		 exec('killall node ; echo "Succeeded"');
    return 0;
  }
 else{

  console.log('stdout: ${stdout}');
  console.log('stderr: ${stderr}');

  return 1;
 }
});
<commit_msg>Update testsA.js<commit_after>
var t = 0;
const exec = require('child_process').exec;
exec('node nodejs_app/app.js', function(error, stdout, stderr){
  if (error) {
    console.error('exec error: ${error}');
	t =1;
    return 1;
  }
 else{

  console.log('stdout: ${stdout}');
  console.log('stderr: ${stderr}');
  return 0;
 }
});

exec('node nodejs_app/app.js', function(error, stdout, stderr){
  if (error) {
    console.error('exec error: ${error}'+error);
	t =1;
		 exec('echo "Succeeded" | killall node ');
    return 0;
  }
 else{

  console.log('stdout: ${stdout}');
  console.log('stderr: ${stderr}');

  return 1;
 }
});
<|endoftext|>


<commit_before>var memblox = (function(window, document, undefined) {
  if(!window.console || !console.log){
    console = {};
    console.log = alert;
  }
  // makeHud method for creating new Heads up display
  function makeHud(id, cols, rows, font, x, y, prefix, suffix){
   var thishud = (function(Port, id, cols, rows, font, x, y, prefix, suffix){
      var hud = new HUD(id);
      var lastmsg = "";
      var prefix = prefix;
      var suffix = suffix;

      hud.setFont(font);
      hud.setPosition(x, y);
      hud.setTableSize(cols, rows);
      hud.setTracking(.7, 1.2);

      Port.attach(hud);

      return {
        hud: hud,
        write: function(msg){
          var clearString = "";
          var i = cols;
          while(i--){
            clearString += " ";
          };
          hud.setString(0,0,clearString)
          lastmessage = msg;
          msg = (prefix) ? prefix + msg : msg;
          msg = (suffix) ? msg + suffix : msg;
          hud.setString(0,0,msg);
        },
        read: function(){
          return lastmsg;
        }
      };
    })(Effect.Port,id, cols, rows, font, x, y, prefix, suffix)
    return thishud;
  }

  /* randomInt
   *  @param low : the low number in the return set
   *  @param high : the high number in the return set
   */

  // EventTarget class acts as base for custom events
  var memblox = {
    objects : {
      blocks : [],
      makeHud : makeHud
    },
    options : {
      pSize:40,
      boardHeight: 480,
      boardWidth: 320,
    },
    io : {
      messageDisplay: {},
      scoreDisplay: {},
      levelDisplay: {}
    },
    events: {
      levelCleared : function(obj, level){
        if((level + 1) >= 8){
          obj.environment.currentLevel = 1;
        };
        obj.environment.currentLevel = level + 1;
        obj.environment.matchSetSize = (level + 1) * 2;
        obj.environment.matchCount = 0;
      },
      gameOver : function(obj){
        obj.active = false;
      }
    },
    actions : {
      changeTheme : function(obj, theme_number){
        if(theme_number < obj.environment.themes.length){
          obj.environment.theme = theme_number;
          //var bpanel = Effect.Game.g
        }
      }
    },
    environment: {
      player : "",
      score : 0,
      currentLevel :1,
      level : [1,2,3,4,5,6,7,8],
      flipped : {
        count : 0,
        blocks : []
      },
      matchSetSize : 3, // in level change algorithm should be currentLevel * 2
      matchCount : 0,
      topScores : [],
      players : [],
      theme : 1,
      themes : ["default","mario"],
      activeblock : null
    },
    start_new_game: function() {
		// start new game (from title screen)
		var port = Effect.Port;

		//memblox.spriteGroups = {};

		Effect.Audio.quiet();
		Effect.Game.clearSchedule();
		Effect.Game.removeAllTweens();
		Effect.Port.removeAll();
		Effect.Port.setBackgroundColor('black');
        memblox.io.messageDisplay = memblox.objects.makeHud("message", 20, 5,
            memblox.environment.themes[memblox.environment.theme] + "Font", 20, 100, null, null);
        memblox.io.scoreDisplay =  memblox.objects.makeHud("score", 13, 1, memblox.environment.themes
            [memblox.environment.theme] + "Font", 3, 3, "Score:", null);
        memblox.io.levelDisplay =  memblox.objects.makeHud("level", 5, 1, memblox.environment.themes
            [memblox.environment.theme] + "Font", 176, 3, "Lvl:", null);
        var music = Effect.Audio.getTrack("/audio/music/" + memblox.environment.themes
            [memblox.environment.theme] + "/bg-music.mp3");
        Effect.Port.addEventListener( 'onMouseDown', function(pt, buttonIdx){
            var splane = Effect.Port.getPlane("Blocks");
            var sprite = splane.lookupSpriteFromGlobal(pt);
            if(sprite){
                sprite.flip(splane);
            }
        });
        Effect.Game.loadLevel( 'Default', function(){
            var bplane = Effect.Port.getPlane("Background");
            var backsprite = bplane.createSprite("Background");
            splane = Effect.Port.getPlane("Blocks");
            splane.createSprite("Block",{x:120, y:-40});
            splane.draw();
            music.playSound();
        });
        Effect.Game.addEventListener( 'onLogic', function(clock){
            if(memblox.environment.matchCount > memblox.environment.currentLevel * 10){
                memblox.events.levelCleared(memblox, memblox.environment.currentLevel);
            }
            memblox.io.levelDisplay.write(memblox.environment.currentLevel);
            memblox.io.scoreDisplay.write(memblox.environment.score);
        });
	}, // start_new_game
    data : (function(){
      if(openDatabase){
        var db = openDatabase("scubed", "1.0", "Scubed High Scores", "1024");
        var msg = [];
        var addScore = function(player, score){
          db.transaction(function(tx){
            tx.executeSql("INSERT INTO scubed (player, score) VALUES (?,?)",
            [player, score],
            function(tx, data){msg.push(data);},
            function(tx, e){msg.push(e);})
          })
        };
        var highScores = function(){
          db.transaction(function(tx){
            tx.executeSql("SELECT * FROM scubed ORDER BY score"),
            function(tx, data){msg.push(data);},
            function(tx, e){msg.push(e);}
          })
        };
        return {
          addScore : addScore,
          highScores: highScores,
          msg: msg
        }
      }else{
        return {};
      }
    })(),
  }
  return memblox;
})(window, window.document)

var speed = 4;
var BLOCK_HEIGHT = 40;
var BLOCK_WIDTH  = 40;
var GAME_LEFT_BOUNDARY = 0;
var GAME_RIGHT_BOUNDARY = GAME_LEFT_BOUNDARY + (BLOCK_WIDTH*8);
var GAME_UPPER_BOUNDARY = 0;
var GAME_LOWER_BOUNDARY = GAME_UPPER_BOUNDARY + (BLOCK_HEIGHT*12);

// These are the delays in secs. between block movements for each level
// index 0 is the delay for level 1, etc.
//
var FALL_DELAY = new Array(0.5, 0.45, 0.4, 0.35, 0.25, 0.2, 0.15, 0.1, 0.05);

var FAST_FALL_DELAY = 0.05;
function randomInt(low, high){
  return Math.floor(Math.random() * (high - (low - 1))) + low;
}
Sprite.extend("TitleButton",{ url: '/images/sprites/title/startGameBtn.png'});
Sprite.extend('Background',{ url: '/images/backgrounds/' + memblox.environment.themes[memblox.environment.theme] + '/bg1.jpg',
  width: memblox.options.boardWidth,
  height: memblox.options.boardHeight,
  setup : function(clock){
    console.log('/images/backgrounds/' + memblox.environment.themes[memblox.environment.theme] + '/bg1.jpg');
    this.setImage('/images/backgrounds/' + memblox.environment.themes[memblox.environment.theme] + '/bg1.jpg');
  }
});
Sprite.extend('Block',{	url: '/images/sprites/' + memblox.environment.themes[memblox.environment.theme] + '/' + randomInt(1, 16) + '.png',
        width: memblox.options.pSize,
	height: memblox.options.pSize,
	hitRect: new Rect(1, 1, memblox.options.pSize, memblox.options.pSize),
	collisions: true,
	state: 'falling',
	bumpedSide: false,
        setup: function(clock){
          this.matchNumber = randomInt(1, memblox.environment.matchSetSize);
          this.setImage("/images/sprites/" + memblox.environment.themes[memblox.environment.theme] + "/" + this.matchNumber + ".png");
        },
	logic: function(clock) {
          this.bumpedSide = false;
          this.prevX = this.x;
          this.prevY = this.y;
          if(this.flipping){
            if (this.frameX < 9){
              this.setFrameX(this.frameX + 1);
            }else{
              this.flipping = false;
            }
          }else if(this.unflipping && !this.flipping){
            if( this.frameX > 0){
              this.setFrameX(this.frameX - 1);
            }else{
              this.unflipping = false;
            }
          }
          this[ this.state ](clock);
	}
});
Block.add({
	falling: function(clock) {
		// now move the sprite, horizontal only first
		//
        var hit;
        var dir;
        if (clock % 3 == 0) { // only update key presses every so many tics
            if (Effect.Game.isKeyDown("right")) {
                hit = this.move( this.width, 0 );
                dir = -1;
            }else if(Effect.Game.isKeyDown("left")){
                hit = this.move( -this.width, 0 );
                dir = 1;
            }//else if(Effect.Game.isKeyDown("down")){
             //   this.y += 10;
            //}
        }
        if(Effect.Game.isKeyDown("down")){
            this.y += 10;
        }
		if (this.didCollideX(hit)) {
		    	this.bumpedSide = true;
			this.x = this.x + (this.width * dir) ;
		}
                var hit = this.move( 0, 1 * memblox.environment.currentLevel );
                if (this.didCollideY(hit)) {
                        // if we hit something solid, stop our vert movement
                        this.y = this.y - (1 * memblox.environment.currentLevel);
                        var splane = Effect.Port.getPlane("Blocks");
                        if(this.y >= 0){
                          memblox.environment.activeblock = splane.createSprite("Block",{x: 120, y:-40});
                        }else{
                          memblox.io.messageDisplay.write("GAME OVER SUCKA!");
                        }
                        this.state = 'stuck';
                        if (this.y > GAME_LOWER_BOUNDARY - this.height)
                            this.y = GAME_LOWER_BOUNDARY - this.height;
                }
	}
});
Block.add({
	didCollideX: function(hit) {
		return (hit && (hit.target.solid ||
		       (hit.target.type == 'Block' && hit.target.state == 'stuck'))) ||
		       this.x < GAME_LEFT_BOUNDARY ||
		       this.x > GAME_RIGHT_BOUNDARY - this.width;
	},

	didCollideY: function(hit) {
		return (hit && (hit.target.solid ||
		       (hit.target.type == 'Block' && hit.target.state == 'stuck'))) ||
		       this.y > GAME_LOWER_BOUNDARY - this.height;
	}
});

Block.add({
	stuck: function(clock) {
		var hit = this.move( 0, 1 * memblox.environment.currentLevel );
                if (this.didCollideY(hit)) {
                        // if we hit something solid, stop our vert movement
                        this.y = this.y - (1 * memblox.environment.currentLevel);
                        var splane = Effect.Port.getPlane("Blocks");
                        this.state = 'stuck';
                }
	}
});

Block.add({
  flip : function(splane){
    this.flipping = true;
    if(memblox.environment.flipped.blocks.length == 1){
        if (this.matchNumber == memblox.environment.flipped.blocks[0].matchNumber && this !== memblox.environment.flipped.blocks[0]){
          if(this == memblox.environment.activeblock || memblox.environment.flipped.blocks[0] == memblox.environment.activeblock){
            memblox.environment.activeblock = splane.createSprite("Block", {x: 120, y: -40});
          }// otherwise just use the active block that is already there, the match was done on the ground
          splane.deleteSprite(this.id);
          splane.deleteSprite(memblox.environment.flipped.blocks[0].id);
          memblox.environment.matchCount += 1;
          memblox.environment.score += 20 * memblox.environment.currentLevel;
          console.log(memblox.environment.matchCount);
        }
        memblox.environment.flipped.blocks[0].unflipping = true;
        this.unflipping = true;
        memblox.environment.flipped.blocks = [];
      }else{
        memblox.environment.flipped.blocks.push(this);
      }

      console.log(this.matchNumber);
    }
});
Effect.Game.addEventListener( 'onLoadGame',function(){
  Effect.Game.loadLevel( 'TitleScreen', function(){
  		// title screen is now loaded
		Effect.Game.clearSchedule();
		Effect.Game.setState( 'title' );
		Effect.Port.setScroll( 0, 0 );
		var splane = Effect.Port.getPlane('TitleSprites');
		splane.createSprite( StaticImageSprite, { url: '/images/sprites/title/scubed.png', x: 0, y: -150, zIndex: 3 } ).tween({
			delay: 0,
			duration: 180,
			mode: 'EaseOut',
			algorithm: 'Quintic',
			properties: {
				y: { start: -150, end: 40 }
			}
		});
        // hook mouse events for the buttons
		splane.createSprite( 'TitleButton', {
			url: '/images/sprites/title/startGameBtn.png',
			x: 340,
			y: 600,
			zIndex: 4,
			onMouseUp: function() { memblox.start_new_game(); }
		} ).tween({
			delay: 0,
			duration: 180,
			mode: 'EaseOut',
			algorithm: 'Quintic',
			properties: {
				x: { start: 340, end: 70 },
				y: { start: 600, end: 350 }
			}
		}).captureMouse();

  });

});<commit_msg>separating out title level function<commit_after>var memblox = (function(window, document, undefined) {
  if(!window.console || !console.log){
    console = {};
    console.log = alert;
  }
  // makeHud method for creating new Heads up display
  function makeHud(id, cols, rows, font, x, y, prefix, suffix){
   var thishud = (function(Port, id, cols, rows, font, x, y, prefix, suffix){
      var hud = new HUD(id);
      var lastmsg = "";
      var prefix = prefix;
      var suffix = suffix;

      hud.setFont(font);
      hud.setPosition(x, y);
      hud.setTableSize(cols, rows);
      hud.setTracking(.7, 1.2);

      Port.attach(hud);

      return {
        hud: hud,
        write: function(msg){
          var clearString = "";
          var i = cols;
          while(i--){
            clearString += " ";
          };
          hud.setString(0,0,clearString)
          lastmessage = msg;
          msg = (prefix) ? prefix + msg : msg;
          msg = (suffix) ? msg + suffix : msg;
          hud.setString(0,0,msg);
        },
        read: function(){
          return lastmsg;
        }
      };
    })(Effect.Port,id, cols, rows, font, x, y, prefix, suffix)
    return thishud;
  }

  /* randomInt
   *  @param low : the low number in the return set
   *  @param high : the high number in the return set
   */

  // EventTarget class acts as base for custom events
  var memblox = {
    objects : {
      blocks : [],
      makeHud : makeHud
    },
    options : {
      pSize:40,
      boardHeight: 480,
      boardWidth: 320,
    },
    io : {
      messageDisplay: {},
      scoreDisplay: {},
      levelDisplay: {}
    },
    events: {
      levelCleared : function(obj, level){
        if((level + 1) >= 8){
          obj.environment.currentLevel = 1;
        };
        obj.environment.currentLevel = level + 1;
        obj.environment.matchSetSize = (level + 1) * 2;
        obj.environment.matchCount = 0;
      },
      gameOver : function(obj){
        obj.active = false;
      }
    },
    actions : {
      changeTheme : function(obj, theme_number){
        if(theme_number < obj.environment.themes.length){
          obj.environment.theme = theme_number;
          //var bpanel = Effect.Game.g
        }
      }
    },
    environment: {
      player : "",
      score : 0,
      currentLevel :1,
      level : [1,2,3,4,5,6,7,8],
      flipped : {
        count : 0,
        blocks : []
      },
      matchSetSize : 3, // in level change algorithm should be currentLevel * 2
      matchCount : 0,
      topScores : [],
      players : [],
      theme : 1,
      themes : ["default","mario"],
      activeblock : null
    },
    doTitleScreen: function() {
  		// title screen is now loaded
		Effect.Game.clearSchedule();
		Effect.Game.setState( 'title' );
		Effect.Port.setScroll( 0, 0 );
		var splane = Effect.Port.getPlane('TitleSprites');
		splane.createSprite( StaticImageSprite, { url: '/images/sprites/title/scubed.png', x: 0, y: -150, zIndex: 3 } ).tween({
			delay: 0,
			duration: 180,
			mode: 'EaseOut',
			algorithm: 'Quintic',
			properties: {
				y: { start: -150, end: 40 }
			}
		});
        // hook mouse events for the buttons
		splane.createSprite( 'TitleButton', {
			url: '/images/sprites/title/startGameBtn.png',
			x: 340,
			y: 600,
			zIndex: 4,
			onMouseUp: function() { memblox.startNewGame(); }
		} ).tween({
			delay: 0,
			duration: 180,
			mode: 'EaseOut',
			algorithm: 'Quintic',
			properties: {
				x: { start: 340, end: 70 },
				y: { start: 600, end: 350 }
			}
		}).captureMouse();
        var themeNames = "Available Themes:\n"
        for (i=0; i < memblox.environment.themes.length; i++) {
            themeNames += memblox.environment.themes[i] + "\n";
        }
        alert(themeNames);
    }, // doTitleScreen
    startNewGame: function() {
		// start new game (from title screen)
		var port = Effect.Port;

		//memblox.spriteGroups = {};

		Effect.Audio.quiet();
		Effect.Game.clearSchedule();
		Effect.Game.removeAllTweens();
		Effect.Port.removeAll();
		//Effect.Port.setBackgroundColor('black');
        memblox.io.messageDisplay = memblox.objects.makeHud("message", 20, 5,
            memblox.environment.themes[memblox.environment.theme] + "Font", 20, 100, null, null);
        memblox.io.scoreDisplay =  memblox.objects.makeHud("score", 13, 1, memblox.environment.themes
            [memblox.environment.theme] + "Font", 3, 3, "Score:", null);
        memblox.io.levelDisplay =  memblox.objects.makeHud("level", 5, 1, memblox.environment.themes
            [memblox.environment.theme] + "Font", 176, 3, "Lvl:", null);
        var music = Effect.Audio.getTrack("/audio/music/" + memblox.environment.themes
            [memblox.environment.theme] + "/bg-music.mp3");
        Effect.Port.addEventListener( 'onMouseDown', function(pt, buttonIdx){
            var splane = Effect.Port.getPlane("Blocks");
            var sprite = splane.lookupSpriteFromGlobal(pt);
            if(sprite){
                sprite.flip(splane);
            }
        });
        Effect.Game.loadLevel( 'Default', function(){
            var bplane = Effect.Port.getPlane("Background");
            var backsprite = bplane.createSprite("Background");
            splane = Effect.Port.getPlane("Blocks");
            splane.createSprite("Block",{x:120, y:-40});
            splane.draw();
            music.playSound();
        });
        Effect.Game.addEventListener( 'onLogic', function(clock){
            if(memblox.environment.matchCount > memblox.environment.currentLevel * 10){
                memblox.events.levelCleared(memblox, memblox.environment.currentLevel);
            }
            memblox.io.levelDisplay.write(memblox.environment.currentLevel);
            memblox.io.scoreDisplay.write(memblox.environment.score);
        });
	}, // startNewGame
    data : (function(){
      if(openDatabase){
        var db = openDatabase("scubed", "1.0", "Scubed High Scores", "1024");
        var msg = [];
        var addScore = function(player, score){
          db.transaction(function(tx){
            tx.executeSql("INSERT INTO scubed (player, score) VALUES (?,?)",
            [player, score],
            function(tx, data){msg.push(data);},
            function(tx, e){msg.push(e);})
          })
        };
        var highScores = function(){
          db.transaction(function(tx){
            tx.executeSql("SELECT * FROM scubed ORDER BY score"),
            function(tx, data){msg.push(data);},
            function(tx, e){msg.push(e);}
          })
        };
        return {
          addScore : addScore,
          highScores: highScores,
          msg: msg
        }
      }else{
        return {};
      }
    })(),
  }
  return memblox;
})(window, window.document)

var speed = 4;
var BLOCK_HEIGHT = 40;
var BLOCK_WIDTH  = 40;
var GAME_LEFT_BOUNDARY = 0;
var GAME_RIGHT_BOUNDARY = GAME_LEFT_BOUNDARY + (BLOCK_WIDTH*8);
var GAME_UPPER_BOUNDARY = 0;
var GAME_LOWER_BOUNDARY = GAME_UPPER_BOUNDARY + (BLOCK_HEIGHT*12);

// These are the delays in secs. between block movements for each level
// index 0 is the delay for level 1, etc.
//
var FALL_DELAY = new Array(0.5, 0.45, 0.4, 0.35, 0.25, 0.2, 0.15, 0.1, 0.05);

var FAST_FALL_DELAY = 0.05;
function randomInt(low, high){
  return Math.floor(Math.random() * (high - (low - 1))) + low;
}
Sprite.extend("TitleButton",{ url: '/images/sprites/title/startGameBtn.png'});
Sprite.extend('Background',{ url: '/images/backgrounds/' + memblox.environment.themes[memblox.environment.theme] + '/bg1.jpg',
  width: memblox.options.boardWidth,
  height: memblox.options.boardHeight,
  setup : function(clock){
    console.log('/images/backgrounds/' + memblox.environment.themes[memblox.environment.theme] + '/bg1.jpg');
    this.setImage('/images/backgrounds/' + memblox.environment.themes[memblox.environment.theme] + '/bg1.jpg');
  }
});
Sprite.extend('Block',{	url: '/images/sprites/' + memblox.environment.themes[memblox.environment.theme] + '/' + randomInt(1, 16) + '.png',
        width: memblox.options.pSize,
	height: memblox.options.pSize,
	hitRect: new Rect(1, 1, memblox.options.pSize, memblox.options.pSize),
	collisions: true,
	state: 'falling',
	bumpedSide: false,
        setup: function(clock){
          this.matchNumber = randomInt(1, memblox.environment.matchSetSize);
          this.setImage("/images/sprites/" + memblox.environment.themes[memblox.environment.theme] + "/" + this.matchNumber + ".png");
        },
	logic: function(clock) {
          this.bumpedSide = false;
          this.prevX = this.x;
          this.prevY = this.y;
          if(this.flipping){
            if (this.frameX < 9){
              this.setFrameX(this.frameX + 1);
            }else{
              this.flipping = false;
            }
          }else if(this.unflipping && !this.flipping){
            if( this.frameX > 0){
              this.setFrameX(this.frameX - 1);
            }else{
              this.unflipping = false;
            }
          }
          this[ this.state ](clock);
	}
});
Block.add({
	falling: function(clock) {
		// now move the sprite, horizontal only first
		//
        var hit;
        var dir;
        if (clock % 3 == 0) { // only update key presses every so many tics
            if (Effect.Game.isKeyDown("right")) {
                hit = this.move( this.width, 0 );
                dir = -1;
            }else if(Effect.Game.isKeyDown("left")){
                hit = this.move( -this.width, 0 );
                dir = 1;
            }//else if(Effect.Game.isKeyDown("down")){
             //   this.y += 10;
            //}
        }
        if(Effect.Game.isKeyDown("down")){
            this.y += 10;
        }
		if (this.didCollideX(hit)) {
		    	this.bumpedSide = true;
			this.x = this.x + (this.width * dir) ;
		}
                var hit = this.move( 0, 1 * memblox.environment.currentLevel );
                if (this.didCollideY(hit)) {
                        // if we hit something solid, stop our vert movement
                        this.y = this.y - (1 * memblox.environment.currentLevel);
                        var splane = Effect.Port.getPlane("Blocks");
                        if(this.y >= 0){
                          memblox.environment.activeblock = splane.createSprite("Block",{x: 120, y:-40});
                        }else{
                          memblox.io.messageDisplay.write("GAME OVER SUCKA!");
                        }
                        this.state = 'stuck';
                        if (this.y > GAME_LOWER_BOUNDARY - this.height)
                            this.y = GAME_LOWER_BOUNDARY - this.height;
                }
	}
});
Block.add({
	didCollideX: function(hit) {
		return (hit && (hit.target.solid ||
		       (hit.target.type == 'Block' && hit.target.state == 'stuck'))) ||
		       this.x < GAME_LEFT_BOUNDARY ||
		       this.x > GAME_RIGHT_BOUNDARY - this.width;
	},

	didCollideY: function(hit) {
		return (hit && (hit.target.solid ||
		       (hit.target.type == 'Block' && hit.target.state == 'stuck'))) ||
		       this.y > GAME_LOWER_BOUNDARY - this.height;
	}
});

Block.add({
	stuck: function(clock) {
		var hit = this.move( 0, 1 * memblox.environment.currentLevel );
                if (this.didCollideY(hit)) {
                        // if we hit something solid, stop our vert movement
                        this.y = this.y - (1 * memblox.environment.currentLevel);
                        var splane = Effect.Port.getPlane("Blocks");
                        this.state = 'stuck';
                }
	}
});

Block.add({
  flip : function(splane){
    this.flipping = true;
    if(memblox.environment.flipped.blocks.length == 1){
        if (this.matchNumber == memblox.environment.flipped.blocks[0].matchNumber && this !== memblox.environment.flipped.blocks[0]){
          if(this == memblox.environment.activeblock || memblox.environment.flipped.blocks[0] == memblox.environment.activeblock){
            memblox.environment.activeblock = splane.createSprite("Block", {x: 120, y: -40});
          }// otherwise just use the active block that is already there, the match was done on the ground
          splane.deleteSprite(this.id);
          splane.deleteSprite(memblox.environment.flipped.blocks[0].id);
          memblox.environment.matchCount += 1;
          memblox.environment.score += 20 * memblox.environment.currentLevel;
          console.log(memblox.environment.matchCount);
        }
        memblox.environment.flipped.blocks[0].unflipping = true;
        this.unflipping = true;
        memblox.environment.flipped.blocks = [];
      }else{
        memblox.environment.flipped.blocks.push(this);
      }

      console.log(this.matchNumber);
    }
});
    Effect.Game.addEventListener( 'onLoadGame',function(){
        Effect.Game.loadLevel( 'TitleScreen', memblox.doTitleScreen );

});
<|endoftext|>


<commit_before>'use strict';
import React from 'react';
import { connect } from 'react-redux';
import Preloader from '../../components/Preloader{{#if sectionNames}}/Preloader{{/if}}';
import {setReady, setProgress} from './actions';
import TransitionGroup from 'react-transition-group-plus';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.onResize = this.onResize.bind(this);
    this.state = {
      width: 960,
      height: 570
    };
  }
  onResize() {
    this.setState({
      width: window.innerWidth,
      height: window.innerHeight
    });
  }
  componentWillMount() {
    window.addEventListener('resize',this.onResize);
    this.onResize();
  }
  componentWillUnmount() {
    window.removeEventListener('resize',this.onResize);
  }
  getContent() {
    if (this.props.ready) {
      return React.cloneElement(this.props.children, { key: this.props.section, width: this.state.width, height: this.state.height});
    } else {
      return <Preloader
        onProgress={this.props.onProgress}
        onReady={this.props.onReady}
        assets={this.props.assets}
        width={this.state.width}
        height={this.state.height}
      />
    }
  }
  render() {
    return <TransitionGroup id="app" component="div" transitionMode="out-in">
      {this.getContent()}
    </TransitionGroup>;
  }
};

const mapStateToProps = (state, ownProps) => {
  let section = ownProps.location.pathname.split('/')[1] || 'landing';
  return {
    progress: state.progress,
    ready: state.ready,
    assets: state.assets,
    section: section
  }
};

const mapDispatchToProps = (dispatch) => {
  return {
    onProgress: function(val) {
      dispatch(setProgress(val));
    },
    onReady: function(val) {
      dispatch(setReady(val));
    }
  }
};

App.defaultProps = {
  assets: [],
  progress: 0,
  ready: false
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);
<commit_msg>fix section<commit_after>'use strict';
import React from 'react';
import { connect } from 'react-redux';
import Preloader from '../../components/Preloader{{#if sectionNames}}/Preloader{{/if}}';
import {setReady, setProgress} from './actions';
import TransitionGroup from 'react-transition-group-plus';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.onResize = this.onResize.bind(this);
    this.state = {
      width: 960,
      height: 570
    };
  }
  onResize() {
    this.setState({
      width: window.innerWidth,
      height: window.innerHeight
    });
  }
  componentWillMount() {
    window.addEventListener('resize',this.onResize);
    this.onResize();
  }
  componentWillUnmount() {
    window.removeEventListener('resize',this.onResize);
  }
  getContent() {
    if (this.props.ready) {
      return React.cloneElement(this.props.children, { key: this.props.section, width: this.state.width, height: this.state.height});
    } else {
      return <Preloader
        onProgress={this.props.onProgress}
        onReady={this.props.onReady}
        assets={this.props.assets}
        width={this.state.width}
        height={this.state.height}
      />
    }
  }
  render() {
    return <TransitionGroup id="app" component="div" transitionMode="out-in">
      {this.getContent()}
    </TransitionGroup>;
  }
};

const mapStateToProps = (state, ownProps) => {
  let section = ownProps.location.pathname.split('/').filter(Boolean)[0] || 'landing';
  return {
    progress: state.progress,
    ready: state.ready,
    assets: state.assets,
    section: section
  }
};

const mapDispatchToProps = (dispatch) => {
  return {
    onProgress: function(val) {
      dispatch(setProgress(val));
    },
    onReady: function(val) {
      dispatch(setReady(val));
    }
  }
};

App.defaultProps = {
  assets: [],
  progress: 0,
  ready: false
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);
<|endoftext|>