<commit_before>'use strict';

function create_gates(new_gates){
    new_gates = new_gates || [{}];
    for(var gate in new_gates){
        gates.push({
          'color': new_gates[gate]['color'] || '#fff',
          'destroy': new_gates[gate]['destroy'] !== void 0
            ? new_gates[gate]['destroy']
            : false,
          'dx': new_gates[gate]['dx'] || false,
          'dy': new_gates[gate]['dy'] || false,
          'event': new_gates[gate]['event'] || function(){},
          'height': new_gates[gate]['height'] || 40,
          'interval': new_gates[gate]['interval'] || 0,
          'x': x + new_gates[gate]['x'] || x,
          'y': y + new_gates[gate]['y'] || y,
          'width': new_gates[gate]['width'] || 40,
        });
    }
}

function draw(){
    buffer.clearRect(
      0,
      0,
      width,
      height
    );

    buffer.save();
    buffer.translate(
      -camera_x,
      -camera_y
    );

    // Draw gates.
    for(var gate in gates){
        buffer.fillStyle = gates[gate]['color'];
        buffer.fillRect(
          gates[gate]['x'],
          gates[gate]['y'],
          gates[gate]['width'],
          gates[gate]['height']
       );
    }

    // Draw particles.
    buffer.fillStyle = '#fff';
    for(var particle in particles){
        buffer.fillRect(
          particles[particle]['x'],
          particles[particle]['y'],
          5,
          5
        );
    };

    buffer.restore();

    buffer.fillStyle = '#fff';
    // Draw camera position.
    buffer.fillText(
      camera_x + 'x ' + camera_y + 'y',
      5,
      25
    );

    // Draw number of particles
    //   and max-particles.
    buffer.fillText(
      particles.length
        + ' / '
        + settings['max-particles'],
      5,
      50
    );

    canvas.clearRect(
      0,
      0,
      width,
      height
    );
    canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );

    animationFrame = window.requestAnimationFrame(draw);
}

function logic(){
    if(key_left){
        camera_x -= settings['scroll-speed'];
    }

    if(key_right){
        camera_x += settings['scroll-speed'];
    }

    if(key_down){
        camera_y += settings['scroll-speed'];
    }

    if(key_up){
        camera_y -= settings['scroll-speed'];
    }

    frame_counter += 1;
    if(frame_counter > 99){
        frame_counter = 0;
    }

    for(var particle in particles){
        particles[particle]['x'] += particles[particle]['dx'];
        particles[particle]['y'] += particles[particle]['dy'];

        if(particles[particle]['x'] > boundaries['right']
          || particles[particle]['x'] < boundaries['left']
          || particles[particle]['y'] > boundaries['bottom']
          || particles[particle]['y'] < boundaries['top']){
            particles.splice(
              particle,
              1
            );
        }
    }

    for(var gate in gates){
        if(gates[gate]['interval'] > 0
          && frame_counter % gates[gate]['interval'] === 0){
            gates[gate]['event']();
        }

        for(var particle in particles){
            if(particles[particle]['x'] > gates[gate]['x']
              && particles[particle]['x'] < gates[gate]['x'] + gates[gate]['width']
              && particles[particle]['y'] > gates[gate]['y']
              && particles[particle]['y'] < gates[gate]['y'] + gates[gate]['height']){
                if(gates[gate]['destroy']){
                    particles.splice(
                      particle,
                      1
                    );
                    continue;
                }

                if(gates[gate]['dx'] !== false){
                    particles[particle]['dx'] = gates[gate]['dx'];
                }
                if(gates[gate]['dy'] !== false){
                    particles[particle]['dy'] = gates[gate]['dy'];
                }
            }
        }
    }
}

function play_audio(id){
    if(settings['audio-volume'] <= 0){
        return;
    }

    document.getElementById(id).currentTime = 0;
    document.getElementById(id).play();
}

function reset(){
    if(!window.confirm('Reset settings?')){
        return;
    }

    document.getElementById('audio-volume').value = 1;
    document.getElementById('movement-keys').value = 'WASD';
    document.getElementById('max-particles').value = 1000;
    document.getElementById('ms-per-frame').value = 25;
    document.getElementById('reset-camera-key').value = 'H';
    document.getElementById('scroll-speed').value = 5;

    save();
}

function resize(){
    if(mode <= 0){
        return;
    }

    height = window.innerHeight;
    document.getElementById('buffer').height = height;
    document.getElementById('canvas').height = height;
    y = height / 2;

    width = window.innerWidth;
    document.getElementById('buffer').width = width;
    document.getElementById('canvas').width = width;
    x = width / 2;

    buffer.font = '23pt sans-serif';
}

// Save settings into window.localStorage if they differ from default.
function save(){
    var ids = {
      'audio-volume': 1,
      'max-particles': 1000,
      'ms-per-frame': 25,
      'scroll-speed': 5,
    };
    for(var id in ids){
        if(isNaN(document.getElementById(id).value)
          || document.getElementById(id).value == ids[id]){
            window.localStorage.removeItem('ParticleRun-2D.htm-' + id);
            settings[id] = ids[id];

        }else{
            settings[id] = parseFloat(document.getElementById(id).value);
            window.localStorage.setItem(
              'ParticleRun-2D.htm-' + id,
              settings[id]
            );
        }
    }

    ids = {
      'movement-keys': 'WASD',
      'reset-camera-key': 'H',
    };
    for(id in ids){
        if(document.getElementById(id).value === ids[id]){
            window.localStorage.removeItem('ParticleRun-2D.htm-' + id);
            settings[id] = ids[id];

        }else{
            settings[id] = document.getElementById(id).value;
            window.localStorage.setItem(
              'ParticleRun-2D.htm-' + id,
              settings[id]
            );
        }
    }
}

function setmode(newmode, newgame){
    window.cancelAnimationFrame(animationFrame);
    window.clearInterval(interval);

    gates = [];
    particles = [];

    mode = newmode;

    // New game mode.
    if(mode > 0){
        // If it's a newgame from the main menu, save settings.
        if(newgame){
            save();
        }

        // Reset.
        camera_x = 0;
        camera_y = 0;
        frame_counter = 0;
        key_left = false;
        key_right = false;

        // If it's a newgame from the main menu, setup canvas and buffers.
        if(newgame){
            document.body.innerHTML =
              '<canvas id=canvas></canvas><canvas id=buffer></canvas>';

            var contextAttributes = {
              'alpha': false,
            };
            buffer = document.getElementById('buffer').getContext(
              '2d',
              contextAttributes
            );
            canvas = document.getElementById('canvas').getContext(
              '2d',
              contextAttributes
            );

            resize();
        }

        load_level(mode);

        animationFrame = window.requestAnimationFrame(draw);
        interval = window.setInterval(
          'logic()',
          settings['ms-per-frame']
        );

        return;
    }

    // Main menu mode.
    buffer = 0;
    canvas = 0;

    document.body.innerHTML = '

Test Level

<input disabled value=ESC>Main Menu
<input id=movement-keys maxlength=4 value='
      + settings['movement-keys'] + '>Camera ↑←↓→
<input id=reset-camera-key maxlength=1 value='
      + settings['reset-camera-key'] + '>Reset Camera

<input id=audio-volume max=1 min=0 step=".01" type=range value='
      + settings['audio-volume'] + '>Audio
<input id=max-particles value='
      + settings['max-particles'] + '>Max Particles
<input id=ms-per-frame value='
      + settings['ms-per-frame'] + '>ms/Frame
<input id=scroll-speed value='
      + settings['scroll-speed'] + '>Scroll Speed
Reset Settings

';
}

var animationFrame = 0;
var boundaries = {};
var buffer = 0;
var camera_x = 0;
var camera_y = 0;
var canvas = 0;
var drag = false;
var drag_x = 0;
var drag_y = 0;
var frame_counter = 0;
var gates = [];
var height = 0;
var interval = 0;
var key_down = false;
var key_left = false;
var key_right = false;
var key_up = false;
var mode = 0;
var particles = [];
var settings = {
  'audio-volume': window.localStorage.getItem('ParticleRun-2D.htm-audio-volume') !== null
    ? parseFloat(window.localStorage.getItem('ParticleRun-2D.htm-audio-volume'))
    : 1,
  'movement-keys': window.localStorage.getItem('ParticleRun-2D.htm-movement-keys') || 'WASD',
  'max-particles': parseInt(window.localStorage.getItem('ParticleRun-2D.htm-max-particles')) || 1000,
  'ms-per-frame': parseInt(window.localStorage.getItem('ParticleRun-2D.htm-ms-per-frame')) || 25,
  'reset-camera-key': window.localStorage.getItem('ParticleRun-2D.htm-reset-camera-key') || 'H',
  'scroll-speed': window.localStorage.getItem('ParticleRun-2D.htm-scroll-speed') || 5,
};
var x = 0;
var width = 0;
var y = 0;

window.onkeydown = function(e){
    if(mode <= 0){
        return;
    }

    var key = e.keyCode || e.which;

    // ESC: return to main menu.
    if(key === 27){
        setmode(
          0,
          true
        );
        return;
    }

    key = String.fromCharCode(key);

    if(key === settings['movement-keys'][0]){
        key_up = true;

    }else if(key === settings['movement-keys'][1]){
        key_left = true;

    }else if(key === settings['movement-keys'][2]){
        key_down = true;

    }else if(key === settings['movement-keys'][3]){
        key_right = true;

    }else if(key === settings['reset-camera-key']){
        camera_x = 0;
        camera_y = 0;
    }
};

window.onkeyup = function(e){
    var key = String.fromCharCode(e.keyCode || e.which);

    if(key === settings['movement-keys'][0]){
        key_up = false;

    }else if(key === settings['movement-keys'][1]){
        key_left = false;

    }else if(key === settings['movement-keys'][2]){
        key_down = false;

    }else if(key === settings['movement-keys'][3]){
        key_right = false;
    }
};

window.onload = function(e){
    setmode(
      0,
      true
    );
};

window.onmousedown =
  window.ontouchstart = function(e){
    drag = true;
    drag_x = e.pageX;
    drag_y = e.pageY;
};

window.onmousemove =
  window.ontouchmove = function(e){
    if(!drag){
        return;
    }

    camera_x += drag_x - e.pageX;
    camera_y += drag_y - e.pageY;
    drag_x = e.pageX;
    drag_y = e.pageY;
};

window.onmouseup =
  window.ontouchend = function(e){
    drag = false;
};

window.onresize = resize;
<commit_msg>fixed step error<commit_after>'use strict';

function create_gates(new_gates){
    new_gates = new_gates || [{}];
    for(var gate in new_gates){
        gates.push({
          'color': new_gates[gate]['color'] || '#fff',
          'destroy': new_gates[gate]['destroy'] !== void 0
            ? new_gates[gate]['destroy']
            : false,
          'dx': new_gates[gate]['dx'] || false,
          'dy': new_gates[gate]['dy'] || false,
          'event': new_gates[gate]['event'] || function(){},
          'height': new_gates[gate]['height'] || 40,
          'interval': new_gates[gate]['interval'] || 0,
          'x': x + new_gates[gate]['x'] || x,
          'y': y + new_gates[gate]['y'] || y,
          'width': new_gates[gate]['width'] || 40,
        });
    }
}

function draw(){
    buffer.clearRect(
      0,
      0,
      width,
      height
    );

    buffer.save();
    buffer.translate(
      -camera_x,
      -camera_y
    );

    // Draw gates.
    for(var gate in gates){
        buffer.fillStyle = gates[gate]['color'];
        buffer.fillRect(
          gates[gate]['x'],
          gates[gate]['y'],
          gates[gate]['width'],
          gates[gate]['height']
       );
    }

    // Draw particles.
    buffer.fillStyle = '#fff';
    for(var particle in particles){
        buffer.fillRect(
          particles[particle]['x'],
          particles[particle]['y'],
          5,
          5
        );
    };

    buffer.restore();

    buffer.fillStyle = '#fff';
    // Draw camera position.
    buffer.fillText(
      camera_x + 'x ' + camera_y + 'y',
      5,
      25
    );

    // Draw number of particles
    //   and max-particles.
    buffer.fillText(
      particles.length
        + ' / '
        + settings['max-particles'],
      5,
      50
    );

    canvas.clearRect(
      0,
      0,
      width,
      height
    );
    canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );

    animationFrame = window.requestAnimationFrame(draw);
}

function logic(){
    if(key_left){
        camera_x -= settings['scroll-speed'];
    }

    if(key_right){
        camera_x += settings['scroll-speed'];
    }

    if(key_down){
        camera_y += settings['scroll-speed'];
    }

    if(key_up){
        camera_y -= settings['scroll-speed'];
    }

    frame_counter += 1;
    if(frame_counter > 99){
        frame_counter = 0;
    }

    for(var particle in particles){
        particles[particle]['x'] += particles[particle]['dx'];
        particles[particle]['y'] += particles[particle]['dy'];

        if(particles[particle]['x'] > boundaries['right']
          || particles[particle]['x'] < boundaries['left']
          || particles[particle]['y'] > boundaries['bottom']
          || particles[particle]['y'] < boundaries['top']){
            particles.splice(
              particle,
              1
            );
        }
    }

    for(var gate in gates){
        if(gates[gate]['interval'] > 0
          && frame_counter % gates[gate]['interval'] === 0){
            gates[gate]['event']();
        }

        for(var particle in particles){
            if(particles[particle]['x'] > gates[gate]['x']
              && particles[particle]['x'] < gates[gate]['x'] + gates[gate]['width']
              && particles[particle]['y'] > gates[gate]['y']
              && particles[particle]['y'] < gates[gate]['y'] + gates[gate]['height']){
                if(gates[gate]['destroy']){
                    particles.splice(
                      particle,
                      1
                    );
                    continue;
                }

                if(gates[gate]['dx'] !== false){
                    particles[particle]['dx'] = gates[gate]['dx'];
                }
                if(gates[gate]['dy'] !== false){
                    particles[particle]['dy'] = gates[gate]['dy'];
                }
            }
        }
    }
}

function play_audio(id){
    if(settings['audio-volume'] <= 0){
        return;
    }

    document.getElementById(id).currentTime = 0;
    document.getElementById(id).play();
}

function reset(){
    if(!window.confirm('Reset settings?')){
        return;
    }

    document.getElementById('audio-volume').value = 1;
    document.getElementById('movement-keys').value = 'WASD';
    document.getElementById('max-particles').value = 1000;
    document.getElementById('ms-per-frame').value = 25;
    document.getElementById('reset-camera-key').value = 'H';
    document.getElementById('scroll-speed').value = 5;

    save();
}

function resize(){
    if(mode <= 0){
        return;
    }

    height = window.innerHeight;
    document.getElementById('buffer').height = height;
    document.getElementById('canvas').height = height;
    y = height / 2;

    width = window.innerWidth;
    document.getElementById('buffer').width = width;
    document.getElementById('canvas').width = width;
    x = width / 2;

    buffer.font = '23pt sans-serif';
}

// Save settings into window.localStorage if they differ from default.
function save(){
    var ids = {
      'audio-volume': 1,
      'max-particles': 1000,
      'ms-per-frame': 25,
      'scroll-speed': 5,
    };
    for(var id in ids){
        if(isNaN(document.getElementById(id).value)
          || document.getElementById(id).value == ids[id]){
            window.localStorage.removeItem('ParticleRun-2D.htm-' + id);
            settings[id] = ids[id];

        }else{
            settings[id] = parseFloat(document.getElementById(id).value);
            window.localStorage.setItem(
              'ParticleRun-2D.htm-' + id,
              settings[id]
            );
        }
    }

    ids = {
      'movement-keys': 'WASD',
      'reset-camera-key': 'H',
    };
    for(id in ids){
        if(document.getElementById(id).value === ids[id]){
            window.localStorage.removeItem('ParticleRun-2D.htm-' + id);
            settings[id] = ids[id];

        }else{
            settings[id] = document.getElementById(id).value;
            window.localStorage.setItem(
              'ParticleRun-2D.htm-' + id,
              settings[id]
            );
        }
    }
}

function setmode(newmode, newgame){
    window.cancelAnimationFrame(animationFrame);
    window.clearInterval(interval);

    gates = [];
    particles = [];

    mode = newmode;

    // New game mode.
    if(mode > 0){
        // If it's a newgame from the main menu, save settings.
        if(newgame){
            save();
        }

        // Reset.
        camera_x = 0;
        camera_y = 0;
        frame_counter = 0;
        key_left = false;
        key_right = false;

        // If it's a newgame from the main menu, setup canvas and buffers.
        if(newgame){
            document.body.innerHTML =
              '<canvas id=canvas></canvas><canvas id=buffer></canvas>';

            var contextAttributes = {
              'alpha': false,
            };
            buffer = document.getElementById('buffer').getContext(
              '2d',
              contextAttributes
            );
            canvas = document.getElementById('canvas').getContext(
              '2d',
              contextAttributes
            );

            resize();
        }

        load_level(mode);

        animationFrame = window.requestAnimationFrame(draw);
        interval = window.setInterval(
          'logic()',
          settings['ms-per-frame']
        );

        return;
    }

    // Main menu mode.
    buffer = 0;
    canvas = 0;

    document.body.innerHTML = '

Test Level

<input disabled value=ESC>Main Menu
<input id=movement-keys maxlength=4 value='
      + settings['movement-keys'] + '>Camera ↑←↓→
<input id=reset-camera-key maxlength=1 value='
      + settings['reset-camera-key'] + '>Reset Camera

<input id=audio-volume max=1 min=0 step=0.01 type=range value='
      + settings['audio-volume'] + '>Audio
<input id=max-particles value='
      + settings['max-particles'] + '>Max Particles
<input id=ms-per-frame value='
      + settings['ms-per-frame'] + '>ms/Frame
<input id=scroll-speed value='
      + settings['scroll-speed'] + '>Scroll Speed
Reset Settings

';
}

var animationFrame = 0;
var boundaries = {};
var buffer = 0;
var camera_x = 0;
var camera_y = 0;
var canvas = 0;
var drag = false;
var drag_x = 0;
var drag_y = 0;
var frame_counter = 0;
var gates = [];
var height = 0;
var interval = 0;
var key_down = false;
var key_left = false;
var key_right = false;
var key_up = false;
var mode = 0;
var particles = [];
var settings = {
  'audio-volume': window.localStorage.getItem('ParticleRun-2D.htm-audio-volume') !== null
    ? parseFloat(window.localStorage.getItem('ParticleRun-2D.htm-audio-volume'))
    : 1,
  'movement-keys': window.localStorage.getItem('ParticleRun-2D.htm-movement-keys') || 'WASD',
  'max-particles': parseInt(window.localStorage.getItem('ParticleRun-2D.htm-max-particles')) || 1000,
  'ms-per-frame': parseInt(window.localStorage.getItem('ParticleRun-2D.htm-ms-per-frame')) || 25,
  'reset-camera-key': window.localStorage.getItem('ParticleRun-2D.htm-reset-camera-key') || 'H',
  'scroll-speed': window.localStorage.getItem('ParticleRun-2D.htm-scroll-speed') || 5,
};
var x = 0;
var width = 0;
var y = 0;

window.onkeydown = function(e){
    if(mode <= 0){
        return;
    }

    var key = e.keyCode || e.which;

    // ESC: return to main menu.
    if(key === 27){
        setmode(
          0,
          true
        );
        return;
    }

    key = String.fromCharCode(key);

    if(key === settings['movement-keys'][0]){
        key_up = true;

    }else if(key === settings['movement-keys'][1]){
        key_left = true;

    }else if(key === settings['movement-keys'][2]){
        key_down = true;

    }else if(key === settings['movement-keys'][3]){
        key_right = true;

    }else if(key === settings['reset-camera-key']){
        camera_x = 0;
        camera_y = 0;
    }
};

window.onkeyup = function(e){
    var key = String.fromCharCode(e.keyCode || e.which);

    if(key === settings['movement-keys'][0]){
        key_up = false;

    }else if(key === settings['movement-keys'][1]){
        key_left = false;

    }else if(key === settings['movement-keys'][2]){
        key_down = false;

    }else if(key === settings['movement-keys'][3]){
        key_right = false;
    }
};

window.onload = function(e){
    setmode(
      0,
      true
    );
};

window.onmousedown =
  window.ontouchstart = function(e){
    drag = true;
    drag_x = e.pageX;
    drag_y = e.pageY;
};

window.onmousemove =
  window.ontouchmove = function(e){
    if(!drag){
        return;
    }

    camera_x += drag_x - e.pageX;
    camera_y += drag_y - e.pageY;
    drag_x = e.pageX;
    drag_y = e.pageY;
};

window.onmouseup =
  window.ontouchend = function(e){
    drag = false;
};

window.onresize = resize;
<|endoftext|>


<commit_before>'use strict'

const _ = require('lodash')
const _h = require('./_helpers')
const { ObjectId } = require('mongodb')

exports.handler = async (event, context) => {
  if (event.source === 'aws.events') { return }

  try {
    const user = await _h.user(event)
    if (!user.id) { return _h.error([403, 'Forbidden']) }

    var eId = new ObjectId(event.pathParameters.id)
    const entity = await user.db.collection('entity').findOne({ _id: eId }, { projection: { _id: false, 'private._owner': true } })
    if (!entity) { return _h.error([404, 'Entity not found']) }

    const access = _.map(_.get(entity, 'private._owner', []), (s) => s.reference.toString())

    if (access.indexOf(user.id) === -1) { return _h.error([403, 'Forbidden']) }

    await user.db.collection('property').insertOne({ entity: eId, type: '_deleted', reference: new ObjectId(user.id), datetime: new Date(), created: { at: new Date(), by: new ObjectId(user.id) } })
    await _h.aggregateEntity(user.db, eId, '_deleted')

    const properties = await user.db.collection('property').find({ reference: eId, deleted: { $exists: false } }, { projection: { entity: true, type: true } }).toArray()

    for (let i = 0; i < properties.length; i++) {
      const property = properties[i]

      await user.db.collection('property').updateOne({ _id: property._id }, { $set: { deleted: { at: new Date(), by: new ObjectId(user.id) } } })
      await _h.aggregateEntity(user.db, property.entity, property.type)
    }

    _h.json({ deleted: true })
  } catch (e) {
    return _h.error(e)
  }
}
<commit_msg>Fix delete method<commit_after>'use strict'

const _ = require('lodash')
const _h = require('./_helpers')
const { ObjectId } = require('mongodb')

exports.handler = async (event, context) => {
  if (event.source === 'aws.events') { return }

  try {
    const user = await _h.user(event)
    if (!user.id) { return _h.error([403, 'Forbidden']) }

    var eId = new ObjectId(event.pathParameters.id)
    const entity = await user.db.collection('entity').findOne({ _id: eId }, { projection: { _id: false, 'private._owner': true } })
    if (!entity) { return _h.error([404, 'Entity not found']) }

    const access = _.map(_.get(entity, 'private._owner', []), (s) => s.reference.toString())

    if (access.indexOf(user.id) === -1) { return _h.error([403, 'Forbidden']) }

    await user.db.collection('property').insertOne({ entity: eId, type: '_deleted', reference: new ObjectId(user.id), datetime: new Date(), created: { at: new Date(), by: new ObjectId(user.id) } })
    await _h.aggregateEntity(user.db, eId, '_deleted')

    const properties = await user.db.collection('property').find({ reference: eId, deleted: { $exists: false } }, { projection: { entity: true, type: true } }).toArray()

    for (let i = 0; i < properties.length; i++) {
      const property = properties[i]

      await user.db.collection('property').updateOne({ _id: property._id }, { $set: { deleted: { at: new Date(), by: new ObjectId(user.id) } } })
      await _h.aggregateEntity(user.db, property.entity, property.type)
    }

    return _h.json({ deleted: true })
  } catch (e) {
    return _h.error(e)
  }
}
<|endoftext|>


<commit_before>'use strict';

function draw_logic(){
    // Draw sky gradient.
    canvas_setproperties({
      'properties': {
        'fillStyle': gradient_sky,
      },
    });
    canvas_buffer.fillRect(
      0,
      0,
      canvas_width,
      canvas_y
    );

    // Draw mountains with gradient fillstyle.
    var loop_counter = 2;
    var vertices = [];
    do{
        vertices.push({
          'type': 'moveTo',
          'x': [
            canvas_x,
            math[2],
            math[3],
          ][loop_counter],
          'y': [
            math[10],
            math[8],
            math[9],
          ][loop_counter],
        });
        vertices.push({
          'x': [
            canvas_x,
            math[2],
            math[3],
          ][loop_counter] + [
            math[5],
            math[6],
            math[5],
          ][loop_counter],
          'y': canvas_y,
        });
        vertices.push({
          'x': [
            canvas_x,
            0,
            math[3],
          ][loop_counter] - [
            math[6],
            math[6],
            math[5],
          ][loop_counter],
          'y': canvas_y,
        });
    }while(loop_counter--);
    canvas_draw_path({
      'vertices': vertices,
    });

    // Draw ground gradient.
    canvas_setproperties({
      'properties': {
        'fillStyle': gradient_ground,
      },
    });
    canvas_buffer.fill();

    // Draw tree trunks.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#930',
      },
    });
    for(var tree in trees){
        canvas_buffer.fillRect(
          canvas_width * trees[tree][0] - math[0] * 2,
          trees[tree][1],
          math[0] * trees[tree][2],
          math[0] * trees[tree][2]
        );
    }

    // Draw tree leaves.
    loop_counter = trees.length - 1;
    do{
        canvas_draw_path({
          'properties': {
            'fillStyle': trees[loop_counter][3],
          },
          'vertices': [
            {
              'type': 'moveTo',
              'x': canvas_width * trees[loop_counter][0],
              'y': trees[loop_counter][1] - math[7] * trees[loop_counter][2],
            },
            {
              'x': canvas_width * trees[loop_counter][0] + math[1] * trees[loop_counter][2],
              'y': trees[loop_counter][1] + 1,
            },
            {
              'x': canvas_width * trees[loop_counter][0] - math[1] * trees[loop_counter][2],
              'y': trees[loop_counter][1] + 1,
            },
          ],
        });
    }while(loop_counter--);

    // Draw wreathe on top of closest tree.
    loop_counter = 1;
    do{
        canvas_draw_path({
          'properties': {
            'fillStyle': [
              trees[0][3],
              '#0d0',
            ][loop_counter],
          },
          'vertices': [
            {
              'endAngle': math_tau,
              'radius': canvas_height / (40 - 20 * loop_counter),
              'startAngle': 0,
              'type': 'arc',
              'x': canvas_width * trees[0][0],
              'y': trees[0][1] - math[7],
            },
          ],
        });
    }while(loop_counter--);

    // Draw red ornaments on top of wreathe.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#f00',
      },
    });
    loop_counter = 7;
    do{
        canvas_draw_path({
          'vertices': [
            {
              'endAngle': math_tau,
              'radius': math[4],
              'startAngle': 0,
              'type': 'arc',
              'x': canvas_width * trees[0][0] + math[4] * (
                [
                  -3.7,
                  -2.7,
                  0,
                  2.7,
                  3.7,
                  2.7,
                  0,
                  -2.7,
                ][loop_counter]
              ),
              'y': trees[0][1] - math[7] + math[4] * (
                [
                  0,
                  -2.7,
                  -3.7,
                  -2.7,
                  0,
                  2.7,
                  3.7,
                  2.7,
                ][loop_counter]
              ),
            },
          ],
        });
    }while(loop_counter--);

    // Draw snowflakes.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#fff',
      },
    });
    core_group_modify({
      'groups': [
        'snowflake',
      ],
      'todo': function(entity){
          canvas_buffer.fillRect(
            core_entities[entity]['x'],
            core_entities[entity]['y'],
            core_entities[entity]['size'],
            core_entities[entity]['size']
          );
      },
    });
}

function logic(){
    // Add 2 snowflakes.
    var loop_counter = 1;
    do{
        core_entity_create({
          'properties': {
            'size': core_random_integer({
              'max': 2,
            }) + 3,
            'speed': core_random_integer({
              'max': 4,
            }),
            'x': core_random_integer({
              'max': canvas_width,
            }),
          },
          'types': [
            'snowflake',
          ],
        });
    }while(loop_counter--);

    // Update snowflake positions.
    core_group_modify({
      'groups': [
        'snowflake',
      ],
      'todo': function(entity){
          core_entities[entity]['x'] += Math.random() * 2 - 1;
          core_entities[entity]['y'] += Math.random() * 4 + core_entities[entity]['speed'];

          if(core_entities[entity]['y'] > canvas_height){
              core_entity_remove({
                'entities': [
                  entity,
                ],
              });
          }
      },
    });
}

function repo_init(){
    core_repo_init({
      'entities': {
        'snowflake': {},
      },
      'title': 'SnowyMountains.htm',
    });

    document.body.style.background = '#fff';

    canvas_init();
}

function resize_logic(){
    // Precalculate stuff.
    math = [
      canvas_width / 100,
      canvas_width / 45,
      canvas_x * .4,
      canvas_x * 1.6,
      canvas_height / 100,
      canvas_x * .9,
      canvas_x * .7,
      canvas_height / 7,
      canvas_y * .25,
      canvas_y * .3,
      canvas_y * .4,
    ];

    trees = [];

    var a = canvas_y * .75;
    var k = canvas_y * .35;
    var j = 0;

    // Create 300 trees.
    var loop_counter = 299;
    do{
        if(loop_counter > 200){
            j = core_random_integer({
              'max': canvas_y * 1.1,
            }) + a;

        }else if(loop_counter > 10){
            j = core_random_integer({
              'max': canvas_y * .7,
            }) + a;

        }else{
            j = core_random_integer({
              'max': canvas_y * .2,
            }) + a;
        }

        trees.push([
          Math.random(),
          j,
          -(canvas_y / 2 - j) / k,
          '#' + core_random_integer({
              'max': 5,
            })
            + (core_random_integer({
              'max': 5,
            }) + 4)
            + core_random_integer({
              'max': 5,
            }),
        ]);
    }while(loop_counter--);

    // Sort trees so closer trees are drawn on top.
    sort_property({
      'array': trees,
      'property': 2,
      'reverse': true,
    });

    // Create gradients.
    gradient_ground = canvas_gradient({
      'height': canvas_y * .65,
      'stops': [
        {
          'color': '#eee',
        },
        {
          'color': '#730',
          'offset': 1,
        },
      ],
      'width': canvas_x,
      'x': canvas_x,
      'y': math[10],
    });
    gradient_sky = canvas_gradient({
      'height': canvas_y,
      'stops': [
        {
          'color': '#ccc',
        },
        {
          'color': '#003',
          'offset': 1,
        },
      ],
      'width': canvas_x,
      'x': canvas_x,
      'y': 10,
    });
}

var gradient_ground = 0;
var gradient_sky = 0;
var math = [];
var trees = [];
<commit_msg>updated canvas height/width usage<commit_after>'use strict';

function draw_logic(){
    // Draw sky gradient.
    canvas_setproperties({
      'properties': {
        'fillStyle': gradient_sky,
      },
    });
    canvas_buffer.fillRect(
      0,
      0,
      canvas_properties['width'],
      canvas_y
    );

    // Draw mountains with gradient fillstyle.
    var loop_counter = 2;
    var vertices = [];
    do{
        vertices.push({
          'type': 'moveTo',
          'x': [
            canvas_x,
            math[2],
            math[3],
          ][loop_counter],
          'y': [
            math[10],
            math[8],
            math[9],
          ][loop_counter],
        });
        vertices.push({
          'x': [
            canvas_x,
            math[2],
            math[3],
          ][loop_counter] + [
            math[5],
            math[6],
            math[5],
          ][loop_counter],
          'y': canvas_y,
        });
        vertices.push({
          'x': [
            canvas_x,
            0,
            math[3],
          ][loop_counter] - [
            math[6],
            math[6],
            math[5],
          ][loop_counter],
          'y': canvas_y,
        });
    }while(loop_counter--);
    canvas_draw_path({
      'vertices': vertices,
    });

    // Draw ground gradient.
    canvas_setproperties({
      'properties': {
        'fillStyle': gradient_ground,
      },
    });
    canvas_buffer.fill();

    // Draw tree trunks.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#930',
      },
    });
    for(var tree in trees){
        canvas_buffer.fillRect(
          canvas_properties['width'] * trees[tree][0] - math[0] * 2,
          trees[tree][1],
          math[0] * trees[tree][2],
          math[0] * trees[tree][2]
        );
    }

    // Draw tree leaves.
    loop_counter = trees.length - 1;
    do{
        canvas_draw_path({
          'properties': {
            'fillStyle': trees[loop_counter][3],
          },
          'vertices': [
            {
              'type': 'moveTo',
              'x': canvas_properties['width'] * trees[loop_counter][0],
              'y': trees[loop_counter][1] - math[7] * trees[loop_counter][2],
            },
            {
              'x': canvas_properties['width'] * trees[loop_counter][0] + math[1] * trees[loop_counter][2],
              'y': trees[loop_counter][1] + 1,
            },
            {
              'x': canvas_properties['width'] * trees[loop_counter][0] - math[1] * trees[loop_counter][2],
              'y': trees[loop_counter][1] + 1,
            },
          ],
        });
    }while(loop_counter--);

    // Draw wreathe on top of closest tree.
    loop_counter = 1;
    do{
        canvas_draw_path({
          'properties': {
            'fillStyle': [
              trees[0][3],
              '#0d0',
            ][loop_counter],
          },
          'vertices': [
            {
              'endAngle': math_tau,
              'radius': canvas_properties['height'] / (40 - 20 * loop_counter),
              'startAngle': 0,
              'type': 'arc',
              'x': canvas_properties['width'] * trees[0][0],
              'y': trees[0][1] - math[7],
            },
          ],
        });
    }while(loop_counter--);

    // Draw red ornaments on top of wreathe.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#f00',
      },
    });
    loop_counter = 7;
    do{
        canvas_draw_path({
          'vertices': [
            {
              'endAngle': math_tau,
              'radius': math[4],
              'startAngle': 0,
              'type': 'arc',
              'x': canvas_properties['width'] * trees[0][0] + math[4] * (
                [
                  -3.7,
                  -2.7,
                  0,
                  2.7,
                  3.7,
                  2.7,
                  0,
                  -2.7,
                ][loop_counter]
              ),
              'y': trees[0][1] - math[7] + math[4] * (
                [
                  0,
                  -2.7,
                  -3.7,
                  -2.7,
                  0,
                  2.7,
                  3.7,
                  2.7,
                ][loop_counter]
              ),
            },
          ],
        });
    }while(loop_counter--);

    // Draw snowflakes.
    canvas_setproperties({
      'properties': {
        'fillStyle': '#fff',
      },
    });
    core_group_modify({
      'groups': [
        'snowflake',
      ],
      'todo': function(entity){
          canvas_buffer.fillRect(
            core_entities[entity]['x'],
            core_entities[entity]['y'],
            core_entities[entity]['size'],
            core_entities[entity]['size']
          );
      },
    });
}

function logic(){
    // Add 2 snowflakes.
    var loop_counter = 1;
    do{
        core_entity_create({
          'properties': {
            'size': core_random_integer({
              'max': 2,
            }) + 3,
            'speed': core_random_integer({
              'max': 4,
            }),
            'x': core_random_integer({
              'max': canvas_properties['width'],
            }),
          },
          'types': [
            'snowflake',
          ],
        });
    }while(loop_counter--);

    // Update snowflake positions.
    core_group_modify({
      'groups': [
        'snowflake',
      ],
      'todo': function(entity){
          core_entities[entity]['x'] += Math.random() * 2 - 1;
          core_entities[entity]['y'] += Math.random() * 4 + core_entities[entity]['speed'];

          if(core_entities[entity]['y'] > canvas_properties['height']){
              core_entity_remove({
                'entities': [
                  entity,
                ],
              });
          }
      },
    });
}

function repo_init(){
    core_repo_init({
      'entities': {
        'snowflake': {},
      },
      'title': 'SnowyMountains.htm',
    });

    document.body.style.background = '#fff';

    canvas_init();
}

function resize_logic(){
    // Precalculate stuff.
    math = [
      canvas_properties['width'] / 100,
      canvas_properties['width'] / 45,
      canvas_x * .4,
      canvas_x * 1.6,
      canvas_properties['height'] / 100,
      canvas_x * .9,
      canvas_x * .7,
      canvas_properties['height'] / 7,
      canvas_y * .25,
      canvas_y * .3,
      canvas_y * .4,
    ];

    trees = [];

    var a = canvas_y * .75;
    var k = canvas_y * .35;
    var j = 0;

    // Create 300 trees.
    var loop_counter = 299;
    do{
        if(loop_counter > 200){
            j = core_random_integer({
              'max': canvas_y * 1.1,
            }) + a;

        }else if(loop_counter > 10){
            j = core_random_integer({
              'max': canvas_y * .7,
            }) + a;

        }else{
            j = core_random_integer({
              'max': canvas_y * .2,
            }) + a;
        }

        trees.push([
          Math.random(),
          j,
          -(canvas_y / 2 - j) / k,
          '#' + core_random_integer({
              'max': 5,
            })
            + (core_random_integer({
              'max': 5,
            }) + 4)
            + core_random_integer({
              'max': 5,
            }),
        ]);
    }while(loop_counter--);

    // Sort trees so closer trees are drawn on top.
    sort_property({
      'array': trees,
      'property': 2,
      'reverse': true,
    });

    // Create gradients.
    gradient_ground = canvas_gradient({
      'height': canvas_y * .65,
      'stops': [
        {
          'color': '#eee',
        },
        {
          'color': '#730',
          'offset': 1,
        },
      ],
      'width': canvas_x,
      'x': canvas_x,
      'y': math[10],
    });
    gradient_sky = canvas_gradient({
      'height': canvas_y,
      'stops': [
        {
          'color': '#ccc',
        },
        {
          'color': '#003',
          'offset': 1,
        },
      ],
      'width': canvas_x,
      'x': canvas_x,
      'y': 10,
    });
}

var gradient_ground = 0;
var gradient_sky = 0;
var math = [];
var trees = [];
<|endoftext|>


<commit_before>if (typeof define !== 'function') { var define = require('amdefine')(module) }
/*
 * QuickBlox JavaScript SDK
 *
 * Utilities
 *
 */

define(['qbConfig'],
function(config) {

  var Utils = {
    randomNonce: function() {
      return Math.floor(Math.random() * 10000);
    },

    unixTime: function() {
      return Math.floor(Date.now() / 1000);
    },

    getUrl: function(base, id) {
      var protocol = config.ssl ? 'https://' : 'http://';
      var resource = id ? '/' + id : '';
      return protocol + config.endpoints.api + '/' + base + resource + config.urls.type;
    }
  };

  return Utils;
});
<commit_msg>[browserify] qbUtils.js<commit_after>/*
 * QuickBlox JavaScript SDK
 *
 * Utilities
 *
 */

var config = require('./qbConfig');

var Utils = {
  randomNonce: function() {
    return Math.floor(Math.random() * 10000);
  },

  unixTime: function() {
    return Math.floor(Date.now() / 1000);
  },

  getUrl: function(base, id) {
    var protocol = config.ssl ? 'https://' : 'http://';
    var resource = id ? '/' + id : '';
    return protocol + config.endpoints.api + '/' + base + resource + config.urls.type;
  }
};

module.exports = Utils;
<|endoftext|>


<commit_before>function draw_body(id){
    // Bodies orbit around their parent.
    bodies[id][6] += bodies[id][5];
    if(bodies[id][6] > 360){
        bodies[id][6] -= 360;
    }else if(bodies[id][6] < 0){
        bodies[id][6] += 360;
    }
    bodies[id][0] = bodies[id][4] * Math.cos(bodies[id][6]);
    bodies[id][1] = bodies[id][4] * Math.sin(bodies[id][6]);

    // Draw body.
    buffer.fillStyle = bodies[id][7];
    buffer.beginPath();
    buffer.arc(
      bodies[id][0],
      bodies[id][1],
      bodies[id][2],
      0,
      pi_times_two,
      1
    );
    buffer.closePath();
    buffer.fill();

    // Draw orbit path and line to parent, if player allows it.
    if(settings['line-orbit']
      || settings['line-parent']){
        buffer.strokeStyle = bodies[id][7];
        buffer.lineWidth = Math.ceil(bodies[id][2] / 10) / zoom;

        buffer.beginPath();
        if(settings['line-orbit']){
            buffer.arc(
              0,
              0,
              bodies[id][4],
              0,
              pi_times_two,
              1
            );
        }
        if(settings['line-parent']){
            buffer.moveTo(
              bodies[id][0],
              bodies[id][1]
            );
            buffer.lineTo(
              0,
              0
            );
        }
        buffer.closePath();
        buffer.stroke();
    }

    // If no moons, we're done here.
    if(bodies[id][8] == 0){
        return;
    }

    // Draw moons.
    var moonloop_counter = bodies[id][8].length - 1;
    if(moonloop_counter >= 0){
        do{
            bodies[id][8][moonloop_counter][6] += bodies[id][8][moonloop_counter][5];
            if(bodies[id][8][moonloop_counter][6] > 360){
                bodies[id][8][moonloop_counter][6] -= 360;
            }else if(bodies[id][8][moonloop_counter][6] < 0){
                bodies[id][8][moonloop_counter][6] += 360;
            }
            bodies[id][8][moonloop_counter][0] =
              bodies[id][8][moonloop_counter][4]
              * Math.cos(bodies[id][8][moonloop_counter][6])
              + bodies[id][0];
            bodies[id][8][moonloop_counter][1] =
              bodies[id][8][moonloop_counter][4]
              * Math.sin(bodies[id][8][moonloop_counter][6])
              + bodies[id][1];

            buffer.fillStyle = bodies[id][8][moonloop_counter][7];
            buffer.beginPath();
            buffer.arc(
              bodies[id][8][moonloop_counter][0],
              bodies[id][8][moonloop_counter][1],
              bodies[id][8][moonloop_counter][2],
              0,
              pi_times_two,
              1
            );
            buffer.closePath();
            buffer.fill();

            // Draw orbit path and line to parent, if player allows it.
            if(settings['line-orbit']
              || settings['line-parent']){
                buffer.strokeStyle = bodies[id][8][moonloop_counter][7];
                buffer.lineWidth = Math.ceil(bodies[id][8][moonloop_counter][2] / 10) / zoom;

                buffer.beginPath();
                if(settings['line-orbit']){
                    buffer.arc(
                      bodies[id][0],
                      bodies[id][1],
                      bodies[id][8][moonloop_counter][4],
                      0,
                      pi_times_two,
                      1
                    );
                }
                if(settings['line-parent']){
                    buffer.moveTo(
                      bodies[id][0],
                      bodies[id][1]
                    );
                    buffer.lineTo(
                      bodies[id][8][moonloop_counter][0],
                      bodies[id][8][moonloop_counter][1]
                    );
                }
                buffer.closePath();
                buffer.stroke();
            }
        }while(moonloop_counter--);
    }
}

function draw(){
    buffer.clearRect(
      0,
      0,
      width,
      height
    );

    // Save the current buffer state.
    buffer.save();

    // Setup camera offset.
    buffer.translate(
      x,
      y
    );
    buffer.scale(
      zoom,
      zoom
    );
    buffer.translate(
      camera_x,
      camera_y
    );

    // Draw bodies.
    var loop_counter = bodies.length - 1;
    if(loop_counter >= 0){
        do{
            draw_body(loop_counter);
        }while(loop_counter--);
    }

    // Draw the star.
    buffer.fillStyle = settings['solar-color'];
    buffer.beginPath();
    buffer.arc(
      0,
      0,
      settings['solar-radius'],
      0,
      pi_times_two,
      1
    );
    buffer.closePath();
    buffer.fill();

    // Restore the buffer state.
    buffer.restore();

    // Draw instructions.
    buffer.font = '23pt sans-serif';
    buffer.fillStyle = '#fff';
    buffer.fillText(
      'H,L,MouseWheel,O,WASD',
      0,
      23
    );
    buffer.fillText(
      zoom,
      0,
      50
    );

    canvas.clearRect(
      0,
      0,
      width,
      height
    );
    canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );

    window.requestAnimationFrame(draw);
}

function generate_solarsystem(){
    bodies.length = 0;

    var bodyloop_counter = random_number(5) + 1;
    var moonloop_counter = 0;
    var radius = 0;
    do{
        radius = random_number(10) + 3;

        // Create body.
        bodies.push([
          0,
          0,
          radius,
          radius,
          random_number(2323) + 232,
          Math.random() / 100,
          random_number(360),
          '#'
            + (random_number(5) + 4)
            + (random_number(5) + 4)
            + (random_number(5) + 4),
          0,
        ]);

        // Should this new body have moons?
        if(Math.random() > .5){
            bodies[bodies.length - 1][8] = [];

            moonloop_counter = random_number(2) + 1;
            do{
                radius = random_number(5) + 2;

                // Create moon for this new body.
                bodies[bodies.length - 1][8].push([
                  0,
                  0,
                  radius,
                  radius,
                  random_number(100) + 15,
                  (Math.random() - .5) / 5,
                  random_number(360),
                  '#'
                    + (random_number(5) + 4)
                    + (random_number(5) + 4)
                    + (random_number(5) + 4),
                  bodies.length - 1
                ]);
            }while(moonloop_counter--);
        }
    }while(bodyloop_counter--);

    settings['solar-color'] = '#'
        + (random_number(4) + 5)
        + (random_number(4) + 5)
        + (random_number(4) + 5);
    settings['solar-radius'] = random_number(99) + 5;
}

function init(){
    window.onresize = resize;
    resize();

    generate_solarsystem();

    if('onmousewheel' in window){
        window.onmousewheel = mouse_wheel;

    }else{
        document.addEventListener(
          'DOMMouseScroll',
          mouse_wheel,
          false
        );
    }

    window.requestAnimationFrame(draw);
    setInterval(
      'logic()',
      35
    );
}

function logic(){
    // Update camera position.
    if(key_down){
        camera_y -= 10 / zoom;
    }
    if(key_left){
        camera_x += 10 / zoom;
    }
    if(key_right){
        camera_x -= 10 / zoom;
    }
    if(key_up){
        camera_y += 10 / zoom;
    }
}

function mouse_wheel(e){
    zoom += (e.wheelDelta || -e.detail > 0) > 0
      ? .05
      : -.05;

    if(zoom < .1){
        zoom = .1;

    }else if(zoom > 3){
        zoom = 3;
    }

    zoom = parseFloat(zoom.toFixed(2));
}

function random_number(i){
    return Math.floor(Math.random() * i);
}

function resize(){
    height = window.innerHeight;
    document.getElementById('buffer').height = height;
    document.getElementById('canvas').height = height;
    y = height / 2;

    width = window.innerWidth;
    document.getElementById('buffer').width = width;
    document.getElementById('canvas').width = width;
    x = width / 2;
}

var bodies = [];
var buffer = document.getElementById('buffer').getContext('2d');
var camera_x = 0;
var camera_y = 0;
var canvas = document.getElementById('canvas').getContext('2d');
var height = 0;
var key_down = false;
var key_left = false;
var key_right = false;
var key_up = false;
var pi_times_two = Math.PI * 2;
var settings = {
  'line-orbit': true,
  'line-parent': true,
  'solar-color': '#fff',
  'solar-radius': 1,
};
var width = 0;
var x = 0;
var y = 0;
var zoom = 1;

window.onkeydown = function(e){
    var key = e.keyCode || e.which;

    if(key === 65){ // A
        key_left = true;

    }else if(key === 68){ // D
        key_right = true;

    }else if(key === 83){ // S
        key_down = true;

    }else if(key === 87){ // W
        key_up = true;

    }else if(key === 76){ // L
        settings['line-parent'] = !settings['line-parent'];

    }else if(key === 79){ // O
        settings['line-orbit'] = !settings['line-orbit'];

    }else if(key === 72){ // H
        generate_solarsystem();
    }
};

window.onkeyup = function(e){
    var key = e.keyCode || e.which;

    if(key === 65){ // A
        key_left = false;

    }else if(key === 68){ // D
        key_right = false;

    }else if(key === 83){ // S
        key_down = false;

    }else if(key === 87){ // W
        key_up = false;
    }
};

window.onload = init;
<commit_msg>removed useless function declaration<commit_after>function draw_body(id){
    // Bodies orbit around their parent.
    bodies[id][6] += bodies[id][5];
    if(bodies[id][6] > 360){
        bodies[id][6] -= 360;
    }else if(bodies[id][6] < 0){
        bodies[id][6] += 360;
    }
    bodies[id][0] = bodies[id][4] * Math.cos(bodies[id][6]);
    bodies[id][1] = bodies[id][4] * Math.sin(bodies[id][6]);

    // Draw body.
    buffer.fillStyle = bodies[id][7];
    buffer.beginPath();
    buffer.arc(
      bodies[id][0],
      bodies[id][1],
      bodies[id][2],
      0,
      pi_times_two,
      1
    );
    buffer.closePath();
    buffer.fill();

    // Draw orbit path and line to parent, if player allows it.
    if(settings['line-orbit']
      || settings['line-parent']){
        buffer.strokeStyle = bodies[id][7];
        buffer.lineWidth = Math.ceil(bodies[id][2] / 10) / zoom;

        buffer.beginPath();
        if(settings['line-orbit']){
            buffer.arc(
              0,
              0,
              bodies[id][4],
              0,
              pi_times_two,
              1
            );
        }
        if(settings['line-parent']){
            buffer.moveTo(
              bodies[id][0],
              bodies[id][1]
            );
            buffer.lineTo(
              0,
              0
            );
        }
        buffer.closePath();
        buffer.stroke();
    }

    // If no moons, we're done here.
    if(bodies[id][8] == 0){
        return;
    }

    // Draw moons.
    var moonloop_counter = bodies[id][8].length - 1;
    if(moonloop_counter >= 0){
        do{
            bodies[id][8][moonloop_counter][6] += bodies[id][8][moonloop_counter][5];
            if(bodies[id][8][moonloop_counter][6] > 360){
                bodies[id][8][moonloop_counter][6] -= 360;
            }else if(bodies[id][8][moonloop_counter][6] < 0){
                bodies[id][8][moonloop_counter][6] += 360;
            }
            bodies[id][8][moonloop_counter][0] =
              bodies[id][8][moonloop_counter][4]
              * Math.cos(bodies[id][8][moonloop_counter][6])
              + bodies[id][0];
            bodies[id][8][moonloop_counter][1] =
              bodies[id][8][moonloop_counter][4]
              * Math.sin(bodies[id][8][moonloop_counter][6])
              + bodies[id][1];

            buffer.fillStyle = bodies[id][8][moonloop_counter][7];
            buffer.beginPath();
            buffer.arc(
              bodies[id][8][moonloop_counter][0],
              bodies[id][8][moonloop_counter][1],
              bodies[id][8][moonloop_counter][2],
              0,
              pi_times_two,
              1
            );
            buffer.closePath();
            buffer.fill();

            // Draw orbit path and line to parent, if player allows it.
            if(settings['line-orbit']
              || settings['line-parent']){
                buffer.strokeStyle = bodies[id][8][moonloop_counter][7];
                buffer.lineWidth = Math.ceil(bodies[id][8][moonloop_counter][2] / 10) / zoom;

                buffer.beginPath();
                if(settings['line-orbit']){
                    buffer.arc(
                      bodies[id][0],
                      bodies[id][1],
                      bodies[id][8][moonloop_counter][4],
                      0,
                      pi_times_two,
                      1
                    );
                }
                if(settings['line-parent']){
                    buffer.moveTo(
                      bodies[id][0],
                      bodies[id][1]
                    );
                    buffer.lineTo(
                      bodies[id][8][moonloop_counter][0],
                      bodies[id][8][moonloop_counter][1]
                    );
                }
                buffer.closePath();
                buffer.stroke();
            }
        }while(moonloop_counter--);
    }
}

function draw(){
    buffer.clearRect(
      0,
      0,
      width,
      height
    );

    // Save the current buffer state.
    buffer.save();

    // Setup camera offset.
    buffer.translate(
      x,
      y
    );
    buffer.scale(
      zoom,
      zoom
    );
    buffer.translate(
      camera_x,
      camera_y
    );

    // Draw bodies.
    var loop_counter = bodies.length - 1;
    if(loop_counter >= 0){
        do{
            draw_body(loop_counter);
        }while(loop_counter--);
    }

    // Draw the star.
    buffer.fillStyle = settings['solar-color'];
    buffer.beginPath();
    buffer.arc(
      0,
      0,
      settings['solar-radius'],
      0,
      pi_times_two,
      1
    );
    buffer.closePath();
    buffer.fill();

    // Restore the buffer state.
    buffer.restore();

    // Draw instructions.
    buffer.font = '23pt sans-serif';
    buffer.fillStyle = '#fff';
    buffer.fillText(
      'H,L,MouseWheel,O,WASD',
      0,
      23
    );
    buffer.fillText(
      zoom,
      0,
      50
    );

    canvas.clearRect(
      0,
      0,
      width,
      height
    );
    canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );

    window.requestAnimationFrame(draw);
}

function generate_solarsystem(){
    bodies.length = 0;

    var bodyloop_counter = random_number(5) + 1;
    var moonloop_counter = 0;
    var radius = 0;
    do{
        radius = random_number(10) + 3;

        // Create body.
        bodies.push([
          0,
          0,
          radius,
          radius,
          random_number(2323) + 232,
          Math.random() / 100,
          random_number(360),
          '#'
            + (random_number(5) + 4)
            + (random_number(5) + 4)
            + (random_number(5) + 4),
          0,
        ]);

        // Should this new body have moons?
        if(Math.random() > .5){
            bodies[bodies.length - 1][8] = [];

            moonloop_counter = random_number(2) + 1;
            do{
                radius = random_number(5) + 2;

                // Create moon for this new body.
                bodies[bodies.length - 1][8].push([
                  0,
                  0,
                  radius,
                  radius,
                  random_number(100) + 15,
                  (Math.random() - .5) / 5,
                  random_number(360),
                  '#'
                    + (random_number(5) + 4)
                    + (random_number(5) + 4)
                    + (random_number(5) + 4),
                  bodies.length - 1
                ]);
            }while(moonloop_counter--);
        }
    }while(bodyloop_counter--);

    settings['solar-color'] = '#'
        + (random_number(4) + 5)
        + (random_number(4) + 5)
        + (random_number(4) + 5);
    settings['solar-radius'] = random_number(99) + 5;
}

function logic(){
    // Update camera position.
    if(key_down){
        camera_y -= 10 / zoom;
    }
    if(key_left){
        camera_x += 10 / zoom;
    }
    if(key_right){
        camera_x -= 10 / zoom;
    }
    if(key_up){
        camera_y += 10 / zoom;
    }
}

function mouse_wheel(e){
    zoom += (e.wheelDelta || -e.detail > 0) > 0
      ? .05
      : -.05;

    if(zoom < .1){
        zoom = .1;

    }else if(zoom > 3){
        zoom = 3;
    }

    zoom = parseFloat(zoom.toFixed(2));
}

function random_number(i){
    return Math.floor(Math.random() * i);
}

function resize(){
    height = window.innerHeight;
    document.getElementById('buffer').height = height;
    document.getElementById('canvas').height = height;
    y = height / 2;

    width = window.innerWidth;
    document.getElementById('buffer').width = width;
    document.getElementById('canvas').width = width;
    x = width / 2;
}

var bodies = [];
var buffer = document.getElementById('buffer').getContext('2d');
var camera_x = 0;
var camera_y = 0;
var canvas = document.getElementById('canvas').getContext('2d');
var height = 0;
var key_down = false;
var key_left = false;
var key_right = false;
var key_up = false;
var pi_times_two = Math.PI * 2;
var settings = {
  'line-orbit': true,
  'line-parent': true,
  'solar-color': '#fff',
  'solar-radius': 1,
};
var width = 0;
var x = 0;
var y = 0;
var zoom = 1;

window.onkeydown = function(e){
    var key = e.keyCode || e.which;

    if(key === 65){ // A
        key_left = true;

    }else if(key === 68){ // D
        key_right = true;

    }else if(key === 83){ // S
        key_down = true;

    }else if(key === 87){ // W
        key_up = true;

    }else if(key === 76){ // L
        settings['line-parent'] = !settings['line-parent'];

    }else if(key === 79){ // O
        settings['line-orbit'] = !settings['line-orbit'];

    }else if(key === 72){ // H
        generate_solarsystem();
    }
};

window.onkeyup = function(e){
    var key = e.keyCode || e.which;

    if(key === 65){ // A
        key_left = false;

    }else if(key === 68){ // D
        key_right = false;

    }else if(key === 83){ // S
        key_down = false;

    }else if(key === 87){ // W
        key_up = false;
    }
};

window.onload = function(){
    window.onresize = resize;
    resize();

    generate_solarsystem();

    if('onmousewheel' in window){
        window.onmousewheel = mouse_wheel;

    }else{
        document.addEventListener(
          'DOMMouseScroll',
          mouse_wheel,
          false
        );
    }

    window.requestAnimationFrame(draw);
    setInterval(
      'logic()',
      35
    );
};
<|endoftext|>


<commit_before>"use strict";

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

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

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

module.exports = class qryptos extends Exchange {

    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'qryptos',
            'name': 'QRYPTOS',
            'countries': [ 'CN', 'TW' ],
            'version': '2',
            'rateLimit': 1000,
            'hasFetchTickers': true,
            'hasCORS': false,
            'has': {
                'fetchOrder': true,
                'fetchOrders': true,
                'fetchOpenOrders': true,
                'fetchClosedOrders': true,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/30953915-b1611dc0-a436-11e7-8947-c95bd5a42086.jpg',
                'api': 'https://api.qryptos.com',
                'www': 'https://www.qryptos.com',
                'doc': 'https://developers.quoine.com',
            },
            'api': {
                'public': {
                    'get': [
                        'products',
                        'products/{id}',
                        'products/{id}/price_levels',
                        'executions',
                        'ir_ladders/{currency}',
                    ],
                },
                'private': {
                    'get': [
                        'accounts/balance',
                        'crypto_accounts',
                        'executions/me',
                        'fiat_accounts',
                        'loan_bids',
                        'loans',
                        'orders',
                        'orders/{id}',
                        'orders/{id}/trades',
                        'trades',
                        'trades/{id}/loans',
                        'trading_accounts',
                        'trading_accounts/{id}',
                    ],
                    'post': [
                        'fiat_accounts',
                        'loan_bids',
                        'orders',
                    ],
                    'put': [
                        'loan_bids/{id}/close',
                        'loans/{id}',
                        'orders/{id}',
                        'orders/{id}/cancel',
                        'trades/{id}',
                        'trades/{id}/close',
                        'trades/close_all',
                        'trading_accounts/{id}',
                    ],
                },
            },
        });
    }

    async fetchMarkets () {
        let markets = await this.publicGetProducts ();
        let result = [];
        for (let p = 0; p < markets.length; p++) {
            let market = markets[p];
            let id = market['id'].toString ();
            let base = market['base_currency'];
            let quote = market['quoted_currency'];
            let symbol = base + '/' + quote;
            let maker = this.safeFloat (market, 'maker_fee');
            let taker = this.safeFloat (market, 'taker_fee');
            let active = !market['disabled'];
            let minAmount = undefined;
            if (base === 'BTC') {
                minAmount = 0.001;
            } else if (base === 'ETH') {
                minAmount = 0.01;
            } else if (base === 'QASH' || base === 'UBTC' || base === 'DASH' || base === 'NEO' || base === 'BCH') {
                minAmount = 0.0001;
            }
            let minPrice = 0.00001;
            let limits = {
                amount: { min: minAmount },
                price: { min: minPrice },
                cost: { min: minPrice * minAmount },
            };
            let precision = { amount: 8, price: 5 };
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'maker': maker,
                'taker': taker,
                'limits': limits,
                'precision': precision,
                'active': active,
                'info': market,
            });
        }
        return result;
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let balances = await this.privateGetAccountsBalance ();
        let result = { 'info': balances };
        for (let b = 0; b < balances.length; b++) {
            let balance = balances[b];
            let currency = balance['currency'];
            let total = parseFloat (balance['balance']);
            let account = {
                'free': total,
                'used': 0.0,
                'total': total,
            };
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    async fetchOrderBook (symbol, params = {}) {
        await this.loadMarkets ();
        let orderbook = await this.publicGetProductsIdPriceLevels (this.extend ({
            'id': this.marketId (symbol),
        }, params));
        return this.parseOrderBook (orderbook, undefined, 'buy_price_levels', 'sell_price_levels');
    }

    parseTicker (ticker, market = undefined) {
        let timestamp = this.milliseconds ();
        let last = undefined;
        if ('last_traded_price' in ticker) {
            if (ticker['last_traded_price']) {
                let length = ticker['last_traded_price'].length;
                if (length > 0)
                    last = parseFloat (ticker['last_traded_price']);
            }
        }
        let symbol = undefined;
        if (market)
            symbol = market['symbol'];
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': this.safeFloat (ticker, 'high_market_ask'),
            'low': this.safeFloat (ticker, 'low_market_bid'),
            'bid': this.safeFloat (ticker, 'market_bid'),
            'ask': this.safeFloat (ticker, 'market_ask'),
            'vwap': undefined,
            'open': undefined,
            'close': undefined,
            'first': undefined,
            'last': last,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': this.safeFloat (ticker, 'volume_24h'),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    async fetchTickers (symbols = undefined, params = {}) {
        await this.loadMarkets ();
        let tickers = await this.publicGetProducts (params);
        let result = {};
        for (let t = 0; t < tickers.length; t++) {
            let ticker = tickers[t];
            let base = ticker['base_currency'];
            let quote = ticker['quoted_currency'];
            let symbol = base + '/' + quote;
            let market = this.markets[symbol];
            result[symbol] = this.parseTicker (ticker, market);
        }
        return result;
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let ticker = await this.publicGetProductsId (this.extend ({
            'id': market['id'],
        }, params));
        return this.parseTicker (ticker, market);
    }

    parseTrade (trade, market) {
        let timestamp = trade['created_at'] * 1000;
        return {
            'info': trade,
            'id': trade['id'].toString (),
            'order': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'type': undefined,
            'side': trade['taker_side'],
            'price': parseFloat (trade['price']),
            'amount': parseFloat (trade['quantity']),
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'product_id': market['id'],
        };
        if (limit)
            request['limit'] = limit;
        let response = await this.publicGetExecutions (this.extend (request, params));
        return this.parseTrades (response['models'], market, since, limit);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        let order = {
            'order_type': type,
            'product_id': this.marketId (symbol),
            'side': side,
            'quantity': amount,
        };
        if (type == 'limit')
            order['price'] = price;
        let response = await this.privatePostOrders (this.extend ({
            'order': order,
        }, params));
        return this.parseOrder(response);
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let result = await this.privatePutOrdersIdCancel (this.extend ({
            'id': id,
        }, params));
        let order = this.parseOrder (result);
        if (order['status'] == 'closed')
            throw new OrderNotFound (this.id + ' ' + this.json (order));
        return order;
    }

    parseOrder (order) {
        let timestamp = order['created_at'] * 1000;
        let marketId = order['product_id'].toString ();
        let market = this.marketsById[marketId];
        let status = undefined;
        if ('status' in order) {
            if (order['status'] == 'live') {
                status = 'open';
            } else if (order['status'] == 'filled') {
                status = 'closed';
            } else if (order['status'] == 'cancelled') { // 'll' intended
                status = 'canceled';
            }
        }
        let amount = parseFloat (order['quantity']);
        let filled = parseFloat (order['filled_quantity']);
        let price = parseFloat (order['price']);
        let symbol = undefined;
        if (market) {
            symbol = market['symbol'];
        }
        return {
            'id': order['id'].toString (),
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'type': order['order_type'],
            'status': status,
            'symbol': symbol,
            'side': order['side'],
            'price': price,
            'amount': amount,
            'filled': filled,
            'remaining': amount - filled,
            'trades': undefined,
            'fee': {
                'currency': undefined,
                'cost': parseFloat (order['order_fee']),
            },
            'info': order,
        };
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let order = await this.privateGetOrdersId (this.extend ({
            'id': id,
        }, params));
        return this.parseOrder (order);
    }

    async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params={}) {
        await this.loadMarkets ();
        let market = undefined;
        let request = {};
        if (symbol) {
            market = this.market (symbol);
            request['product_id'] = market['id'];
        }
        let status = params['status'];
        if (status == 'open') {
            request['status'] = 'live';
        } else if (status == 'closed') {
            request['status'] = 'filled';
        } else if (status == 'canceled') {
            request['status'] = 'cancelled';
        }
        let result = await this.privateGetOrders (request);
        let orders = result['models'];
        return this.parseOrders (orders, market, since, limit);
    }

    fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        return this.fetchOrders (symbol, since, limit, this.extend ({ 'status': 'open' }, params));
    }

    fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        return this.fetchOrders (symbol, since, limit, this.extend ({ 'status': 'closed' }, params));
    }

    handleErrors (code, reason, url, method, headers, body) {
        let response = undefined;
        if (code == 200 || code == 404 || code == 422) {
            if ((body[0] == '{') || (body[0] == '[')) {
                response = JSON.parse (body);
            } else {
                // if not a JSON response
                throw new ExchangeError (this.id + ' returned a non-JSON reply: ' + body);
            }
        }
        if (code == 404) {
            if ('message' in response) {
                if (response['message'] == 'Order not found') {
                    throw new OrderNotFound (this.id + ' ' + body);
                }
            }
        } else if (code == 422) {
            if ('errors' in response) {
                let errors = response['errors'];
                if ('user' in errors) {
                    let messages = errors['user'];
                    if (messages.indexOf ('not_enough_free_balance') >= 0) {
                        throw new InsufficientFunds (this.id + ' ' + body);
                    }
                } else if ('quantity' in errors) {
                    let messages = errors['quantity'];
                    if (messages.indexOf ('less_than_order_size') >= 0) {
                        throw new InvalidOrder (this.id + ' ' + body);
                    }
                }
            }
        }
    }

    nonce () {
        return this.milliseconds ();
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        headers = {
            'X-Quoine-API-Version': this.version,
            'Content-Type': 'application/json',
        };
        if (api == 'public') {
            if (Object.keys (query).length)
                url += '?' + this.urlencode (query);
        } else {
            this.checkRequiredCredentials ();
            if (method == 'GET') {
                if (Object.keys (query).length)
                    url += '?' + this.urlencode (query);
            } else if (Object.keys (query).length) {
                body = this.json (query);
            }
            let nonce = this.nonce ();
            let request = {
                'path': url,
                'nonce': nonce,
                'token_id': this.apiKey,
                'iat': Math.floor (nonce / 1000), // issued at
            };
            headers['X-Quoine-Auth'] = this.jwt (request, this.secret);
        }
        url = this.urls['api'] + url;
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
}
<commit_msg>qryptos: linting<commit_after>"use strict";

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

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

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

module.exports = class qryptos extends Exchange {

    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'qryptos',
            'name': 'QRYPTOS',
            'countries': [ 'CN', 'TW' ],
            'version': '2',
            'rateLimit': 1000,
            'hasFetchTickers': true,
            'hasCORS': false,
            'has': {
                'fetchOrder': true,
                'fetchOrders': true,
                'fetchOpenOrders': true,
                'fetchClosedOrders': true,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/30953915-b1611dc0-a436-11e7-8947-c95bd5a42086.jpg',
                'api': 'https://api.qryptos.com',
                'www': 'https://www.qryptos.com',
                'doc': 'https://developers.quoine.com',
            },
            'api': {
                'public': {
                    'get': [
                        'products',
                        'products/{id}',
                        'products/{id}/price_levels',
                        'executions',
                        'ir_ladders/{currency}',
                    ],
                },
                'private': {
                    'get': [
                        'accounts/balance',
                        'crypto_accounts',
                        'executions/me',
                        'fiat_accounts',
                        'loan_bids',
                        'loans',
                        'orders',
                        'orders/{id}',
                        'orders/{id}/trades',
                        'trades',
                        'trades/{id}/loans',
                        'trading_accounts',
                        'trading_accounts/{id}',
                    ],
                    'post': [
                        'fiat_accounts',
                        'loan_bids',
                        'orders',
                    ],
                    'put': [
                        'loan_bids/{id}/close',
                        'loans/{id}',
                        'orders/{id}',
                        'orders/{id}/cancel',
                        'trades/{id}',
                        'trades/{id}/close',
                        'trades/close_all',
                        'trading_accounts/{id}',
                    ],
                },
            },
        });
    }

    async fetchMarkets () {
        let markets = await this.publicGetProducts ();
        let result = [];
        for (let p = 0; p < markets.length; p++) {
            let market = markets[p];
            let id = market['id'].toString ();
            let base = market['base_currency'];
            let quote = market['quoted_currency'];
            let symbol = base + '/' + quote;
            let maker = this.safeFloat (market, 'maker_fee');
            let taker = this.safeFloat (market, 'taker_fee');
            let active = !market['disabled'];
            let minAmount = undefined;
            if (base === 'BTC') {
                minAmount = 0.001;
            } else if (base === 'ETH') {
                minAmount = 0.01;
            } else if (base === 'QASH' || base === 'UBTC' || base === 'DASH' || base === 'NEO' || base === 'BCH') {
                minAmount = 0.0001;
            }
            let minPrice = 0.00001;
            let limits = {
                amount: { min: minAmount },
                price: { min: minPrice },
                cost: { min: minPrice * minAmount },
            };
            let precision = { amount: 8, price: 5 };
            result.push ({
                'id': id,
                'symbol': symbol,
                'base': base,
                'quote': quote,
                'maker': maker,
                'taker': taker,
                'limits': limits,
                'precision': precision,
                'active': active,
                'info': market,
            });
        }
        return result;
    }

    async fetchBalance (params = {}) {
        await this.loadMarkets ();
        let balances = await this.privateGetAccountsBalance (params);
        let result = { 'info': balances };
        for (let b = 0; b < balances.length; b++) {
            let balance = balances[b];
            let currency = balance['currency'];
            let total = parseFloat (balance['balance']);
            let account = {
                'free': total,
                'used': 0.0,
                'total': total,
            };
            result[currency] = account;
        }
        return this.parseBalance (result);
    }

    async fetchOrderBook (symbol, params = {}) {
        await this.loadMarkets ();
        let orderbook = await this.publicGetProductsIdPriceLevels (this.extend ({
            'id': this.marketId (symbol),
        }, params));
        return this.parseOrderBook (orderbook, undefined, 'buy_price_levels', 'sell_price_levels');
    }

    parseTicker (ticker, market = undefined) {
        let timestamp = this.milliseconds ();
        let last = undefined;
        if ('last_traded_price' in ticker) {
            if (ticker['last_traded_price']) {
                let length = ticker['last_traded_price'].length;
                if (length > 0)
                    last = parseFloat (ticker['last_traded_price']);
            }
        }
        let symbol = undefined;
        if (market)
            symbol = market['symbol'];
        return {
            'symbol': symbol,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'high': this.safeFloat (ticker, 'high_market_ask'),
            'low': this.safeFloat (ticker, 'low_market_bid'),
            'bid': this.safeFloat (ticker, 'market_bid'),
            'ask': this.safeFloat (ticker, 'market_ask'),
            'vwap': undefined,
            'open': undefined,
            'close': undefined,
            'first': undefined,
            'last': last,
            'change': undefined,
            'percentage': undefined,
            'average': undefined,
            'baseVolume': this.safeFloat (ticker, 'volume_24h'),
            'quoteVolume': undefined,
            'info': ticker,
        };
    }

    async fetchTickers (symbols = undefined, params = {}) {
        await this.loadMarkets ();
        let tickers = await this.publicGetProducts (params);
        let result = {};
        for (let t = 0; t < tickers.length; t++) {
            let ticker = tickers[t];
            let base = ticker['base_currency'];
            let quote = ticker['quoted_currency'];
            let symbol = base + '/' + quote;
            let market = this.markets[symbol];
            result[symbol] = this.parseTicker (ticker, market);
        }
        return result;
    }

    async fetchTicker (symbol, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let ticker = await this.publicGetProductsId (this.extend ({
            'id': market['id'],
        }, params));
        return this.parseTicker (ticker, market);
    }

    parseTrade (trade, market) {
        let timestamp = trade['created_at'] * 1000;
        return {
            'info': trade,
            'id': trade['id'].toString (),
            'order': undefined,
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'symbol': market['symbol'],
            'type': undefined,
            'side': trade['taker_side'],
            'price': parseFloat (trade['price']),
            'amount': parseFloat (trade['quantity']),
        };
    }

    async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
        await this.loadMarkets ();
        let market = this.market (symbol);
        let request = {
            'product_id': market['id'],
        };
        if (limit)
            request['limit'] = limit;
        let response = await this.publicGetExecutions (this.extend (request, params));
        return this.parseTrades (response['models'], market, since, limit);
    }

    async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
        await this.loadMarkets ();
        let order = {
            'order_type': type,
            'product_id': this.marketId (symbol),
            'side': side,
            'quantity': amount,
        };
        if (type == 'limit')
            order['price'] = price;
        let response = await this.privatePostOrders (this.extend ({
            'order': order,
        }, params));
        return this.parseOrder(response);
    }

    async cancelOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let result = await this.privatePutOrdersIdCancel (this.extend ({
            'id': id,
        }, params));
        let order = this.parseOrder (result);
        if (order['status'] == 'closed')
            throw new OrderNotFound (this.id + ' ' + this.json (order));
        return order;
    }

    parseOrder (order) {
        let timestamp = order['created_at'] * 1000;
        let marketId = order['product_id'].toString ();
        let market = this.marketsById[marketId];
        let status = undefined;
        if ('status' in order) {
            if (order['status'] == 'live') {
                status = 'open';
            } else if (order['status'] == 'filled') {
                status = 'closed';
            } else if (order['status'] == 'cancelled') { // 'll' intended
                status = 'canceled';
            }
        }
        let amount = parseFloat (order['quantity']);
        let filled = parseFloat (order['filled_quantity']);
        let price = parseFloat (order['price']);
        let symbol = undefined;
        if (market) {
            symbol = market['symbol'];
        }
        return {
            'id': order['id'].toString (),
            'timestamp': timestamp,
            'datetime': this.iso8601 (timestamp),
            'type': order['order_type'],
            'status': status,
            'symbol': symbol,
            'side': order['side'],
            'price': price,
            'amount': amount,
            'filled': filled,
            'remaining': amount - filled,
            'trades': undefined,
            'fee': {
                'currency': undefined,
                'cost': parseFloat (order['order_fee']),
            },
            'info': order,
        };
    }

    async fetchOrder (id, symbol = undefined, params = {}) {
        await this.loadMarkets ();
        let order = await this.privateGetOrdersId (this.extend ({
            'id': id,
        }, params));
        return this.parseOrder (order);
    }

    async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params={}) {
        await this.loadMarkets ();
        let market = undefined;
        let request = {};
        if (symbol) {
            market = this.market (symbol);
            request['product_id'] = market['id'];
        }
        let status = params['status'];
        if (status == 'open') {
            request['status'] = 'live';
        } else if (status == 'closed') {
            request['status'] = 'filled';
        } else if (status == 'canceled') {
            request['status'] = 'cancelled';
        }
        let result = await this.privateGetOrders (request);
        let orders = result['models'];
        return this.parseOrders (orders, market, since, limit);
    }

    fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        return this.fetchOrders (symbol, since, limit, this.extend ({ 'status': 'open' }, params));
    }

    fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
        return this.fetchOrders (symbol, since, limit, this.extend ({ 'status': 'closed' }, params));
    }

    handleErrors (code, reason, url, method, headers, body) {
        let response = undefined;
        if (code == 200 || code == 404 || code == 422) {
            if ((body[0] == '{') || (body[0] == '[')) {
                response = JSON.parse (body);
            } else {
                // if not a JSON response
                throw new ExchangeError (this.id + ' returned a non-JSON reply: ' + body);
            }
        }
        if (code == 404) {
            if ('message' in response) {
                if (response['message'] == 'Order not found') {
                    throw new OrderNotFound (this.id + ' ' + body);
                }
            }
        } else if (code == 422) {
            if ('errors' in response) {
                let errors = response['errors'];
                if ('user' in errors) {
                    let messages = errors['user'];
                    if (messages.indexOf ('not_enough_free_balance') >= 0) {
                        throw new InsufficientFunds (this.id + ' ' + body);
                    }
                } else if ('quantity' in errors) {
                    let messages = errors['quantity'];
                    if (messages.indexOf ('less_than_order_size') >= 0) {
                        throw new InvalidOrder (this.id + ' ' + body);
                    }
                }
            }
        }
    }

    nonce () {
        return this.milliseconds ();
    }

    sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
        let url = '/' + this.implodeParams (path, params);
        let query = this.omit (params, this.extractParams (path));
        headers = {
            'X-Quoine-API-Version': this.version,
            'Content-Type': 'application/json',
        };
        if (api == 'public') {
            if (Object.keys (query).length)
                url += '?' + this.urlencode (query);
        } else {
            this.checkRequiredCredentials ();
            if (method == 'GET') {
                if (Object.keys (query).length)
                    url += '?' + this.urlencode (query);
            } else if (Object.keys (query).length) {
                body = this.json (query);
            }
            let nonce = this.nonce ();
            let request = {
                'path': url,
                'nonce': nonce,
                'token_id': this.apiKey,
                'iat': Math.floor (nonce / 1000), // issued at
            };
            headers['X-Quoine-Auth'] = this.jwt (request, this.secret);
        }
        url = this.urls['api'] + url;
        return { 'url': url, 'method': method, 'body': body, 'headers': headers };
    }
}
<|endoftext|>