<commit_before>import path from 'path';
import Zip from 'jszip';
import Promise, { all, promisifyAll, resolve } from 'bluebird';
import {
    __,
    complement,
    concat,
    contains,
    curry,
    drop,
    equals,
    filter,
    identity,
    join,
    map,
    mapObjIndexed,
    merge,
    pipe,
    prop,
    propEq,
    sort,
    subtract,
    takeWhile,
    test,
    tryCatch,
    type,
    when,
    without
} from 'ramda';
import deepmerge from 'deepmerge';
import { emitWarning } from './input';
import { compileIndex } from './run';
import { getProperties } from './vm';

const fs = promisifyAll(require('fs'));

const defaultFileOptions = { date: new Date(1149562800000) };
const requiredFiles = ['package.json', 'index.js'];
const projectFiles = ['icon.png', ...requiredFiles];

const localeByFile = pipe(
    drop(8),
    takeWhile(complement(equals('.'))),
    join('')
);

/**
 * Converts a list of locale files to pairs containing locale strng and content
 *
 * @param {String[]} localeFiles
 * @return {Promise}
 */
function localesToPairs(localeFiles) {
    return all(localeFiles.map(localeFile => fs.readFileAsync(localeFile, 'utf-8')
        .then(JSON.parse)
        .then(json => [localeByFile(localeFile), json])));
}

/**
 * Projects locale for each translatable subfield
 *
 * @param {String} locale
 * @param {Object} config
 * @return {Object}
 */
const project = curry((locale, config) => ({
    title: { [locale]: config.title },
    description: { [locale]: config.description },
    preview: { [locale]: config.preview },
    params: mapObjIndexed(param => merge(param,
        { description: { [locale]: param.description } }), config.params)
}));

/**
 * Lazily runs the extension using all possible listed locales and extracts
 * the meta-data
 *
 * @param {[(String, *)]} locales
 * @param {String} source
 * @return {Promise}
 */
function runInAllLocales(locales, source) {
    return all([['default', {}], ...locales].map(([locale, strings]) =>
        getProperties({ name: `precompile-${locale}`, source }, strings)
            .then(project(locale))))
            .then(when(complement(propEq('length', 1)), deepmerge.all));
}

/**
 * Creates a meta file where the information about precompilation is stored
 *
 * @param {Object} locales
 * @return {Promise}
 */
function createMetaFile(locales) {
    return fs.writeFileAsync('.meta', JSON.stringify(locales));
}

/**
 * Precompiles the locale files, generating a meta file containing the meta
 *
 * @param {String[]} files
 * @return {Promise}
 */
function precompileLocales(files) {
    return resolve(files)
        .then(filter(test(/^locales\/[a-z]{2,3}(_[A-Z]{2})?\.json$/)))
        .then(localesToPairs)
        .then(locales => all([locales, compileIndex()]))
        .spread(runInAllLocales)
        .then(createMetaFile)
        .thenReturn(['.meta', ...files]);
}

/**
 * Ensures there are missing no files in order to a allow a basic compilation.
 * It also warns about possible improvements in the extensions
 *
 * @param {String[]} files
 */
function analyzeFiles(files) {
    const missingFiles = without(files, requiredFiles);

    if (missingFiles.length > 0) {
        throw new Error(`missing ${missingFiles.join(', ')} from the project`);
    }

    if (!contains('icon.png', files)) {
        emitWarning('compiling extension without providing an icon.png file');
    }

    return files;
}

const filterProjectFiles = filter(contains(__, projectFiles));

/**
 * Filters true locale files and appends the full qualified name for the
 * previous files
 *
 * @param {String[]} files
 * @return {Promise}
 */
function appendLocales(files) {
    return fs.lstatAsync('locales')
        .then(lstat => lstat.isDirectory() ? fs.readdirAsync('locales') : [])
        .then(filter(test(/^[a-z]{2}(_[A-Z]{2,3})?\.json$/)))
        .filter(filename => fs.readFileAsync(path.join('locales', filename))
            .then(pipe(JSON.parse, item => type(item) === 'Object'))
            .catchReturn(false))
        .then(pipe(map(file => path.join('locales', file)), concat(files)))
        .catchReturn(files);
}

/**
 * Opens package.json and extrats its contents. Returns a promise containing
 * the file list to be zipped and the package.json content parsed
 *
 * @param {String} dir
 * @return {Promise}
 */
function getProjectName(dir) {
    return fs.readFileAsync(path.join(dir, 'package.json'))
        .then(pipe(JSON.parse, prop('name')))
        .catchThrow(new Error('Failed to parse package.json from the project'));
}

/**
 * Generates a zip package using a node buffer containing the necessary files
 *
 * @param {String} dir
 * @param {String[]} files
 * @param {String} name
 */
const createZip = curry((dir, files) => {
    const zip = new Zip();
    files.forEach(filename => addToZip(zip, dir, filename));
    return zip;
});

/**
 * Taking account the -o parameter can be used to specify the output directory,
 * let's deal with it
 *
 * @param {String} customPath
 * @param {String} filename
 * @return {String}
 */
function resolveOutputTarget(customPath, filename) {
    const realPath = path.resolve('.', customPath);

    const getPath = tryCatch(realPath => fs.lstatSync(realPath).isDirectory()
        ? path.join(realPath, filename)
        : realPath
    , identity);

    return getPath(realPath);
}

/**
 * Saves the zip file from buffer to the filesystem
 *
 * @param {String} dir
 * @param {Zip} zip
 * @param {String} name
 */
const saveZip = curry((dir, zip, name) => {
    const target = resolveOutputTarget(dir, `${name}.rung`);

    return new Promise((resolve, reject) => {
        zip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
            .pipe(fs.createWriteStream(target))
            .on('error', reject)
            .on('finish', () => resolve(target));
    });
});

/**
 * Appends a file or folder to the zip buffer
 *
 * @param {Zip} zip
 * @param {String} dir
 * @param {String} filename
 */
function addToZip(zip, dir, filename) {
    const filePath = path.join(dir, filename);
    const lstat = fs.lstatSync(filePath);

    if (lstat.isFile()) {
        return zip.file(filename, fs.readFileSync(filePath), defaultFileOptions);
    }

    if (lstat.isDirectory()) {
        return map(file => addToZip(zip.folder(filename), filePath, file),
            fs.readdirSync(filePath));
    }

    throw new Error(`Invalid file type for ${filePath}`);
}

/**
 * Precompiles an extension and generates a .rung package
 *
 * @param {Object} args
 */
export default function build(args) {
    const dir = path.resolve('.', args._[1] || '');

    return fs.readdirAsync(dir)
        .then(analyzeFiles)
        .then(filterProjectFiles)
        .then(appendLocales)
        .then(sort(subtract))
        .then(precompileLocales)
        .then(createZip(dir))
        .then(zip => all([zip, getProjectName(dir)]))
        .spread(saveZip(args.output || '.'));
}
<commit_msg>I was using identity instead of head. :a::a::a::a:<commit_after>import path from 'path';
import Zip from 'jszip';
import Promise, { all, promisifyAll, resolve } from 'bluebird';
import {
    __,
    complement,
    concat,
    contains,
    curry,
    drop,
    equals,
    filter,
    head,
    identity,
    ifElse,
    join,
    map,
    mapObjIndexed,
    merge,
    pipe,
    prop,
    propEq,
    sort,
    subtract,
    takeWhile,
    test,
    tryCatch,
    type,
    unary,
    without
} from 'ramda';
import deepmerge from 'deepmerge';
import { emitWarning } from './input';
import { compileIndex } from './run';
import { getProperties } from './vm';

const fs = promisifyAll(require('fs'));

const defaultFileOptions = { date: new Date(1149562800000) };
const requiredFiles = ['package.json', 'index.js'];
const projectFiles = ['icon.png', ...requiredFiles];

const localeByFile = pipe(
    drop(8),
    takeWhile(complement(equals('.'))),
    join('')
);

/**
 * Converts a list of locale files to pairs containing locale strng and content
 *
 * @param {String[]} localeFiles
 * @return {Promise}
 */
function localesToPairs(localeFiles) {
    return all(localeFiles.map(localeFile => fs.readFileAsync(localeFile, 'utf-8')
        .then(JSON.parse)
        .then(json => [localeByFile(localeFile), json])));
}

/**
 * Projects locale for each translatable subfield
 *
 * @param {String} locale
 * @param {Object} config
 * @return {Object}
 */
const project = curry((locale, config) => ({
    title: { [locale]: config.title },
    description: { [locale]: config.description },
    preview: { [locale]: config.preview },
    params: mapObjIndexed(param => merge(param,
        { description: { [locale]: param.description } }), config.params)
}));

/**
 * Lazily runs the extension using all possible listed locales and extracts
 * the meta-data
 *
 * @param {[(String, *)]} locales
 * @param {String} source
 * @return {Promise}
 */
function runInAllLocales(locales, source) {
    return all([['default', {}], ...locales].map(([locale, strings]) =>
        getProperties({ name: `precompile-${locale}`, source }, strings)
            .then(project(locale))))
            .then(ifElse(propEq('length', 1), head, unary(deepmerge.all)));
}

/**
 * Creates a meta file where the information about precompilation is stored
 *
 * @param {Object} locales
 * @return {Promise}
 */
function createMetaFile(locales) {
    return fs.writeFileAsync('.meta', JSON.stringify(locales));
}

/**
 * Precompiles the locale files, generating a meta file containing the meta
 *
 * @param {String[]} files
 * @return {Promise}
 */
function precompileLocales(files) {
    return resolve(files)
        .then(filter(test(/^locales\/[a-z]{2,3}(_[A-Z]{2})?\.json$/)))
        .then(localesToPairs)
        .then(locales => all([locales, compileIndex()]))
        .spread(runInAllLocales)
        .then(createMetaFile)
        .thenReturn(['.meta', ...files]);
}

/**
 * Ensures there are missing no files in order to a allow a basic compilation.
 * It also warns about possible improvements in the extensions
 *
 * @param {String[]} files
 */
function analyzeFiles(files) {
    const missingFiles = without(files, requiredFiles);

    if (missingFiles.length > 0) {
        throw new Error(`missing ${missingFiles.join(', ')} from the project`);
    }

    if (!contains('icon.png', files)) {
        emitWarning('compiling extension without providing an icon.png file');
    }

    return files;
}

const filterProjectFiles = filter(contains(__, projectFiles));

/**
 * Filters true locale files and appends the full qualified name for the
 * previous files
 *
 * @param {String[]} files
 * @return {Promise}
 */
function appendLocales(files) {
    return fs.lstatAsync('locales')
        .then(lstat => lstat.isDirectory() ? fs.readdirAsync('locales') : [])
        .then(filter(test(/^[a-z]{2}(_[A-Z]{2,3})?\.json$/)))
        .filter(filename => fs.readFileAsync(path.join('locales', filename))
            .then(pipe(JSON.parse, item => type(item) === 'Object'))
            .catchReturn(false))
        .then(pipe(map(file => path.join('locales', file)), concat(files)))
        .catchReturn(files);
}

/**
 * Opens package.json and extrats its contents. Returns a promise containing
 * the file list to be zipped and the package.json content parsed
 *
 * @param {String} dir
 * @return {Promise}
 */
function getProjectName(dir) {
    return fs.readFileAsync(path.join(dir, 'package.json'))
        .then(pipe(JSON.parse, prop('name')))
        .catchThrow(new Error('Failed to parse package.json from the project'));
}

/**
 * Generates a zip package using a node buffer containing the necessary files
 *
 * @param {String} dir
 * @param {String[]} files
 * @param {String} name
 */
const createZip = curry((dir, files) => {
    const zip = new Zip();
    files.forEach(filename => addToZip(zip, dir, filename));
    return zip;
});

/**
 * Taking account the -o parameter can be used to specify the output directory,
 * let's deal with it
 *
 * @param {String} customPath
 * @param {String} filename
 * @return {String}
 */
function resolveOutputTarget(customPath, filename) {
    const realPath = path.resolve('.', customPath);

    const getPath = tryCatch(realPath => fs.lstatSync(realPath).isDirectory()
        ? path.join(realPath, filename)
        : realPath
    , identity);

    return getPath(realPath);
}

/**
 * Saves the zip file from buffer to the filesystem
 *
 * @param {String} dir
 * @param {Zip} zip
 * @param {String} name
 */
const saveZip = curry((dir, zip, name) => {
    const target = resolveOutputTarget(dir, `${name}.rung`);

    return new Promise((resolve, reject) => {
        zip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
            .pipe(fs.createWriteStream(target))
            .on('error', reject)
            .on('finish', () => resolve(target));
    });
});

/**
 * Appends a file or folder to the zip buffer
 *
 * @param {Zip} zip
 * @param {String} dir
 * @param {String} filename
 */
function addToZip(zip, dir, filename) {
    const filePath = path.join(dir, filename);
    const lstat = fs.lstatSync(filePath);

    if (lstat.isFile()) {
        return zip.file(filename, fs.readFileSync(filePath), defaultFileOptions);
    }

    if (lstat.isDirectory()) {
        return map(file => addToZip(zip.folder(filename), filePath, file),
            fs.readdirSync(filePath));
    }

    throw new Error(`Invalid file type for ${filePath}`);
}

/**
 * Precompiles an extension and generates a .rung package
 *
 * @param {Object} args
 */
export default function build(args) {
    const dir = path.resolve('.', args._[1] || '');

    return fs.readdirAsync(dir)
        .then(analyzeFiles)
        .then(filterProjectFiles)
        .then(appendLocales)
        .then(sort(subtract))
        .then(precompileLocales)
        .then(createZip(dir))
        .then(zip => all([zip, getProjectName(dir)]))
        .spread(saveZip(args.output || '.'));
}
<|endoftext|>


<commit_before>;(function () {
  const painter = {
    greet(user) {
      const name = user.displayName.split(' ')[0]
      document.querySelector('#user--info').textContent = `Hi ${name}, how are you feeling today?`
    // qs('#user--photo').src = user.photoURL
    },
    getEmotion(emotion) {
      const emo = document.createElement('span');
      emo.className = `emojicon e1a-${emotion}`;
      return emo;
    }
  }
  firebase.initializeApp(config)

  var provider = new firebase.auth.GoogleAuthProvider()
  firebase.auth().onAuthStateChanged(user => {
    if (user) {
      painter.greet(user)
    } else {
      firebase.auth().signInWithRedirect(provider)
    }
  })
}())
<commit_msg>Removed dead code<commit_after>;(function () {
  const painter = {
    greet(user) {
      const name = user.displayName.split(' ')[0]
      document.querySelector('#user--info').textContent = `Hi ${name}, how are you feeling today?`
    }
  }
  firebase.initializeApp(config)

  var provider = new firebase.auth.GoogleAuthProvider()
  firebase.auth().onAuthStateChanged(user => {
    if (user) painter.greet(user)
    else firebase.auth().signInWithRedirect(provider)
  })
}())
<|endoftext|>


<commit_before>var path = require('path');
var fs = require('fs');
var proxy = require('./lib');
var util = require('./util');
var config = util.config;
var argvs = util.argvs;
var rulesUtil = require('./lib/rules/util');

function parseHosts(hostsPath) {
	if (hostsPath) {
		try {
			rulesUtil.setPublicHosts(fs.readFileSync(path.resolve(hostsPath), {encoding: 'utf8'}));
		} catch(e) {}
	}

	rulesUtil.loadHosts();
}

function start(options) {
	var app = proxy(options.port, options.plugins);
	require('util')._extend(app, config);

	try {
		require(app.uipath || './biz/webui/app')(app);
		util.installTianma();
	} catch(e) {}
	return app;
}

function updateConfig(options) {
	if (options.plugins) {
		options.plugins = options.plugins.split(',').map(function(plugin) {
			return /[^\w-]/i.test(plugin) ? path.resolve(plugin.trim()) : plugin;
		});
	}

	for (var i in argvs) {
		config[i] = options[i] || config[i];
	}

	var port = config.port;
	if (Array.isArray(config.ports)) {
		config.ports.forEach(function(name) {
			config[name] = ++port;
		});
	}
}

module.exports = function init(options) {
	options = options || {};
	updateConfig(options);
	parseHosts(options.hosts);
	return start(options);
};<commit_msg>config<commit_after>var path = require('path');
var fs = require('fs');
var util = require('./util');
var proxy = require('./lib');
var config = util.config;
var argvs = util.argvs;
var rulesUtil = require('./lib/rules/util');

function parseHosts(hostsPath) {
	if (hostsPath) {
		try {
			rulesUtil.setPublicHosts(fs.readFileSync(path.resolve(hostsPath), {encoding: 'utf8'}));
		} catch(e) {}
	}

	rulesUtil.loadHosts();
}

function start(options) {
	var app = proxy(options.port, options.plugins);
	require('util')._extend(app, config);

	try {
		require(app.uipath || './biz/webui/app')(app);
		util.installTianma();
	} catch(e) {}
	return app;
}

function updateConfig(options) {
	if (options.plugins) {
		options.plugins = options.plugins.split(',').map(function(plugin) {
			return /[^\w-]/i.test(plugin) ? path.resolve(plugin.trim()) : plugin;
		});
	}

	for (var i in argvs) {
		config[i] = options[i] || config[i];
	}

	var port = config.port;
	if (Array.isArray(config.ports)) {
		config.ports.forEach(function(name) {
			config[name] = ++port;
		});
	}
}

module.exports = function init(options) {
	options = options || {};
	updateConfig(options);
	parseHosts(options.hosts);
	return start(options);
};<|endoftext|>


<commit_before>/**
 * apps.js
 */

function makeClearable() {
    $('#new').button({ disabled: false });
    $("#save").button({ disabled: false });
}

function makeSelectable(that) {
    if($(that).prop("checked")) {
        $("#phone").removeAttr('disabled');
        $("#tablet").removeAttr('disabled');
        $("#desktop").removeAttr('disabled');
        $("#plugin").removeAttr('disabled');
    } else {
        $("#phone").prop('checked',false).attr('disabled', 'disabled');
        $("#tablet").prop('checked',false).attr('disabled', 'disabled');
        $("#desktop").prop('checked',false).attr('disabled', 'disabled');
        $("#plugin").prop('checked',false).attr('disabled', 'disabled');
    }
}

$(document).ready(function() {

    var isPageDirty = false;
    var selected_app_id = -1;
    var current_apps = null;
    var selectApp = null;
    var reselectApp = false;

    /**
     *
     * @param id
     * @param name
     * @param container
     */
    function makeAppButton(id,name,container) {
        container.append($('<button id="APP_'+id+'" class="app_button selector_btn cW100">'+name+'</button>'));
    }

    /**
     *
     * @param container
     * @param apps
     */
    function renderApps(container,apps) {
        for(var i = 0; i < apps.length; i++) {
            if(!apps[i]) continue;
            makeAppButton(i,apps[i].label,container);
            if(selected_app_id > -1 && parseInt(apps[i].id) == selected_app_id) {
                selected_user = i;
                selected_app_id = -1;
            }
        }
        $('.app_button').button({icons: {primary: "ui-icon-star"}}).click(function(){
            showApp(null); // clear user selection
            $(this).button( "option", "icons", {primary: 'ui-icon-seek-next', secondary:'ui-icon-seek-next'} );
            showApp(current_apps[parseInt($(this).attr('id').substring('APP_'.length))]);
        });
    }

    /**
     *
     */
    function selectCurrentApp() {
        if(selectApp && current_apps) {
            for(var i in current_apps) {
                if(current_apps[i].name == selectApp) {
                    $('#APP_'+i).button( "option", "icons", {primary: "ui-icon-seek-next", secondary:"ui-icon-seek-next"} );
                    showApp(current_apps[i]);
                    return;
                }
            }
        } else {
            showApp();
        }
    }
    /**
     *
     * @param app
     */
    function showApp(app) {

        if(selectApp && app == null && reselectApp) {
            reselectApp = false;
            app = selectApp;
        } else {
            selectApp = app;
        }

        if(app) {
            $('input:text[name=Name]').val(app.name);
            $('input:text[name=Label]').val(app.label);
            $('input:text[name=Description]').val(app.description);
            $('input:text[name=Url]').val(app.url);
            if(app.is_active) {
                $('input[name="IsActive"]')[0].checked = true;
            } else {
                $('input[name="IsActive"]')[1].checked = true;
            }
            if(app.is_url_external) {
                $('input[name="IsUrlExternal"]')[0].checked = true;
            } else {
                $('input[name="IsUrlExternal"]')[1].checked = true;
            }
            $("#save").button({ disabled: true });
            if(app.is_url_external) {
                $("#filemanager").button({ disabled: true });
            } else {
                $("#filemanager").button({ disabled: false });
            }
            $("#exportpkg").button({ disabled: false });
            $("#importpkg").button({ disabled: true });

            $('#delete').button({ disabled: false });
            $('#new').button({ disabled: false });

            $("#deviceTarget").prop('checked',app.filter_by_device);
            $("#phone").prop('checked',app.filter_phone);
            $("#tablet").prop('checked',app.filter_tablet);
            $("#desktop").prop('checked',app.filter_desktop);
            $("#plugin").prop('checked',app.requires_plugin);
            $("#deviceTarget").trigger("onchange");

        } else {
            if(current_apps) {
                for(var i in current_apps) {
                    $('#APP_'+i).button( "option", "icons", {primary: 'ui-icon-star', secondary:''} );
                }
            }
            $('input:text[name=Name]').val('');
            $('input:text[name=Label]').val('');
            $('input:text[name=Description]').val('');
            $('input:text[name=Url]').val('');
            $('input[name="IsActive"]')[1].checked = true;
            $('input[name="IsUrlExternal"]')[1].checked = true;
            $('#save').button({ disabled: false });

            $("#filemanager").button({ disabled: true });
            $("#exportpkg").button({ disabled: true });
            $("#importpkg").button({ disabled: false });

            $('#delete').button({ disabled: true });
            $('#new').button({ disabled: true });

            $("#deviceTarget").prop('checked',true);
            $("#phone").prop('checked',true);
            $("#tablet").prop('checked',true);
            $("#desktop").prop('checked',true);
            $("#plugin").prop('checked',true);
            $("#deviceTarget").trigger("onchange");
        }

        selectSchemas(app);
    }

    /**
     *
     */
    var appio = new DFRequest({
        app: "admin",
        service: "System",
        resource: "/app",
        success: function(json,request) {
            if(!parseErrors(json,errorHandler)) {
                if(request) {
                    switch(request.action) {
                        case DFRequestActions.UPDATE:
                            $("#appsList").dfSearchWidget('go');
                            window.top.Actions.upDateSession();
                            break;
                        case DFRequestActions.CREATE:
                            $("#appsList").dfSearchWidget('go');
                            //updateLaunchPad("Do you want to update LaunchPad now with the new Application?");
                            window.top.Actions.upDateSession();
                            break;
                        case DFRequestActions.DELETE:
                            $("#appsList").dfSearchWidget('go');
                            //updateLaunchPad("Do you want to update LaunchPad now without the Application?");
                            window.top.Actions.upDateSession();
                            break;
                        default:
                            window.top.Actions.upDateSession();
                            break;
                    }
                }
            }
            $("#save").button({ disabled: true });
        }
    });

    /**
     *
     * @param confirmed
     */
    function deleteApp(confirmed) {
        if(selectApp) {
            if(confirmed) {
                appio.deletes(selectApp.id);
                showApp();
            } else {
                $( "#deleteApp" ).html(selectApp.label);
                $( "#confirmDeleteAppDialog" ).dialog('open');
            }
        }
    }

    /**
     *
     * @param app
     */
    function getForm(app) {
        app.name = $('input:text[name=Name]').val();
        app.label = $('input:text[name=Label]').val();
        app.description = $('input:text[name=Description]').val();
        app.url = $('input:text[name=Url]').val();

        if($('input[name="IsActive"]')[0].checked) {
            app.is_active = 1;
        } else {
            app.is_active = 0;
        }
        if($('input[name="IsUrlExternal"]')[0].checked) {
            app.is_url_external = 1;
        } else {
            app.is_url_external = 0;
        }

        if($("#deviceTarget").prop('checked')) {
            app.filter_by_device = 1;
        } else {
            app.filter_by_device = 0;
        }

        if($("#phone").prop('checked')) {
            app.filter_phone = 1;
        } else {
            app.filter_phone = 0;
        }

        if($("#tablet").prop('checked')) {
            app.filter_tablet = 1;
        } else {
            app.filter_tablet = 0;
        }

        if($("#desktop").prop('checked')) {
            app.filter_desktop = 1;
        } else {
            app.filter_desktop = 0;
        }

        if($("#plugin").prop('checked')) {
            app.requires_plugin = 1;
        } else {
            app.requires_plugin = 0;
        }

        app.schemas = getSelectSchemas();
    }

    function selectSchemas(app) {
        $("#SELECT_ALL_SCHEMAS").prop('checked',false);
        $(".SCHEMA_CBX").each(function(){
            $(this).prop('checked',false);
        });
        if(app && app.schemas) {
            var tmp = app.schemas.split(",");
            for(var i in tmp) {
                var str = $.trim(tmp[i]);
                if(str.length > 0) {
                    $("input[value='"+str+"']").prop('checked',true);
                }
            }
        }
    }

    function getSelectSchemas() {
        var str = "";
        $(".SCHEMA_CBX").each(function(){
            if($(this).prop('checked')) {
                if(str.length > 0) str += ",";
                str += $(this).val();
            }
        });
        return str;
    }

    function showSchemas(schema) {
        var con = $('#SCHEMA_ID_LIST');
        con.html('');
        for(var i in schema) {
            if(schema[i].name == undefined) continue;
            con.append('
<input type="checkbox" name="SCHEMA_ID_'+schema[i].name+'" value="'+schema[i].name+'" class="SCHEMA_CBX" onchange="makeClearable()"/>'+schema[i].label+'
');
        }
    }

    /**
     * The Role IO object
     */
    var schemas = new DFRequest({
        app: "admin",
        service: "DB",
        resource: "/schema",
        type: DFRequestType.POST,
        success: function(json,request) {
            if(!parseErrors(json,errorHandler)) {
                showSchemas(json.table);
            }
        }
    });

    makeAdminNav('apps');

    schemas.retrieve();

    if(CommonUtilities.getQueryParameter('selectedApp')) {
        reselectApp = true;
    }

    $("#deviceTarget").trigger("onchange");

    $("#exportpkg").button({icons: {primary: "ui-icon-circle-arrow-s"}}).click(function(){
        $("#pkgFileIframe").attr("src","/REST/APP/"+selectApp.name+"/?pkg=true&app_name=admin");
    });

    $("#importpkg").button({icons: {primary: "ui-icon-circle-arrow-n"}}).click(function(){
        $("#pkgFileInput").trigger("click");
    });

    $("#delete").button({icons: {primary: "ui-icon-trash"}}).click(function(){
        deleteApp();
    });

    $("#save").button({icons: {primary: "ui-icon-disk"}}).click(function(){
        if(selectApp) {
            getForm(selectApp);
            var t = selectApp.name;
            delete selectApp.name;
            delete selectApp.created_by_id;
            delete selectApp.created_date;
            delete selectApp.last_modified_by_id;
            delete selectApp.last_modified_date;
            appio.update(selectApp);
            selectApp = t;
        } else {
            var app = {};
            getForm(app);
            appio.create(app);
            selectApp = app.name;

        }
    });

    $("#new").button({icons: {primary: "ui-icon-document"}}).click(function(){
        showApp();
    });

    $("#filemanager").button({icons: {primary: "ui-icon-folder-collapsed"}}).click(function(){

        var returnUrl = window.location.href;
        var startIndex = 0;
        var stopIndex = returnUrl.indexOf('?');
        if (stopIndex >= 0) {
            returnUrl = returnUrl.substring(startIndex, stopIndex);
        }
        returnUrl = escape(returnUrl);
        returnUrl += '?selectedApp='+selectApp.name;
        window.location = 'filemanager/index.html?hostApp=admin&path='+selectApp.name+'&returnUrl=' + returnUrl;
    });

    $( "#confirmDeleteAppDialog" ).dialog({
        resizable: false,
        modal: true,
        autoOpen: false,
        buttons: {
            Continue: function() {
                deleteApp(true);
                $( this ).dialog( "close" );
            },
            Cancel: function() {
                $( this ).dialog( "close" );
            }
        }
    });

    $(".ONKEYUP").keyup(makeClearable);
    $(".ONCHANGE").change(makeClearable);
    $(".SCHEMA_SELECT_ALL").change(function() {
        var select = $(this).prop('checked');
        $(".SCHEMA_CBX").each(function(){
            $(this).prop('checked',select);
        });
        makeClearable();
    });
    $("#pkgFileIframe").load(function() {
        var that = $(this);
        var str = that.contents().text();
        if(str && str.length > 0) {
            try {
                str = JSON.parse(str);
                var result = parseErrors(str,errorHandler);
                appio.retrieve();
            } catch (e) {
                alert(e);
            }
        }
    });

    $("#appsList").dfSearchWidget({
        app: 'admin',
        service: "System",
        resource: '/app',
        offsetHeight: 25,
        noSearchTerm: true,
        renderer: function(container,apps) {
            for(var i in apps) {
                if(reselectApp && apps[i].name == CommonUtilities.getQueryParameter('selectedApp')) {
                    selectApp = apps[i];
                }
            }
            if(apps.length > 0) {
                current_apps = apps;
                renderApps(container,apps);
                resizeUi();
                selectCurrentApp();
                return apps.length;
            } else {
                renderApps(container,users);
                container.append('No apps...');
                resizeUi();
                showApp();
                return 0;
            }
        }
    });
});

function importPkg() {

    var filename = $("#pkgFileInput").val();
    if(filename.substr(filename.length - 6) != '.dfpkg') {
        alert("Please select a package file that ends with the extension '.dfpkg'.");
        return;
    }
    $("#pkgFileInput").form.submit();
}
<commit_msg>Fixed package import, still not working in IE.<commit_after>/**
 * apps.js
 */

function makeClearable() {
    $('#new').button({ disabled: false });
    $("#save").button({ disabled: false });
}

function makeSelectable(that) {
    if($(that).prop("checked")) {
        $("#phone").removeAttr('disabled');
        $("#tablet").removeAttr('disabled');
        $("#desktop").removeAttr('disabled');
        $("#plugin").removeAttr('disabled');
    } else {
        $("#phone").prop('checked',false).attr('disabled', 'disabled');
        $("#tablet").prop('checked',false).attr('disabled', 'disabled');
        $("#desktop").prop('checked',false).attr('disabled', 'disabled');
        $("#plugin").prop('checked',false).attr('disabled', 'disabled');
    }
}

$(document).ready(function() {

    var isPageDirty = false;
    var selected_app_id = -1;
    var current_apps = null;
    var selectApp = null;
    var reselectApp = false;

    /**
     *
     * @param id
     * @param name
     * @param container
     */
    function makeAppButton(id,name,container) {
        container.append($('<button id="APP_'+id+'" class="app_button selector_btn cW100">'+name+'</button>'));
    }

    /**
     *
     * @param container
     * @param apps
     */
    function renderApps(container,apps) {
        for(var i = 0; i < apps.length; i++) {
            if(!apps[i]) continue;
            makeAppButton(i,apps[i].label,container);
            if(selected_app_id > -1 && parseInt(apps[i].id) == selected_app_id) {
                selected_user = i;
                selected_app_id = -1;
            }
        }
        $('.app_button').button({icons: {primary: "ui-icon-star"}}).click(function(){
            showApp(null); // clear user selection
            $(this).button( "option", "icons", {primary: 'ui-icon-seek-next', secondary:'ui-icon-seek-next'} );
            showApp(current_apps[parseInt($(this).attr('id').substring('APP_'.length))]);
        });
    }

    /**
     *
     */
    function selectCurrentApp() {
        if(selectApp && current_apps) {
            for(var i in current_apps) {
                if(current_apps[i].name == selectApp) {
                    $('#APP_'+i).button( "option", "icons", {primary: "ui-icon-seek-next", secondary:"ui-icon-seek-next"} );
                    showApp(current_apps[i]);
                    return;
                }
            }
        } else {
            showApp();
        }
    }
    /**
     *
     * @param app
     */
    function showApp(app) {

        if(selectApp && app == null && reselectApp) {
            reselectApp = false;
            app = selectApp;
        } else {
            selectApp = app;
        }

        if(app) {
            $('input:text[name=Name]').val(app.name);
            $('input:text[name=Label]').val(app.label);
            $('input:text[name=Description]').val(app.description);
            $('input:text[name=Url]').val(app.url);
            if(app.is_active) {
                $('input[name="IsActive"]')[0].checked = true;
            } else {
                $('input[name="IsActive"]')[1].checked = true;
            }
            if(app.is_url_external) {
                $('input[name="IsUrlExternal"]')[0].checked = true;
            } else {
                $('input[name="IsUrlExternal"]')[1].checked = true;
            }
            $("#save").button({ disabled: true });
            if(app.is_url_external) {
                $("#filemanager").button({ disabled: true });
            } else {
                $("#filemanager").button({ disabled: false });
            }
            $("#exportpkg").button({ disabled: false });
            $("#importpkg").button({ disabled: true });

            $('#delete').button({ disabled: false });
            $('#new').button({ disabled: false });

            $("#deviceTarget").prop('checked',app.filter_by_device);
            $("#phone").prop('checked',app.filter_phone);
            $("#tablet").prop('checked',app.filter_tablet);
            $("#desktop").prop('checked',app.filter_desktop);
            $("#plugin").prop('checked',app.requires_plugin);
            $("#deviceTarget").trigger("onchange");

        } else {
            if(current_apps) {
                for(var i in current_apps) {
                    $('#APP_'+i).button( "option", "icons", {primary: 'ui-icon-star', secondary:''} );
                }
            }
            $('input:text[name=Name]').val('');
            $('input:text[name=Label]').val('');
            $('input:text[name=Description]').val('');
            $('input:text[name=Url]').val('');
            $('input[name="IsActive"]')[1].checked = true;
            $('input[name="IsUrlExternal"]')[1].checked = true;
            $('#save').button({ disabled: false });

            $("#filemanager").button({ disabled: true });
            $("#exportpkg").button({ disabled: true });
            $("#importpkg").button({ disabled: false });

            $('#delete').button({ disabled: true });
            $('#new').button({ disabled: true });

            $("#deviceTarget").prop('checked',true);
            $("#phone").prop('checked',true);
            $("#tablet").prop('checked',true);
            $("#desktop").prop('checked',true);
            $("#plugin").prop('checked',true);
            $("#deviceTarget").trigger("onchange");
        }

        selectSchemas(app);
    }

    /**
     *
     */
    var appio = new DFRequest({
        app: "admin",
        service: "System",
        resource: "/app",
        success: function(json,request) {
            if(!parseErrors(json,errorHandler)) {
                if(request) {
                    switch(request.action) {
                        case DFRequestActions.UPDATE:
                            $("#appsList").dfSearchWidget('go');
                            window.top.Actions.upDateSession();
                            break;
                        case DFRequestActions.CREATE:
                            $("#appsList").dfSearchWidget('go');
                            //updateLaunchPad("Do you want to update LaunchPad now with the new Application?");
                            window.top.Actions.upDateSession();
                            break;
                        case DFRequestActions.DELETE:
                            $("#appsList").dfSearchWidget('go');
                            //updateLaunchPad("Do you want to update LaunchPad now without the Application?");
                            window.top.Actions.upDateSession();
                            break;
                        default:
                            window.top.Actions.upDateSession();
                            break;
                    }
                }
            }
            $("#save").button({ disabled: true });
        }
    });

    /**
     *
     * @param confirmed
     */
    function deleteApp(confirmed) {
        if(selectApp) {
            if(confirmed) {
                appio.deletes(selectApp.id);
                showApp();
            } else {
                $( "#deleteApp" ).html(selectApp.label);
                $( "#confirmDeleteAppDialog" ).dialog('open');
            }
        }
    }

    /**
     *
     * @param app
     */
    function getForm(app) {
        app.name = $('input:text[name=Name]').val();
        app.label = $('input:text[name=Label]').val();
        app.description = $('input:text[name=Description]').val();
        app.url = $('input:text[name=Url]').val();

        if($('input[name="IsActive"]')[0].checked) {
            app.is_active = 1;
        } else {
            app.is_active = 0;
        }
        if($('input[name="IsUrlExternal"]')[0].checked) {
            app.is_url_external = 1;
        } else {
            app.is_url_external = 0;
        }

        if($("#deviceTarget").prop('checked')) {
            app.filter_by_device = 1;
        } else {
            app.filter_by_device = 0;
        }

        if($("#phone").prop('checked')) {
            app.filter_phone = 1;
        } else {
            app.filter_phone = 0;
        }

        if($("#tablet").prop('checked')) {
            app.filter_tablet = 1;
        } else {
            app.filter_tablet = 0;
        }

        if($("#desktop").prop('checked')) {
            app.filter_desktop = 1;
        } else {
            app.filter_desktop = 0;
        }

        if($("#plugin").prop('checked')) {
            app.requires_plugin = 1;
        } else {
            app.requires_plugin = 0;
        }

        app.schemas = getSelectSchemas();
    }

    function selectSchemas(app) {
        $("#SELECT_ALL_SCHEMAS").prop('checked',false);
        $(".SCHEMA_CBX").each(function(){
            $(this).prop('checked',false);
        });
        if(app && app.schemas) {
            var tmp = app.schemas.split(",");
            for(var i in tmp) {
                var str = $.trim(tmp[i]);
                if(str.length > 0) {
                    $("input[value='"+str+"']").prop('checked',true);
                }
            }
        }
    }

    function getSelectSchemas() {
        var str = "";
        $(".SCHEMA_CBX").each(function(){
            if($(this).prop('checked')) {
                if(str.length > 0) str += ",";
                str += $(this).val();
            }
        });
        return str;
    }

    function showSchemas(schema) {
        var con = $('#SCHEMA_ID_LIST');
        con.html('');
        for(var i in schema) {
            if(schema[i].name == undefined) continue;
            con.append('
<input type="checkbox" name="SCHEMA_ID_'+schema[i].name+'" value="'+schema[i].name+'" class="SCHEMA_CBX" onchange="makeClearable()"/>'+schema[i].label+'
');
        }
    }

    /**
     * The Role IO object
     */
    var schemas = new DFRequest({
        app: "admin",
        service: "DB",
        resource: "/schema",
        type: DFRequestType.POST,
        success: function(json,request) {
            if(!parseErrors(json,errorHandler)) {
                showSchemas(json.table);
            }
        }
    });

    makeAdminNav('apps');

    schemas.retrieve();

    if(CommonUtilities.getQueryParameter('selectedApp')) {
        reselectApp = true;
    }

    $("#deviceTarget").trigger("onchange");

    $("#exportpkg").button({icons: {primary: "ui-icon-circle-arrow-s"}}).click(function(){
        $("#pkgFileIframe").attr("src","/REST/APP/"+selectApp.name+"/?pkg=true&app_name=admin");
    });

    $("#importpkg").button({icons: {primary: "ui-icon-circle-arrow-n"}}).click(function(){
        $("#pkgFileInput").trigger("click");
    });

    $("#delete").button({icons: {primary: "ui-icon-trash"}}).click(function(){
        deleteApp();
    });

    $("#save").button({icons: {primary: "ui-icon-disk"}}).click(function(){
        if(selectApp) {
            getForm(selectApp);
            var t = selectApp.name;
            delete selectApp.name;
            delete selectApp.created_by_id;
            delete selectApp.created_date;
            delete selectApp.last_modified_by_id;
            delete selectApp.last_modified_date;
            appio.update(selectApp);
            selectApp = t;
        } else {
            var app = {};
            getForm(app);
            appio.create(app);
            selectApp = app.name;

        }
    });

    $("#new").button({icons: {primary: "ui-icon-document"}}).click(function(){
        showApp();
    });

    $("#filemanager").button({icons: {primary: "ui-icon-folder-collapsed"}}).click(function(){

        var returnUrl = window.location.href;
        var startIndex = 0;
        var stopIndex = returnUrl.indexOf('?');
        if (stopIndex >= 0) {
            returnUrl = returnUrl.substring(startIndex, stopIndex);
        }
        returnUrl = escape(returnUrl);
        returnUrl += '?selectedApp='+selectApp.name;
        window.location = 'filemanager/index.html?hostApp=admin&path='+selectApp.name+'&returnUrl=' + returnUrl;
    });

    $( "#confirmDeleteAppDialog" ).dialog({
        resizable: false,
        modal: true,
        autoOpen: false,
        buttons: {
            Continue: function() {
                deleteApp(true);
                $( this ).dialog( "close" );
            },
            Cancel: function() {
                $( this ).dialog( "close" );
            }
        }
    });

    $(".ONKEYUP").keyup(makeClearable);
    $(".ONCHANGE").change(makeClearable);
    $(".SCHEMA_SELECT_ALL").change(function() {
        var select = $(this).prop('checked');
        $(".SCHEMA_CBX").each(function(){
            $(this).prop('checked',select);
        });
        makeClearable();
    });
    $("#pkgFileIframe").load(function() {
        var that = $(this);
        var str = that.contents().text();
        if(str && str.length > 0) {
            try {
                str = JSON.parse(str);
                var result = parseErrors(str,errorHandler);
                appio.retrieve();
            } catch (e) {
                alert(e);
            }
        }
    });

    $("#appsList").dfSearchWidget({
        app: 'admin',
        service: "System",
        resource: '/app',
        offsetHeight: 25,
        noSearchTerm: true,
        renderer: function(container,apps) {
            for(var i in apps) {
                if(reselectApp && apps[i].name == CommonUtilities.getQueryParameter('selectedApp')) {
                    selectApp = apps[i];
                }
            }
            if(apps.length > 0) {
                current_apps = apps;
                renderApps(container,apps);
                resizeUi();
                selectCurrentApp();
                return apps.length;
            } else {
                renderApps(container,users);
                container.append('No apps...');
                resizeUi();
                showApp();
                return 0;
            }
        }
    });
});

function importPkg() {

    var filename = $("#pkgFileInput").val();
    if(filename.substr(filename.length - 6) != '.dfpkg') {
        alert("Please select a package file that ends with the extension '.dfpkg'.");
        return;
    }
    $("#pkgFileForm").submit();
}
<|endoftext|>


<commit_before>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ArgumentsRequired, ExchangeError, OrderNotFound } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class bkex extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bkex',
            'name': 'BKEX',
            'countries': ['BVI'],
            'version': 'v2',
            'rateLimit': 1000,
            'has': {
                'createMarketOrder': false,
                'fetchOrder': true,
                'fetchOrders': true,
                'fetchOpenOrders': true,
                'fetchCurrencies': false,
                'fetchTicker': true,
                'fetchTickers': false,
                'fetchOHLCV': true,
                'fetchOrderBook': true,
                'fetchTrades': false,
            },
            'urls': {
                'api': {
                    'public': 'https://api.bkex.io/v2',
                    'private': 'https://api.bkex.io/v2/u',
                },
                'www': 'https://www.bkex.com',
                'doc': [
                    'https://bkexapi.github.io/docs/api_en.htm',
                ],
                'fees': 'https://www.bkex.com/help/instruction/33',
            },
            'api': {
                'public': {
                    'get': [
                        'common/symbols',
                        'common/currencys',
                        'exchangeInfo',
                        'q/depth',
                        'q/deals',
                        'q/tickers',
                        'q/ticker/price',
                        'q/kline',
                    ],
                },
                'private': {
                    'get': [
                        'account/balance',
                        'order/openOrders',
                        'order/openOrder/detail',
                        'order/historyOrders',
                    ],
                    'post': [
                        'order/create',
                        'order/cancel',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.09,
                    'taker': 0.12,
                },
            },
        });
    }

    async fetchMarkets (params = {}) {
        const response = await this.publicGetCommonSymbols (params);
        const data = this.safeValue (response, 'data');
        const numMarkets = data.length;
        if (numMarkets < 1) {
            throw new ExchangeError (this.id + ' publicGetExchangeInfo returned empty response: ' + this.json (markets));
        }
        const result = [];
        for (let i = 0; i < data.length; i++) {
            const market = data[i];
            const id = this.safeString (market, 'symbol');
            const baseId = id.split ('_')[0];
            const quoteId = id.split ('_')[1];
            const base = this.safeCurrencyCode (baseId);
            const quote = this.safeCurrencyCode (quoteId);
            const symbol = base + '/' + quote;
            const precision = {
                'amount': undefined,
                'price': this.safeInteger (market, 'pricePrecision'),
            };
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': true,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'price': {
                        'min': Math.pow (10, -precision['price']),
                        'max': undefined,
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'info': market,
            });
        }
        // console.log('result', result);
        return result;
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        const timestamp = this.milliseconds ();
        const request = this.extend ({
            'symbol': symbol,
        }, params);
        const response = await this.publicGetQTickers (request);
        const ticker = this.safeValue (response, 'data');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': this.safeFloat (ticker[0], 'high'),
            'low': this.safeFloat (ticker[0], 'low'),
            'bid': undefined,
            'bidVolume': undefined,
            'ask': undefined,
            'askVolume': undefined,
            'vwap': undefined,
            'previousClose': undefined,
            'open': this.safeFloat (ticker[0], 'open'),
            'close': this.safeFloat (ticker[0], 'close'),
            'last': undefined,
            'percentage': undefined,
            'change': this.safeFloat (ticker[0], 'change'),
            'average': undefined,
            'baseVolume': this.safeFloat (ticker[0], 'volume'),
            'quoteVolume': this.safeFloat (ticker[0], 'quoteVolume'),
            'info': ticker[0],
        };
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'symbol': symbol,
        };
        if (limit !== undefined) {
            request['size'] = limit;
        }
        const response = await this.publicGetQDepth (this.extend (request, params));
        const data = this.safeValue (response, 'data');
        return this.parseOrderBook (data, undefined, 'bid', 'ask');
    }

    parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
        return [
            this.timeInSeconds (ohlcv[0]),
            this.safeFloat (ohlcv, 1),
            this.safeFloat (ohlcv, 2),
            this.safeFloat (ohlcv, 3),
            this.safeFloat (ohlcv, 4),
            this.safeFloat (ohlcv, 5),
        ];
    }

    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = 1, params = {}) {
        const request = {
            'symbol': symbol,
            'size': limit,
        };
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['since'] = parseInt (since / 1000);
        }
        const duration = this.parseTimeframe (timeframe);
        const timerange = limit * duration * 1000;
        if (since === undefined) {
            if (limit === undefined) {
                throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument');
            } else {
                request['to'] = this.milliseconds ();
                request['from'] = request['to'] - timerange;
            }
        } else {
            request['from'] = parseInt (since);
            request['to'] = this.sum (request['from'], timerange);
        }
        const response = await this.publicGetQKline (request);
        // {
        //     "symbol": "BTC_USDT",
        //     "volume": 12321.1234,
        //     "open": 4124.3,
        //     "close": 3873.213,
        //     "low": 3521.1,
        //     "high": 4521.5,
        //     "quoteVolume": 71031537.978665,
        //     "ts": 1529739295000
        // }
        const data = this.safeValue (response, 'data', []);
        return this.parseOHLCVs (data, undefined, timeframe, since, limit);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        const query = this.omit (params, 'type');
        const response = await this.privateGetAccountBalance (query);
        const balances = this.safeValue (response, 'data');
        const wallets = this.safeValue (balances, 'WALLET');
        const result = { 'info': wallets };
        for (let i = 0; i < wallets.length; i++) {
            const wallet = wallets[i];
            const currencyId = wallet['currency'];
            const code = this.safeCurrencyCode (currencyId);
            const account = this.account ();
            account['free'] = this.safeFloat (wallet, 'available');
            account['total'] = this.safeFloat (wallet, 'total');
            result[code] = account;
        }
        return this.parseBalance (result);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        const method = 'privatePostOrderCreate';
        const direction = side === 'buy' ? 'BID' : 'ASK';
        const request = {
            'volume': amount,
            'direction': direction,
            'symbol': symbol,
            'price': price,
            'type': type,
        };
        const response = await this[method] (this.extend (request, params));
        return {
            'id': this.safeValue (response, 'data'),
            'info': response,
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'orderId': id,
        };
        return await this.privatePostOrderCancel (this.extend (request, params));
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'symbol': this.safeString (market, 'id'),
        };
        if (limit !== undefined) {
            request['size'] = limit;
        }
        const response = await this.privateGetOrderOpenOrders (this.extend (request, params));
        const result = this.safeValue (response, 'data');
        return this.parseOrders (this.safeValue (result, 'data'), market, since, limit);
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        const request = {
            'orderId': id,
        };
        const response = await this.privateGetOrderOpenOrderDetail (this.extend (request, params));
        const data = this.safeValue (response, 'data');
        if (!data) {
            throw new OrderNotFound (this.id + ' order ' + id + ' not found');
        }
        return this.parseOrder (data);
    }

    parseTrade (trade, market = undefined) {
        const timestamp = this.safeTimestamp (trade, 'createdTime');
        let symbol = undefined;
        if (market !== undefined) {
            symbol = market['symbol'];
        }
        const id = this.safeString (trade, 'id');
        const price = this.safeFloat (trade, 'price');
        const amount = this.safeFloat (trade, 'totalVolume');
        let cost = undefined;
        if (amount !== undefined) {
            if (price !== undefined) {
                cost = price * amount;
            }
        }
        const type = undefined;
        const side = this.safeString (trade, 'type');
        return {
            'info': trade,
            'id': id,
            'order': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'type': type,
            'side': side,
            'takerOrMaker': undefined,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': undefined,
        };
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {};
        if (symbol !== undefined) {
            const market = this.market (symbol);
            request['symbol'] = market['id'];
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const trades = await this.privateGetOrderHistoryOrders (this.extend (request, params));
        return this.parseTrades (trades, undefined, since, limit);
    }

    parseOrder (order, market = undefined) {
        const marketName = this.safeString (order, 'pair');
        market = market || this.findMarket (marketName);
        let timestamp = this.safeString (order, 'createdTime');
        if (timestamp !== undefined) {
            timestamp = Math.round (parseFloat (timestamp) * 1000);
        }
        const direction = this.safeValue (order, 'direction');
        const side = direction === 'BID' ? 'BUY' : 'SELL';
        const amount = this.safeFloat (order, 'totalAmount');
        const fillAmount = this.safeFloat (order, 'dealAmount', amount);
        const remaining = amount - fillAmount;
        return {
            'id': this.safeString (order, 'id'),
            'datetime': this.iso8601 (timestamp),
            'timestamp': timestamp,
            'lastTradeTimestamp': undefined,
            'status': undefined,
            'symbol': this.safeString (market, 'symbol'),
            'side': side,
            'type': this.safeString (order, 'orderType'),
            'price': this.safeFloat (order, 'price'),
            'cost': undefined,
            'amount': amount,
            'filled': fillAmount,
            'remaining': remaining,
            'fee': undefined,
            'info': order,
        };
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'][api] + '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        if (method === 'GET') {
            if (Object.keys (query).length) {
                url += '?' + this.urlencode (query);
            }
        }
        if (api === 'private') {
            this.checkRequiredCredentials ();
            query = this.urlencode (query);
            if (method === 'POST') {
                body = query;
            }
            const sortedQuery = query.split ('&').sort ((a, b) => a.localeCompare (b)).join ('&');
            const secret = this.encode (this.secret);
            const signature = this.hmac (sortedQuery, secret, 'sha256');
            headers = {
                'Cache-Control': 'no-cache',
                'Content-type': 'application/x-www-form-urlencoded',
                'X_ACCESS_KEY': this.apiKey,
                'X_SIGNATURE': signature,
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        const httpCode = this.safeInteger (response, 'code', 200);
        if (response === undefined) {
            return;
        }
        if (code >= 400) {
            throw new ExchangeError (this.id + ' HTTP Error ' + code + ' reason: ' + reason);
        }
        if (httpCode >= 400) {
            const message = this.safeValue (response, 'msg', '');
            throw new ExchangeError (this.id + ' HTTP Error ' + httpCode + ' message: ' + message);
        }
    }
};
<commit_msg>refactor<commit_after>'use strict';

//  ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');
const { ArgumentsRequired, ExchangeError, OrderNotFound } = require ('./base/errors');

//  ---------------------------------------------------------------------------

module.exports = class bkex extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bkex',
            'name': 'BKEX',
            'countries': ['BVI'],
            'version': 'v2',
            'rateLimit': 1000,
            'has': {
                'createMarketOrder': false,
                'fetchOrder': true,
                'fetchOrders': true,
                'fetchOpenOrders': true,
                'fetchCurrencies': false,
                'fetchTicker': true,
                'fetchTickers': false,
                'fetchOHLCV': true,
                'fetchOrderBook': true,
                'fetchTrades': false,
            },
            'urls': {
                'api': {
                    'public': 'https://api.bkex.io/v2',
                    'private': 'https://api.bkex.io/v2/u',
                },
                'www': 'https://www.bkex.com',
                'doc': [
                    'https://bkexapi.github.io/docs/api_en.htm',
                ],
                'fees': 'https://www.bkex.com/help/instruction/33',
            },
            'api': {
                'public': {
                    'get': [
                        'common/symbols',
                        'common/currencys',
                        'exchangeInfo',
                        'q/depth',
                        'q/deals',
                        'q/tickers',
                        'q/ticker/price',
                        'q/kline',
                    ],
                },
                'private': {
                    'get': [
                        'account/balance',
                        'order/openOrders',
                        'order/openOrder/detail',
                        'order/historyOrders',
                    ],
                    'post': [
                        'order/create',
                        'order/cancel',
                    ],
                },
            },
            'fees': {
                'trading': {
                    'maker': 0.09,
                    'taker': 0.12,
                },
            },
        });
    }

    async fetchMarkets (params = {}) {
        const response = await this.publicGetCommonSymbols (params);
        const data = this.safeValue (response, 'data');
        const numMarkets = data.length;
        if (numMarkets < 1) {
            throw new ExchangeError (this.id + ' publicGetExchangeInfo returned empty response: ' + this.json (markets));
        }
        const result = [];
        for (let i = 0; i < data.length; i++) {
            const market = data[i];
            const id = this.safeString (market, 'symbol');
            const baseId = id.split ('_')[0];
            const quoteId = id.split ('_')[1];
            const base = this.safeCurrencyCode (baseId);
            const quote = this.safeCurrencyCode (quoteId);
            const symbol = base + '/' + quote;
            const precision = {
                'amount': undefined,
                'price': this.safeInteger (market, 'pricePrecision'),
            };
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'baseId': baseId,
                'quoteId': quoteId,
                'active': true,
                'precision': precision,
                'limits': {
                    'amount': {
                        'min': undefined,
                        'max': undefined,
                    },
                    'price': {
                        'min': Math.pow (10, -precision['price']),
                        'max': undefined,
                    },
                    'cost': {
                        'min': undefined,
                        'max': undefined,
                    },
                },
                'info': market,
            });
        }
        return result;
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        const timestamp = this.milliseconds ();
        const request = this.extend ({
            'symbol': symbol,
        }, params);
        const response = await this.publicGetQTickers (request);
        const ticker = this.safeValue (response, 'data');
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': this.safeFloat (ticker[0], 'high'),
            'low': this.safeFloat (ticker[0], 'low'),
            'bid': undefined,
            'bidVolume': undefined,
            'ask': undefined,
            'askVolume': undefined,
            'vwap': undefined,
            'previousClose': undefined,
            'open': this.safeFloat (ticker[0], 'open'),
            'close': this.safeFloat (ticker[0], 'close'),
            'last': undefined,
            'percentage': undefined,
            'change': this.safeFloat (ticker[0], 'change'),
            'average': undefined,
            'baseVolume': this.safeFloat (ticker[0], 'volume'),
            'quoteVolume': this.safeFloat (ticker[0], 'quoteVolume'),
            'info': ticker[0],
        };
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'symbol': symbol,
        };
        if (limit !== undefined) {
            request['size'] = limit;
        }
        const response = await this.publicGetQDepth (this.extend (request, params));
        const data = this.safeValue (response, 'data');
        return this.parseOrderBook (data, undefined, 'bid', 'ask');
    }

    parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
        return [
            this.timeInSeconds (ohlcv[0]),
            this.safeFloat (ohlcv, 1),
            this.safeFloat (ohlcv, 2),
            this.safeFloat (ohlcv, 3),
            this.safeFloat (ohlcv, 4),
            this.safeFloat (ohlcv, 5),
        ];
    }

    async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = 1, params = {}) {
        const request = {
            'symbol': symbol,
            'size': limit,
        };
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        if (since !== undefined) {
            request['since'] = parseInt (since / 1000);
        }
        const duration = this.parseTimeframe (timeframe);
        const timerange = limit * duration * 1000;
        if (since === undefined) {
            if (limit === undefined) {
                throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument');
            } else {
                request['to'] = this.milliseconds ();
                request['from'] = request['to'] - timerange;
            }
        } else {
            request['from'] = parseInt (since);
            request['to'] = this.sum (request['from'], timerange);
        }
        const response = await this.publicGetQKline (request);
        // {
        //     "symbol": "BTC_USDT",
        //     "volume": 12321.1234,
        //     "open": 4124.3,
        //     "close": 3873.213,
        //     "low": 3521.1,
        //     "high": 4521.5,
        //     "quoteVolume": 71031537.978665,
        //     "ts": 1529739295000
        // }
        const data = this.safeValue (response, 'data', []);
        return this.parseOHLCVs (data, undefined, timeframe, since, limit);
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        const query = this.omit (params, 'type');
        const response = await this.privateGetAccountBalance (query);
        const balances = this.safeValue (response, 'data');
        const wallets = this.safeValue (balances, 'WALLET');
        const result = { 'info': wallets };
        for (let i = 0; i < wallets.length; i++) {
            const wallet = wallets[i];
            const currencyId = wallet['currency'];
            const code = this.safeCurrencyCode (currencyId);
            const account = this.account ();
            account['free'] = this.safeFloat (wallet, 'available');
            account['total'] = this.safeFloat (wallet, 'total');
            result[code] = account;
        }
        return this.parseBalance (result);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        const method = 'privatePostOrderCreate';
        const direction = side === 'buy' ? 'BID' : 'ASK';
        const request = {
            'volume': amount,
            'direction': direction,
            'symbol': symbol,
            'price': price,
            'type': type,
        };
        const response = await this[method] (this.extend (request, params));
        return {
            'id': this.safeValue (response, 'data'),
            'info': response,
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {
            'orderId': id,
        };
        return await this.privatePostOrderCancel (this.extend (request, params));
    }

    async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        if (symbol === undefined) {
            throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
        }
        await this.loadMarkets ();
        const market = this.market (symbol);
        const request = {
            'symbol': this.safeString (market, 'id'),
        };
        if (limit !== undefined) {
            request['size'] = limit;
        }
        const response = await this.privateGetOrderOpenOrders (this.extend (request, params));
        const result = this.safeValue (response, 'data');
        return this.parseOrders (this.safeValue (result, 'data'), market, since, limit);
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        const request = {
            'orderId': id,
        };
        const response = await this.privateGetOrderOpenOrderDetail (this.extend (request, params));
        const data = this.safeValue (response, 'data');
        if (!data) {
            throw new OrderNotFound (this.id + ' order ' + id + ' not found');
        }
        return this.parseOrder (data);
    }

    parseTrade (trade, market = undefined) {
        const timestamp = this.safeTimestamp (trade, 'createdTime');
        let symbol = undefined;
        if (market !== undefined) {
            symbol = market['symbol'];
        }
        const id = this.safeString (trade, 'id');
        const price = this.safeFloat (trade, 'price');
        const amount = this.safeFloat (trade, 'totalVolume');
        let cost = undefined;
        if (amount !== undefined) {
            if (price !== undefined) {
                cost = price * amount;
            }
        }
        const type = undefined;
        const side = this.safeString (trade, 'type');
        return {
            'info': trade,
            'id': id,
            'order': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': symbol,
            'type': type,
            'side': side,
            'takerOrMaker': undefined,
            'price': price,
            'amount': amount,
            'cost': cost,
            'fee': undefined,
        };
    }

    async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        const request = {};
        if (symbol !== undefined) {
            const market = this.market (symbol);
            request['symbol'] = market['id'];
        }
        if (limit !== undefined) {
            request['limit'] = limit;
        }
        const trades = await this.privateGetOrderHistoryOrders (this.extend (request, params));
        return this.parseTrades (trades, undefined, since, limit);
    }

    parseOrder (order, market = undefined) {
        const marketName = this.safeString (order, 'pair');
        market = market || this.findMarket (marketName);
        let timestamp = this.safeString (order, 'createdTime');
        if (timestamp !== undefined) {
            timestamp = Math.round (parseFloat (timestamp) * 1000);
        }
        const direction = this.safeValue (order, 'direction');
        const side = direction === 'BID' ? 'BUY' : 'SELL';
        const amount = this.safeFloat (order, 'totalAmount');
        const fillAmount = this.safeFloat (order, 'dealAmount', amount);
        const remaining = amount - fillAmount;
        return {
            'id': this.safeString (order, 'id'),
            'datetime': this.iso8601 (timestamp),
            'timestamp': timestamp,
            'lastTradeTimestamp': undefined,
            'status': undefined,
            'symbol': this.safeString (market, 'symbol'),
            'side': side,
            'type': this.safeString (order, 'orderType'),
            'price': this.safeFloat (order, 'price'),
            'cost': undefined,
            'amount': amount,
            'filled': fillAmount,
            'remaining': remaining,
            'fee': undefined,
            'info': order,
        };
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = this.urls['api'][api] + '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        if (method === 'GET') {
            if (Object.keys (query).length) {
                url += '?' + this.urlencode (query);
            }
        }
        if (api === 'private') {
            this.checkRequiredCredentials ();
            query = this.urlencode (query);
            if (method === 'POST') {
                body = query;
            }
            const sortedQuery = query.split ('&').sort ((a, b) => a.localeCompare (b)).join ('&');
            const secret = this.encode (this.secret);
            const signature = this.hmac (sortedQuery, secret, 'sha256');
            headers = {
                'Cache-Control': 'no-cache',
                'Content-type': 'application/x-www-form-urlencoded',
                'X_ACCESS_KEY': this.apiKey,
                'X_SIGNATURE': signature,
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }

    handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
        const httpCode = this.safeInteger (response, 'code', 200);
        if (response === undefined) {
            return;
        }
        if (code >= 400) {
            throw new ExchangeError (this.id + ' HTTP Error ' + code + ' reason: ' + reason);
        }
        if (httpCode >= 400) {
            const message = this.safeValue (response, 'msg', '');
            throw new ExchangeError (this.id + ' HTTP Error ' + httpCode + ' message: ' + message);
        }
    }
};
<|endoftext|>


<commit_before>'use strict';

// ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');

// ---------------------------------------------------------------------------

module.exports = class bl3p extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bl3p',
            'name': 'BL3P',
            'countries': [ 'NL', 'EU' ], // Netherlands, EU
            'rateLimit': 1000,
            'version': '1',
            'comment': 'An exchange market by BitonicNL',
            'has': {
                'CORS': false,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/28501752-60c21b82-6feb-11e7-818b-055ee6d0e754.jpg',
                'api': 'https://api.bl3p.eu',
                'www': [
                    'https://bl3p.eu',
                    'https://bitonic.nl',
                ],
                'doc': [
                    'https://github.com/BitonicNL/bl3p-api/tree/master/docs',
                    'https://bl3p.eu/api',
                    'https://bitonic.nl/en/api',
                ],
            },
            'api': {
                'public': {
                    'get': [
                        '{market}/ticker',
                        '{market}/orderbook',
                        '{market}/trades',
                    ],
                },
                'private': {
                    'post': [
                        '{market}/money/depth/full',
                        '{market}/money/order/add',
                        '{market}/money/order/cancel',
                        '{market}/money/order/result',
                        '{market}/money/orders',
                        '{market}/money/orders/history',
                        '{market}/money/trades/fetch',
                        'GENMKT/money/info',
                        'GENMKT/money/deposit_address',
                        'GENMKT/money/new_deposit_address',
                        'GENMKT/money/wallet/history',
                        'GENMKT/money/withdraw',
                    ],
                },
            },
            'markets': {
                'BTC/EUR': { 'id': 'BTCEUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'maker': 0.0025, 'taker': 0.0025 },
                'LTC/EUR': { 'id': 'LTCEUR', 'symbol': 'LTC/EUR', 'base': 'LTC', 'quote': 'EUR', 'maker': 0.0025, 'taker': 0.0025 },
            },
        });
    }

    async fetchBalance (params = {}) {
        let response = await this.privatePostGENMKTMoneyInfo ();
        let data = response['data'];
        let balance = data['wallets'];
        let result = { 'info': data };
        let currencies = Object.keys (this.currencies);
        for (let i = 0; i < currencies.length; i++) {
            let currency = currencies[i];
            let account = this.account ();
            if (currency in balance) {
                if ('available' in balance[currency]) {
                    account['free'] = parseFloat (balance[currency]['available']['value']);
                }
            }
            if (currency in balance) {
                if ('balance' in balance[currency]) {
                    account['total'] = parseFloat (balance[currency]['balance']['value']);
                }
            }
            if (account['total']) {
                if (account['free']) {
                    account['used'] = account['total'] - account['free'];
                }
            }
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    parseBidAsk (bidask, priceKey = 0, amountKey = 0) {
        return [
            bidask[priceKey] / 100000.0,
            bidask[amountKey] / 100000000.0,
        ];
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        let market = this.market (symbol);
        let response = await this.publicGetMarketOrderbook (this.extend ({
            'market': market['id'],
        }, params));
        let orderbook = response['data'];
        return this.parseOrderBook (orderbook, undefined, 'bids', 'asks', 'price_int', 'amount_int');
    }

    async fetchTicker (symbol, params = {}) {
        let ticker = await this.publicGetMarketTicker (this.extend ({
            'market': this.marketId (symbol),
        }, params));
        let timestamp = ticker['timestamp'] * 1000;
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': parseFloat (ticker['high']),
            'low': parseFloat (ticker['low']),
            'bid': parseFloat (ticker['bid']),
            'ask': parseFloat (ticker['ask']),
            'vwap': undefined,
            'open': undefined,
            'close': undefined,
            'first': undefined,
            'last': parseFloat (ticker['last']),
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': parseFloat (ticker['volume']['24h']),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    parseTrade (trade, market) {
        return {
            'id': trade['trade_id'].toString (),
            'timestamp': trade['date'],
            'datetime': this.iso8601 (trade['date']),
            'symbol': market['symbol'],
            'type': undefined,
            'side': undefined,
            'price': trade['price_int'] / 100000.0,
            'amount': trade['amount_int'] / 100000000.0,
            'info': trade,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        let market = this.market (symbol);
        let response = await this.publicGetMarketTrades (this.extend ({
            'market': market['id'],
        }, params));
        let result = this.parseTrades (response['data']['trades'], market, since, limit);
        return result;
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        let market = this.market (symbol);
        let order = {
            'market': market['id'],
            'amount_int': parseInt (amount * 100000000),
            'fee_currency': market['quote'],
            'type': (side === 'buy') ? 'bid' : 'ask',
        };
        if (type === 'limit')
            order['price_int'] = parseInt (price * 100000.0);
        let response = await this.privatePostMarketMoneyOrderAdd (this.extend (order, params));
        return {
            'info': response,
            'id': response['data']['order_id'].toString (),
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        return await this.privatePostMarketMoneyOrderCancel ({ 'order_id': id });
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let request = this.implodeParams (path, params);
        let url = this.urls['api'] + '/' + this.version + '/' + request;
        let query = this.omit (params, this.extractParams (path));
        if (api === 'public') {
            if (Object.keys (query).length)
                url += '?' + this.urlencode (query);
        } else {
            this.checkRequiredCredentials ();
            let nonce = this.nonce ();
            body = this.urlencode (this.extend ({ 'nonce': nonce }, query));
            let secret = this.base64ToBinary (this.secret);
            let auth = request + "\0" + body;
            let signature = this.hmac (this.encode (auth), secret, 'sha512', 'base64');
            headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Rest-Key': this.apiKey,
                'Rest-Sign': this.decode (signature),
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
};
<commit_msg>bl3p linting<commit_after>'use strict';

// ---------------------------------------------------------------------------

const Exchange = require ('./base/Exchange');

// ---------------------------------------------------------------------------

module.exports = class bl3p extends Exchange {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'bl3p',
            'name': 'BL3P',
            'countries': [ 'NL', 'EU' ], // Netherlands, EU
            'rateLimit': 1000,
            'version': '1',
            'comment': 'An exchange market by BitonicNL',
            'has': {
                'CORS': false,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/28501752-60c21b82-6feb-11e7-818b-055ee6d0e754.jpg',
                'api': 'https://api.bl3p.eu',
                'www': [
                    'https://bl3p.eu',
                    'https://bitonic.nl',
                ],
                'doc': [
                    'https://github.com/BitonicNL/bl3p-api/tree/master/docs',
                    'https://bl3p.eu/api',
                    'https://bitonic.nl/en/api',
                ],
            },
            'api': {
                'public': {
                    'get': [
                        '{market}/ticker',
                        '{market}/orderbook',
                        '{market}/trades',
                    ],
                },
                'private': {
                    'post': [
                        '{market}/money/depth/full',
                        '{market}/money/order/add',
                        '{market}/money/order/cancel',
                        '{market}/money/order/result',
                        '{market}/money/orders',
                        '{market}/money/orders/history',
                        '{market}/money/trades/fetch',
                        'GENMKT/money/info',
                        'GENMKT/money/deposit_address',
                        'GENMKT/money/new_deposit_address',
                        'GENMKT/money/wallet/history',
                        'GENMKT/money/withdraw',
                    ],
                },
            },
            'markets': {
                'BTC/EUR': { 'id': 'BTCEUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'maker': 0.0025, 'taker': 0.0025 },
                'LTC/EUR': { 'id': 'LTCEUR', 'symbol': 'LTC/EUR', 'base': 'LTC', 'quote': 'EUR', 'maker': 0.0025, 'taker': 0.0025 },
            },
        });
    }

    async fetchBalance (params = {}) {
        let response = await this.privatePostGENMKTMoneyInfo ();
        let data = response['data'];
        let balance = data['wallets'];
        let result = { 'info': data };
        let currencies = Object.keys (this.currencies);
        for (let i = 0; i < currencies.length; i++) {
            let currency = currencies[i];
            let account = this.account ();
            if (currency in balance) {
                if ('available' in balance[currency]) {
                    account['free'] = parseFloat (balance[currency]['available']['value']);
                }
            }
            if (currency in balance) {
                if ('balance' in balance[currency]) {
                    account['total'] = parseFloat (balance[currency]['balance']['value']);
                }
            }
            if (account['total']) {
                if (account['free']) {
                    account['used'] = account['total'] - account['free'];
                }
            }
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    parseBidAsk (bidask, priceKey = 0, amountKey = 0) {
        return [
            bidask[priceKey] / 100000.0,
            bidask[amountKey] / 100000000.0,
        ];
    }

    async fetchOrderBook (symbol, limit = undefined, params = {}) {
        let market = this.market (symbol);
        let response = await this.publicGetMarketOrderbook (this.extend ({
            'market': market['id'],
        }, params));
        let orderbook = response['data'];
        return this.parseOrderBook (orderbook, undefined, 'bids', 'asks', 'price_int', 'amount_int');
    }

    async fetchTicker (symbol, params = {}) {
        let ticker = await this.publicGetMarketTicker (this.extend ({
            'market': this.marketId (symbol),
        }, params));
        let timestamp = ticker['timestamp'] * 1000;
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': parseFloat (ticker['high']),
            'low': parseFloat (ticker['low']),
            'bid': parseFloat (ticker['bid']),
            'ask': parseFloat (ticker['ask']),
            'vwap': undefined,
            'open': undefined,
            'close': undefined,
            'first': undefined,
            'last': parseFloat (ticker['last']),
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': parseFloat (ticker['volume']['24h']),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    parseTrade (trade, market) {
        return {
            'id': trade['trade_id'].toString (),
            'timestamp': trade['date'],
            'datetime': this.iso8601 (trade['date']),
            'symbol': market['symbol'],
            'type': undefined,
            'side': undefined,
            'price': trade['price_int'] / 100000.0,
            'amount': trade['amount_int'] / 100000000.0,
            'info': trade,
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        let market = this.market (symbol);
        let response = await this.publicGetMarketTrades (this.extend ({
            'market': market['id'],
        }, params));
        let result = this.parseTrades (response['data']['trades'], market, since, limit);
        return result;
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        let market = this.market (symbol);
        let order = {
            'market': market['id'],
            'amount_int': parseInt (amount * 100000000),
            'fee_currency': market['quote'],
            'type': (side === 'buy') ? 'bid' : 'ask',
        };
        if (type === 'limit')
            order['price_int'] = parseInt (price * 100000.0);
        let response = await this.privatePostMarketMoneyOrderAdd (this.extend (order, params));
        return {
            'info': response,
            'id': response['data']['order_id'].toString (),
        };
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        return await this.privatePostMarketMoneyOrderCancel ({ 'order_id': id });
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let request = this.implodeParams (path, params);
        let url = this.urls['api'] + '/' + this.version + '/' + request;
        let query = this.omit (params, this.extractParams (path));
        if (api === 'public') {
            if (Object.keys (query).length)
                url += '?' + this.urlencode (query);
        } else {
            this.checkRequiredCredentials ();
            let nonce = this.nonce ();
            body = this.urlencode (this.extend ({ 'nonce': nonce }, query));
            let secret = this.base64ToBinary (this.secret);
            // eslint-disable-next-line quotes
            let auth = request + "\0" + body;
            let signature = this.hmac (this.encode (auth), secret, 'sha512', 'base64');
            headers = {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Rest-Key': this.apiKey,
                'Rest-Sign': this.decode (signature),
            };
        }
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
};
<|endoftext|>


<commit_before>/*
 *    boot.js
 *    Sets up game and loads preloader assets
 */

/* Sets a global object to hold all the states of the game */
YINS = {

	/* declare global variables, these will persist across different states */
	score: 0,

	/* Declare global colors used throughout the game
	Usage example: YINS.color.purple  */
	color: {
		purple: '#673ab7',
		purple_light: '#b39ddb'
	},

	/* Text styles are available by calling: YINS.text.STYLE
	for example: YINS.text.header  */
	text: {
		title: {
			font: '12vh Courier New',
			fill: '#404040',
			align: 'center'
		},

		header: {
			font: '8vh Arial',
			fill: '#f0f0f0',
			align: 'center'
		}
	}

}

/* Constructor creates the game object */
YINS.Boot = function(game) {
	console.log('%cStarting YINS..', 'color: white; background: #673ab7');
};

YINS.Boot.prototype = {
	preload: function() {
		// Load assets for the preloader state
	},

	create: function() {
		//  Phaser will automatically pause if the browser tab the game is in loses focus.
		//  This disables that
        YINS.game.stage.disableVisibilityChange = true;

		YINS.game.state.start('preloader');
	}
};
<commit_msg>Add subtitle text style<commit_after>/*
 *    boot.js
 *    Sets up game and loads preloader assets
 */

/* Sets a global object to hold all the states of the game */
YINS = {

	/* declare global variables, these will persist across different states */
	score: 0,

	/* Declare global colors used throughout the game
	Usage example: YINS.color.purple  */
	color: {
		purple: '#673ab7',
		purple_light: '#b39ddb'
	},

	/* Text styles are available by calling: YINS.text.STYLE
	for example: YINS.text.header  */
	text: {
		title: {
			font: '12vh Courier New',
			fill: '#404040',
			align: 'center'
		},

		subtitle: {
			font: '3vh Courier New',
			fill: '#707070',
			align: 'center',
		},

		header: {
			font: '8vh Arial',
			fill: '#f0f0f0',
			align: 'center'
		}
	}

}

/* Constructor creates the game object */
YINS.Boot = function(game) {
	console.log('%cStarting YINS..', 'color: white; background: #673ab7');
};

YINS.Boot.prototype = {
	preload: function() {
		// Load assets for the preloader state
	},

	create: function() {
		//  Phaser will automatically pause if the browser tab the game is in loses focus.
		//  This disables that
        YINS.game.stage.disableVisibilityChange = true;

		YINS.game.state.start('preloader');
	}
};
<|endoftext|>