<commit_before>import {Headers} from './headers';
import {RequestBuilder} from './request-builder';
import {HttpRequestMessage,createHttpRequestMessageProcessor} from './http-request-message';
import {JSONPRequestMessage,createJSONPRequestMessageProcessor} from './jsonp-request-message';

function trackRequestStart(client, processor){
  client.pendingRequests.push(processor);
  client.isRequesting = true;
}

function trackRequestEnd(client, processor){
  var index = client.pendingRequests.indexOf(processor);

  client.pendingRequests.splice(index, 1);
  client.isRequesting = client.pendingRequests.length > 0;

  if(!client.isRequesting){
    var evt = new window.CustomEvent('aurelia-http-client-requests-drained', { bubbles: true, cancelable: true });
    setTimeout(() => document.dispatchEvent(evt), 1);
  }
}

/**
* The main HTTP client object.
*
* @class HttpClient
* @constructor
*/
export class HttpClient {
  constructor(){
    this.requestTransformers = [];
    this.requestProcessorFactories = new Map();
    this.requestProcessorFactories.set(HttpRequestMessage, createHttpRequestMessageProcessor);
    this.requestProcessorFactories.set(JSONPRequestMessage, createJSONPRequestMessageProcessor);
    this.pendingRequests = [];
    this.isRequesting = false;
  }

  /**
   * Configure this HttpClient with default settings to be used by all requests.
   *
   * @method configure
   * @param {Function} fn A function that takes a RequestBuilder as an argument.
   * @chainable
   */
  configure(fn){
    var builder = new RequestBuilder(this);
    fn(builder);
    this.requestTransformers = builder.transformers;
    return this;
  }

  /**
   * Returns a new RequestBuilder for this HttpClient instance that can be used to build and send HTTP requests.
   *
   * @method createRequest
   * @param uri The target URI.
   * @type RequestBuilder
   */
  createRequest(uri){
    let builder = new RequestBuilder(this);

    if(uri) {
      builder.withUri(uri);
    }

    return builder;
  }

  /**
   * Sends a message using the underlying networking stack.
   *
   * @method send
   * @param message A configured HttpRequestMessage or JSONPRequestMessage.
   * @param {Array} transformers A collection of transformers to apply to the HTTP request.
   * @return {Promise} A cancellable promise object.
   */
  send(message, transformers){
    var createProcessor = this.requestProcessorFactories.get(message.constructor),
        processor, promise, i, ii;

    if(!createProcessor){
        throw new Error(`No request message processor factory for ${message.constructor}.`);
    }

    processor = createProcessor();
    trackRequestStart(this, processor);

    transformers = transformers || this.requestTransformers;

    for(i = 0, ii = transformers.length; i < ii; ++i){
      transformers[i](this, processor, message);
    }

    promise = processor.process(this, message);

    promise.abort = promise.cancel = function() {
      processor.abort();
    };

    return promise.then(response => {
      trackRequestEnd(this, processor);
      return response;
    }).catch(response => {
      trackRequestEnd(this, processor);
      throw response;
    });
  }

  /**
   * Sends an HTTP DELETE request.
   *
   * @method delete
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  delete(uri){
    return this.createRequest(uri).asDelete().send();
  }

  /**
   * Sends an HTTP GET request.
   *
   * @method get
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  get(uri){
    return this.createRequest(uri).asGet().send();
  }

  /**
   * Sends an HTTP HEAD request.
   *
   * @method head
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  head(uri){
    return this.createRequest(uri).asHead().send();
  }

  /**
   * Sends a JSONP request.
   *
   * @method jsonp
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  jsonp(uri, callbackParameterName='jsoncallback'){
    return this.createRequest(uri).asJsonp(callbackParameterName).send();
  }

  /**
   * Sends an HTTP OPTIONS request.
   *
   * @method options
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  options(uri){
    return this.createRequest(uri).asOptions().send();
  }

  /**
   * Sends an HTTP PUT request.
   *
   * @method put
   * @param {String} uri The target URI.
   * @param {Object} uri The request payload.
   * @return {Promise} A cancellable promise object.
   */
  put(uri, content){
    return this.createRequest(uri).asPut().withContent(content).send();
  }

  /**
   * Sends an HTTP PATCH request.
   *
   * @method patch
   * @param {String} uri The target URI.
   * @param {Object} uri The request payload.
   * @return {Promise} A cancellable promise object.
   */
  patch(uri, content){
    return this.createRequest(uri).asPatch().withContent(content).send();
  }

  /**
   * Sends an HTTP POST request.
   *
   * @method post
   * @param {String} uri The target URI.
   * @param {Object} uri The request payload.
   * @return {Promise} A cancellable promise object.
   */
  post(uri, content){
    return this.createRequest(uri).asPost().withContent(content).send();
  }
}
<commit_msg>fix(http-client): abort/cancel  attached to wrong promise instance<commit_after>import {Headers} from './headers';
import {RequestBuilder} from './request-builder';
import {HttpRequestMessage,createHttpRequestMessageProcessor} from './http-request-message';
import {JSONPRequestMessage,createJSONPRequestMessageProcessor} from './jsonp-request-message';

function trackRequestStart(client, processor){
  client.pendingRequests.push(processor);
  client.isRequesting = true;
}

function trackRequestEnd(client, processor){
  var index = client.pendingRequests.indexOf(processor);

  client.pendingRequests.splice(index, 1);
  client.isRequesting = client.pendingRequests.length > 0;

  if(!client.isRequesting){
    var evt = new window.CustomEvent('aurelia-http-client-requests-drained', { bubbles: true, cancelable: true });
    setTimeout(() => document.dispatchEvent(evt), 1);
  }
}

/**
* The main HTTP client object.
*
* @class HttpClient
* @constructor
*/
export class HttpClient {
  constructor(){
    this.requestTransformers = [];
    this.requestProcessorFactories = new Map();
    this.requestProcessorFactories.set(HttpRequestMessage, createHttpRequestMessageProcessor);
    this.requestProcessorFactories.set(JSONPRequestMessage, createJSONPRequestMessageProcessor);
    this.pendingRequests = [];
    this.isRequesting = false;
  }

  /**
   * Configure this HttpClient with default settings to be used by all requests.
   *
   * @method configure
   * @param {Function} fn A function that takes a RequestBuilder as an argument.
   * @chainable
   */
  configure(fn){
    var builder = new RequestBuilder(this);
    fn(builder);
    this.requestTransformers = builder.transformers;
    return this;
  }

  /**
   * Returns a new RequestBuilder for this HttpClient instance that can be used to build and send HTTP requests.
   *
   * @method createRequest
   * @param uri The target URI.
   * @type RequestBuilder
   */
  createRequest(uri){
    let builder = new RequestBuilder(this);

    if(uri) {
      builder.withUri(uri);
    }

    return builder;
  }

  /**
   * Sends a message using the underlying networking stack.
   *
   * @method send
   * @param message A configured HttpRequestMessage or JSONPRequestMessage.
   * @param {Array} transformers A collection of transformers to apply to the HTTP request.
   * @return {Promise} A cancellable promise object.
   */
  send(message, transformers){
    var createProcessor = this.requestProcessorFactories.get(message.constructor),
        processor, promise, i, ii;

    if(!createProcessor){
      throw new Error(`No request message processor factory for ${message.constructor}.`);
    }

    processor = createProcessor();
    trackRequestStart(this, processor);

    transformers = transformers || this.requestTransformers;

    for(i = 0, ii = transformers.length; i < ii; ++i){
      transformers[i](this, processor, message);
    }

    promise = processor.process(this, message).then(response => {
      trackRequestEnd(this, processor);
      return response;
    }).catch(response => {
      trackRequestEnd(this, processor);
      throw response;
    });

    promise.abort = promise.cancel = function() {
      processor.abort();
    };

    return promise;
  }

  /**
   * Sends an HTTP DELETE request.
   *
   * @method delete
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  delete(uri){
    return this.createRequest(uri).asDelete().send();
  }

  /**
   * Sends an HTTP GET request.
   *
   * @method get
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  get(uri){
    return this.createRequest(uri).asGet().send();
  }

  /**
   * Sends an HTTP HEAD request.
   *
   * @method head
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  head(uri){
    return this.createRequest(uri).asHead().send();
  }

  /**
   * Sends a JSONP request.
   *
   * @method jsonp
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  jsonp(uri, callbackParameterName='jsoncallback'){
    return this.createRequest(uri).asJsonp(callbackParameterName).send();
  }

  /**
   * Sends an HTTP OPTIONS request.
   *
   * @method options
   * @param {String} uri The target URI.
   * @return {Promise} A cancellable promise object.
   */
  options(uri){
    return this.createRequest(uri).asOptions().send();
  }

  /**
   * Sends an HTTP PUT request.
   *
   * @method put
   * @param {String} uri The target URI.
   * @param {Object} uri The request payload.
   * @return {Promise} A cancellable promise object.
   */
  put(uri, content){
    return this.createRequest(uri).asPut().withContent(content).send();
  }

  /**
   * Sends an HTTP PATCH request.
   *
   * @method patch
   * @param {String} uri The target URI.
   * @param {Object} uri The request payload.
   * @return {Promise} A cancellable promise object.
   */
  patch(uri, content){
    return this.createRequest(uri).asPatch().withContent(content).send();
  }

  /**
   * Sends an HTTP POST request.
   *
   * @method post
   * @param {String} uri The target URI.
   * @param {Object} uri The request payload.
   * @return {Promise} A cancellable promise object.
   */
  post(uri, content){
    return this.createRequest(uri).asPost().withContent(content).send();
  }
}
<|endoftext|>


<commit_before>/**
 * @file NodeJS specific HTTP implementation
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST*/ // Host types
/*global _gpfHttpRequestImplByHost*/ // HTTP Request Implementation per host
/*global _GpfNodeReadableStream*/ // gpf.node.ReadableStream
/*global _GpfStreamWritableString*/ // gpf.stream.WritableString
/*global _gpfNodeHttp*/ // Node require("http")
/*global  _gpfNodeUrl*/ // Node require("url")
/*#endif*/

/*jshint node: true*/
/*eslint-env node*/

function _gpfHttpNodeProcessResponse (nodeResponse, resolve) {
    nodeResponse.setEncoding("utf8");
    var iReadableStream = new _GpfNodeReadableStream(nodeResponse),
        iWritableStream = new _GpfStreamWritableString();
    iReadableStream
        .read(iWritableStream)
        .then(function () {
            resolve({
                status: nodeResponse.statusCode,
                headers: nodeResponse.headers,
                responseText: iWritableStream.toString()
            });
        });
}

function _gpfHttpNodeAllocate (request, resolve) {
    return _gpfNodeHttp.request(Object.assign(_gpfNodeUrl.parse(request.url), request), function (nodeResponse) {
        _gpfHttpNodeProcessResponse(nodeResponse, resolve);
    });
}

function _gpfHttpNodeSend (clientRequest, data) {
    if (data) {
        clientRequest.write(data);
    }
    clientRequest.end();
}

_gpfHttpRequestImplByHost[_GPF_HOST.NODEJS] = function (request, resolve, reject) {
    var clientRequest = _gpfHttpNodeAllocate(request, resolve);
    clientRequest.on("error", reject);
    _gpfHttpNodeSend(clientRequest, request.data);
};
<commit_msg>Improves maintainability<commit_after>/**
 * @file NodeJS specific HTTP implementation
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_HOST*/ // Host types
/*global _gpfHttpRequestImplByHost*/ // HTTP Request Implementation per host
/*global _GpfNodeReadableStream*/ // gpf.node.ReadableStream
/*global _gpfStringFromStream*/ // Read the stream
/*global _gpfNodeHttp*/ // Node require("http")
/*global  _gpfNodeUrl*/ // Node require("url")
/*#endif*/

/*jshint node: true*/
/*eslint-env node*/

function _gpfHttpNodeProcessResponse (nodeResponse, resolve) {
    nodeResponse.setEncoding("utf8");
    var iReadableStream = new _GpfNodeReadableStream(nodeResponse);
    _gpfStringFromStream(iReadableStream)
        .then(function (responseText) {
            iReadableStream.close();
            resolve({
                status: nodeResponse.statusCode,
                headers: nodeResponse.headers,
                responseText: responseText
            });
        });
}

function _gpfHttpNodeAllocate (request, resolve) {
    return _gpfNodeHttp.request(Object.assign(_gpfNodeUrl.parse(request.url), request), function (nodeResponse) {
        _gpfHttpNodeProcessResponse(nodeResponse, resolve);
    });
}

function _gpfHttpNodeSend (clientRequest, data) {
    if (data) {
        clientRequest.write(data);
    }
    clientRequest.end();
}

_gpfHttpRequestImplByHost[_GPF_HOST.NODEJS] = function (request, resolve, reject) {
    var clientRequest = _gpfHttpNodeAllocate(request, resolve);
    clientRequest.on("error", reject);
    _gpfHttpNodeSend(clientRequest, request.data);
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Pterodactyl - Daemon
 * Copyright (c) 2015 - 2016 Dane Everitt <dane@daneeveritt.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.
 */
const rfr = require('rfr');
const binaryJS = require('binaryjs').BinaryServer;
const Fs = require('fs-extra');
const Path = require('path');

const ConfigHelper = rfr('src/helpers/config.js');
const RestServer = rfr('src/http/restify.js');

const Config = new ConfigHelper();

class Upload {
    constructor(server) {
        this.server = server;
    }

    init() {
        const self = this;
        const BinaryServer = binaryJS({
            server: RestServer,
            chunkSize: 40960,
            path: '/upload/' + this.server.json.uuid,
        });

        // Prevents a scary looking error from NodeJS about possible
        // memory leak. There is no leak. (only leeks!)
        BinaryServer.removeAllListeners('connection');

        BinaryServer.on('connection', function initBinaryServerConnection(client) {
            client.on('stream', function initBinaryServerConnectionStream(stream, meta) {
                if (!meta.token || !meta.server) {
                    stream.write({ 'error': 'Missing required meta variables in the request.' });
                    stream.end();
                    return;
                }

                if (!self.server.hasPermission('s:files:upload', meta.token)) {
                    stream.write({ 'error': 'You do not have permission to upload files to this server.' });
                    stream.end();
                    return;
                }

                if (meta.size > Config.get('uploads.maximumSize', 100000000)) {
                    stream.write({ 'error': 'That file is too big to upload.' });
                    stream.end();
                    return;
                }

                Fs.ensureDir(self.server.path(meta.path), function (err) {
                    if (err) {
                        this.server.log.error(err);
                        return;
                    }

                    // Write uploaded file to server
                    const FileWriter = Fs.createWriteStream(self.server.path(Path.join(meta.path, meta.name)));
                    stream.pipe(FileWriter);
                    stream.on('data', function (data) {
                        stream.write({ rx: data.length / meta.size });
                    });
                });
            });
        });
    }
}

module.exports = Upload;
<commit_msg>Fix upload socket bugs, closes #11<commit_after>'use strict';

/**
 * Pterodactyl - Daemon
 * Copyright (c) 2015 - 2016 Dane Everitt <dane@daneeveritt.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.
 */
const rfr = require('rfr');
const binaryJS = require('binaryjs').BinaryServer;
const Fs = require('fs-extra');
const Path = require('path');

const Initializer = rfr('src/helpers/initialize.js');
const ConfigHelper = rfr('src/helpers/config.js');
const RestServer = rfr('src/http/restify.js');
const BinaryServer = binaryJS({
    server: RestServer,
    chunkSize: 40960,
    path: '/upload/',
});

const Config = new ConfigHelper();

class Upload {
    constructor() {
        //
    }

    init() {
        const self = this;
        // Prevents a scary looking error from NodeJS about possible
        // memory leak. There is no leak. (only leeks!)
        BinaryServer.removeAllListeners('connection');

        BinaryServer.on('connection', function initBinaryServerConnection(client) {
            client.on('stream', function initBinaryServerConnectionStream(stream, meta) {
                if (!meta.token || !meta.server) {
                    stream.write({ 'error': 'Missing required meta variables in the request.' });
                    stream.end();
                    return;
                }

                if (typeof Initializer.Servers === 'undefined' || typeof Initializer.Servers[meta.server] === 'undefined') {
                    stream.write({ 'error': 'You do not have permission to upload files to this server.' });
                    stream.end();
                    return;
                }

                const Server = Initializer.Servers[meta.server];
                if (!Server.hasPermission('s:files:upload', meta.token)) {
                    stream.write({ 'error': 'You do not have permission to upload files to this server.' });
                    stream.end();
                    return;
                }

                if (meta.size > Config.get('uploads.maximumSize', 100000000)) {
                    stream.write({ 'error': 'That file is too big to upload.' });
                    stream.end();
                    return;
                }

                Fs.ensureDir(Server.path(meta.path), function (err) {
                    if (err) {
                        Server.log.error(err);
                        return;
                    }

                    // Write uploaded file to server
                    const FileWriter = Fs.createWriteStream(Server.path(Path.join(meta.path, meta.name)));
                    stream.pipe(FileWriter);
                    stream.on('data', function (data) {
                        stream.write({ rx: data.length / meta.size });
                    });
                });
            });
        });
    }
}

module.exports = Upload;
<|endoftext|>


<commit_before>"use strict";

const Shortlink = require("./shortlink");
const trim_slashes = require("./string_utility").trim_slashes;

module.exports = (server) => {

  server.get("/", (req, res) => {
    res.redirect(301, "http://jotaen.net");
  });

  server.get("*", (req, res) => {
    const path = trim_slashes(req.params[0]);
    Shortlink.findOne({
      path: path
    }).then((shortlink) => {
      if (shortlink) {
        res.redirect(301, shortlink.url);
      } else {
        res.sendStatus(404);
      }
    });
  });

  server.put("*", (req, res) => {
    const shortlink = new Shortlink({
      url: req.query.url,
      path: trim_slashes(req.params[0])
    });

    shortlink
      .save()
      .then(() => {
        res.sendStatus(200);
      })
      .catch((error) => {
        res.status(500).send(error);
      });
  });

};
<commit_msg>Use path parameters in http routes<commit_after>"use strict";

const Shortlink = require("./shortlink");
const trim_slashes = require("./string_utility").trim_slashes;

module.exports = (server) => {

  server.get("/", (req, res) => {
    res.redirect(301, "http://jotaen.net");
  });

  server.get("/:token", (req, res) => {
    const path = trim_slashes(req.params.token);
    Shortlink.findOne({
      path: path
    }).then((shortlink) => {
      if (shortlink) {
        res.redirect(301, shortlink.url);
      } else {
        res.sendStatus(404);
      }
    });
  });

  server.put("/:token", (req, res) => {
    const shortlink = new Shortlink({
      url: req.query.url,
      path: trim_slashes(req.params.token)
    });

    shortlink
      .save()
      .then(() => {
        res.sendStatus(200);
      })
      .catch((error) => {
        res.status(500).send(error);
      });
  });

};
<|endoftext|>


<commit_before>#!/usr/bin/env node
var fs              = require('fs');
var Cucumber        = require('./lib/cucumber');
var supportCodePath = process.ARGV[3] ? process.cwd() + '/' + process.ARGV[3] : './features/step_definitions/cucumber_steps';
var supportCode     = require(supportCodePath);
var cucumber        = Cucumber(fs.readFileSync(process.ARGV[2]), supportCode);
var formatter       = Cucumber.Listener.ProgressFormatter();
cucumber.attachListener(formatter);
cucumber.start(function(succeeded) {
  var code = succeeded ? 0 : 1;
  var exitFunction = function() {
    process.exit(code);
  };

  // --- exit after waiting for all pending output ---
  var waitingIO = false;
  process.stdout.on('drain', function() {
    if (waitingIO) {
      // the kernel buffer is now empty
      exitFunction();
    }
  });
  if (process.stdout.write("")) {
    // no buffer left, exit now:
    exitFunction();
  } else {
    // write() returned false, kernel buffer is not empty yet...
    waitingIO = true;
  }
});<commit_msg>Throw a more explicit exception on missing feature path CLI argument<commit_after>#!/usr/bin/env node
var fs              = require('fs');
var Cucumber        = require('./lib/cucumber');
var featurePath     = process.ARGV[2];
var supportCodePath = process.ARGV[3] ? process.cwd() + '/' + process.ARGV[3] : './features/step_definitions/cucumber_steps';

if (typeof(featurePath) == 'undefined') {
  throw("Please give me a feature, try something like `" + process.ARGV[1] + " features/cucumber-features/core.feature`.");
}

var supportCode     = require(supportCodePath);
var cucumber        = Cucumber(fs.readFileSync(featurePath), supportCode);
var formatter       = Cucumber.Listener.ProgressFormatter();
cucumber.attachListener(formatter);
cucumber.start(function(succeeded) {
  var code = succeeded ? 0 : 1;
  var exitFunction = function() {
    process.exit(code);
  };

  // --- exit after waiting for all pending output ---
  var waitingIO = false;
  process.stdout.on('drain', function() {
    if (waitingIO) {
      // the kernel buffer is now empty
      exitFunction();
    }
  });
  if (process.stdout.write("")) {
    // no buffer left, exit now:
    exitFunction();
  } else {
    // write() returned false, kernel buffer is not empty yet...
    waitingIO = true;
  }
});
<|endoftext|>


<commit_before>"use strict";

const DEFAULT_DELAY_TIME = 5;
const TEMP_DIRECTRY_PREFIX = 'kirakira';
const temp = require('temp').track();
const fs   = require('fs');
const util  = require('util');
const sprintf = require('sprintf').sprintf
const path = require('path');
const im = require('imagemagick');

function increaseVerbosity(v, total) {
  return total + 1;
}

let program = require('commander');
program.version('0.0.1');
program.usage('-i <input file> [options]');
program.option('-i, --input <path>', 'input file');
program.option('-o, --output [path]', 'output path');
program.option('-s, --saturation [percent value]', 'saturation value');
program.option('-p, --plain', 'Do NOT Kirakira effect', function(){return true}, 0);
program.option('--framenum [integer]', 'frame number', parseInt);
program.option('--delay [time]', 'delay time', parseInt);
program.option('--guruguru', 'enable guruguru effect', function(){return true}, 0);
program.parse(process.argv);
const input = program.input;
const output = program.output !== undefined ? program.output : "out.gif";
const delay = program.delay !== undefined ? program.delay : DEFAULT_DELAY_TIME;
const saturation = program.saturation !== undefined ? program.saturation : 100;
const frame_num = program.framenum !== undefined ? program.framenum : 10;

const doNothing = function(){};

const createFrames = function(dirPath, cb){
    let counter = 0;

    const filePaths = Array.apply(null, new Array(frame_num)).map(function(v, c){
        const filename = sprintf("%03d.gif", c);
        const filepath = path.join(dirPath, filename);
        return filepath;
    });

    const maybeFinished = function(){
        if(counter < frame_num){
            return;
        }
        cb(filePaths);
    };

    filePaths.forEach(function(outputPath, c){
        let imArgs = [input];
        if(!program.plain){
            imArgs = imArgs.concat(['-modulate',
                                    ['100', saturation, Math.floor(c * 360 / frame_num)].join(',')]);
        }
        if(program.guruguru){
            imArgs = imArgs.concat(['-clone', '0', '-distort', 'SRT',  Math.floor(c * 360 / frame_num)]);
        }
        imArgs.push(outputPath);
        im.convert(imArgs, function(err, stdout){
            if(err){
                console.log(stdout.trim());
                console.error(err);
                return;
            }
            counter++;
           maybeFinished();
        });
    });
};

const onAllocatedTempDirectory = function(err, dirPath) {
    if (err) {
        console.error(err);
        return;
    }
    createFrames(dirPath, function(filePaths){
        let imArgs = ['-dispose', 'Background',
                     '-delay', delay,
                     '-loop', '0'].concat(filePaths);
        imArgs.push(output)
        im.convert(imArgs, function(err, stdout){
            if(err){
                console.error(err);
                return;
            }
        });
    });
};

module.exports = function(){
    if(input === undefined){
        console.error('input file is required');
        return;
    }
    // file exists?
    fs.open(input, 'r', function(err, fd){
        if(err){
            console.error(err);
            return;
        }
        // create temp working dir if file exists
        temp.mkdir(TEMP_DIRECTRY_PREFIX, onAllocatedTempDirectory);
        fs.close(fd);
    });
};
<commit_msg>add subtractive color processing function<commit_after>"use strict";

const DEFAULT_DELAY_TIME = 5;
const TEMP_DIRECTRY_PREFIX = 'kirakira';
const temp = require('temp').track();
const fs   = require('fs');
const util  = require('util');
const sprintf = require('sprintf').sprintf
const path = require('path');
const im = require('imagemagick');

function increaseVerbosity(v, total) {
  return total + 1;
}

let program = require('commander');
program.version('0.0.1');
program.usage('-i <input file> [options]');
program.option('-i, --input <path>', 'input file');
program.option('-o, --output [path]', 'output path');
program.option('-s, --saturation [percent value]', 'saturation value');
program.option('-p, --plain', 'Do NOT Kirakira effect', function(){return true}, 0);
program.option('--colors [value]', 'preferred number of colors in the image', parseInt);
program.option('--delay [time]', 'delay time', parseInt);
program.option('--framenum [integer]', 'frame number', parseInt);
program.option('--guruguru', 'enable guruguru effect', function(){return true}, 0);
program.parse(process.argv);
const input = program.input;
const output = program.output !== undefined ? program.output : "out.gif";
const delay = program.delay !== undefined ? program.delay : DEFAULT_DELAY_TIME;
const saturation = program.saturation !== undefined ? program.saturation : 100;
const frame_num = program.framenum !== undefined ? program.framenum : 10;

const doNothing = function(){};

const createFrames = function(dirPath, cb){
    let counter = 0;

    const filePaths = Array.apply(null, new Array(frame_num)).map(function(v, c){
        const filename = sprintf("%03d.gif", c);
        const filepath = path.join(dirPath, filename);
        return filepath;
    });

    const maybeFinished = function(){
        if(counter < frame_num){
            return;
        }
        cb(filePaths);
    };

    filePaths.forEach(function(outputPath, c){
        let imArgs = [input];
        if(!program.plain){
            imArgs = imArgs.concat(['-modulate',
                                    ['100', saturation, Math.floor(c * 360 / frame_num)].join(',')]);
        }
        if(program.colors !== undefined){
            imArgs = imArgs.concat(['-colors', program.colors]);
        }
        if(program.guruguru !== undefined){
            imArgs = imArgs.concat(['-clone', '0', '-distort', 'SRT',  Math.floor(c * 360 / frame_num)]);
        }
        imArgs.push(outputPath);
        im.convert(imArgs, function(err, stdout){
            if(err){
                console.log(stdout.trim());
                console.error(err);
                return;
            }
            counter++;
           maybeFinished();
        });
    });
};

const onAllocatedTempDirectory = function(err, dirPath) {
    if (err) {
        console.error(err);
        return;
    }
    createFrames(dirPath, function(filePaths){
        let imArgs = ['-dispose', 'Background',
                     '-delay', delay,
                     '-loop', '0'].concat(filePaths);
        imArgs.push(output)
        im.convert(imArgs, function(err, stdout){
            if(err){
                console.error(err);
                return;
            }
        });
    });
};

module.exports = function(){
    if(input === undefined){
        console.error('input file is required');
        return;
    }
    // file exists?
    fs.open(input, 'r', function(err, fd){
        if(err){
            console.error(err);
            return;
        }
        // create temp working dir if file exists
        temp.mkdir(TEMP_DIRECTRY_PREFIX, onAllocatedTempDirectory);
        fs.close(fd);
    });
};
<|endoftext|>


<commit_before>
/* Dasca, an idle game by @CylonicRaider (github.com/CylonicRaider/dasca)
 * Game implementation */

'use strict';

/* *** Utilities *** */

function $id(id, elem) {
  return (elem || document).getElementById(id);
}
function $sel(sel, elem) {
  return (elem || document).querySelector(sel);
}
function $selAll(sel, elem) {
  return (elem || document).querySelectorAll(sel);
}

/* Create a DOM element */
function $makeNode(tag, className, attrs, children) {
  /* Allow omitting parameters */
  if (Array.isArray(className)) {
    if (! attrs && ! children) {
      children = className;
      attrs = null;
      className = null;
    }
  } else if (typeof className == "object" && className != null) {
    if (! children) {
      children = attrs;
      attrs = className;
      className = null;
    }
  } else if (Array.isArray(attrs) || typeof attrs == "string") {
    if (! children) {
      children = attrs;
      attrs = null;
    }
  }
  /* Create node */
  var ret = document.createElement(tag);
  /* Set classes */
  if (className) ret.className = className;
  /* Set additional attributes */
  if (attrs) {
    for (var name in attrs) {
      if (! attrs.hasOwnProperty(name)) continue;
      ret.setAttribute(name, attrs[name]);
    }
  }
  /* Add children */
  if (children) {
    if (typeof children == "string") children = [children];
    for (var i = 0; i < children.length; i++) {
      var e = children[i];
      if (! e) {
        /* Allow conditional node omission */
      } else if (typeof e == "string") {
        /* Strings become text nodes */
        ret.appendChild(document.createTextNode(e));
      } else if (typeof e != "object") {
        /* Other primitive types are not allowed */
        throw new Error("Bad child encountered during DOM node creation");
      } else if (Array.isArray(e)) {
        /* Arrays are handled recursively */
        ret.appendChild($makeNode.apply(null, e));
      } else {
        /* Everything else is assumed to be a DOM node */
        ret.appendChild(e);
      }
    }
  }
  return ret;
}

/* Show the given UI element, hiding any siblings and showing all its
 * showable parents */
function showNode(node) {
  if (! node) return;
  /* Resolve ID-s */
  if (typeof node == "string") node = $id(node);
  /* Hide siblings */
  var prev = node.previousElementSibling, next = node.nextElementSibling;
  while (prev) {
    if (prev.classList.contains("selectable"))
      prev.classList.remove("selected");
    prev = prev.previousElementSibling;
  }
  while (next) {
    if (next.classList.contains("selectable"))
      next.classList.remove("selected");
    next = next.nextElementSibling;
  }
  /* Show parent */
  showNode(node.parentNode);
  /* Show node */
  if (node.classList && node.classList.contains("selectable"))
      node.classList.add("selected");
}

/* Hide all selectable children of node
 * Approximate opposite of showNode. */
function hideNodes(node) {
  if (! node) return;
  /* Resolve ID-s */
  if (typeof node == "string") node = $id("node");
  /* Hide children */
  for (var ch = node.firstElementChild; ch; ch = ch.nextElementSibling) {
    if (ch.classList.contains("selectable"))
      ch.classList.remove("selected");
  }
}

/* *** Game mechanics *** */

/* A value changing over time
 * A variable has a value, and a set of handlers which are invoked on every
 * update of it that return increments which are applied to the variable
 * cumulatively.
 * Handlers are objects whose "cb" method is called with three parameters:
 * variable: The Variable object.
 * delta   : The time difference since the last update.
 * now     : The current time.
 * The return values are differences whose sum is added to the value of the
 * variable after each update.
 * If the handler has a rate property, the callback is not invoked, and
 * the change is instead calculated as the product of the time passed and
 * the rate. */
function Variable(value) {
  this.value = value;
  this.handlers = [];
  this.lastUpdate = null;
}

Variable.prototype = {
  /* Aggregate the results of the handlers' return values and increment the
   * value by them. */
  update: function(now) {
    if (this.lastUpdate == null) this.lastUpdate = now;
    var delta = now - this.lastUpdate, incr = 0, hnd = this.handlers;
    for (var i = 0; i < hnd.length; i++) {
      if (hdn[i].rate != null) {
        incr += hnd[i].rate * delta;
      } else {
        incr += hnd[i].cb(this, delta, now);
      }
    }
    this.value += incr;
  },

  /* OOP */
  constructor: Variable
};

/* The main game object */
function Game(state) {
  if (state == null) {
    this.state = new GameState(this);
  } else {
    var env = Object.create(window);
    env.game = this;
    this.state = deserialize(state, env);
  }
}

Game.prototype = {
  /* OOP */
  constructor: Game
};

/* The (serializable) state of a game
 * The constructor creates a new state; for restoring a saved one, use the
 * deserialization function (in a suitable environment, which is created by
 * the constructor of Game). */
function GameState(game) {
  this._game = game;
}

GameState.prototype = {
  /* OOP */
  constructor: GameState,

  /* Deserialization */
  __restore__: function(obj, env) {
    var ret = Object.create(GameState);
    for (var key in obj) {
      if (! /^_/.test(key) && obj.hasOwnProperty(key)) ret[key] = obj[key];
    }
    ret._game = env.game;
    return ret;
  }
};

/* *** Initialization *** */

function init() {
  $id("startgame").addEventListener("click", function() {
    showNode("mainscreen");
  });
  $id("credits-title").addEventListener("click", function() {
    showNode("creditscreen");
  });
  $id("back-credits").addEventListener("click", function() {
    showNode("titlescreen");
  });
  showNode("titlescreen");
}

window.addEventListener("load", init);
<commit_msg>Commence game UI object<commit_after>
/* Dasca, an idle game by @CylonicRaider (github.com/CylonicRaider/dasca)
 * Game implementation */

'use strict';

/* *** Utilities *** */

function $id(id, elem) {
  return (elem || document).getElementById(id);
}
function $sel(sel, elem) {
  return (elem || document).querySelector(sel);
}
function $selAll(sel, elem) {
  return (elem || document).querySelectorAll(sel);
}

/* Create a DOM element */
function $makeNode(tag, className, attrs, children) {
  /* Allow omitting parameters */
  if (Array.isArray(className)) {
    if (! attrs && ! children) {
      children = className;
      attrs = null;
      className = null;
    }
  } else if (typeof className == "object" && className != null) {
    if (! children) {
      children = attrs;
      attrs = className;
      className = null;
    }
  } else if (Array.isArray(attrs) || typeof attrs == "string") {
    if (! children) {
      children = attrs;
      attrs = null;
    }
  }
  /* Create node */
  var ret = document.createElement(tag);
  /* Set classes */
  if (className) ret.className = className;
  /* Set additional attributes */
  if (attrs) {
    for (var name in attrs) {
      if (! attrs.hasOwnProperty(name)) continue;
      ret.setAttribute(name, attrs[name]);
    }
  }
  /* Add children */
  if (children) {
    if (typeof children == "string") children = [children];
    for (var i = 0; i < children.length; i++) {
      var e = children[i];
      if (! e) {
        /* Allow conditional node omission */
      } else if (typeof e == "string") {
        /* Strings become text nodes */
        ret.appendChild(document.createTextNode(e));
      } else if (typeof e != "object") {
        /* Other primitive types are not allowed */
        throw new Error("Bad child encountered during DOM node creation");
      } else if (Array.isArray(e)) {
        /* Arrays are handled recursively */
        ret.appendChild($makeNode.apply(null, e));
      } else {
        /* Everything else is assumed to be a DOM node */
        ret.appendChild(e);
      }
    }
  }
  return ret;
}

/* Show the given UI element, hiding any siblings and showing all its
 * showable parents */
function showNode(node) {
  if (! node) return;
  /* Resolve ID-s */
  if (typeof node == "string") node = $id(node);
  /* Hide siblings */
  var prev = node.previousElementSibling, next = node.nextElementSibling;
  while (prev) {
    if (prev.classList.contains("selectable"))
      prev.classList.remove("selected");
    prev = prev.previousElementSibling;
  }
  while (next) {
    if (next.classList.contains("selectable"))
      next.classList.remove("selected");
    next = next.nextElementSibling;
  }
  /* Show parent */
  showNode(node.parentNode);
  /* Show node */
  if (node.classList && node.classList.contains("selectable"))
      node.classList.add("selected");
}

/* Hide all selectable children of node
 * Approximate opposite of showNode. */
function hideNodes(node) {
  if (! node) return;
  /* Resolve ID-s */
  if (typeof node == "string") node = $id("node");
  /* Hide children */
  for (var ch = node.firstElementChild; ch; ch = ch.nextElementSibling) {
    if (ch.classList.contains("selectable"))
      ch.classList.remove("selected");
  }
}

/* *** Game mechanics *** */

/* A value changing over time
 * A variable has a value, and a set of handlers which are invoked on every
 * update of it that return increments which are applied to the variable
 * cumulatively.
 * Handlers are objects whose "cb" method is called with three parameters:
 * variable: The Variable object.
 * delta   : The time difference since the last update.
 * now     : The current time.
 * The return values are differences whose sum is added to the value of the
 * variable after each update.
 * If the handler has a rate property, the callback is not invoked, and
 * the change is instead calculated as the product of the time passed and
 * the rate. */
function Variable(value) {
  this.value = value;
  this.handlers = [];
  this.lastUpdate = null;
}

Variable.prototype = {
  /* Aggregate the results of the handlers' return values and increment the
   * value by them. */
  update: function(now) {
    if (this.lastUpdate == null) this.lastUpdate = now;
    var delta = now - this.lastUpdate, incr = 0, hnd = this.handlers;
    for (var i = 0; i < hnd.length; i++) {
      if (hdn[i].rate != null) {
        incr += hnd[i].rate * delta;
      } else {
        incr += hnd[i].cb(this, delta, now);
      }
    }
    this.value += incr;
  },

  /* OOP */
  constructor: Variable
};

/* The main game object */
function Game(state) {
  if (state == null) {
    this.state = new GameState(this);
  } else {
    var env = Object.create(window);
    env.game = this;
    this.state = deserialize(state, env);
  }
  this.ui = new GameUI(this);
}

Game.prototype = {
  /* OOP */
  constructor: Game
};

/* The (serializable) state of a game
 * The constructor creates a new state; for restoring a saved one, use the
 * deserialization function (in a suitable environment, which is created by
 * the constructor of Game). */
function GameState(game) {
  this._game = game;
}

GameState.prototype = {
  /* OOP */
  constructor: GameState,

  /* Deserialization */
  __restore__: function(obj, env) {
    var ret = Object.create(GameState);
    for (var key in obj) {
      if (! /^_/.test(key) && obj.hasOwnProperty(key)) ret[key] = obj[key];
    }
    ret._game = env.game;
    return ret;
  }
};

/* The DOM-based user interface of the game */
function GameUI(game) {
  this.game = game;
  this.root = null;
  this.parent = null;
}

GameUI.prototype = {
  /* Produce the DOM tree corresponding to this object */
  render: function() {
    if (this.root == null) {
      this.root = $makeNode("div", {id: "gamepane"});
    }
    return this.root;
  },

  /* Embed the game's UI into the given DOM node
   * If not already done, the UI is constructed. */
  mount: function(parent) {
    this.parent = parent;
    parent.appendChild(this.render());
  },

  /* Consistency */
  constructor: GameUI
};

/* *** Initialization *** */

function init() {
  $id("startgame").addEventListener("click", function() {
    showNode("mainscreen");
  });
  $id("credits-title").addEventListener("click", function() {
    showNode("creditscreen");
  });
  $id("back-credits").addEventListener("click", function() {
    showNode("titlescreen");
  });
  showNode("titlescreen");
}

window.addEventListener("load", init);
<|endoftext|>


<commit_before>var Bind = require("github/jillix/bind");
var Events = require("github/jillix/events");

module.exports = function(config) {

    var DmsTree = this;
    Events.call(DmsTree, config);

    var storage = {};

    DmsTree.buildFrom = function (items, options) {

        var $tree = $(".dms-tree", DmsTree.dom);
        var $typeTemplates = $(".type-templates", DmsTree.dom);

        switch (Object.prototype.toString.call(items)) {
            // object
            case "[object Object]":
                var crudObj = {
                    t: "_list",
                    q: {
                        "_ln._tp": {
                            $ne: "_list"
                        },
                        "_ln": {
                            $elemMatch: {
                                _id: items._id,
                                _tp: "_template"
                            }
                        }
                    }
                };

                // -> emit -> bind-crud -> callback -> buildFrom Array
                DmsTree.emit("find", crudObj, function (err, docs) {
                    if (err) {
                        alert(err);
                        return;
                    }

                    DmsTree.buildFrom(docs, options);
                });

                crudObj = {
                    t: "_list",
                    q: {
                        _ln: {
                            $elemMatch: {
                                _id: items._id
                            }
                        }
                    },
                    f: {
                        $none: 1,
                        _id: 0
                    }
                };

                DmsTree.emit("find", crudObj, function (err, docs) {
                    if (err) {
                        alert(err);
                        return;
                    }

                    var $all = $(".all-template", $typeTemplates)
                        .clone()
                        .removeClass("all-template");

                    $(".all", $all).text(docs.length);
                    $tree.prepend($all);
                });
                return;
            // array
            case "[object Array]":
                break;
            // other type
            default:
                return;
        }

        $tree.empty();
        // an empty array
        if (!items || !items.length) { return; }
        storage = {};

        var $folderTempl = $(".folder-template", $typeTemplates);
        var $itemsToAppend = $("<div>");

        for (var i in items) {
            var item = items[i];

            storage[item._id] = item;

            var $newFolder = $folderTempl.clone();

            $newFolder
                .attr("data-id", item._id)
                .removeClass("folder-template")
                .find(".name").text(item.name)

            $itemsToAppend.append($newFolder);
        }

        $tree.append($itemsToAppend.html());
        $tree.find("li").hide().slideDown();
    };

    $(DmsTree.dom).off("click", ".folder");
    $(DmsTree.dom).on("click", ".folder", function () {

        var $item = $(this);
        $item = $item.closest("li");

        if (DmsTree.isLoading($item)) { return; }

        var dataItem = storage[$item.attr("data-id")];

        if (DmsTree.folderIsOpened($item)) {
            DmsTree.closeFolder($item);
            DmsTree.collapse($item);
            return;
        }

        DmsTree.startLoading($item);

        var crudObj = {
            t: "_list",
            q: {
                "_ln._id": dataItem._id
            }
        }

        DmsTree.emit("find", crudObj, function (err, docs) {

            if (err) {
                alert(err);
                return;
            }

            // TODO Just simulating a timeout
            setTimeout(function () {
            DmsTree.expand($item, docs);
            DmsTree.stopLoading($item);
            DmsTree.openFolder($item);
            }, 1000);
        });
    });

    ///////////////////////////////
    // Open-Close functions
    ///////////////////////////////
    DmsTree.openFolder = function (jQueryElement) {

        jQueryElement = $(jQueryElement);
        if (jQueryElement.attr("data-loading")) { return; }

        var $openClose = jQueryElement.find(".open-close");

        $openClose.children().first().addClass("hide");
        $openClose.children().last().removeClass("hide");
        jQueryElement.find(".chevron").toggleClass("icon-chevron-right icon-chevron-down");
    };

    DmsTree.closeFolder = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        if (jQueryElement.attr("data-loading")) { return; }

        var $openClose = jQueryElement.find(".open-close");

        $openClose.children().last().addClass("hide");
        $openClose.children().first().removeClass("hide");
        jQueryElement.find(".chevron").toggleClass("icon-chevron-right icon-chevron-down");
    };

    DmsTree.folderIsOpened = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        var $openClose = jQueryElement.find(".open-close");

        if ($openClose.children().last().hasClass("hide")) { return false; }
        return true;
    };

    ///////////////////////////////
    // Loading functions
    ///////////////////////////////
    DmsTree.startLoading = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        var $loading = jQueryElement.find(".loading-toggle");

        $loading.children().first().removeClass("hide");
        $loading.children().last().addClass("hide");
        jQueryElement.attr("data-loading", "true");
    };

    DmsTree.stopLoading = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        var $loading = jQueryElement.find(".loading-toggle");

        $loading.children().first().addClass("hide");
        var $last = $loading.children().last();
        $last.removeClass("hide");
        jQueryElement.attr("data-loading", "");
    };

    DmsTree.isLoading = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        if (jQueryElement.attr("data-loading")) { return true; }
        return false;
    };

    DmsTree.expand = function (clickedElement, docs) {

        clickedElement = $(clickedElement);

        if (clickedElement.next().prop("tagName") === "UL") { return; }

        var $ul = $("<ul>");
        for (var i in docs) {
            var doc = docs[i];
            storage[doc._id] = doc;
            var templClass = doc.type + "-template";
            var $newItem = $("." + templClass)
                            .clone()
                            .removeClass(templClass);

            $newItem.attr("data-id", doc._id);
            $newItem.find(".name").text(doc.name);
            $ul.append($newItem);
        }

        clickedElement.after($ul);
        $ul.hide().slideDown();
    };

    DmsTree.collapse = function (clickedElement) {
        clickedElement = $(clickedElement);
        var folderContent = clickedElement.next();
        folderContent.slideUp(function () {
            folderContent.remove();
        });
    };
};
<commit_msg>The new item can be a folder or a list, not only a folder.<commit_after>var Bind = require("github/jillix/bind");
var Events = require("github/jillix/events");

module.exports = function(config) {

    var DmsTree = this;
    Events.call(DmsTree, config);

    var storage = {};

    DmsTree.buildFrom = function (items, options) {

        var $tree = $(".dms-tree", DmsTree.dom);
        var $typeTemplates = $(".type-templates", DmsTree.dom);

        switch (Object.prototype.toString.call(items)) {
            // object
            case "[object Object]":
                var crudObj = {
                    t: "_list",
                    q: {
                        "_ln._tp": {
                            $ne: "_list"
                        },
                        "_ln": {
                            $elemMatch: {
                                _id: items._id,
                                _tp: "_template"
                            }
                        }
                    }
                };

                // -> emit -> bind-crud -> callback -> buildFrom Array
                DmsTree.emit("find", crudObj, function (err, docs) {
                    if (err) {
                        alert(err);
                        return;
                    }

                    DmsTree.buildFrom(docs, options);
                });

                crudObj = {
                    t: "_list",
                    q: {
                        _ln: {
                            $elemMatch: {
                                _id: items._id
                            }
                        }
                    },
                    f: {
                        $none: 1,
                        _id: 0
                    }
                };

                DmsTree.emit("find", crudObj, function (err, docs) {
                    if (err) {
                        alert(err);
                        return;
                    }

                    var $all = $(".all-template", $typeTemplates)
                        .clone()
                        .removeClass("all-template");

                    $(".all", $all).text(docs.length);
                    $tree.prepend($all);
                });
                return;
            // array
            case "[object Array]":
                break;
            // other type
            default:
                return;
        }

        $tree.empty();
        // an empty array
        if (!items || !items.length) { return; }
        storage = {};

        var $itemsToAppend = $("<div>");

        for (var i in items) {
            var item = items[i];
            var $newItem = $("." + item.type + "-template", $typeTemplates).clone();

            storage[item._id] = item;

            $newItem
                .attr("data-id", item._id)
                .removeClass(item.type + "-template")
                .find(".name").text(item.name)

            $itemsToAppend.append($newItem);
        }

        $tree.append($itemsToAppend.html());
        $tree.find("li").hide().slideDown();
    };

    $(DmsTree.dom).off("click", ".folder");
    $(DmsTree.dom).on("click", ".folder", function () {

        var $item = $(this);
        $item = $item.closest("li");

        if (DmsTree.isLoading($item)) { return; }

        var dataItem = storage[$item.attr("data-id")];

        if (DmsTree.folderIsOpened($item)) {
            DmsTree.closeFolder($item);
            DmsTree.collapse($item);
            return;
        }

        DmsTree.startLoading($item);

        var crudObj = {
            t: "_list",
            q: {
                "_ln._id": dataItem._id
            }
        }

        DmsTree.emit("find", crudObj, function (err, docs) {

            if (err) {
                alert(err);
                return;
            }

            // TODO Just simulating a timeout
            setTimeout(function () {
            DmsTree.expand($item, docs);
            DmsTree.stopLoading($item);
            DmsTree.openFolder($item);
            }, 200);
        });
    });

    ///////////////////////////////
    // Open-Close functions
    ///////////////////////////////
    DmsTree.openFolder = function (jQueryElement) {

        jQueryElement = $(jQueryElement);
        if (jQueryElement.attr("data-loading")) { return; }

        var $openClose = jQueryElement.find(".open-close");

        $openClose.children().first().addClass("hide");
        $openClose.children().last().removeClass("hide");
        jQueryElement.find(".chevron").toggleClass("icon-chevron-right icon-chevron-down");
    };

    DmsTree.closeFolder = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        if (jQueryElement.attr("data-loading")) { return; }

        var $openClose = jQueryElement.find(".open-close");

        $openClose.children().last().addClass("hide");
        $openClose.children().first().removeClass("hide");
        jQueryElement.find(".chevron").toggleClass("icon-chevron-right icon-chevron-down");
    };

    DmsTree.folderIsOpened = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        var $openClose = jQueryElement.find(".open-close");

        if ($openClose.children().last().hasClass("hide")) { return false; }
        return true;
    };

    ///////////////////////////////
    // Loading functions
    ///////////////////////////////
    DmsTree.startLoading = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        var $loading = jQueryElement.find(".loading-toggle");

        $loading.children().first().removeClass("hide");
        $loading.children().last().addClass("hide");
        jQueryElement.attr("data-loading", "true");
    };

    DmsTree.stopLoading = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        var $loading = jQueryElement.find(".loading-toggle");

        $loading.children().first().addClass("hide");
        var $last = $loading.children().last();
        $last.removeClass("hide");
        jQueryElement.attr("data-loading", "");
    };

    DmsTree.isLoading = function (jQueryElement) {
        jQueryElement = $(jQueryElement);
        if (jQueryElement.attr("data-loading")) { return true; }
        return false;
    };

    DmsTree.expand = function (clickedElement, docs) {

        clickedElement = $(clickedElement);

        if (clickedElement.next().prop("tagName") === "UL") { return; }

        var $ul = $("<ul>");
        for (var i in docs) {
            var doc = docs[i];
            storage[doc._id] = doc;
            var templClass = doc.type + "-template";
            var $newItem = $("." + templClass)
                            .clone()
                            .removeClass(templClass);

            $newItem.attr("data-id", doc._id);
            $newItem.find(".name").text(doc.name);
            $ul.append($newItem);
        }

        clickedElement.after($ul);
        $ul.hide().slideDown();
    };

    DmsTree.collapse = function (clickedElement) {
        clickedElement = $(clickedElement);
        var folderContent = clickedElement.next();
        folderContent.slideUp(function () {
            folderContent.remove();
        });
    };
};
<|endoftext|>


<commit_before>if (require('electron-squirrel-startup')) return;
const $ = jQuery = require('jquery')
const http       = require('http')
, CLogger  = require('node-clogger')
const path = require('path')
const nightlife  = require('nightlife-rabbit')
    , autobahn = require('autobahn')
const child_process = require("child_process")
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow

let backendProcess = undefined

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
  mainWindow = new BrowserWindow({width: 1200, height: 900})
  mainWindow.loadURL("file://" + __dirname + "/src/index.html")

  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null

    if (backendProcess){
      try {
        if (process.platform == "darwin") {
          backendProcess.kill()
        } else if (process.platform == "win32") {
          child_process.spawn('taskkill', ['/pid', backendProcess.pid, '/T', '/F'])
        }
        console.log('************** KILLED BACKEND ****************')
      }
      catch(e){
        console.log(e)
      }
    }

    app.quit()
  })
}

function startWampRouter() {
    var router = nightlife.createRouter({
        httpServer: http.createServer(),
        port: 8080,
        path: '/ws',
        autoCreateRealms: true,
        logger: new CLogger({name: 'nightlife-router'})
    });
}

function startBackend() {
  if (process.platform == "darwin") {
    backendProcess = child_process.exec(app.getAppPath() + "/backend-dist/mac/otone_client " + app.getAppPath());
  } else if (process.platform == "win32") {
    backendProcess = child_process.spawn(app.getAppPath() + "\\backend-dist\\win\\otone_client.exe ", [app.getAppPath()]);
  }
}

app.on('ready', createWindow)
app.on('ready', startWampRouter)
app.on('ready', startBackend)

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  if (mainWindow === null) {
    createWindow()
  }
})
<commit_msg>kill otone_client.exe on load incase a process is still running<commit_after>if (require('electron-squirrel-startup')) return;
const $ = jQuery = require('jquery')
const http       = require('http')
, CLogger  = require('node-clogger')
const path = require('path')
const nightlife  = require('nightlife-rabbit')
    , autobahn = require('autobahn')
const child_process = require("child_process")
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow

let backendProcess = undefined

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
  mainWindow = new BrowserWindow({width: 1200, height: 900})
  mainWindow.loadURL("file://" + __dirname + "/src/index.html")

  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null

    if (backendProcess){
      try {
        if (process.platform == "darwin") {
          backendProcess.kill()
        } else if (process.platform == "win32") {
          child_process.exec('taskkill /T /F /IM otone_client.exe');
        }
        console.log('************** KILLED BACKEND ****************')
      }
      catch(e){
        console.log(e)
      }
    }

    app.quit()
  })
}

function startWampRouter() {
    var router = nightlife.createRouter({
        httpServer: http.createServer(),
        port: 8080,
        path: '/ws',
        autoCreateRealms: true,
        logger: new CLogger({name: 'nightlife-router'})
    });
}

function startBackend() {
  if (process.platform == "darwin") {
    backendProcess = child_process.exec(app.getAppPath() + "/backend-dist/mac/otone_client " + app.getAppPath());
  } else if (process.platform == "win32") {
    if (process.platform == "win32") {
      child_process.exec('taskkill /T /F /IM otone_client.exe',function(error, stdout, stderr){
        backendProcess = child_process.spawn(app.getAppPath() + "\\backend-dist\\win\\otone_client.exe ", [app.getAppPath()]);
      });
    }
  }
}

app.on('ready', createWindow)
app.on('ready', startWampRouter)
app.on('ready', startBackend)

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  if (mainWindow === null) {
    createWindow()
  }
})
<|endoftext|>


<commit_before>var APIClient = require('./lib/api_client');
var blocktrail = require('./lib/blocktrail');

Object.keys(blocktrail).forEach(function(key) {
    APIClient[key] = blocktrail[key];
});

/*
 * we used APIClient as base export so that people can client require('blocktrail')
 *  but that's deprecated and they should require('blocktrail').BlocktrailSDK now, but leaving it for now
 */

APIClient.BlocktrailSDK = APIClient;
APIClient.Wallet = require('./lib/wallet');
APIClient.BackupGenerator = require('./lib/backup_generator');
APIClient.Request = require('./lib/request');

APIClient.WalletSweeper = require('./lib/wallet_sweeper');
APIClient.UnspentOutputFinder = require('./lib/unspent_output_finder');

// data service providers, for wallet recovery
APIClient.BlocktrailBitcoinService = require('./lib/services/blocktrail_bitcoin_service');
APIClient.InsightBitcoinService = require('./lib/services/insight_bitcoin_service');

// expose these for using in the browser
APIClient.randomBytes = require('randombytes');
APIClient.lodash = require('lodash');
APIClient.CryptoJS = require('crypto-js');
APIClient.debug = require('debug');
APIClient.bip39 = require('bip39');
APIClient.bitcoin = require('bitcoinjs-lib');
APIClient.superagent = require('superagent');

exports = module.exports = APIClient;
<commit_msg>expore Buffer for debugging purposes<commit_after>var APIClient = require('./lib/api_client');
var blocktrail = require('./lib/blocktrail');

Object.keys(blocktrail).forEach(function(key) {
    APIClient[key] = blocktrail[key];
});

/*
 * we used APIClient as base export so that people can client require('blocktrail')
 *  but that's deprecated and they should require('blocktrail').BlocktrailSDK now, but leaving it for now
 */

APIClient.BlocktrailSDK = APIClient;
APIClient.Wallet = require('./lib/wallet');
APIClient.BackupGenerator = require('./lib/backup_generator');
APIClient.Request = require('./lib/request');

APIClient.WalletSweeper = require('./lib/wallet_sweeper');
APIClient.UnspentOutputFinder = require('./lib/unspent_output_finder');

// data service providers, for wallet recovery
APIClient.BlocktrailBitcoinService = require('./lib/services/blocktrail_bitcoin_service');
APIClient.InsightBitcoinService = require('./lib/services/insight_bitcoin_service');

// expose these for using in the browser
APIClient.randomBytes = require('randombytes');
APIClient.lodash = require('lodash');
APIClient.CryptoJS = require('crypto-js');
APIClient.debug = require('debug');
APIClient.bip39 = require('bip39');
APIClient.bitcoin = require('bitcoinjs-lib');
APIClient.superagent = require('superagent');
APIClient.Buffer = Buffer;

exports = module.exports = APIClient;
<|endoftext|>


<commit_before>document.addEventListener('DOMContentLoaded', function(){
	function teamValue () {
		return document.forms[0].teams.value;
		}

	var people = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven"];

	document.getElementById('submit').addEventListener("click", function(){
			switch (teamValue()) {
				case "randomstudent":
				    var rand = getRandomInt(0, people.length);
				    var person = people[rand];
					event.preventDefault();
					var $li = document.createElement('li');
					$li.innerHTML = person;
					var $ul = document.getElementById('results');
					$ul.appendChild($li);
					break;
				case "neighboringpair":
					alert("You clicked the 2nd selection of " + teamValue());
					break;
				case "neighboringthree":
					alert("You clicked the 3rd selection of " + teamValue());
					break;
				case "randompair":
					alert("You clicked the 4th selection of " + teamValue());
					break;
				case "randomthree":
					alert("You clicked the 5th selection of " + teamValue());
					break;
				case "randomnpair":
					alert("You clicked the 6th selection of " + teamValue());
					break;
				}
		});

});

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}<commit_msg>Added neighboring pair and neighboring three function<commit_after>document.addEventListener('DOMContentLoaded', function(){
	function teamValue () {
		return document.forms[0].teams.value;
		}

	var people = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven"];

	function getRandomInt(min, max) {
  		return Math.floor(Math.random() * (max - min)) + min;
	}

	function addItemToList($list, items){
    var $li = document.createElement("li");
    $li.innerHTML = items;
    $list.appendChild($li);
}

	document.getElementById('submit').addEventListener("click", function(){
			event.preventDefault();
        	var $ul = document.getElementById("results");
       		 $ul.innerHTML = "";

			switch (teamValue()) {
				case "randomstudent":
				    var rand = getRandomInt(0, people.length);
				    var person = people[rand];
					event.preventDefault();
					addItemToList($ul, person);
					break;

				case "neighboringpair":
					var peopleClone = people.slice(0);
					while( peopleClone.length > 0 ){
                		var studentNames = peopleClone.splice(0, 2);
                		addItemToList($ul, studentNames.join(" & "));
					}
					break;

				case "neighboringthree":
					var peopleClone = people.slice(0);
					while( peopleClone.length > 0 ){
                		var studentNames = peopleClone.splice(0, 3);
                		addItemToList($ul, studentNames.join(" & "));
					}
					break;

				case "randompair":
					alert("You clicked the 4th selection of " + teamValue());
					break;
				case "randomthree":
					alert("You clicked the 5th selection of " + teamValue());
					break;
				case "randomnpair":
					alert("You clicked the 6th selection of " + teamValue());
					break;
				}
		});

});
<|endoftext|>


<commit_before>
import { ShaderCache } from './shader_cache.js';
//import { WebGl } from './webgl.js';

import iblFiltering from './shaders/ibl_filtering.frag';
import panoramaToCubeMap from './shaders/panorama_to_cubemap.frag';
import debugOutput from './shaders/debug.frag';
import fullscreenShader from './shaders/fullscreen.vert';

class iblSampler
{
    constructor(canvas, basePath)
    {
        this.canvas = canvas;
        this.basePath = basePath;

        this.gl = canvas.getContext('webgl2');
        this.shader = undefined; // current shader
        this.currentWidth = 0;
        this.currentHeight = 0;
        this.textureSize = 1024;

        this.inputTextureID = undefined;
        this.inputImage = undefined;

        this.cubemapTextureID = undefined;
        this.lambertianTextureID = undefined;
        this.ggxTextureID = undefined;
        this.sheenTextureID = undefined;

        this.framebuffer = undefined;

        const shaderSources = new Map();

        shaderSources.set("fullscreen.vert", fullscreenShader);
        shaderSources.set("panorama_to_cubemap.frag", panoramaToCubeMap);
        shaderSources.set("ibl_filtering.frag", iblFiltering);
        shaderSources.set("debug.frag", debugOutput);

        this.shaderCache = new ShaderCache(shaderSources);

        this.init();
        this.resize(canvas.clientWidth, canvas.clientHeight);

        this.status = 0;
    }

    /////////////////////////////////////////////////////////////////////

    loadTexture(src)
    {

        var image = new Image();
        image.src = src;

        var texture = this.gl.createTexture();

        this.gl.bindTexture( this.gl.TEXTURE_2D,  texture);

        var gl =   this.gl;

        image.onload =  function()
        {
            gl.bindTexture(gl.TEXTURE_2D, texture); // as this function is asynchronus, another texture could be set in between
            gl.texImage2D( gl.TEXTURE_2D, 0,  gl.RGBA,  gl.RGBA, gl.UNSIGNED_BYTE, image);
        };

        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_WRAP_S,  this.gl.MIRRORED_REPEAT);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_WRAP_T,  this.gl.MIRRORED_REPEAT);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_MIN_FILTER,  this.gl.LINEAR);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_MAG_FILTER,  this.gl.LINEAR);

        return texture;
    }

    createRenderTargetTexture()
    {

        var targetTexture =  this.gl.createTexture();
        this.gl.bindTexture( this.gl.TEXTURE_2D, targetTexture);

        // define size and format of level 0
        const level = 0;
        const internalFormat =  this.gl.RGBA;
        const border = 0;
        const format = this.gl.RGBA;
        const type =  this.gl.UNSIGNED_BYTE;
        const data = null;
        this.gl.texImage2D( this.gl.TEXTURE_2D, level, internalFormat,
            this.textureSize, this.textureSize, border,
            format, type, data);

        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_MIN_FILTER,  this.gl.LINEAR);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_WRAP_S,  this.gl.CLAMP_TO_EDGE);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_WRAP_T,  this.gl.CLAMP_TO_EDGE);

        return targetTexture;
    }

    createCubemapTexture(withMipmaps)
    {
        var targetTexture =  this.gl.createTexture();
        this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, targetTexture);

        // define size and format of level 0
        const level = 0;
        const internalFormat =  this.gl.RGBA;
        const border = 0;
        const format = this.gl.RGBA;
        const type =  this.gl.UNSIGNED_BYTE;
        const data = null;

        for(var i = 0; i < 6; ++i)
        {
            this.gl.texImage2D(this.gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, internalFormat,
                this.textureSize, this.textureSize, border,
                format, type, data);

        }

        if(withMipmaps)
        {
            this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_MIN_FILTER,  this.gl.LINEAR_MIPMAP_LINEAR);
        }
        else
        {
            this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_MIN_FILTER,  this.gl.LINEAR);
        }
        this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_MAG_FILTER,  this.gl.LINEAR);
        this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_WRAP_S,  this.gl.CLAMP_TO_EDGE);
        this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_WRAP_T,  this.gl.CLAMP_TO_EDGE);
        this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_WRAP_R,  this.gl.CLAMP_TO_EDGE);

        return targetTexture;
    }

    init()
    {
        this.gl.disable(this.gl.DEPTH_TEST);
        this.gl.clearDepth(1.0);

        this.inputTextureID = this.loadTexture("assets/environments/helipad.jpg");

        this.cubemapTextureID = this.createCubemapTexture(true);

        this.framebuffer = this.gl.createFramebuffer();

        this.lambertianTextureID = this.createCubemapTexture(false);
        this.ggxTextureID = this.createCubemapTexture(true);
        this.sheenTextureID = this.createCubemapTexture(true);

        this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.ggxTextureID);
        this.gl.generateMipmap(this.gl.TEXTURE_CUBE_MAP);

    }

    resize(width, height)
    {
        if (this.currentWidth !== width || this.currentHeight !== height)
        {
            this.canvas.width = width;
            this.canvas.height = height;
            this.currentHeight = height;
            this.currentWidth = width;
            this.gl.viewport(0, 0, width, height);
        }
    }

    panoramaToCubeMap()
    {
        var gl = this.gl;

        for(var i = 0; i < 6; ++i)
        {
            gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
            var side = i;
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X+side, this.cubemapTextureID, 0);

            gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.cubemapTextureID);

            gl.viewport(0, 0,  this.textureSize,  this.textureSize);

            gl.clearColor(0, 0.0, 0.0, 0.0);
            gl.clear(gl.COLOR_BUFFER_BIT| gl.DEPTH_BUFFER_BIT);

            const vertexHash = this.shaderCache.selectShader("fullscreen.vert", []);
            const fragmentHash = this.shaderCache.selectShader("panorama_to_cubemap.frag", []);

            this.shader = this.shaderCache.getShaderProgram(fragmentHash, vertexHash);
            this.gl.useProgram(this.shader.program);

            //  TEXTURE0 = active.
            this.gl.activeTexture(this.gl.TEXTURE0+0);

            // Bind texture ID to active texture
            this.gl.bindTexture(this.gl.TEXTURE_2D, this.inputTextureID);

            // map shader uniform to texture unit (TEXTURE0)
            const location = this.gl.getUniformLocation(this.shader.program,"u_panorama");
            this.gl.uniform1i(location, 0); // texture unit 0 (TEXTURE0)

            this.shader.updateUniform("u_currentFace", i);

            //fullscreen triangle
            this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
        }

        gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.cubemapTextureID);
        this.gl.generateMipmap(this.gl.TEXTURE_CUBE_MAP);

    }

    applyFilter(
        distribution,
        roughness,
        targetMipLevel,
        targetTexture)
    {
        var gl = this.gl;
        var currentTextureSize =  this.textureSize>>(targetMipLevel);

        for(var i = 0; i < 6; ++i)
        {

            gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
            var side = i;
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X+side, targetTexture, targetMipLevel);

            gl.bindTexture(gl.TEXTURE_CUBE_MAP, targetTexture);

            gl.viewport(0, 0, currentTextureSize, currentTextureSize);

            gl.clearColor(0, 0.0, 0.0, 0.0);
            gl.clear(gl.COLOR_BUFFER_BIT| gl.DEPTH_BUFFER_BIT);

            const vertexHash = this.shaderCache.selectShader("fullscreen.vert", []);
            const fragmentHash = this.shaderCache.selectShader("ibl_filtering.frag", []);

            this.shader = this.shaderCache.getShaderProgram(fragmentHash, vertexHash);
            this.gl.useProgram(this.shader.program);

            //  TEXTURE0 = active.
            this.gl.activeTexture(this.gl.TEXTURE0+0);

            // Bind texture ID to active texture
            this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.cubemapTextureID);

            // map shader uniform to texture unit (TEXTURE0)
            const location = this.gl.getUniformLocation(this.shader.program,"u_cubemapTexture");
            this.gl.uniform1i(location, 0); // texture unit 0

            //const roughness =  (currentMipLevel) /  (outputMipLevels - 1);
            const sampleCount = 1024;
            //const currentMipLevel = 0;

            const width = this.textureSize;
            const lodBias = 0.0;
            //const distribution = 1;

            this.shader.updateUniform("u_roughness", roughness);
            this.shader.updateUniform("u_sampleCount", sampleCount);
            this.shader.updateUniform("u_currentMipLevel", targetMipLevel);
            this.shader.updateUniform("u_width", width);
            this.shader.updateUniform("u_lodBias", lodBias);
            this.shader.updateUniform("u_distribution", distribution);
            this.shader.updateUniform("u_currentFace", i);

            //fullscreen triangle
            this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);

        }

    }

    cubeMapToLambertian()
    {
        this.applyFilter(
            0,
            0.0,
            0,
            this.lambertianTextureID);
    }

    cubeMapToGGX()
    {
        var outputMipLevels = 11;
        for(var currentMipLevel = 0; currentMipLevel < 6; ++currentMipLevel)
        {
            const roughness =  (currentMipLevel) /  (outputMipLevels - 1);
            this.applyFilter(
                1,
                roughness,
                currentMipLevel,
                this.ggxTextureID);
        }
    }

    drawDebugOutput()
    {
        //render to canvas:
        this.gl.bindFramebuffer(  this.gl.FRAMEBUFFER, null);
        this.gl.viewport(0, 0,  this.gl.canvas.width,  this.gl.canvas.height);

        this.gl.clearColor(0, 0.1, 0.1, 1);
        this.gl.clear( this.gl.COLOR_BUFFER_BIT|  this.gl.DEPTH_BUFFER_BIT);

        if( this.cubemapTextureID === undefined)
        {
            console.log("cubemapTextureID undefined");
            return;
        }

        const vertexHash = this.shaderCache.selectShader("fullscreen.vert", []);
        const fragmentHash = this.shaderCache.selectShader("debug.frag", []);

        if (fragmentHash && vertexHash)
        {
            this.shader = this.shaderCache.getShaderProgram(fragmentHash, vertexHash);
        }

        if (this.shader === undefined)
        {
            console.log("shader program undefined");
            return;
        }

        this.gl.useProgram(this.shader.program);

        //  TEXTURE0 = active.
        this.gl.activeTexture(this.gl.TEXTURE0+0);

        // Bind texture ID to active texture
        // this.gl.bindTexture(this.gl.TEXTURE_2D, this.inputTextureID);
        // this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.cubemapTextureID);
        //this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.lambertianTextureID);
        this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.ggxTextureID);
        // this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.sheenTextureID);

        // map shader uniform to texture unit (TEXTURE0)
        const location = this.gl.getUniformLocation(this.shader.program,"u_inputTexture");
        this.gl.uniform1i(location, 0); // texture unit 0

        this.shader.updateUniform("u_currentFace", 0);

        //fullscreen triangle
        this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
    }

    filter()
    {

        this.panoramaToCubeMap();
        this.cubeMapToLambertian();
        this.cubeMapToGGX();
        //this.cubeMapToSheen();
    }

    drawScene()
    {

        if(this.status == 0) // filtering is done once
        {
            this.filter();
            this.status = 1;
        }

        this.drawDebugOutput();

    }

    destroy()
    {
        this.shaderCache.destroy();
    }
}

export { iblSampler };
<commit_msg>add sheen<commit_after>
import { ShaderCache } from './shader_cache.js';
//import { WebGl } from './webgl.js';

import iblFiltering from './shaders/ibl_filtering.frag';
import panoramaToCubeMap from './shaders/panorama_to_cubemap.frag';
import debugOutput from './shaders/debug.frag';
import fullscreenShader from './shaders/fullscreen.vert';

class iblSampler
{
    constructor(canvas, basePath)
    {
        this.canvas = canvas;
        this.basePath = basePath;

        this.gl = canvas.getContext('webgl2');
        this.shader = undefined; // current shader
        this.currentWidth = 0;
        this.currentHeight = 0;
        this.textureSize = 1024;

        this.inputTextureID = undefined;
        this.inputImage = undefined;

        this.cubemapTextureID = undefined;
        this.lambertianTextureID = undefined;
        this.ggxTextureID = undefined;
        this.sheenTextureID = undefined;

        this.framebuffer = undefined;

        const shaderSources = new Map();

        shaderSources.set("fullscreen.vert", fullscreenShader);
        shaderSources.set("panorama_to_cubemap.frag", panoramaToCubeMap);
        shaderSources.set("ibl_filtering.frag", iblFiltering);
        shaderSources.set("debug.frag", debugOutput);

        this.shaderCache = new ShaderCache(shaderSources);

        this.init();
        this.resize(canvas.clientWidth, canvas.clientHeight);

        this.status = 0;
    }

    /////////////////////////////////////////////////////////////////////

    loadTexture(src)
    {

        var image = new Image();
        image.src = src;

        var texture = this.gl.createTexture();

        this.gl.bindTexture( this.gl.TEXTURE_2D,  texture);

        var gl =   this.gl;

        image.onload =  function()
        {
            gl.bindTexture(gl.TEXTURE_2D, texture); // as this function is asynchronus, another texture could be set in between
            gl.texImage2D( gl.TEXTURE_2D, 0,  gl.RGBA,  gl.RGBA, gl.UNSIGNED_BYTE, image);
        };

        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_WRAP_S,  this.gl.MIRRORED_REPEAT);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_WRAP_T,  this.gl.MIRRORED_REPEAT);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_MIN_FILTER,  this.gl.LINEAR);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_MAG_FILTER,  this.gl.LINEAR);

        return texture;
    }

    createRenderTargetTexture()
    {

        var targetTexture =  this.gl.createTexture();
        this.gl.bindTexture( this.gl.TEXTURE_2D, targetTexture);

        // define size and format of level 0
        const level = 0;
        const internalFormat =  this.gl.RGBA;
        const border = 0;
        const format = this.gl.RGBA;
        const type =  this.gl.UNSIGNED_BYTE;
        const data = null;
        this.gl.texImage2D( this.gl.TEXTURE_2D, level, internalFormat,
            this.textureSize, this.textureSize, border,
            format, type, data);

        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_MIN_FILTER,  this.gl.LINEAR);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_WRAP_S,  this.gl.CLAMP_TO_EDGE);
        this.gl.texParameteri( this.gl.TEXTURE_2D,  this.gl.TEXTURE_WRAP_T,  this.gl.CLAMP_TO_EDGE);

        return targetTexture;
    }

    createCubemapTexture(withMipmaps)
    {
        var targetTexture =  this.gl.createTexture();
        this.gl.bindTexture( this.gl.TEXTURE_CUBE_MAP, targetTexture);

        // define size and format of level 0
        const level = 0;
        const internalFormat =  this.gl.RGBA;
        const border = 0;
        const format = this.gl.RGBA;
        const type =  this.gl.UNSIGNED_BYTE;
        const data = null;

        for(var i = 0; i < 6; ++i)
        {
            this.gl.texImage2D(this.gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, internalFormat,
                this.textureSize, this.textureSize, border,
                format, type, data);

        }

        if(withMipmaps)
        {
            this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_MIN_FILTER,  this.gl.LINEAR_MIPMAP_LINEAR);
        }
        else
        {
            this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_MIN_FILTER,  this.gl.LINEAR);
        }
        this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_MAG_FILTER,  this.gl.LINEAR);
        this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_WRAP_S,  this.gl.CLAMP_TO_EDGE);
        this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_WRAP_T,  this.gl.CLAMP_TO_EDGE);
        this.gl.texParameteri( this.gl.TEXTURE_CUBE_MAP,  this.gl.TEXTURE_WRAP_R,  this.gl.CLAMP_TO_EDGE);

        return targetTexture;
    }

    init()
    {
        this.gl.disable(this.gl.DEPTH_TEST);
        this.gl.clearDepth(1.0);

        this.inputTextureID = this.loadTexture("assets/environments/helipad.jpg");

        this.cubemapTextureID = this.createCubemapTexture(true);

        this.framebuffer = this.gl.createFramebuffer();

        this.lambertianTextureID = this.createCubemapTexture(false);
        this.ggxTextureID = this.createCubemapTexture(true);
        this.sheenTextureID = this.createCubemapTexture(true);

        this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.ggxTextureID);
        this.gl.generateMipmap(this.gl.TEXTURE_CUBE_MAP);

        this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.sheenTextureID);
        this.gl.generateMipmap(this.gl.TEXTURE_CUBE_MAP);

    }

    resize(width, height)
    {
        if (this.currentWidth !== width || this.currentHeight !== height)
        {
            this.canvas.width = width;
            this.canvas.height = height;
            this.currentHeight = height;
            this.currentWidth = width;
            this.gl.viewport(0, 0, width, height);
        }
    }

    panoramaToCubeMap()
    {
        var gl = this.gl;

        for(var i = 0; i < 6; ++i)
        {
            gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
            var side = i;
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X+side, this.cubemapTextureID, 0);

            gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.cubemapTextureID);

            gl.viewport(0, 0,  this.textureSize,  this.textureSize);

            gl.clearColor(0, 0.0, 0.0, 0.0);
            gl.clear(gl.COLOR_BUFFER_BIT| gl.DEPTH_BUFFER_BIT);

            const vertexHash = this.shaderCache.selectShader("fullscreen.vert", []);
            const fragmentHash = this.shaderCache.selectShader("panorama_to_cubemap.frag", []);

            this.shader = this.shaderCache.getShaderProgram(fragmentHash, vertexHash);
            this.gl.useProgram(this.shader.program);

            //  TEXTURE0 = active.
            this.gl.activeTexture(this.gl.TEXTURE0+0);

            // Bind texture ID to active texture
            this.gl.bindTexture(this.gl.TEXTURE_2D, this.inputTextureID);

            // map shader uniform to texture unit (TEXTURE0)
            const location = this.gl.getUniformLocation(this.shader.program,"u_panorama");
            this.gl.uniform1i(location, 0); // texture unit 0 (TEXTURE0)

            this.shader.updateUniform("u_currentFace", i);

            //fullscreen triangle
            this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
        }

        gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.cubemapTextureID);
        this.gl.generateMipmap(this.gl.TEXTURE_CUBE_MAP);

    }

    applyFilter(
        distribution,
        roughness,
        targetMipLevel,
        targetTexture)
    {
        var gl = this.gl;
        var currentTextureSize =  this.textureSize>>(targetMipLevel);

        for(var i = 0; i < 6; ++i)
        {

            gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
            var side = i;
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X+side, targetTexture, targetMipLevel);

            gl.bindTexture(gl.TEXTURE_CUBE_MAP, targetTexture);

            gl.viewport(0, 0, currentTextureSize, currentTextureSize);

            gl.clearColor(0, 0.0, 0.0, 0.0);
            gl.clear(gl.COLOR_BUFFER_BIT| gl.DEPTH_BUFFER_BIT);

            const vertexHash = this.shaderCache.selectShader("fullscreen.vert", []);
            const fragmentHash = this.shaderCache.selectShader("ibl_filtering.frag", []);

            this.shader = this.shaderCache.getShaderProgram(fragmentHash, vertexHash);
            this.gl.useProgram(this.shader.program);

            //  TEXTURE0 = active.
            this.gl.activeTexture(this.gl.TEXTURE0+0);

            // Bind texture ID to active texture
            this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.cubemapTextureID);

            // map shader uniform to texture unit (TEXTURE0)
            const location = this.gl.getUniformLocation(this.shader.program,"u_cubemapTexture");
            this.gl.uniform1i(location, 0); // texture unit 0

            //const roughness =  (currentMipLevel) /  (outputMipLevels - 1);
            const sampleCount = 1024;
            //const currentMipLevel = 0;

            const width = this.textureSize;
            const lodBias = 0.0;
            //const distribution = 1;

            this.shader.updateUniform("u_roughness", roughness);
            this.shader.updateUniform("u_sampleCount", sampleCount);
            this.shader.updateUniform("u_currentMipLevel", targetMipLevel);
            this.shader.updateUniform("u_width", width);
            this.shader.updateUniform("u_lodBias", lodBias);
            this.shader.updateUniform("u_distribution", distribution);
            this.shader.updateUniform("u_currentFace", i);

            //fullscreen triangle
            this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);

        }

    }

    cubeMapToLambertian()
    {
        this.applyFilter(
            0,
            0.0,
            0,
            this.lambertianTextureID);
    }

    cubeMapToGGX()
    {
        var outputMipLevels = 11;
        for(var currentMipLevel = 0; currentMipLevel < 6; ++currentMipLevel)
        {
            const roughness =  (currentMipLevel) /  (outputMipLevels - 1);
            this.applyFilter(
                1,
                roughness,
                currentMipLevel,
                this.ggxTextureID);
        }
    }

    cubeMapToSheen()
    {
        var outputMipLevels = 11;
        for(var currentMipLevel = 0; currentMipLevel < 6; ++currentMipLevel)
        {
            const roughness =  (currentMipLevel) /  (outputMipLevels - 1);
            this.applyFilter(
                2,
                roughness,
                currentMipLevel,
                this.sheenTextureID);
        }
    }

    drawDebugOutput()
    {
        //render to canvas:
        this.gl.bindFramebuffer(  this.gl.FRAMEBUFFER, null);
        this.gl.viewport(0, 0,  this.gl.canvas.width,  this.gl.canvas.height);

        this.gl.clearColor(0, 0.1, 0.1, 1);
        this.gl.clear( this.gl.COLOR_BUFFER_BIT|  this.gl.DEPTH_BUFFER_BIT);

        if( this.cubemapTextureID === undefined)
        {
            console.log("cubemapTextureID undefined");
            return;
        }

        const vertexHash = this.shaderCache.selectShader("fullscreen.vert", []);
        const fragmentHash = this.shaderCache.selectShader("debug.frag", []);

        if (fragmentHash && vertexHash)
        {
            this.shader = this.shaderCache.getShaderProgram(fragmentHash, vertexHash);
        }

        if (this.shader === undefined)
        {
            console.log("shader program undefined");
            return;
        }

        this.gl.useProgram(this.shader.program);

        //  TEXTURE0 = active.
        this.gl.activeTexture(this.gl.TEXTURE0+0);

        // Bind texture ID to active texture
        // this.gl.bindTexture(this.gl.TEXTURE_2D, this.inputTextureID);
        // this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.cubemapTextureID);
        //this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.lambertianTextureID);
        //this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.ggxTextureID);
        this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, this.sheenTextureID);

        // map shader uniform to texture unit (TEXTURE0)
        const location = this.gl.getUniformLocation(this.shader.program,"u_inputTexture");
        this.gl.uniform1i(location, 0); // texture unit 0

        this.shader.updateUniform("u_currentFace", 0);

        //fullscreen triangle
        this.gl.drawArrays(this.gl.TRIANGLES, 0, 3);
    }

    filter()
    {

        this.panoramaToCubeMap();
        this.cubeMapToLambertian();
        this.cubeMapToGGX();
        this.cubeMapToSheen();
    }

    drawScene()
    {

        if(this.status == 0) // filtering is done once
        {
            this.filter();
            this.status = 1;
        }

        this.drawDebugOutput();

    }

    destroy()
    {
        this.shaderCache.destroy();
    }
}

export { iblSampler };
<|endoftext|>