<commit_before>// For SegWit there are two options:
// 1. Backward compatible support (e.g. for Bitcoin) using P2SH.
// 2. Native SegWit addresses using P2WPKH (e.g. for an altcoin that only supports SegWit).
//
//
// ## 1. Basic segregated witness support
// https://bitcoincore.org/en/segwit_wallet_dev/#basic-segregated-witness-support
//
// Requirements:
// - Like any other P2SH address, P2SH-P2WPKH address has prefix 3.
// - Until a P2SH-P2WPKH UTXO is spent and the redeemScript is exposed, a P2SH-P2WPKH address is indistinguishable from a non-segwit P2SH address
// - P2SH-P2WPKH addresses should be used when only 1 public key is used to receive payment (like P2PKH)
// - The public key used in P2SH-P2WPKH MUST be compressed, i.e. 33 bytes in size, and starting with a 0x02 or 0x03.
//
// To create a P2SH-P2WPKH address:
// 1. Calculate the RIPEMD160 of the SHA256 of a public key (keyhash)
// 2. The P2SH redeemScript is always 22 bytes. It starts with a OP_0, followed by a canonical push of the keyhash (i.e. 0x0014{20-byte keyhash})
// 3. Same as any other P2SH, the scriptPubKey is OP_HASH160 hash160(redeemScript) OP_EQUAL, and the address is the corresponding P2SH address with prefix 3.
//
//
// ## 2. Segwit native addresses
// https://bitcoincore.org/en/segwit_wallet_dev/#advanced-designs
//
// Native Pay-to-Witness-Public-Key-Hash (P2WPKH)
// - Native P2WPKH is a scripPubKey of 22 bytes. It starts with a OP_0, followed by a push of the keyhash (i.e. 0x0014{20-byte keyhash})
// - keyhash is RIPEMD160(SHA256) of a compressed public key.
// - When spending a native P2WPKH, the scriptSig MUST be empty

const Buffer = require('safe-buffer').Buffer
// const bitcoin = require('bitcoinjs-lib')
const OPS = require('bitcoin-ops')
const typeforce = require('typeforce')
const types = require('./types')
const { createHash } = require('./tx-decoder')
const { bufferTxid } = require('./tx-builder')
const { getHexFromBech32Address, outputScript, outputScriptWitness, createPubKeyHash } = require('./utils')
const { bufferUInt8, bufferUInt32, bufferUInt64, bufferVarSliceBuffer } = require('./buffer-build')
const { EMPTY_BUFFER, compose, prop } = require('./compose-build')
const CONSTANTS = require('./constants')

/**
 * @param {Object} options Options like sha algorithm.
 * @param {String} segwitAddress SegWit bitcoin address.
 */
// createP2shP2wpkhAddress :: Object -> String -> String
const createP2shP2wpkhAddress = options => publicKey => {
  // typeforce(types.SegWitAddress, segwitAddress)

}

// hashPrevouts :: Object -> Array<Object> -> Buffer
const hashPrevouts = options => vins => {
  const buffer = Buffer.concat(vins.map(vin => {
    return Buffer.concat([bufferTxid(vin.txid), bufferUInt32(vin.vout)])
  }))
  return createHash(options)(buffer)
}

// hashSequenceRaw :: Array<Object> -> Buffer
const hashSequenceRaw = vins => {
  return Buffer.concat(vins.map(vin => bufferUInt32(vin.sequence)))
}

// hashSequence :: Object -> Array<Object> -> Buffer
const hashSequence = options => vins => {
  const buffer = hashSequenceRaw(vins)
  return createHash(options)(buffer)
}

// inputValue :: Object -> Buffer
const inputValue = input => bufferUInt64(input.value)

// todo: should be defined  as a general payment utility (outside of this utility set).
const scriptCode = options => input => {
  // let script
  // if (input.scriptPubKey) {
  //   script = Buffer.from(input.scriptPubKey, 'hex')
  //   return bufferVarSliceBuffer(script)
  // }
  typeforce({
    address: typeforce.maybe(types.Address),
    publicKey: typeforce.maybe('String'),
    type: typeforce.value('P2WPKH')
  }, input)
  if (input.type === 'P2WPKH') {
    // For P2WPKH witness program, the scriptCode is:
    // `0x1976a914{20-byte-pubkey-hash}88ac` (bip-0143)
    let pubKeyHash
    if (input.address) {
      pubKeyHash = getHexFromBech32Address(input.address).toString('hex')
    } else if (input.publicKey) {
      const pubKeyBuffer = Buffer.from(input.publicKey, 'hex')
      pubKeyHash = createPubKeyHash(options)(pubKeyBuffer).toString('hex')
    }
    return Buffer.from(`1976a914${pubKeyHash}88ac`, 'hex')
  }
}

// serializeOutputs :: Array -> Buffer
const serializeOutputs = vouts => {
  return Buffer.concat(vouts.map(vout => {
    if (!vout.script) {
      typeforce(types.Address, vout.address)
      typeforce.oneOf(
        typeforce.value('P2PKH'), typeforce.value('P2WPKH'),
        vout.type
      )
      vout.script = vout.type === 'P2WPKH'
        ? outputScriptWitness({address: vout.address})
        : outputScript({address: vout.address})
    }
    return Buffer.concat([bufferUInt64(vout.value), bufferVarSliceBuffer(vout.script)])
  }))
}

// hashOutputs :: Object -> Array -> Buffer
const hashOutputs = options => vouts => {
  const buffer = serializeOutputs(vouts)
  return createHash(options)(buffer)
}

const hashType = input => {
  if (['P2PKH', 'P2WPKH'].indexOf(input.type) !== -1) {
    return CONSTANTS.SIGHASH_ALL
  }
  return CONSTANTS.SIGHASH_ALL
}

/*
 [Transaction Signature Verification structure](segwit.md#Transaction-Signature-Verification-for-Version-0-Witness-Program)
 Double hash of:
 1. `nVersion` of the transaction (4-byte little endian)
 2. `hashPrevouts` (32-byte hash)
 3. `hashSequence` (32-byte hash)
 4. `outpoint` (32-byte hash + 4-byte little endian)
 5. `scriptCode` of the input (serialized as scripts inside CTxOuts)
 6. `value` of the output spent by this input (8-byte little endian)
 7. `nSequence` of the input (4-byte little endian)
 8. `hashOutputs` (32-byte hash)
 9. `nLocktime` of the transaction (4-byte little endian)
 10. `sighash` type of the signature (4-byte little endian)
 */
const hashForWitnessV0 = options => input => tx => {
  const buffer = serializeWitnessV0(options)(input)(tx, EMPTY_BUFFER)
  return createHash(options)(buffer)
}

const serializeWitnessV0 = options => input => {
  typeforce(types.TxVin, input)

  return compose([
    prop('version', bufferUInt32),
    prop('vin', hashPrevouts(options)),
    prop('vin', hashSequence(options)),
    () => bufferTxid(input.txid),       // outpoint
    () => bufferUInt32(input.vout),     // outpoint
    () => scriptCode(options)(input),
    () => inputValue(input),            // amount
    () => bufferUInt32(input.sequence),
    prop('vout', hashOutputs(options)),
    prop('locktime', bufferUInt32),
    () => bufferUInt32(hashType(input))
  ])
}

module.exports = {
  createP2shP2wpkhAddress,
  hashPrevouts,
  hashSequenceRaw,
  hashSequence,
  serializeOutputs,
  hashOutputs,
  inputValue,
  scriptCode,
  serializeWitnessV0,
  hashForWitnessV0
}
<commit_msg>linting<commit_after>// For SegWit there are two options:
// 1. Backward compatible support (e.g. for Bitcoin) using P2SH.
// 2. Native SegWit addresses using P2WPKH (e.g. for an altcoin that only supports SegWit).
//
//
// ## 1. Basic segregated witness support
// https://bitcoincore.org/en/segwit_wallet_dev/#basic-segregated-witness-support
//
// Requirements:
// - Like any other P2SH address, P2SH-P2WPKH address has prefix 3.
// - Until a P2SH-P2WPKH UTXO is spent and the redeemScript is exposed, a P2SH-P2WPKH address is indistinguishable from a non-segwit P2SH address
// - P2SH-P2WPKH addresses should be used when only 1 public key is used to receive payment (like P2PKH)
// - The public key used in P2SH-P2WPKH MUST be compressed, i.e. 33 bytes in size, and starting with a 0x02 or 0x03.
//
// To create a P2SH-P2WPKH address:
// 1. Calculate the RIPEMD160 of the SHA256 of a public key (keyhash)
// 2. The P2SH redeemScript is always 22 bytes. It starts with a OP_0, followed by a canonical push of the keyhash (i.e. 0x0014{20-byte keyhash})
// 3. Same as any other P2SH, the scriptPubKey is OP_HASH160 hash160(redeemScript) OP_EQUAL, and the address is the corresponding P2SH address with prefix 3.
//
//
// ## 2. Segwit native addresses
// https://bitcoincore.org/en/segwit_wallet_dev/#advanced-designs
//
// Native Pay-to-Witness-Public-Key-Hash (P2WPKH)
// - Native P2WPKH is a scripPubKey of 22 bytes. It starts with a OP_0, followed by a push of the keyhash (i.e. 0x0014{20-byte keyhash})
// - keyhash is RIPEMD160(SHA256) of a compressed public key.
// - When spending a native P2WPKH, the scriptSig MUST be empty

const Buffer = require('safe-buffer').Buffer
// const bitcoin = require('bitcoinjs-lib')
// const OPS = require('bitcoin-ops')
const typeforce = require('typeforce')
const types = require('./types')
const { createHash } = require('./tx-decoder')
const { bufferTxid } = require('./tx-builder')
const { getHexFromBech32Address, outputScript, outputScriptWitness, createPubKeyHash } = require('./utils')
const { bufferUInt32, bufferUInt64, bufferVarSliceBuffer } = require('./buffer-build')
const { EMPTY_BUFFER, compose, prop } = require('./compose-build')
const CONSTANTS = require('./constants')

/**
 * @param {Object} options Options like sha algorithm.
 * @param {String} segwitAddress SegWit bitcoin address.
 */
// createP2shP2wpkhAddress :: Object -> String -> String
const createP2shP2wpkhAddress = options => publicKey => {
  // typeforce(types.SegWitAddress, segwitAddress)

}

// hashPrevouts :: Object -> Array<Object> -> Buffer
const hashPrevouts = options => vins => {
  const buffer = Buffer.concat(vins.map(vin => {
    return Buffer.concat([bufferTxid(vin.txid), bufferUInt32(vin.vout)])
  }))
  return createHash(options)(buffer)
}

// hashSequenceRaw :: Array<Object> -> Buffer
const hashSequenceRaw = vins => {
  return Buffer.concat(vins.map(vin => bufferUInt32(vin.sequence)))
}

// hashSequence :: Object -> Array<Object> -> Buffer
const hashSequence = options => vins => {
  const buffer = hashSequenceRaw(vins)
  return createHash(options)(buffer)
}

// inputValue :: Object -> Buffer
const inputValue = input => bufferUInt64(input.value)

// todo: should be defined  as a general payment utility (outside of this utility set).
const scriptCode = options => input => {
  // let script
  // if (input.scriptPubKey) {
  //   script = Buffer.from(input.scriptPubKey, 'hex')
  //   return bufferVarSliceBuffer(script)
  // }
  typeforce({
    address: typeforce.maybe(types.Address),
    publicKey: typeforce.maybe('String'),
    type: typeforce.value('P2WPKH')
  }, input)
  if (input.type === 'P2WPKH') {
    // For P2WPKH witness program, the scriptCode is:
    // `0x1976a914{20-byte-pubkey-hash}88ac` (bip-0143)
    let pubKeyHash
    if (input.address) {
      pubKeyHash = getHexFromBech32Address(input.address).toString('hex')
    } else if (input.publicKey) {
      const pubKeyBuffer = Buffer.from(input.publicKey, 'hex')
      pubKeyHash = createPubKeyHash(options)(pubKeyBuffer).toString('hex')
    }
    return Buffer.from(`1976a914${pubKeyHash}88ac`, 'hex')
  }
}

// serializeOutputs :: Array -> Buffer
const serializeOutputs = vouts => {
  return Buffer.concat(vouts.map(vout => {
    if (!vout.script) {
      typeforce(types.Address, vout.address)
      typeforce.oneOf(
        typeforce.value('P2PKH'), typeforce.value('P2WPKH'),
        vout.type
      )
      vout.script = vout.type === 'P2WPKH'
        ? outputScriptWitness({address: vout.address})
        : outputScript({address: vout.address})
    }
    return Buffer.concat([bufferUInt64(vout.value), bufferVarSliceBuffer(vout.script)])
  }))
}

// hashOutputs :: Object -> Array -> Buffer
const hashOutputs = options => vouts => {
  const buffer = serializeOutputs(vouts)
  return createHash(options)(buffer)
}

const hashType = input => {
  if (['P2PKH', 'P2WPKH'].indexOf(input.type) !== -1) {
    return CONSTANTS.SIGHASH_ALL
  }
  return CONSTANTS.SIGHASH_ALL
}

/*
 [Transaction Signature Verification structure](segwit.md#Transaction-Signature-Verification-for-Version-0-Witness-Program)
 Double hash of:
 1. `nVersion` of the transaction (4-byte little endian)
 2. `hashPrevouts` (32-byte hash)
 3. `hashSequence` (32-byte hash)
 4. `outpoint` (32-byte hash + 4-byte little endian)
 5. `scriptCode` of the input (serialized as scripts inside CTxOuts)
 6. `value` of the output spent by this input (8-byte little endian)
 7. `nSequence` of the input (4-byte little endian)
 8. `hashOutputs` (32-byte hash)
 9. `nLocktime` of the transaction (4-byte little endian)
 10. `sighash` type of the signature (4-byte little endian)
 */
const hashForWitnessV0 = options => input => tx => {
  const buffer = serializeWitnessV0(options)(input)(tx, EMPTY_BUFFER)
  return createHash(options)(buffer)
}

const serializeWitnessV0 = options => input => {
  typeforce(types.TxVin, input)

  return compose([
    prop('version', bufferUInt32),
    prop('vin', hashPrevouts(options)),
    prop('vin', hashSequence(options)),
    () => bufferTxid(input.txid),       // outpoint
    () => bufferUInt32(input.vout),     // outpoint
    () => scriptCode(options)(input),
    () => inputValue(input),            // amount
    () => bufferUInt32(input.sequence),
    prop('vout', hashOutputs(options)),
    prop('locktime', bufferUInt32),
    () => bufferUInt32(hashType(input))
  ])
}

module.exports = {
  createP2shP2wpkhAddress,
  hashPrevouts,
  hashSequenceRaw,
  hashSequence,
  serializeOutputs,
  hashOutputs,
  inputValue,
  scriptCode,
  serializeWitnessV0,
  hashForWitnessV0
}
<|endoftext|>


<commit_before>/*global require*/
require([
	"esri/map",
	"esri/layers/ArcGISImageServiceLayer",
	"AirspaceCalculator/ArcGisUI"
], function (Map, ArcGISImageServiceLayer, ArcGisUI) {
	var map, imageServiceUrl;

	// Define the image service URL with airport surfaces.
	imageServiceUrl = "http://hqolymgis99t/arcgis/rest/services/Airport/Airport_Surfaces_40ft_Int/ImageServer";

	// Create the map.
	map = new Map("map", {
		basemap: "streets",
		center: [-120.80566406246835, 47.41322033015946],
		zoom: 7,
		showAttribution: true
	});

	// Create the ArcGIS Airspace Calculator UI.
	var ui = new ArcGisUI(imageServiceUrl);
	ui.zoomLevel = 11;

	ui.form.addEventListener("calculation-error", function (e) {
		console.error("calculation error", e);
	});

	// Insert the UI's <form> into the "tools" div as the first element.
	var toolsDiv = document.getElementById("tools");
	toolsDiv.insertBefore(ui.form, toolsDiv.firstChild);

	// Once the map has loaded...
	map.on("load", function () {
		// Assign the AirspaceCalculator/ArcGisUI's map property.
		ui.map = map;

		ui.form.addEventListener("draw-complete", function () {
			map.setInfoWindowOnClick(true);
		});

		ui.form.addEventListener("add-from-map", function () {
			map.setInfoWindowOnClick(false);
		});

		// You can add the image service to the map, but it's not necessary for the airspace calculator to function.
		map.addLayer(new ArcGISImageServiceLayer(imageServiceUrl, {
			id: "surfaces",
			opacity: 0.5
		}));
	});
});<commit_msg>Demo now uses production img svc URL<commit_after>/*global require*/
require([
	"esri/map",
	"esri/layers/ArcGISImageServiceLayer",
	"AirspaceCalculator/ArcGisUI"
], function (Map, ArcGISImageServiceLayer, ArcGisUI) {
	var map, imageServiceUrl;

	// Define the image service URL with airport surfaces.
	imageServiceUrl = "http://data.wsdot.wa.gov/arcgis/rest/services/AirportMapApplication/AirspaceCalculatorSurface/ImageServer";

	// Create the map.
	map = new Map("map", {
		basemap: "streets",
		center: [-120.80566406246835, 47.41322033015946],
		zoom: 7,
		showAttribution: true
	});

	// Create the ArcGIS Airspace Calculator UI.
	var ui = new ArcGisUI(imageServiceUrl);
	ui.zoomLevel = 11;

	ui.form.addEventListener("calculation-error", function (e) {
		console.error("calculation error", e);
	});

	// Insert the UI's <form> into the "tools" div as the first element.
	var toolsDiv = document.getElementById("tools");
	toolsDiv.insertBefore(ui.form, toolsDiv.firstChild);

	// Once the map has loaded...
	map.on("load", function () {
		// Assign the AirspaceCalculator/ArcGisUI's map property.
		ui.map = map;

		ui.form.addEventListener("draw-complete", function () {
			map.setInfoWindowOnClick(true);
		});

		ui.form.addEventListener("add-from-map", function () {
			map.setInfoWindowOnClick(false);
		});

		// You can add the image service to the map, but it's not necessary for the airspace calculator to function.
		map.addLayer(new ArcGISImageServiceLayer(imageServiceUrl, {
			id: "surfaces",
			opacity: 0.5
		}));
	});
});<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
var src;
var srcarray = [];

function plsuccess(data){
    //console.log("Data = "+JSON.stringify(data));
    src = data[0].exportedurl;
    src = src.replace("file://localhost/","/");
    src = decodeURI(src);
    document.getElementById('playbtn').disabled = false;
    document.getElementById('delbtn').disabled = false;
    document.getElementById('delMbtn').disabled = false;
    console.log(src);
    var slen = data.length;
    console.log(slen);
    for(var i=0;i<slen;i++)
    {
        var fileurl = data[i].exportedurl;
        fileurl = fileurl.replace("file:///","/");
        fileurl = decodeURI(fileurl);
        srcarray.push(fileurl);
    }
}
function playsong()
{
    console.log("Inisde Playsong");
    my_media = new Media(src, onSuccess, onError);

    // Play audio
    my_media.play();
}

function delsong()
{
    window.plugins.iOSAudioPicker.deleteSongs(delSuccess,delError,'false',src);
}

function delmsong()
{
    window.plugins.iOSAudioPicker.deleteSongs(delSuccess,delError,'true',srcarray);
}

function delSuccess(a)
{
    console.log(JSON.stringify(a));
}
function delError(e)
{
    console.log(JSON.stringify(e));
}

// onSuccess Callback
//
function onSuccess() {
    console.log("playAudio():Audio Success");
}

// onError Callback
//
function onError(error) {
    alert('code: '    + error.code    + '\n' +
          'message: ' + error.message + '\n');
}
<commit_msg>Update index.js<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
var src;
var srcarray = [];

function plsuccess(data){
    //console.log("Data = "+JSON.stringify(data));
    src = data[0].exportedurl;
    src = src.replace("file://localhost/","/");
    src = decodeURI(src);
    document.getElementById('playbtn').disabled = false;
    document.getElementById('delbtn').disabled = false;
    document.getElementById('delMbtn').disabled = false;
    console.log(src);
    var slen = data.length;
    console.log(slen);
    for(var i=0;i<slen;i++)
    {
        var fileurl = data[i].exportedurl;
        fileurl = fileurl.replace("file:///","/");
        fileurl = decodeURI(fileurl);
        srcarray.push(fileurl);
    }
}
function playsong()
{
    console.log("Inisde Playsong");
    my_media = new Media(src, onSuccess, onError);

    // Play audio
    my_media.play();
}

function delsong()
{
    window.plugins.mediapicker.deleteSongs(delSuccess,delError,'false',src);
}

function delmsong()
{
    window.plugins.mediapicker.deleteSongs(delSuccess,delError,'true',srcarray);
}

function delSuccess(a)
{
    console.log(JSON.stringify(a));
}
function delError(e)
{
    console.log(JSON.stringify(e));
}

// onSuccess Callback
//
function onSuccess() {
    console.log("playAudio():Audio Success");
}

// onError Callback
//
function onError(error) {
    alert('code: '    + error.code    + '\n' +
          'message: ' + error.message + '\n');
}
<|endoftext|>


<commit_before>import React from 'react';
import Demo from './demo';

main();
function main() {
	let app;

	if (process.env.NODE_ENV === 'development') {
		app = document.createElement('div');
		app.setAttribute('id', 'demo');
		document.body.appendChild(app);
	} else {
		app = document.getElementById('demo');
	}

	React.render(<Demo />, app);
}
<commit_msg>Refactor: simplify main function<commit_after>import React from 'react';
import Demo from './demo';

main();
function main() {
	let app;

	app = document.createElement('div');
	app.setAttribute('id', 'demo');
	document.body.appendChild(app);

	React.render(<Demo />, app);
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

import url from 'url';
import minimist from 'minimist';
import chalk from 'chalk';
import Github from 'github';
import editor from 'editor';
import fs from 'fs';
import logUpdate from 'log-update';
import randomstring from 'randomstring';
import {spawnSync} from 'child_process';

const [command = 'list'] = process.argv.slice(2);
const option = minimist(process.argv.slice(3));
const {host, user, repo} = getUserRepo();
const token = getAccessToken(host);
const githubOption = getGithubOption(host);
const github = new Github(githubOption);
github.authenticate({token, type: 'token'});

if (command === 'list') {
  setStatusMessage('requesting issues');
  github.issues.repoIssues({user, repo}, (err, issues) => {
    if (err) {
      setErrorMessage(err);
      return;
    }
    clearStatus();
    showIssues(issues);
  });
}
else if (command === 'create') {
  getIssueMeesage((title, body) => {
    github.issues.create({user, repo, title, body}, (err, res) => {
      if (err) {
        setErrorMessage(err);
        return;
      }
      clearStatus();
      console.log(res.url);
    });
  });
}
else if (command === 'show') {
  let [number] = option._;

  if (number) {
    setStatusMessage(`requesting #${number} issue and comment`);
    github.issues.getRepoIssue({user, repo, number}, (err, issue) => {
      if (err) {
        setErrorMessage(err);
        return;
      }

      github.issues.getComments({user, repo, number}, (err, comments) => {
        if (err) {
          setErrorMessage(err);
          return;
        }
        clearStatus();
        showIssue(issue);
        showComments(number, comments);
      });
    });
  }
}

function setStatusMessage (msg) {
  logUpdate(`[${chalk.green('gic')}]`, msg);
}

function setErrorMessage (msg) {
  setStatusMessage('error');
  logUpdate.stderr(`[${chalk.red('gic')}]`, msg);
  logUpdate.stderr.done();
}

function clearStatus () {
  setStatusMessage('done');
  logUpdate.clear();
  logUpdate.done();
}

function getUserRepo () {
  setStatusMessage('getting user/repo');
  let remoteInformation = spawnSync('git', ['remote', 'show', 'origin']);
  let stdout = remoteInformation.stdout.toString().split('\n');

  let {host, user, repo} = stdout.map(line => line.trim())
    .filter(line => /^Fetch URL/.test(line))
    .map(line => {
      let origin = line.replace(/^Fetch URL: /, '');
      let {hostname, pathname} = url.parse(origin);
      let [, user, repo] = pathname.replace(/\.git$/, '').split('/');
      return {host: hostname, user, repo};
    })
    .pop() || {};

  if (!host || !user || !repo) {
    console.error(chalk.red('Miss getting Github information(host, user, repo).'));
    console.error(chalk.red('Is not git repository here?.'));
    process.exit(0);
  }

  return {host, user, repo};
}

function getAccessToken (host = 'github.com') {
  setStatusMessage('getting access token');
  const token = spawnSync('git', ['config', '--get', `gic.${host}.token`]).stdout.toString();

  if (!token || !token.length) {
    console.error(chalk.red('gic want your access token.'));
    console.error(chalk.red('$ git config --global gic.github.com.token ${YOUR ACCESSTOKEN}'));
    console.error(chalk.red('if you use Github Enterprise, set below.'));
    console.error(chalk.red('$ git config --global gic.GITHUB.ENTERPRISE.HOST.token ${YOUR ACCESSTOKEN}'));
    process.exit(0);
  }

  return token;
}

function getGithubOption (host) {
  const githubOption = {
    version: '3.0.0',
    protocol: 'https',
    timeout: 5000
  };

  if (host !== 'github.com') {
    return {host, pathPrefix: '/api/v3', ...githubOption};
  }
  return githubOption;
}

function getIssueMeesage (callback) {
  let filename = `.${randomstring.generate()}.gic`;
  editor(filename, () => {
    let message = fs.readFileSync(filename, 'utf-8');
    let [title = '', ...body] = message.split('\n');
    fs.unlinkSync(filename);
    callback(title, body.join('\n').trim());
  });
}

function showIssues (issues) {
  console.log(chalk.yellow(`${user}/${repo} has ${issues.length} issues`));

  issues.sort(compareIssue).forEach(issue => {
    let {number, title/*, user, assignee, comments*/, pull_request} = issue;
    let numberLabel = `#${number}`;
    if (pull_request) {
      numberLabel = `[${numberLabel}]`;
    }
    console.log(
      chalk.green(`  ${numberLabel}`),
      chalk.bold(title)
    );
  });
}

function compareIssue (aIssue, bIssue) {
  if (aIssue.number > bIssue.number) {
    return 1;
  }
  if (aIssue.number < bIssue.number) {
    return -1;
  }
  return 0;
}

function showIssue (issue) {
  let {/*url, */title, body} = issue;

  console.log(chalk.yellow.bold(`\n# ${title}`));
  console.log(`${body}\n`);
}

function showComments (number, comments) {
  comments.forEach(comment => {
    let {body, user} = comment;

    console.log(' ', chalk.blue(`> @${user.login}`));
    console.log(' ', `${body}`);
  });
}
<commit_msg>lightly get user/repo<commit_after>#!/usr/bin/env node

'use strict';

import url from 'url';
import minimist from 'minimist';
import chalk from 'chalk';
import Github from 'github';
import editor from 'editor';
import fs from 'fs';
import logUpdate from 'log-update';
import randomstring from 'randomstring';
import {spawnSync} from 'child_process';

const [command = 'list'] = process.argv.slice(2);
const option = minimist(process.argv.slice(3));
const {host, user, repo} = getUserRepo();
const token = getAccessToken(host);
const githubOption = getGithubOption(host);
const github = new Github(githubOption);
github.authenticate({token, type: 'token'});

if (command === 'list') {
  setStatusMessage('requesting issues');
  github.issues.repoIssues({user, repo}, (err, issues) => {
    if (err) {
      setErrorMessage(err);
      return;
    }
    clearStatus();
    showIssues(issues);
  });
}
else if (command === 'create') {
  getIssueMeesage((title, body) => {
    github.issues.create({user, repo, title, body}, (err, res) => {
      if (err) {
        setErrorMessage(err);
        return;
      }
      clearStatus();
      console.log(res.url);
    });
  });
}
else if (command === 'show') {
  let [number] = option._;

  if (number) {
    setStatusMessage(`requesting #${number} issue and comment`);
    github.issues.getRepoIssue({user, repo, number}, (err, issue) => {
      if (err) {
        setErrorMessage(err);
        return;
      }

      github.issues.getComments({user, repo, number}, (err, comments) => {
        if (err) {
          setErrorMessage(err);
          return;
        }
        clearStatus();
        showIssue(issue);
        showComments(number, comments);
      });
    });
  }
}

function setStatusMessage (msg) {
  logUpdate(`[${chalk.green('gic')}]`, msg);
}

function setErrorMessage (msg) {
  setStatusMessage('error');
  logUpdate.stderr(`[${chalk.red('gic')}]`, msg);
  logUpdate.stderr.done();
}

function clearStatus () {
  setStatusMessage('done');
  logUpdate.clear();
  logUpdate.done();
}

function getUserRepo () {
  setStatusMessage('getting user/repo');
  let origin = getOriginUrl();

  let {hostname, pathname} = url.parse(origin);
  let [, user, repo] = pathname.replace(/\.git$/, '').split('/');

  if (!hostname || !user || !repo) {
    console.error(chalk.red('Miss getting Github information(host, user, repo).'));
    console.error(chalk.red('Is not git repository here?.'));
    process.exit(0);
  }

  return {host: hostname, user, repo};
}

function getOriginUrl () {
  let localInformation = spawnSync('git', ['config', '--get', 'remote.origin.url']);
  if (localInformation.stdout.toString()) {
    return localInformation.stdout.toString();
  }

  let remoteInformation = spawnSync('git', ['remote', 'show', 'origin']);
  return remoteInformation.stdout.toString().split('\n')
    .filter(line => /^Fetch URL/.test(line))
    .map(line => line.trim().replace(/^Fetch URL: /, ''))
    .pop();
}

function getAccessToken (host = 'github.com') {
  setStatusMessage('getting access token');
  const token = spawnSync('git', ['config', '--get', `gic.${host}.token`]).stdout.toString();

  if (!token || !token.length) {
    console.error(chalk.red('gic want your access token.'));
    console.error(chalk.red('$ git config --global gic.github.com.token ${YOUR ACCESSTOKEN}'));
    console.error(chalk.red('if you use Github Enterprise, set below.'));
    console.error(chalk.red('$ git config --global gic.GITHUB.ENTERPRISE.HOST.token ${YOUR ACCESSTOKEN}'));
    process.exit(0);
  }

  return token;
}

function getGithubOption (host) {
  const githubOption = {
    version: '3.0.0',
    protocol: 'https',
    timeout: 5000
  };

  if (host !== 'github.com') {
    return {host, pathPrefix: '/api/v3', ...githubOption};
  }
  return githubOption;
}

function getIssueMeesage (callback) {
  let filename = `.${randomstring.generate()}.gic`;
  editor(filename, () => {
    let message = fs.readFileSync(filename, 'utf-8');
    let [title = '', ...body] = message.split('\n');
    fs.unlinkSync(filename);
    callback(title, body.join('\n').trim());
  });
}

function showIssues (issues) {
  console.log(chalk.yellow(`${user}/${repo} has ${issues.length} issues`));

  issues.sort(compareIssue).forEach(issue => {
    let {number, title/*, user, assignee, comments*/, pull_request} = issue;
    let numberLabel = `#${number}`;
    if (pull_request) {
      numberLabel = `[${numberLabel}]`;
    }
    console.log(
      chalk.green(`  ${numberLabel}`),
      chalk.bold(title)
    );
  });
}

function compareIssue (aIssue, bIssue) {
  if (aIssue.number > bIssue.number) {
    return 1;
  }
  if (aIssue.number < bIssue.number) {
    return -1;
  }
  return 0;
}

function showIssue (issue) {
  let {/*url, */title, body} = issue;

  console.log(chalk.yellow.bold(`\n# ${title}`));
  console.log(`${body}\n`);
}

function showComments (number, comments) {
  comments.forEach(comment => {
    let {body, user} = comment;

    console.log(' ', chalk.blue(`> @${user.login}`));
    console.log(' ', `${body}`);
  });
}
<|endoftext|>


<commit_before>var config = require('./config')

// 几个常量
var semicolon = 0x3b
var equal_sign = 0x3d
var max_size = config.get('gpp.header.max_size')

// 导出
exports.HeaderParser = HeaderParser
exports.prepend_header = prepend_header

// header_def_array:
// [] --> ;;
// [{k:v}] --> k=v;;
// [{k1:v1,k2:v2}] --> k1=v1;k2=v2;;
function prepend_header(header_def_array, chunk) {
	var header_text = array_to_header(header_def_array)
	var header_chunk = new Buffer(header_text, 'utf8')
	return Buffer.concat([header_chunk, chunk])
}

function array_to_header_chunk(array) {
	var header_text = array_to_header(array)
	var header_chunk = new Buffer(header_text, 'utf8')
	return header_chunk
}

// [] --> ;;
// [{k:v}] --> k=v;;
// [{k1:v1,k2:v2}] --> k1=v1;k2=v2;;
function array_to_header(array) {
	if (!Array.isArray(array)) {
		throw new Error('invalid argument')
	}

	array = array.map(function(obj) {
		if (typeof obj !== 'object' || obj === null) {
			throw new Error('invalid element in array')
		}

		var list = []
		for (var k in obj) {
			if (!obj.hasOwnProperty(k)) continue
			// 注意 k 中不应当含有等号或分号
			// obj[k] 中不应当含有分号
			// 但是这里不检查了
			list.push(k + '=' + obj[k])
		}
		return list.join(';')
	})

	var t = array.join(';') + ';'
	if (!/;;$/.test(t)) {
		t += ';'
	}

	return t
}

function test_array_to_header() {
	assert(array_to_header([]) === ';;')
	assert(array_to_header([{k: 'v'}]) === 'k=v;;')
	assert(array_to_header([{k1: 'v1'}, {k2: 'v2'}]) === 'k1=v1;k2=v2;;')
}

// 这个类用于持续的完成头部解析
// 由于解析是一个分块处理的过程，因此使用这个类会很方便
function HeaderParser() {
	this.status = 0				// 状态编号 0 头部尚未解析，1 头部正在解析中，2 头部已经成功解析，-1 头部解析失败
	this.header = null			// 解析成功后这里会保存解析好的 header
	this.header_chunk = null	// 需要时会把 chunk 合并起来暂存到这里
	this.tail_chunk = null		// 解析成功后这里会包含余下的 chunk
}

// 投递新的块给当前解析器，继续完成解析
HeaderParser.prototype.eat = function(chunk) {
	var self = this

	// 头部尚未解析过，这是第一块数据
	if (self.status === 0) {
		process(chunk)
	}
	// 上次数据不足，这次继续解析
	else if (self.status === 1) {
		// 先把新数据块与之前的合并
		self.header_chunk = Buffer.concat([self.header_chunk, chunk])
		// 然后处理
		process(self.header_chunk)
	}
	else {
		// 无效状态，抛出异常
		throw new Error('HeaderParser.eat() invalid status, status=' + self.status)
	}

	function process(chunk) {
		var end = detect_header_end(chunk)
		if (end < 0) {
			// 头部非法，没有找到结尾（越界）
			self.status = -1
		}
		else if (end === chunk.length) {
			// 需要更多的块
			// 我们把这一块先暂存起来
			self.status = 1
			self.header_chunk = chunk
		}
		else {
			// 解析一下
			parse(chunk, end)
		}
	}

	function parse(chunk, end) {
		// 如果真的存在 tail_chunk 就分割一下
		// 否则不需要（也不能，因为 split_chunk 的参数要求比较严格）
		if (chunk.length >= 2 && end <= chunk.length-2) {
			//console.log('<DEBUG-chunk> ' + chunk.toString('hex'))
			var tmp = split_chunk(chunk, end)
			self.header_chunk = tmp[0]
			self.tail_chunk = tmp[1]
			//console.log('<DEBUG-tmp_0> ' + tmp[0].toString('hex'))
			//console.log('<DEBUG-tmp_1> ' + tmp[1].toString('hex'))
		}
		else {
			self.header_chunk = chunk
		}
		// 转换为字符串进行解析
		try {
			var header_text = self.header_chunk.toString('utf8')
			self.header = parse_header_text(header_text)
		}
		catch (err) {
			// 失败了
			self.status = -1
			return
		}
		// 成功了
		self.status = 2
	}
}

HeaderParser.prototype.is_finished = function() {
	// 不管成功或失败都算结束
	return this.status === -1 || this.status === 2
}

HeaderParser.prototype.is_successful = function() {
	return this.status === 2
}

HeaderParser.prototype.get_header = function() {
	return this.header
}

HeaderParser.prototype.exists_tail_chunk = function() {
	return this.tail_chunk !== null
}

HeaderParser.prototype.get_tail_chunk = function() {
	return this.tail_chunk
}

// 这个函数用于解析 header 文本为对象
// 参数 text 必须以 ;; 结尾
function parse_header_text(text) {
	if (text.length < 2 || !(text[text.length-1] === ';' && text[text.length-2] === ';')) {
		throw new Error('parse_header_text(): invalid text, text=' + text)
	}

	// 以分号 ; 进行分割
	var pairs = text.split(';')
	// 移除空串
	pairs = pairs.filter(function(p) {
		return p.length > 0
	})
	// 映射成对
	pairs = pairs.map(function(p) {
		// 根据等号进行分割
		// 注意只从第一个等号出现的位置进行分割
		// 因此如果有多个等号，那么后续的等号会作为 value 部分
		var i = p.indexOf('=')
		if (i === -1) {
			// 可以没有等号
			return {
				name: p,
				value: ''
			}
		}
		else {
			return {
				name: p.substring(0, i),
				value: p.substring(i+1)
			}
		}
	})
	// 组成 object
	var header = {}
	pairs.forEach(function(p) {
		// name 统一转成小写便于处理
		header[p.name.toLowerCase()] = p.value
	})
	// 返回结果
	return validate(header)

	function validate(header) {
		if (!header.pv) {
			throw new Error('invalid header, pv not found')
		}
		else {
			return header
		}
	}
}

// 将一个 chunk 从指定位置 i 处分为两个 chunk
// 其中 i 处的字节属于前一个 chunk
// 注意 chunk 至少要有 2 个字节
// 另外 i 的范围为 [0, chunk.length-2]
function split_chunk(chunk, i) {
	if (chunk.length < 2) {
		throw new Error('split_chunk(): can not split cause chunk.length < 2. chunk.length=' + chunk.length)
	}
	if (i < 0 || i > chunk.length-2) {
		throw new Error('split_chunk(): invalid range, i must be [0, chunk.length-2]. chunk.length=' + chunk.length + ', i=' + i)
	}
	return [chunk.slice(0, i+1), chunk.slice(i+1)]
}

// 这个函数用于判断 header 结尾位置
// 方法是寻找双分号 ;; 位置
// 搜寻时会遵循 config 中 gpp.header.max_size  中的限制
// 返回值：
// -1 代表已经越界，但仍然未找到结尾位置
// n < chunk.length 代表检测成功，n 为双分号中最后一个分号的下标位置
// n === chunk.length 代表未找到结尾位置，也许在结尾在后续块中
function detect_header_end(chunk) {
	for (var i = 0; i < chunk.length; ++i) {
		// 检查是否越界
		if (i >= max_size) {
			// 越界了
			return -1
		}
		// 判断是否有连分号
		if (chunk[i] === semicolon && (i+1) < chunk.length && chunk[i+1] === semicolon) {
			// 找到了
			return (i+1)
		}
	}
	// 未找到结尾位置，也许在后续块中
	return chunk.length
}

function test_detect_header_end() {
	assert(detect_header_end(new Buffer('')) === 0)
	assert(detect_header_end(new Buffer('a')) === 1)
	assert(detect_header_end(new Buffer('aaaaaaaaaaa')) === 'aaaaaaaaaaa'.length)
	assert(detect_header_end(new Buffer(';')) === 1)
	assert(detect_header_end(new Buffer(';;')) === 1)
	assert(detect_header_end(new Buffer('a;;')) === 2)
	assert(detect_header_end(new Buffer('a;;;')) === 2)
	assert(detect_header_end(new Buffer('a;;b')) === 2)
	assert(detect_header_end(new Buffer('a;;bbbbb')) === 2)
	return true
}

function assert(v) {
	if (!v) {
		throw new Error('assert failed')
	}
}

//console.log('test_detect_header_end:', test_detect_header_end())<commit_msg>漏导出一个函数了<commit_after>var config = require('./config')

// 几个常量
var semicolon = 0x3b
var equal_sign = 0x3d
var max_size = config.get('gpp.header.max_size')

// 导出
exports.HeaderParser = HeaderParser
exports.prepend_header = prepend_header
exports.array_to_header_chunk = array_to_header_chunk

// header_def_array:
// [] --> ;;
// [{k:v}] --> k=v;;
// [{k1:v1,k2:v2}] --> k1=v1;k2=v2;;
function prepend_header(header_def_array, chunk) {
	var header_text = array_to_header(header_def_array)
	var header_chunk = new Buffer(header_text, 'utf8')
	return Buffer.concat([header_chunk, chunk])
}

function array_to_header_chunk(array) {
	var header_text = array_to_header(array)
	var header_chunk = new Buffer(header_text, 'utf8')
	return header_chunk
}

// [] --> ;;
// [{k:v}] --> k=v;;
// [{k1:v1,k2:v2}] --> k1=v1;k2=v2;;
function array_to_header(array) {
	if (!Array.isArray(array)) {
		throw new Error('invalid argument')
	}

	array = array.map(function(obj) {
		if (typeof obj !== 'object' || obj === null) {
			throw new Error('invalid element in array')
		}

		var list = []
		for (var k in obj) {
			if (!obj.hasOwnProperty(k)) continue
			// 注意 k 中不应当含有等号或分号
			// obj[k] 中不应当含有分号
			// 但是这里不检查了
			list.push(k + '=' + obj[k])
		}
		return list.join(';')
	})

	var t = array.join(';') + ';'
	if (!/;;$/.test(t)) {
		t += ';'
	}

	return t
}

function test_array_to_header() {
	assert(array_to_header([]) === ';;')
	assert(array_to_header([{k: 'v'}]) === 'k=v;;')
	assert(array_to_header([{k1: 'v1'}, {k2: 'v2'}]) === 'k1=v1;k2=v2;;')
}

// 这个类用于持续的完成头部解析
// 由于解析是一个分块处理的过程，因此使用这个类会很方便
function HeaderParser() {
	this.status = 0				// 状态编号 0 头部尚未解析，1 头部正在解析中，2 头部已经成功解析，-1 头部解析失败
	this.header = null			// 解析成功后这里会保存解析好的 header
	this.header_chunk = null	// 需要时会把 chunk 合并起来暂存到这里
	this.tail_chunk = null		// 解析成功后这里会包含余下的 chunk
}

// 投递新的块给当前解析器，继续完成解析
HeaderParser.prototype.eat = function(chunk) {
	var self = this

	// 头部尚未解析过，这是第一块数据
	if (self.status === 0) {
		process(chunk)
	}
	// 上次数据不足，这次继续解析
	else if (self.status === 1) {
		// 先把新数据块与之前的合并
		self.header_chunk = Buffer.concat([self.header_chunk, chunk])
		// 然后处理
		process(self.header_chunk)
	}
	else {
		// 无效状态，抛出异常
		throw new Error('HeaderParser.eat() invalid status, status=' + self.status)
	}

	function process(chunk) {
		var end = detect_header_end(chunk)
		if (end < 0) {
			// 头部非法，没有找到结尾（越界）
			self.status = -1
		}
		else if (end === chunk.length) {
			// 需要更多的块
			// 我们把这一块先暂存起来
			self.status = 1
			self.header_chunk = chunk
		}
		else {
			// 解析一下
			parse(chunk, end)
		}
	}

	function parse(chunk, end) {
		// 如果真的存在 tail_chunk 就分割一下
		// 否则不需要（也不能，因为 split_chunk 的参数要求比较严格）
		if (chunk.length >= 2 && end <= chunk.length-2) {
			//console.log('<DEBUG-chunk> ' + chunk.toString('hex'))
			var tmp = split_chunk(chunk, end)
			self.header_chunk = tmp[0]
			self.tail_chunk = tmp[1]
			//console.log('<DEBUG-tmp_0> ' + tmp[0].toString('hex'))
			//console.log('<DEBUG-tmp_1> ' + tmp[1].toString('hex'))
		}
		else {
			self.header_chunk = chunk
		}
		// 转换为字符串进行解析
		try {
			var header_text = self.header_chunk.toString('utf8')
			self.header = parse_header_text(header_text)
		}
		catch (err) {
			// 失败了
			self.status = -1
			return
		}
		// 成功了
		self.status = 2
	}
}

HeaderParser.prototype.is_finished = function() {
	// 不管成功或失败都算结束
	return this.status === -1 || this.status === 2
}

HeaderParser.prototype.is_successful = function() {
	return this.status === 2
}

HeaderParser.prototype.get_header = function() {
	return this.header
}

HeaderParser.prototype.exists_tail_chunk = function() {
	return this.tail_chunk !== null
}

HeaderParser.prototype.get_tail_chunk = function() {
	return this.tail_chunk
}

// 这个函数用于解析 header 文本为对象
// 参数 text 必须以 ;; 结尾
function parse_header_text(text) {
	if (text.length < 2 || !(text[text.length-1] === ';' && text[text.length-2] === ';')) {
		throw new Error('parse_header_text(): invalid text, text=' + text)
	}

	// 以分号 ; 进行分割
	var pairs = text.split(';')
	// 移除空串
	pairs = pairs.filter(function(p) {
		return p.length > 0
	})
	// 映射成对
	pairs = pairs.map(function(p) {
		// 根据等号进行分割
		// 注意只从第一个等号出现的位置进行分割
		// 因此如果有多个等号，那么后续的等号会作为 value 部分
		var i = p.indexOf('=')
		if (i === -1) {
			// 可以没有等号
			return {
				name: p,
				value: ''
			}
		}
		else {
			return {
				name: p.substring(0, i),
				value: p.substring(i+1)
			}
		}
	})
	// 组成 object
	var header = {}
	pairs.forEach(function(p) {
		// name 统一转成小写便于处理
		header[p.name.toLowerCase()] = p.value
	})
	// 返回结果
	return validate(header)

	function validate(header) {
		if (!header.pv) {
			throw new Error('invalid header, pv not found')
		}
		else {
			return header
		}
	}
}

// 将一个 chunk 从指定位置 i 处分为两个 chunk
// 其中 i 处的字节属于前一个 chunk
// 注意 chunk 至少要有 2 个字节
// 另外 i 的范围为 [0, chunk.length-2]
function split_chunk(chunk, i) {
	if (chunk.length < 2) {
		throw new Error('split_chunk(): can not split cause chunk.length < 2. chunk.length=' + chunk.length)
	}
	if (i < 0 || i > chunk.length-2) {
		throw new Error('split_chunk(): invalid range, i must be [0, chunk.length-2]. chunk.length=' + chunk.length + ', i=' + i)
	}
	return [chunk.slice(0, i+1), chunk.slice(i+1)]
}

// 这个函数用于判断 header 结尾位置
// 方法是寻找双分号 ;; 位置
// 搜寻时会遵循 config 中 gpp.header.max_size  中的限制
// 返回值：
// -1 代表已经越界，但仍然未找到结尾位置
// n < chunk.length 代表检测成功，n 为双分号中最后一个分号的下标位置
// n === chunk.length 代表未找到结尾位置，也许在结尾在后续块中
function detect_header_end(chunk) {
	for (var i = 0; i < chunk.length; ++i) {
		// 检查是否越界
		if (i >= max_size) {
			// 越界了
			return -1
		}
		// 判断是否有连分号
		if (chunk[i] === semicolon && (i+1) < chunk.length && chunk[i+1] === semicolon) {
			// 找到了
			return (i+1)
		}
	}
	// 未找到结尾位置，也许在后续块中
	return chunk.length
}

function test_detect_header_end() {
	assert(detect_header_end(new Buffer('')) === 0)
	assert(detect_header_end(new Buffer('a')) === 1)
	assert(detect_header_end(new Buffer('aaaaaaaaaaa')) === 'aaaaaaaaaaa'.length)
	assert(detect_header_end(new Buffer(';')) === 1)
	assert(detect_header_end(new Buffer(';;')) === 1)
	assert(detect_header_end(new Buffer('a;;')) === 2)
	assert(detect_header_end(new Buffer('a;;;')) === 2)
	assert(detect_header_end(new Buffer('a;;b')) === 2)
	assert(detect_header_end(new Buffer('a;;bbbbb')) === 2)
	return true
}

function assert(v) {
	if (!v) {
		throw new Error('assert failed')
	}
}

//console.log('test_detect_header_end:', test_detect_header_end())<|endoftext|>


<commit_before>import { ConsoleStyle as Style } from "package:zencmd";
import { parse } from "package:esparse";
import { translate } from "Translator.js";
import { isPackageURI, locatePackage } from "PackageLocator.js";

var FS = require("fs"),
    REPL = require("repl"),
    VM = require("vm"),
    Path = require("path"),
    Util = require("util"),
    Module = module.constructor,
    global = this;

export function formatSyntaxError(e, filename) {

    var msg = e.message,
        text = e.sourceText;

    if (filename === void 0 && e.filename !== void 0)
        filename = e.filename;

    if (filename)
        msg += `\n    ${filename}:${e.line}`;

    if (e.lineOffset < text.length) {

        var code = "\n\n" +
            text.slice(e.lineOffset, e.startOffset) +
            Style.bold(Style.red(text.slice(e.startOffset, e.endOffset))) +
            text.slice(e.endOffset, text.indexOf("\n", e.endOffset)) +
            "\n";

        msg += code.replace(/\n/g, "\n    ");
    }

    return msg;
}

function addExtension() {

    var resolveFilename = Module._resolveFilename;

    Module._resolveFilename = (filename, parent) => {

        if (isPackageURI(filename))
            filename = locatePackage(filename, Path.dirname(parent.filename));

        return resolveFilename(filename, parent);
    };

    // Compile ES6 js files
    require.extensions[".js"] = (module, filename) => {

        var text, source;

        try {

            text = source = FS.readFileSync(filename, "utf8");

            // Only translate as a module if the source module is requesting
            // via import syntax
            var m = !!module.parent.__es6;

            text = translate(text, { wrap: m, module: m });

        } catch (e) {

            if (e instanceof SyntaxError)
                e = new SyntaxError(formatSyntaxError(e, filename));

            throw e;
        }

        return module._compile(text, filename);
    };
}

export function runModule(path) {

    addExtension();

    var path = Path.resolve(process.cwd(), path),
        stat;

    try { stat = FS.statSync(path) }
    catch (x) {}

    if (stat && stat.isDirectory())
        path = Path.join(path, "main.js");

    // "__load" is defined in the module wrapper and ensures that the
    // target is loaded as a module

    var m = __load(path);

    if (m && typeof m.main === "function") {

        var result = m.main(process.argv);
        Promise.resolve(result).then(null, x => setTimeout($=> { throw x }, 0));
    }
}

export function startREPL() {

    addExtension();

    console.log(`es6now ${ _es6now.version } (Node ${ process.version })`);

    // Provide a way to load a module from the REPL
    global.loadModule = path => __load(global.require.resolve(path));

    var prompt = ">>> ", contPrompt = "... ";

    var repl = REPL.start({

        prompt,

        useGlobal: true,

        eval(input, context, filename, cb) {

            var text, result, script, displayErrors = false;

            // Node 0.10.x pessimistically wraps all input in parens and then
            // re-evaluates function expressions as function declarations.  Since
            // Node is unaware of class declarations, this causes classes to
            // always be interpreted as expressions in the REPL.

            // Remove wrapping parens for function and class declaration forms
            if (/^\((class|function\*?)\s[\s\S]*?\n\)$/.test(input))
                input = input.slice(1, -1);

            try {

                text = translate(input, { module: false });

            } catch (x) {

                // Regenerate syntax error to eliminate parser stack
                if (x instanceof SyntaxError)
                    x = new SyntaxError(x.message);

                return cb(x);
            }

            try {

                script = VM.createScript(text, { filename, displayErrors });

                result = repl.useGlobal ?
                    script.runInThisContext({ displayErrors }) :
                    script.runInContext(context, { displayErrors });

            } catch (x) {

                return cb(x);
            }

            if (result instanceof Promise) {

                // Without displayPrompt, asynchronously calling the "eval"
                // callback results in no text being displayed on the screen.

                result
                .then(x => cb(null, x), err => cb(err, null))
                .then($=> this.displayPrompt());

            } else {

                cb(null, result);
            }
        }
    });

    // Override displayPrompt so that ellipses are displayed for
    // cross-line continuations

    if (typeof repl.displayPrompt === "function" &&
        typeof repl._prompt === "string") {

        var displayPrompt = repl.displayPrompt;

        repl.displayPrompt = function(preserveCursor) {

            this._prompt = this.bufferedCommand ? contPrompt : prompt;
            return displayPrompt.call(this, preserveCursor);
        };
    }

    function parseAction(input, module) {

        var text, ast;

        try {

            ast = parse(input, { module });
            text = Util.inspect(ast, { colors: true, depth: 10 });

        } catch (x) {

            text = x instanceof SyntaxError ?
                formatSyntaxError(x, "REPL") :
                x.toString();
        }

        console.log(text);
    }

    if (typeof repl.defineCommand === "function") {

        repl.defineCommand("translate", {

            help: "Translate ES6 to ES5",

            action(input) {

                var text;

                try {

                    text = translate(input, { wrap: false, module: false });

                } catch (x) {

                    text = x instanceof SyntaxError ?
                        formatSyntaxError(x, "REPL") :
                        x.toString();
                }

                console.log(text);

                this.displayPrompt();
            }
        });

        repl.defineCommand("parse", {

            help: "Parse a script",

            action(input) {

                parseAction(input, false);
                this.displayPrompt();
            }

        });

        repl.defineCommand("parseModule", {

            help: "Parse a module",

            action(input) {

                parseAction(input, true);
                this.displayPrompt();
            }

        });
    }

}
<commit_msg>Only remove parens from REPL input for Node v0.10.x.<commit_after>import { ConsoleStyle as Style } from "package:zencmd";
import { parse } from "package:esparse";
import { translate } from "Translator.js";
import { isPackageURI, locatePackage } from "PackageLocator.js";

var FS = require("fs"),
    REPL = require("repl"),
    VM = require("vm"),
    Path = require("path"),
    Util = require("util"),
    Module = module.constructor,
    global = this;

export function formatSyntaxError(e, filename) {

    var msg = e.message,
        text = e.sourceText;

    if (filename === void 0 && e.filename !== void 0)
        filename = e.filename;

    if (filename)
        msg += `\n    ${filename}:${e.line}`;

    if (e.lineOffset < text.length) {

        var code = "\n\n" +
            text.slice(e.lineOffset, e.startOffset) +
            Style.bold(Style.red(text.slice(e.startOffset, e.endOffset))) +
            text.slice(e.endOffset, text.indexOf("\n", e.endOffset)) +
            "\n";

        msg += code.replace(/\n/g, "\n    ");
    }

    return msg;
}

function addExtension() {

    var resolveFilename = Module._resolveFilename;

    Module._resolveFilename = (filename, parent) => {

        if (isPackageURI(filename))
            filename = locatePackage(filename, Path.dirname(parent.filename));

        return resolveFilename(filename, parent);
    };

    // Compile ES6 js files
    require.extensions[".js"] = (module, filename) => {

        var text, source;

        try {

            text = source = FS.readFileSync(filename, "utf8");

            // Only translate as a module if the source module is requesting
            // via import syntax
            var m = !!module.parent.__es6;

            text = translate(text, { wrap: m, module: m });

        } catch (e) {

            if (e instanceof SyntaxError)
                e = new SyntaxError(formatSyntaxError(e, filename));

            throw e;
        }

        return module._compile(text, filename);
    };
}

export function runModule(path) {

    addExtension();

    var path = Path.resolve(process.cwd(), path),
        stat;

    try { stat = FS.statSync(path) }
    catch (x) {}

    if (stat && stat.isDirectory())
        path = Path.join(path, "main.js");

    // "__load" is defined in the module wrapper and ensures that the
    // target is loaded as a module

    var m = __load(path);

    if (m && typeof m.main === "function") {

        var result = m.main(process.argv);
        Promise.resolve(result).then(null, x => setTimeout($=> { throw x }, 0));
    }
}

export function startREPL() {

    // Node 0.10.x pessimistically wraps all input in parens and then
    // re-evaluates function expressions as function declarations.  Since
    // Node is unaware of class declarations, this causes classes to
    // always be interpreted as expressions in the REPL.
    var removeParens = global.process.version.startsWith("v0.10.");

    addExtension();

    console.log(`es6now ${ _es6now.version } (Node ${ process.version })`);

    // Provide a way to load a module from the REPL
    global.loadModule = path => __load(global.require.resolve(path));

    var prompt = ">>> ", contPrompt = "... ";

    var repl = REPL.start({

        prompt,

        useGlobal: true,

        eval(input, context, filename, cb) {

            var text, result, script, displayErrors = false;

            // Remove wrapping parens for function and class declaration forms
            if (removeParens && /^\((class|function\*?)\s[\s\S]*?\n\)$/.test(input))
                input = input.slice(1, -1);

            try {

                text = translate(input, { module: false });

            } catch (x) {

                // Regenerate syntax error to eliminate parser stack
                if (x instanceof SyntaxError)
                    x = new SyntaxError(x.message);

                return cb(x);
            }

            try {

                script = VM.createScript(text, { filename, displayErrors });

                result = repl.useGlobal ?
                    script.runInThisContext({ displayErrors }) :
                    script.runInContext(context, { displayErrors });

            } catch (x) {

                return cb(x);
            }

            if (result instanceof Promise) {

                // Without displayPrompt, asynchronously calling the "eval"
                // callback results in no text being displayed on the screen.

                result
                .then(x => cb(null, x), err => cb(err, null))
                .then($=> this.displayPrompt());

            } else {

                cb(null, result);
            }
        }
    });

    // Override displayPrompt so that ellipses are displayed for
    // cross-line continuations

    if (typeof repl.displayPrompt === "function" &&
        typeof repl._prompt === "string") {

        var displayPrompt = repl.displayPrompt;

        repl.displayPrompt = function(preserveCursor) {

            this._prompt = this.bufferedCommand ? contPrompt : prompt;
            return displayPrompt.call(this, preserveCursor);
        };
    }

    function parseAction(input, module) {

        var text, ast;

        try {

            ast = parse(input, { module });
            text = Util.inspect(ast, { colors: true, depth: 10 });

        } catch (x) {

            text = x instanceof SyntaxError ?
                formatSyntaxError(x, "REPL") :
                x.toString();
        }

        console.log(text);
    }

    if (typeof repl.defineCommand === "function") {

        repl.defineCommand("translate", {

            help: "Translate ES6 to ES5",

            action(input) {

                var text;

                try {

                    text = translate(input, { wrap: false, module: false });

                } catch (x) {

                    text = x instanceof SyntaxError ?
                        formatSyntaxError(x, "REPL") :
                        x.toString();
                }

                console.log(text);

                this.displayPrompt();
            }
        });

        repl.defineCommand("parse", {

            help: "Parse a script",

            action(input) {

                parseAction(input, false);
                this.displayPrompt();
            }

        });

        repl.defineCommand("parseModule", {

            help: "Parse a module",

            action(input) {

                parseAction(input, true);
                this.displayPrompt();
            }

        });
    }

}
<|endoftext|>


<commit_before>/*
 * @license MIT License
 *
 * Copyright (c) 2015 Tetsuharu OHZEKI <saneyuki.snyk@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

var OptionTProto = Object.freeze({
    /**
     *  Return whether this is `Some<T>` or not.
     *
     *  @template   T
     *  @return {boolean}
     */
    get isSome() {
        return this.is_some;
    },

    /**
     *  Returns the inner `T` of a `Some<T>`.
     *
     *  @template   T
     *
     *  @return {T}
     *  @throws {Error}
     *      Throws if the self value equals `None`.
     */
    unwrap: function OptionTUnwrap() {
        if (!this.is_some) {
            throw new Error('called `unwrap()` on a `None` value');
        }

        return this.value;
    },

    /**
     *  Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
     *
     *  @template   T, U
     *
     *  @param  {function(T):U}    fn
     *  @return {Option<U>}
     */
    map: function OptionTMap(fn) {
        if (!this.is_some) {
            // cheat to escape from a needless allocation.
            return this;
        }

        var value = fn(this.value);
        var option = new Some(value);
        return option;
    },

    /**
     *  Returns `None` if the self is `None`,
     *  otherwise calls `fn` with the wrapped value and returns the result.
     *
     *  @template   T, U
     *
     *  @param  {function(T): Option<U>}    fn
     *  @return {Option<U>}
     */
    flatMap: function OptionTFlatMap(fn) {
        if (!this.is_some) {
            // cheat to escape from a needless allocation.
            return this;
        }

        var mapped = fn(this.value);
        var isOption = (mapped instanceof Some || mapped instanceof None);
        if (!isOption) {
            throw new Error('Option<T>.flatMap()\' param `fn` should return `Option<T>`.');
        }

        return mapped;
    },

    /**
     *  The alias of `Option<T>.flatMap()`.
     *
     *  @template   T, U
     *
     *  @param  {function(T): Option<U>}    fn
     *  @return {Option<U>}
     */
    andThen: function OptionTAndThen(fn) {
        return this.flatMap(fn);
    },

    /**
     *  Returns `None` if the self is `None`, otherwise returns `optb`.
     *
     *  @template   T, U
     *
     *  @param  {Option<U>} optb
     *  @return {Option<U>}
     */
    and: function OptionTAnd(optb) {
        if (!this.is_some) {
            return this;
        }
        else {
            return optb;
        }
    },

    /**
     *  Returns the self if it contains a value, otherwise returns `optb`.
     *
     *  @template   T
     *
     *  @param  {Option<T>} optb
     *  @return {Option<T>}
     */
    or: function OptionTOr(optb) {
        if (this.is_some) {
            return this;
        }
        else {
            return optb;
        }
    },

    /**
     *  Returns the self if it contains a value,
     *  otherwise calls `fn` and returns the result.
     *
     *  @template   T
     *
     *  @param  {function(): Option<T>} fn
     *  @return {Option<T>}
     */
    orElse: function OptionTOr(fn) {
        if (this.is_some) {
            return this;
        }
        else {
            var value = fn();
            if (value instanceof Some || value instanceof None) {
                return value;
            }

            throw new Error('Option<T>.orElse()\' param `fn` should return `Option<T>`.');

        }
    },

    /**
     *  Finalize the self.
     *  After this is called, the object's behavior is not defined.
     *
     *  @return {void}
     */
    drop: function OptionTDrop() {
        this.value = null;
        Object.freeze(this);
    },
});

/**
 *  @constructor
 *  @template   T
 *
 *  A base object of `Option<T>`.
 *  This is only used to `option instanceof OptionT`
 *  in an language environment which does not have an interface type system.
 *
 *  The usecase example is a `React.PropTypes.
 */
var OptionT = function OptionTBase() {};
OptionT.prototype = OptionTProto;

/**
 *  @constructor
 *  @template   T
 *
 *  @param  {T}   val
 */
var Some = function OptionTSome(val) {
    /* eslint-disable camelcase */
    /**
     *  @private
     *  @type   {boolean}
     */
    this.is_some = true;
    /* eslint-enable */

    /**
     *  @private
     *  @type   {T}
     */
    this.value = val;
    Object.seal(this);
};
Some.prototype = new OptionT();

/**
 *  @constructor
 *  @template   T
 */
var None = function OptionTNone() {
    /* eslint-disable camelcase */
    /**
     *  @private
     *  @type   {boolean}
     */
    this.is_some = false;
    /* eslint-enable */

    /**
     *  @private
     *  @type   {T}
     */
    this.value = undefined;
    Object.seal(this);
};
None.prototype = new OptionT();

module.exports = {
    Some: Some,
    None: None,
    OptionT: OptionT,
};
<commit_msg>Format defenition position.<commit_after>/*
 * @license MIT License
 *
 * Copyright (c) 2015 Tetsuharu OHZEKI <saneyuki.snyk@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

/**
 *  @constructor
 *  @template   T
 *
 *  A base object of `Option<T>`.
 *  This is only used to `option instanceof OptionT`
 *  in an language environment which does not have an interface type system.
 *
 *  The usecase example is a `React.PropTypes.
 */
var OptionT = function OptionTBase() {};
OptionT.prototype = Object.freeze({
    /**
     *  Return whether this is `Some<T>` or not.
     *
     *  @template   T
     *  @return {boolean}
     */
    get isSome() {
        return this.is_some;
    },

    /**
     *  Returns the inner `T` of a `Some<T>`.
     *
     *  @template   T
     *
     *  @return {T}
     *  @throws {Error}
     *      Throws if the self value equals `None`.
     */
    unwrap: function OptionTUnwrap() {
        if (!this.is_some) {
            throw new Error('called `unwrap()` on a `None` value');
        }

        return this.value;
    },

    /**
     *  Maps an `Option<T>` to `Option<U>` by applying a function to a contained value.
     *
     *  @template   T, U
     *
     *  @param  {function(T):U}    fn
     *  @return {Option<U>}
     */
    map: function OptionTMap(fn) {
        if (!this.is_some) {
            // cheat to escape from a needless allocation.
            return this;
        }

        var value = fn(this.value);
        var option = new Some(value);
        return option;
    },

    /**
     *  Returns `None` if the self is `None`,
     *  otherwise calls `fn` with the wrapped value and returns the result.
     *
     *  @template   T, U
     *
     *  @param  {function(T): Option<U>}    fn
     *  @return {Option<U>}
     */
    flatMap: function OptionTFlatMap(fn) {
        if (!this.is_some) {
            // cheat to escape from a needless allocation.
            return this;
        }

        var mapped = fn(this.value);
        var isOption = (mapped instanceof Some || mapped instanceof None);
        if (!isOption) {
            throw new Error('Option<T>.flatMap()\' param `fn` should return `Option<T>`.');
        }

        return mapped;
    },

    /**
     *  The alias of `Option<T>.flatMap()`.
     *
     *  @template   T, U
     *
     *  @param  {function(T): Option<U>}    fn
     *  @return {Option<U>}
     */
    andThen: function OptionTAndThen(fn) {
        return this.flatMap(fn);
    },

    /**
     *  Returns `None` if the self is `None`, otherwise returns `optb`.
     *
     *  @template   T, U
     *
     *  @param  {Option<U>} optb
     *  @return {Option<U>}
     */
    and: function OptionTAnd(optb) {
        if (!this.is_some) {
            return this;
        }
        else {
            return optb;
        }
    },

    /**
     *  Returns the self if it contains a value, otherwise returns `optb`.
     *
     *  @template   T
     *
     *  @param  {Option<T>} optb
     *  @return {Option<T>}
     */
    or: function OptionTOr(optb) {
        if (this.is_some) {
            return this;
        }
        else {
            return optb;
        }
    },

    /**
     *  Returns the self if it contains a value,
     *  otherwise calls `fn` and returns the result.
     *
     *  @template   T
     *
     *  @param  {function(): Option<T>} fn
     *  @return {Option<T>}
     */
    orElse: function OptionTOr(fn) {
        if (this.is_some) {
            return this;
        }
        else {
            var value = fn();
            if (value instanceof Some || value instanceof None) {
                return value;
            }

            throw new Error('Option<T>.orElse()\' param `fn` should return `Option<T>`.');

        }
    },

    /**
     *  Finalize the self.
     *  After this is called, the object's behavior is not defined.
     *
     *  @return {void}
     */
    drop: function OptionTDrop() {
        this.value = null;
        Object.freeze(this);
    },
});

/**
 *  @constructor
 *  @template   T
 *
 *  @param  {T}   val
 */
var Some = function OptionTSome(val) {
    /* eslint-disable camelcase */
    /**
     *  @private
     *  @type   {boolean}
     */
    this.is_some = true;
    /* eslint-enable */

    /**
     *  @private
     *  @type   {T}
     */
    this.value = val;
    Object.seal(this);
};
Some.prototype = new OptionT();

/**
 *  @constructor
 *  @template   T
 */
var None = function OptionTNone() {
    /* eslint-disable camelcase */
    /**
     *  @private
     *  @type   {boolean}
     */
    this.is_some = false;
    /* eslint-enable */

    /**
     *  @private
     *  @type   {T}
     */
    this.value = undefined;
    Object.seal(this);
};
None.prototype = new OptionT();

module.exports = {
    Some: Some,
    None: None,
    OptionT: OptionT,
};
<|endoftext|>


<commit_before>var process = require('process');
var objectAssign = require('object-assign');
var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var watchify = require('watchify');
var nodemon = require('nodemon');
var del = require('del');
var paths = require('vinyl-paths');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var clean = function(){ return paths( del ); };
var notifier = require('node-notifier');
var $ = require('gulp-load-plugins')();
var runSequence = require('run-sequence');
var pkg = require('./package.json');
var path = require('path');
var through = require('through');
var streamNop = through;
var fs = require('fs');
var nopTarget = function( next ){ next(); }

process.on('SIGINT', function() {
  setTimeout(function() {
    $.util.log($.util.colors.red('Successfully closed gulp process ' + process.pid));
    process.exit(1);
  }, 500);
});

{{#clientOnly}}
var deps = Object.keys( pkg.dependencies ).concat('babel-polyfill');
{{/clientOnly}}

{{#lib}}
var deps = Object.keys( pkg.dependencies ).concat('babel-polyfill');
{{/lib}}

{{#server}}
var deps = pkg.bundledDependencies || [];
{{/server}}

var emptyTask = function( next ){
  next();
};

var logError = function( err ){
  notifier.notify({ title: pkg.name, message: 'Error: ' + err.message });
  $.util.log( $.util.colors.red(err) );
};

var handleErr = function( err ){
  logError( err );

  if( this.emit ){
    this.emit('end');
  }
};

var getBrowserified = function( opts ){
  opts = opts || {};

  opts = objectAssign({
    debug: opts.debug,
    cache: {},
    packageCache: {},
    fullPaths: opts.debug,
    bundleExternal: true,
    entries: [ {{#lib}}'./src'{{/lib}}{{#clientOrServer}}'./src/client'{{/clientOrServer}} ]
  }, opts );

  return browserify( opts ).on( 'log', $.util.log );
};

var transform = function( b ){
  return ( b
    .transform( babelify.configure( JSON.parse( fs.readFileSync('./.babelrc') ) ) )
    .external( deps )
  ) ;
};

var bundle = function( b ){
  return ( b
    .bundle()
    .on( 'error', handleErr )
    .pipe( source('bundle.js') )
    .pipe( buffer() )
  ) ;
};

var setBuildEnv = function( opts ){
  if( !opts.debug ){
    process.env['NODE_ENV'] = 'production';
  }
};

var buildJs = function( opts ){
  opts = objectAssign( { debug: true }, opts );

  setBuildEnv( opts );

  return bundle( transform( getBrowserified( opts ) ) )
    .pipe( opts.debug ? streamNop() : $.uglify( require('./.uglify.json') ) )
    .pipe( gulp.dest('./build') )
  ;
};

var buildJsDeps = function( opts ){
  opts = objectAssign( {
    debug: true
  }, opts );

  setBuildEnv( opts );

  var b = browserify({
    debug: false
  });

  deps.forEach(function( dep ){
    b.require( dep );
  });

  return ( b
    .bundle()
    .on( 'error', handleErr )
    .pipe( source('deps.js') )
    .pipe( buffer() )
    .pipe( opts.debug ? streamNop() : $.uglify( require('./.uglify.json') ) )
    .pipe( gulp.dest('./build') )
  ) ;
};

var buildCss = function( opts ){
  opts = objectAssign( {
    debug: true
  }, opts );

  var s = gulp.src( './src/styles/index.css' );

  if( opts.debug ){
    s = s.pipe( $.sourcemaps.init() );
  }

  s = ( s
    .pipe(
      $.postcss(
        [
          require('postcss-import')(),
          require('postcss-cssnext')( require('./.cssnext.json') )
        ].concat(
          opts.debug ? [] : [ require('cssnano')( require('./.cssnano.json') ) ]
        )
      )
    )

    .on( 'error', handleErr )
  );

  if( opts.debug ){
    s = s.pipe( $.sourcemaps.write() );
  }

  return ( s
    .pipe( $.rename('bundle.css') )
    .pipe( gulp.dest('./build') )
  );
};

{{#buildJs}}
gulp.task('js', function(){ return buildJs(); });
gulp.task('js-prod', function(){ return buildJs({ debug: false }); });
{{/buildJs}}

{{#dontBuildJs}}
gulp.task('js', nopTarget);
gulp.task('js-prod', nopTarget);
{{/dontBuildJs}}

{{#buildDeps}}
gulp.task('js-deps', function(){ return buildJsDeps(); });
gulp.task('js-deps-prod', function(){ return buildJsDeps({ debug: false }); });
{{/buildDeps}}

{{#dontBuildDeps}}
gulp.task('js-deps', nopTarget);
gulp.task('js-deps-prod', nopTarget);
{{/dontBuildDeps}}

{{#buildCss}}
gulp.task('css', function(){ return buildCss(); });
gulp.task('css-prod', function(){ return buildCss({ debug: false }); });
{{/buildCss}}

{{#dontBuildCss}}
gulp.task('css', nopTarget);
gulp.task('css-prod', nopTarget);
{{/dontBuildCss}}

gulp.task('watch', ['css', 'js-deps'], function(){
  {{#server}}
  var config = require('./src/server/config');

  nodemon('--debug -e "js json" ./src/server');

  nodemon.on('restart', function(files){
    $.util.log( $.util.colors.green('Server restarted via watch') );

    files.forEach(function( file ){
      file = file.replace( path.resolve('./'), '' );

      $.util.log( $.util.colors.magenta(file) + ' changed' );
    });
  });

  $.util.log( $.util.colors.green('App hosted on local server at http://localhost:' + config.PORT) );
  {{/server}}

  {{#buildJs}}
  $.livereload.listen({
    basePath: process.cwd()
  });

  gulp.watch( ['./src/views/index.html', './src/demo.html', './build/deps.js', './build/bundle.js', './build/bundle.css'] )
    .on('change', $.livereload.changed)
  ;

  gulp.watch( ['./src/styles/**/*'], ['css'] );

  gulp.watch( ['./package.json'], ['js-deps'] );

  var update = function(){
    $.util.log( $.util.colors.white('JS rebuilding via watch...') );

    bundle( b )
      .pipe( gulp.dest('./build') )
      .on('finish', function(){
        $.util.log( $.util.colors.green('JS rebuild finished via watch') );
      })
    ;
  };

  var b = getBrowserified();

  transform( b );

  b.plugin( watchify, { poll: true } );

  b.on( 'update', update );

  update();
  {{/buildJs}}
});

gulp.task('default', ['watch'], emptyTask);

gulp.task('build', ['js', 'js-deps', 'css'], emptyTask);

gulp.task('build-prod', ['js-prod', 'js-deps-prod', 'css-prod'], emptyTask);

gulp.task('clean', function(){
  return gulp.src('./build')
    .pipe( clean() )
  ;
});
<commit_msg>fullPaths should always be false #8<commit_after>var process = require('process');
var objectAssign = require('object-assign');
var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var watchify = require('watchify');
var nodemon = require('nodemon');
var del = require('del');
var paths = require('vinyl-paths');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var clean = function(){ return paths( del ); };
var notifier = require('node-notifier');
var $ = require('gulp-load-plugins')();
var runSequence = require('run-sequence');
var pkg = require('./package.json');
var path = require('path');
var through = require('through');
var streamNop = through;
var fs = require('fs');
var nopTarget = function( next ){ next(); }

process.on('SIGINT', function() {
  setTimeout(function() {
    $.util.log($.util.colors.red('Successfully closed gulp process ' + process.pid));
    process.exit(1);
  }, 500);
});

{{#clientOnly}}
var deps = Object.keys( pkg.dependencies ).concat('babel-polyfill');
{{/clientOnly}}

{{#lib}}
var deps = Object.keys( pkg.dependencies ).concat('babel-polyfill');
{{/lib}}

{{#server}}
var deps = pkg.bundledDependencies || [];
{{/server}}

var emptyTask = function( next ){
  next();
};

var logError = function( err ){
  notifier.notify({ title: pkg.name, message: 'Error: ' + err.message });
  $.util.log( $.util.colors.red(err) );
};

var handleErr = function( err ){
  logError( err );

  if( this.emit ){
    this.emit('end');
  }
};

var getBrowserified = function( opts ){
  opts = opts || {};

  opts = objectAssign({
    debug: opts.debug,
    cache: {},
    packageCache: {},
    bundleExternal: true,
    entries: [ {{#lib}}'./src'{{/lib}}{{#clientOrServer}}'./src/client'{{/clientOrServer}} ]
  }, opts );

  return browserify( opts ).on( 'log', $.util.log );
};

var transform = function( b ){
  return ( b
    .transform( babelify.configure( JSON.parse( fs.readFileSync('./.babelrc') ) ) )
    .external( deps )
  ) ;
};

var bundle = function( b ){
  return ( b
    .bundle()
    .on( 'error', handleErr )
    .pipe( source('bundle.js') )
    .pipe( buffer() )
  ) ;
};

var setBuildEnv = function( opts ){
  if( !opts.debug ){
    process.env['NODE_ENV'] = 'production';
  }
};

var buildJs = function( opts ){
  opts = objectAssign( { debug: true }, opts );

  setBuildEnv( opts );

  return bundle( transform( getBrowserified( opts ) ) )
    .pipe( opts.debug ? streamNop() : $.uglify( require('./.uglify.json') ) )
    .pipe( gulp.dest('./build') )
  ;
};

var buildJsDeps = function( opts ){
  opts = objectAssign( {
    debug: true
  }, opts );

  setBuildEnv( opts );

  var b = browserify({
    debug: false
  });

  deps.forEach(function( dep ){
    b.require( dep );
  });

  return ( b
    .bundle()
    .on( 'error', handleErr )
    .pipe( source('deps.js') )
    .pipe( buffer() )
    .pipe( opts.debug ? streamNop() : $.uglify( require('./.uglify.json') ) )
    .pipe( gulp.dest('./build') )
  ) ;
};

var buildCss = function( opts ){
  opts = objectAssign( {
    debug: true
  }, opts );

  var s = gulp.src( './src/styles/index.css' );

  if( opts.debug ){
    s = s.pipe( $.sourcemaps.init() );
  }

  s = ( s
    .pipe(
      $.postcss(
        [
          require('postcss-import')(),
          require('postcss-cssnext')( require('./.cssnext.json') )
        ].concat(
          opts.debug ? [] : [ require('cssnano')( require('./.cssnano.json') ) ]
        )
      )
    )

    .on( 'error', handleErr )
  );

  if( opts.debug ){
    s = s.pipe( $.sourcemaps.write() );
  }

  return ( s
    .pipe( $.rename('bundle.css') )
    .pipe( gulp.dest('./build') )
  );
};

{{#buildJs}}
gulp.task('js', function(){ return buildJs(); });
gulp.task('js-prod', function(){ return buildJs({ debug: false }); });
{{/buildJs}}

{{#dontBuildJs}}
gulp.task('js', nopTarget);
gulp.task('js-prod', nopTarget);
{{/dontBuildJs}}

{{#buildDeps}}
gulp.task('js-deps', function(){ return buildJsDeps(); });
gulp.task('js-deps-prod', function(){ return buildJsDeps({ debug: false }); });
{{/buildDeps}}

{{#dontBuildDeps}}
gulp.task('js-deps', nopTarget);
gulp.task('js-deps-prod', nopTarget);
{{/dontBuildDeps}}

{{#buildCss}}
gulp.task('css', function(){ return buildCss(); });
gulp.task('css-prod', function(){ return buildCss({ debug: false }); });
{{/buildCss}}

{{#dontBuildCss}}
gulp.task('css', nopTarget);
gulp.task('css-prod', nopTarget);
{{/dontBuildCss}}

gulp.task('watch', ['css', 'js-deps'], function(){
  {{#server}}
  var config = require('./src/server/config');

  nodemon('--debug -e "js json" ./src/server');

  nodemon.on('restart', function(files){
    $.util.log( $.util.colors.green('Server restarted via watch') );

    files.forEach(function( file ){
      file = file.replace( path.resolve('./'), '' );

      $.util.log( $.util.colors.magenta(file) + ' changed' );
    });
  });

  $.util.log( $.util.colors.green('App hosted on local server at http://localhost:' + config.PORT) );
  {{/server}}

  {{#buildJs}}
  $.livereload.listen({
    basePath: process.cwd()
  });

  gulp.watch( ['./src/views/index.html', './src/demo.html', './build/deps.js', './build/bundle.js', './build/bundle.css'] )
    .on('change', $.livereload.changed)
  ;

  gulp.watch( ['./src/styles/**/*'], ['css'] );

  gulp.watch( ['./package.json'], ['js-deps'] );

  var update = function(){
    $.util.log( $.util.colors.white('JS rebuilding via watch...') );

    bundle( b )
      .pipe( gulp.dest('./build') )
      .on('finish', function(){
        $.util.log( $.util.colors.green('JS rebuild finished via watch') );
      })
    ;
  };

  var b = getBrowserified();

  transform( b );

  b.plugin( watchify, { poll: true } );

  b.on( 'update', update );

  update();
  {{/buildJs}}
});

gulp.task('default', ['watch'], emptyTask);

gulp.task('build', ['js', 'js-deps', 'css'], emptyTask);

gulp.task('build-prod', ['js-prod', 'js-deps-prod', 'css-prod'], emptyTask);

gulp.task('clean', function(){
  return gulp.src('./build')
    .pipe( clean() )
  ;
});
<|endoftext|>


<commit_before>CLASS({
  name: 'Ball',
  extendsModel: 'foam.graphics.Circle',
  traits: ['foam.physics.Physical', 'foam.graphics.MotionBlur'],
  properties: [
    {
      name: 'vx',
      preSet: function(_, v) { return Math.sign(v) * Math.max(5, Math.abs(v)); }
    }
  ]
});

CLASS({
  name: 'Paddle',
  extendsModel: 'foam.graphics.Circle',
  traits: ['foam.physics.Physical', 'foam.graphics.Shadow'],
  properties: [
    { name: 'color', defaultValue: 'white' },
    { name: 'r',     defaultValue: 30 },
    { name: 'mass',  defaultValue: foam.physics.Physical.INFINITE_MASS }
  ]
});

CLASS({
  name: 'Pong',
  extendsModel: 'View',

  requires: [
    'foam.graphics.CView',
    'foam.graphics.Rectangle',
    'foam.physics.Collider'
  ],

  constants: {
    PADDLE_SPEED: 10
  },

  properties: [
    {
      name: 'WIDTH',
      defaultValue: 800
    },
    {
      name: 'HEIGHT',
      defaultValue: 300
    },
    {
      name: 'ball',
      factory: function() { return Ball.create({color: 'white', r: 20}); }
    },
    {
      name: 'lPaddle',
      factory: function() { return Paddle.create(); }
    },
    {
      name: 'rPaddle',
      factory: function() { return Paddle.create(); }
    },
    {
      name: 'table',
      factory: function() {
        return this.CView.create({background: 'lightgray', width: this.WIDTH, height: this.HEIGHT}).addChildren(
          this.Rectangle.create({x: this.WIDTH/2-5, width:10, height: this.HEIGHT, border:'rgba(0,0,0,0)' , background: 'white'}),
          this.ball,
          this.lPaddle,
          this.rPaddle);
      }
    },
    {
      model_: 'IntProperty',
      name: 'lScore'
    },
    {
      model_: 'IntProperty',
      name: 'rScore'
    }
  ],

  listeners: [
    {
      name: 'onBallMove',
      isFramed: true,
      code: function() {
        // Bounce off of top wall
        if ( this.ball.y - this.ball.r <= 0 ) {
          this.ball.vy = Math.abs(this.ball.vy);
        }
        // Bounce off of bottom wall
        if ( this.ball.y + this.ball.r >= this.HEIGHT ) {
          this.ball.vy = -Math.abs(this.ball.vy);
        }
        // Bounce off of left wall
        if ( this.ball.x <= 0 ) {
          this.rScore++;
          this.ball.x = 150;
          this.ball.vx *= -1;
        }
        // Bounce off of right wall
        if ( this.ball.x >= this.WIDTH ) {
          this.lScore++;
          this.ball.x = this.WIDTH - 150;
          this.ball.vx *= -1;
        }
        // Reset scores
        if ( this.lScore == 100 || this.rScore == 100 ) {
          this.lScore = this.rScore = 0;
        }
      }
    }
  ],

  actions: [
    {
      name: 'lUp',
      keyboardShortcuts: [ 81 /* q */ ],
      action: function() { this.lPaddle.y -= this.PADDLE_SPEED; }
    },
    {
      name: 'lDown',
      keyboardShortcuts: [ 65 /* a */ ],
      action: function() { this.lPaddle.y += this.PADDLE_SPEED; }
    },
    {
      name: 'rUp',
      keyboardShortcuts: [ 38 /* up arrow */ ],
      action: function() { this.rPaddle.y -= this.PADDLE_SPEED; }
    },
    {
      name: 'rDown',
      keyboardShortcuts: [ 40 /* down arrow */ ],
      action: function() { this.rPaddle.y += this.PADDLE_SPEED; }
    }
  ],

  templates: [
    function CSS() {/*
      span[name="lScore"] {
        color: white;
        position: absolute;
        top: 20;
        left: 300;
        font-family: sans-serif;
        font-size: 70px;
      }
      span[name="rScore"] {
        color: white;
        position: absolute;
        top: 20;
        left: 450;
        font-family: sans-serif;
        font-size: 70px;
      }
    */},
    function toHTML() {/*

$$lScore{mode: 'read-only'} $$rScore{mode: 'read-only'}
 %%table

    */}
  ],

  methods: {
    initHTML: function() {
      this.SUPER();

      // Position Paddles
      this.lPaddle.x = 25+this.lPaddle.r;
      this.rPaddle.x = this.WIDTH-25-this.rPaddle.r;
      this.lPaddle.y = this.rPaddle.y = (this.HEIGHT-this.rPaddle.height)/2;

      // Setup Ball
      this.ball.x  = this.ball.y = 100;
      this.ball.y  = this.rPaddle.y;
      this.ball.vx = this.ball.vy = 10;

      this.ball.x$.addListener(this.onBallMove);

      // Setup Physics
      this.Collider.create().add(this.ball, this.lPaddle, this.rPaddle).start();
      Movement.inertia(this.ball);
    }
  }
});
<commit_msg>Fix Pong demo after graphics changes.<commit_after>CLASS({
  name: 'Ball',
  extendsModel: 'foam.graphics.Circle',
  traits: ['foam.physics.Physical', 'foam.graphics.MotionBlur'],
  properties: [
    {
      name: 'vx',
      preSet: function(_, v) { return Math.sign(v) * Math.max(5, Math.abs(v)); }
    }
  ]
});

CLASS({
  name: 'Paddle',
  extendsModel: 'foam.graphics.Circle',
  traits: ['foam.physics.Physical', 'foam.graphics.Shadow'],
  properties: [
    { name: 'color', defaultValue: 'white' },
    { name: 'r',     defaultValue: 30 },
    { name: 'mass',  defaultValue: foam.physics.Physical.INFINITE_MASS }
  ]
});

CLASS({
  name: 'Pong',
  extendsModel: 'View',

  requires: [
    'Ball',
    'Paddle',
    'foam.graphics.CView',
    'foam.graphics.Rectangle',
    'foam.physics.Collider'
  ],

  constants: {
    PADDLE_SPEED: 10
  },

  properties: [
    {
      name: 'WIDTH',
      defaultValue: 800
    },
    {
      name: 'HEIGHT',
      defaultValue: 300
    },
    {
      name: 'ball',
      factory: function() { return Ball.create({color: 'white', r: 20}); }
    },
    {
      name: 'lPaddle',
      factory: function() { return Paddle.create(); }
    },
    {
      name: 'rPaddle',
      factory: function() { return Paddle.create(); }
    },
    {
      name: 'table',
      factory: function() {
        return this.CView.create({background: 'lightgray', width: this.WIDTH, height: this.HEIGHT}).addChildren(
          this.Rectangle.create({x: this.WIDTH/2-5, width:10, height: this.HEIGHT, border:'rgba(0,0,0,0)' , background: 'white'}),
          this.ball,
          this.lPaddle,
          this.rPaddle);
      }
    },
    {
      model_: 'IntProperty',
      name: 'lScore'
    },
    {
      model_: 'IntProperty',
      name: 'rScore'
    }
  ],

  listeners: [
    {
      name: 'onBallMove',
      isFramed: true,
      code: function() {
        // Bounce off of top wall
        if ( this.ball.y - this.ball.r <= 0 ) {
          this.ball.vy = Math.abs(this.ball.vy);
        }
        // Bounce off of bottom wall
        if ( this.ball.y + this.ball.r >= this.HEIGHT ) {
          this.ball.vy = -Math.abs(this.ball.vy);
        }
        // Bounce off of left wall
        if ( this.ball.x <= 0 ) {
          this.rScore++;
          this.ball.x = 150;
          this.ball.vx *= -1;
        }
        // Bounce off of right wall
        if ( this.ball.x >= this.WIDTH ) {
          this.lScore++;
          this.ball.x = this.WIDTH - 150;
          this.ball.vx *= -1;
        }
        // Reset scores
        if ( this.lScore == 100 || this.rScore == 100 ) {
          this.lScore = this.rScore = 0;
        }
      }
    }
  ],

  actions: [
    {
      name: 'lUp',
      keyboardShortcuts: [ 81 /* q */ ],
      action: function() { this.lPaddle.y -= this.PADDLE_SPEED; }
    },
    {
      name: 'lDown',
      keyboardShortcuts: [ 65 /* a */ ],
      action: function() { this.lPaddle.y += this.PADDLE_SPEED; }
    },
    {
      name: 'rUp',
      keyboardShortcuts: [ 38 /* up arrow */ ],
      action: function() { this.rPaddle.y -= this.PADDLE_SPEED; }
    },
    {
      name: 'rDown',
      keyboardShortcuts: [ 40 /* down arrow */ ],
      action: function() { this.rPaddle.y += this.PADDLE_SPEED; }
    }
  ],

  templates: [
    function CSS() {/*
      span[name="lScore"] {
        color: white;
        position: absolute;
        top: 20;
        left: 300;
        font-family: sans-serif;
        font-size: 70px;
      }
      span[name="rScore"] {
        color: white;
        position: absolute;
        top: 20;
        left: 450;
        font-family: sans-serif;
        font-size: 70px;
      }
    */},
    function toHTML() {/*

$$lScore{mode: 'read-only'} $$rScore{mode: 'read-only'}
 %%table

    */}
  ],

  methods: {
    initHTML: function() {
      this.SUPER();

      // Position Paddles
      this.lPaddle.x = 25+this.lPaddle.r;
      this.rPaddle.x = this.WIDTH-25-this.rPaddle.r;
      this.lPaddle.y = this.rPaddle.y = (this.HEIGHT-this.rPaddle.height)/2;

      // Setup Ball
      this.ball.x  = this.ball.y = 100;
      this.ball.y  = this.rPaddle.y;
      this.ball.vx = this.ball.vy = 10;

      this.ball.x$.addListener(this.onBallMove);

      // Setup Physics
      this.Collider.create().add(this.ball, this.lPaddle, this.rPaddle).start();
      Movement.inertia(this.ball);
    }
  }
});
<|endoftext|>


<commit_before>import Express from 'express';
import { readFileSync } from 'fs';

import React from 'react';
import Helmet from 'react-helmet';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { fromJS } from 'immutable';
import { I18nextProvider } from 'react-i18next';
import {
  StaticRouter as Router,
  Route,
} from 'react-router-dom';

import configureStore from '../store/configureStore';
import App from '../components/App';
import i18n from './i18n';

import { requestSessions } from '../actions/sessions';
import { requestSpeakers } from '../actions/speakers';
import { requestSponsorsAll } from '../actions/sponsors';
import { requestPosts } from '../actions/posts';

const DEFAULT_META = '<meta data-react-helmet="true" name="og:url" content="https://2017.tgdf.tw/"/><meta data-react-helmet="true" name="og:title" content="台北遊戲開發者論壇"/><meta data-react-helmet="true" name="og:description" content="2017 年即將邁入第六屆的台北遊戲開發者論壇（TGDF，Taipei Game Developers Forum），為台灣最大型之年度專業遊戲開發論壇，每年吸引近千名海內外開發者共襄盛舉，主辦單位除了每年邀請明星級海外講師如「洛克人之父」稻船敬二、「紀念碑谷」製作人、Valve 原廠講師等，亦有大量海內外深度遊戲設計、程式、美術專題講座。去年 TGDF 更加開 VR 體驗區、「TGDF Indie Space」遊戲作品展示區、以及商談媒合區等多元形式，希望打造台灣一年一度，全方位的遊戲開發盛宴！"/><meta data-react-helmet="true" name="og:image" content="https://2017.tgdf.tw/static/tgdf.png"/>';
const TEMPLATE = readFileSync(__dirname + '/../../public/index.html').toString();

const app = new Express();
const port = process.env.PORT || 3000;
const context = {};

function handleRender(req, res) {
  // TODO: Request to API and fetch web page information
  const store = configureStore(fromJS({}));

  const callback = () => {
    const lang = req.acceptsLanguages('zh-TW', 'en');
    i18n.changeLanguage(lang);

    const html = renderToString(
      <Provider store={store}>
        <I18nextProvider i18n={i18n}>
          <Router location={req.url} context={context}>
            <App />
          </Router>
        </I18nextProvider>
      </Provider>
    );

    const head = Helmet.rewind();
    const title = head ? head.title.toString() : '<title>台北遊戲開發者論壇</title>';
    let meta = head ? head.meta.toString() : DEFAULT_META;
    if (meta.length == 0) { meta = DEFAULT_META; }
    const finalState = store.getState();
    res.send(renderFullPage(html, title, meta, finalState));
  }

  if (req.url.startsWith('/schedule')) {
    requestSessions()(store.dispatch).then(() => callback());
  } else if(req.url.startsWith('/speaker')) {
    requestSpeakers()(store.dispatch).then(() => callback());
  } else if(req.url.startsWith('/partner')) {
    requestSponsorsAll(store.dispatch).then(() => callback());
  } else if (req.url.startsWith('/article')) {
    requestPosts()(store.dispatch).then(() => callback());
  } else {
    callback();
  }
}

function renderFullPage(html, title, meta,  preloadedState) {
  return TEMPLATE.replace('__HTML__', html)
                 .replace('__TITLE__', title)
                 .replace('__META__', meta.replace(/ data-react-helmet="true"/g, ''));
}

app.set('env', 'production');
app.use('/static', Express.static(__dirname + '/../../public'));
app.use(handleRender);

app.listen(port, (error) => {
  if (error) {
    console.error(error)
  } else {
    console.info(`==> 🌎  Listening on port ${port}. Open up http://localhost:${port}/ in your browser.`)
  }
});
<commit_msg>Add language query options<commit_after>import Express from 'express';
import { readFileSync } from 'fs';

import React from 'react';
import Helmet from 'react-helmet';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { fromJS } from 'immutable';
import { I18nextProvider } from 'react-i18next';
import {
  StaticRouter as Router,
  Route,
} from 'react-router-dom';

import configureStore from '../store/configureStore';
import App from '../components/App';
import i18n from './i18n';

import { requestSessions } from '../actions/sessions';
import { requestSpeakers } from '../actions/speakers';
import { requestSponsorsAll } from '../actions/sponsors';
import { requestPosts } from '../actions/posts';

const DEFAULT_META = '<meta data-react-helmet="true" name="og:url" content="https://2017.tgdf.tw/"/><meta data-react-helmet="true" name="og:title" content="台北遊戲開發者論壇"/><meta data-react-helmet="true" name="og:description" content="2017 年即將邁入第六屆的台北遊戲開發者論壇（TGDF，Taipei Game Developers Forum），為台灣最大型之年度專業遊戲開發論壇，每年吸引近千名海內外開發者共襄盛舉，主辦單位除了每年邀請明星級海外講師如「洛克人之父」稻船敬二、「紀念碑谷」製作人、Valve 原廠講師等，亦有大量海內外深度遊戲設計、程式、美術專題講座。去年 TGDF 更加開 VR 體驗區、「TGDF Indie Space」遊戲作品展示區、以及商談媒合區等多元形式，希望打造台灣一年一度，全方位的遊戲開發盛宴！"/><meta data-react-helmet="true" name="og:image" content="https://2017.tgdf.tw/static/tgdf.png"/>';
const TEMPLATE = readFileSync(__dirname + '/../../public/index.html').toString();

const app = new Express();
const port = process.env.PORT || 3000;
const context = {};

function handleRender(req, res) {
  // TODO: Request to API and fetch web page information
  const store = configureStore(fromJS({}));

  const callback = () => {
    const lang = req.query.lang || req.acceptsLanguages('zh-TW', 'en');
    i18n.changeLanguage(lang);

    const html = renderToString(
      <Provider store={store}>
        <I18nextProvider i18n={i18n}>
          <Router location={req.url} context={context}>
            <App />
          </Router>
        </I18nextProvider>
      </Provider>
    );

    const head = Helmet.rewind();
    const title = head ? head.title.toString() : '<title>台北遊戲開發者論壇</title>';
    let meta = head ? head.meta.toString() : DEFAULT_META;
    if (meta.length == 0) { meta = DEFAULT_META; }
    const finalState = store.getState();
    res.send(renderFullPage(html, title, meta, finalState));
  }

  if (req.url.startsWith('/schedule')) {
    requestSessions()(store.dispatch).then(() => callback());
  } else if(req.url.startsWith('/speaker')) {
    requestSpeakers()(store.dispatch).then(() => callback());
  } else if(req.url.startsWith('/partner')) {
    requestSponsorsAll(store.dispatch).then(() => callback());
  } else if (req.url.startsWith('/article')) {
    requestPosts()(store.dispatch).then(() => callback());
  } else {
    callback();
  }
}

function renderFullPage(html, title, meta,  preloadedState) {
  return TEMPLATE.replace('__HTML__', html)
                 .replace('__TITLE__', title)
                 .replace('__META__', meta.replace(/ data-react-helmet="true"/g, ''));
}

app.set('env', 'production');
app.use('/static', Express.static(__dirname + '/../../public'));
app.use(handleRender);

app.listen(port, (error) => {
  if (error) {
    console.error(error)
  } else {
    console.info(`==> 🌎  Listening on port ${port}. Open up http://localhost:${port}/ in your browser.`)
  }
});
<|endoftext|>