<commit_before>'use strict'

var net = require('net'),
    util = require('util'),
    DNS = require('dns'),
    log = function(){},///console.log,
    //log = console.log.bind(console),
    //info = console.info.bind(console),
    info = function(){},///console.log,
    errorLog = console.error.bind(console),
    ///clients = [],
    SOCKS_VERSION5 = 5,
    SOCKS_VERSION4 = 4,
    USERPASS,
/*
 * Authentication methods
 ************************
 * o  X'00' NO AUTHENTICATION REQUIRED
 * o  X'01' GSSAPI
 * o  X'02' USERNAME/PASSWORD
 * o  X'03' to X'7F' IANA ASSIGNED
 * o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
 * o  X'FF' NO ACCEPTABLE METHODS
 */
    AUTHENTICATION = {
        NOAUTH: 0x00,
        GSSAPI: 0x01,
        USERPASS: 0x02,
        NONE: 0xFF
    },
/*
 * o  CMD
 *    o  CONNECT X'01'
 *    o  BIND X'02'
 *    o  UDP ASSOCIATE X'03'
 */
    REQUEST_CMD = {
        CONNECT: 0x01,
        BIND: 0x02,
        UDP_ASSOCIATE: 0x03
    },
/*
 * o  ATYP   address type of following address
 *    o  IP V4 address: X'01'
 *    o  DOMAINNAME: X'03'
 *    o  IP V6 address: X'04'
 */
    ATYP = {
        IP_V4: 0x01,
        DNS: 0x03,
        IP_V6: 0x04
    },
    Address = {
        read: function (buffer, offset) {
                  if (buffer[offset] == ATYP.IP_V4) {
                      return util.format('%s.%s.%s.%s', buffer[offset+1], buffer[offset+2], buffer[offset+3], buffer[offset+4]);
                  } else if (buffer[offset] == ATYP.DNS) {
                      return buffer.toString('utf8', offset+2, offset+2+buffer[offset+1]);
                  } else if (buffer[offset] == ATYP.IP_V6) {
                      return buffer.slice(buffer[offset+1], buffer[offset+1+16]);
                  }
              },
        sizeOf: function(buffer, offset) {
                    if (buffer[offset] == ATYP.IP_V4) {
                        return 4;
                    } else if (buffer[offset] == ATYP.DNS) {
                        return buffer[offset+1];
                    } else if (buffer[offset] == ATYP.IP_V6) {
                        return 16;
                    }
                }
    },
    Port = {
        read: function (buffer, offset) {
                  if (buffer[offset] == ATYP.IP_V4) {
                      return buffer.readUInt16BE(8);
                  } else if (buffer[offset] == ATYP.DNS) {
                      return buffer.readUInt16BE(5+buffer[offset+1]);
                  } else if (buffer[offset] == ATYP.IP_V6) {
                      return buffer.readUInt16BE(20);
                  }
              },
    };

function createSocksServer(cb, userpass) {
    // record userpass
    USERPASS = userpass;
    log('userpass:'+userpass);

    var socksServer = net.createServer();
    socksServer.on('listening', function() {
        var address = socksServer.address();
        console.log('LISTENING %s:%d', address.address, address.port);
    });
    socksServer.on('connection', function(socket) {
        info('CONNECTED %s:%d', socket.remoteAddress, socket.remotePort);
        initSocksConnection.bind(socket)(cb);
    });
    return socksServer;
}

// socket is available as this
function initSocksConnection(on_accept) {
    /*
    // keep log of connected clients
    clients.push(this);

    // remove from clients on disconnect
    this.on('end', function() {
        var idx = clients.indexOf(this);
        if (idx != -1) {
            clients.splice(idx, 1);
        }
    });*/

    this.on('error', function(e) {
        errorLog('%j', e);
    });

    // do a handshake
    this.handshake = handshake.bind(this);
    this.on_accept = on_accept; // No bind. We want 'this' to be the server, like it would be for net.createServer
    this.once('data', this.handshake);
}

function handshake(chunk) {
    // SOCKS Version 4/5 is the only support version
    if (chunk[0] == SOCKS_VERSION5) {
        this.socksVersion = SOCKS_VERSION5;
        this.handshake5 = handshake5.bind(this);
        this.handshake5(chunk);
    } else if (chunk[0] == SOCKS_VERSION4) {
        this.socksVersion = SOCKS_VERSION4;
        this.handshake4 = handshake4.bind(this);
        this.handshake4(chunk);
    } else {
        errorLog('handshake: wrong socks version: %d', chunk[0]);
        this.end();
    }
}

// SOCKS5
function handshake5(chunk) {
    var method_count = 0;

    // SOCKS Version 5 is the only support version
    if (chunk[0] != SOCKS_VERSION5) {
        errorLog('socks5 handshake: wrong socks version: %d', chunk[0]);
        this.end();
        return;
    }
    // Number of authentication methods
    method_count = chunk[1];

    this.auth_methods = [];
    // i starts on 2, since we've read chunk 0 & 1 already
    for (var i=2; i < method_count + 2; i++) {
        this.auth_methods.push(chunk[i]);
    }
    log('Supported auth methods: %j', this.auth_methods);

    var resp = new Buffer(2);
    resp[0] = 0x05;

    // user/pass auth
    if (USERPASS && this.auth_methods.indexOf(AUTHENTICATION.USERPASS) > -1) {
        log('Handing off to handleAuthRequest');
        this.handleAuthRequest = handleAuthRequest.bind(this);
        this.once('data', this.handleAuthRequest);
        resp[1] = AUTHENTICATION.USERPASS;
        this.write(resp);
    } else
    // NO Auth
    if (this.auth_methods.indexOf(AUTHENTICATION.NOAUTH) > -1) {
        log('Handing off to handleConnRequest');
        this.handleConnRequest = handleConnRequest.bind(this);
        this.once('data', this.handleConnRequest);
        resp[1] = AUTHENTICATION.NOAUTH;
        this.write(resp);
    } else {
        errorLog('Unsuported authentication method -- disconnecting');
        resp[1] = 0xFF;
        this.end(resp);
    }
}

// SOCKS4/4a
function handshake4(chunk) {
    var cmd = chunk[1],
        address,
        port,
        uid;

    // Wrong version!
    if (chunk[0] !== SOCKS_VERSION4) {
        this.end('%d%d', 0x00, 0x5b);
        errorLog('socks4 handleConnRequest: wrong socks version: %d', chunk[0]);
        return;
    }
    port = chunk.readUInt16BE(2);

    // SOCKS4a
    if ((chunk[4] == 0 && chunk[5] == chunk[6] == 0) && (chunk[7] != 0)) {
        var it = 0;

        uid = '';
        for (it = 0; it < 1024; it++) {
            uid += chunk[8 + it];
            if (chunk[8 + it] == 0x00)
                break;
        }
        address = '';
        if (chunk[8 + it] == 0x00) {
            for (it++; it < 2048; it++) {
                address += chunk[8 + it];
                if (chunk[8 + it] == 0x00)
                    break;
            }
        }
        if (chunk[8 + it] == 0x00) {
            // DNS lookup
            DNS.lookup(address, function (err, ip, family) {
                if (err) {
                    errorLog(err + ',socks4a dns lookup failed');

                    this.end(new Buffer([0x00, 0x5b]));
                    return;
                } else {
                    this.socksAddress = ip;
                    this.socksPort = port;
                    this.socksUid = uid;

                    log('socks4a Request: type: %d -- to: %s:%d:%s', cmd, address, port, uid);

                    if (cmd == REQUEST_CMD.CONNECT) {
                        this.request = chunk;
                        this.on_accept(this, port, ip, proxyReady4.bind(this));
                    } else {
                        this.end(new Buffer([0x00, 0x5b]));
                        return;
                    }
                }
            });
        } else {
            this.end(new Buffer([0x00, 0x5b]));
            return;
        }
    } else {
        // SOCKS4
        address = util.format('%s.%s.%s.%s', chunk[4], chunk[5], chunk[6], chunk[7]);

        uid = '';
        for (it = 0; it < 1024; it++) {
            uid += chunk[8 + it];
            if (chunk[8 + it] == 0x00)
                break;
        }

        this.socksAddress = address;
        this.socksPort = port;
        this.socksUid = uid;

        log('socks4 Request: type: %d -- to: %s:%d:%s', cmd, address, port, uid);

        if (cmd == REQUEST_CMD.CONNECT) {
            this.request = chunk;
            this.on_accept(this, port, address, proxyReady4.bind(this));
        } else {
            this.end(new Buffer([0x00, 0x5b]));
            return;
        }
    }
}

function handlAuthRequest(chunk) {
    var cmd=chunk[1],
        username,
        password;
    // Wrong version!
    if (chunk[0] !== SOCKS_VERSION5) {
        this.end(new Buffer([0x05, x01]));
        errorLog('socks5 handleConnRequest: wrong socks version: %d', chunk[0]);
        return;
    } /* else if (chunk[2] == 0x00) {
        this.end(util.format('%d%d', 0x05, 0x01));
        errorLog('socks5 handleConnRequest: Mangled request. Reserved field is not null: %d', chunk[offset]);
        return;
    } */
    try {
        var na = [],pa=[],ni,pi;
        for (ni=   2;ni<(2+chunk[1]);    ni++) na.push(chunk[ni]);username = new Buffer(na).toString('utf8');
        for (pi=ni+1;pi<(ni+1+chunk[ni]);pi++) pa.push(chunk[pi]);password = new Buffer(pa).toString('utf8');
    } catch (e) {
        errorLog('socks5 handleAuthRequest: username/password '+e);
        return;
    }

    log('socks5 Auth: username:%s,password:%s', username, password);

    // check user:pass
    if (USERPASS && USERPASS.username===username && USERPASS.password===password) {
        log('Handing off to handleConnRequest');
        this.handleConnRequest = handleConnRequest.bind(this);
        this.once('data', this.handleConnRequest);
        this.write(new Buffer([0x05, 0x00]));
    } else {
        this.end(new Buffer([0x05, x01]));
        errorLog('socks5 handleConnRequest: wrong socks version: %d', chunk[0]);
        return;
    }
}

function handleConnRequest(chunk) {
    var cmd=chunk[1],
        address,
        port,
        offset=3;
    // Wrong version!
    if (chunk[0] !== SOCKS_VERSION5) {
        this.end(new Buffer([0x05, x01]));
        errorLog('socks5 handleConnRequest: wrong socks version: %d', chunk[0]);
        return;
    } /* else if (chunk[2] == 0x00) {
        this.end(util.format('%d%d', 0x05, 0x01));
        errorLog('socks5 handleConnRequest: Mangled request. Reserved field is not null: %d', chunk[offset]);
        return;
    } */
    try {
	    address = Address.read(chunk, 3);
	    port = Port.read(chunk, 3);
    } catch (e) {
        errorLog('socks5 handleConnRequest: Address.read '+e);
        return;
    }

    log('socks5 Request: type: %d -- to: %s:%d', chunk[1], address, port);

    if (cmd == REQUEST_CMD.CONNECT) {
        this.request = chunk;
        this.on_accept(this, port, address, proxyReady5.bind(this));
    } else {
        this.end(new Buffer([0x05, x01]));
        return;
    }
}

function proxyReady5() {
    log('Indicating to the client that the proxy is ready');
    // creating response
    var resp = new Buffer(this.request.length);
    this.request.copy(resp);
    // rewrite response header
    resp[0] = SOCKS_VERSION5;
    resp[1] = 0x00;
    resp[2] = 0x00;

    this.write(resp);

    log('socks5 Connected to: %s:%d', Address.read(resp, 3), resp.readUInt16BE(resp.length - 2));
}

function proxyReady4() {
    log('Indicating to the client that the proxy is ready');
    // creating response
    var resp = new Buffer(8);

    // write response header
    resp[0] = 0x00;
    resp[1] = 0x5a;

    // port
    resp.writeUInt16BE(this.socksPort, 2);

    // ip
    var ips = this.socksAddress.split('.');
    resp.writeUInt8(parseInt(ips[0]), 4);
    resp.writeUInt8(parseInt(ips[1]), 5);
    resp.writeUInt8(parseInt(ips[2]), 6);
    resp.writeUInt8(parseInt(ips[3]), 7);

    this.write(resp);

    log('socks4 Connected to: %s:%d:%s', this.socksAddress, this.socksPort, this.socksUid);
}

module.exports = {
    createServer: createSocksServer
};
<commit_msg>use user/pass force auth<commit_after>'use strict'

var net = require('net'),
    util = require('util'),
    DNS = require('dns'),
    log = function(){},///console.log,
    //log = console.log.bind(console),
    //info = console.info.bind(console),
    info = function(){},///console.log,
    errorLog = console.error.bind(console),
    ///clients = [],
    SOCKS_VERSION5 = 5,
    SOCKS_VERSION4 = 4,
    USERPASS,
/*
 * Authentication methods
 ************************
 * o  X'00' NO AUTHENTICATION REQUIRED
 * o  X'01' GSSAPI
 * o  X'02' USERNAME/PASSWORD
 * o  X'03' to X'7F' IANA ASSIGNED
 * o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
 * o  X'FF' NO ACCEPTABLE METHODS
 */
    AUTHENTICATION = {
        NOAUTH: 0x00,
        GSSAPI: 0x01,
        USERPASS: 0x02,
        NONE: 0xFF
    },
/*
 * o  CMD
 *    o  CONNECT X'01'
 *    o  BIND X'02'
 *    o  UDP ASSOCIATE X'03'
 */
    REQUEST_CMD = {
        CONNECT: 0x01,
        BIND: 0x02,
        UDP_ASSOCIATE: 0x03
    },
/*
 * o  ATYP   address type of following address
 *    o  IP V4 address: X'01'
 *    o  DOMAINNAME: X'03'
 *    o  IP V6 address: X'04'
 */
    ATYP = {
        IP_V4: 0x01,
        DNS: 0x03,
        IP_V6: 0x04
    },
    Address = {
        read: function (buffer, offset) {
                  if (buffer[offset] == ATYP.IP_V4) {
                      return util.format('%s.%s.%s.%s', buffer[offset+1], buffer[offset+2], buffer[offset+3], buffer[offset+4]);
                  } else if (buffer[offset] == ATYP.DNS) {
                      return buffer.toString('utf8', offset+2, offset+2+buffer[offset+1]);
                  } else if (buffer[offset] == ATYP.IP_V6) {
                      return buffer.slice(buffer[offset+1], buffer[offset+1+16]);
                  }
              },
        sizeOf: function(buffer, offset) {
                    if (buffer[offset] == ATYP.IP_V4) {
                        return 4;
                    } else if (buffer[offset] == ATYP.DNS) {
                        return buffer[offset+1];
                    } else if (buffer[offset] == ATYP.IP_V6) {
                        return 16;
                    }
                }
    },
    Port = {
        read: function (buffer, offset) {
                  if (buffer[offset] == ATYP.IP_V4) {
                      return buffer.readUInt16BE(8);
                  } else if (buffer[offset] == ATYP.DNS) {
                      return buffer.readUInt16BE(5+buffer[offset+1]);
                  } else if (buffer[offset] == ATYP.IP_V6) {
                      return buffer.readUInt16BE(20);
                  }
              },
    };

function createSocksServer(cb, userpass) {
    // record userpass
    USERPASS = userpass;
    log('userpass:'+userpass);

    var socksServer = net.createServer();
    socksServer.on('listening', function() {
        var address = socksServer.address();
        console.log('LISTENING %s:%d', address.address, address.port);
    });
    socksServer.on('connection', function(socket) {
        info('CONNECTED %s:%d', socket.remoteAddress, socket.remotePort);
        initSocksConnection.bind(socket)(cb);
    });
    return socksServer;
}

// socket is available as this
function initSocksConnection(on_accept) {
    /*
    // keep log of connected clients
    clients.push(this);

    // remove from clients on disconnect
    this.on('end', function() {
        var idx = clients.indexOf(this);
        if (idx != -1) {
            clients.splice(idx, 1);
        }
    });*/

    this.on('error', function(e) {
        errorLog('%j', e);
    });

    // do a handshake
    this.handshake = handshake.bind(this);
    this.on_accept = on_accept; // No bind. We want 'this' to be the server, like it would be for net.createServer
    this.once('data', this.handshake);
}

function handshake(chunk) {
    // SOCKS Version 4/5 is the only support version
    if (chunk[0] == SOCKS_VERSION5) {
        this.socksVersion = SOCKS_VERSION5;
        this.handshake5 = handshake5.bind(this);
        this.handshake5(chunk);
    } else if (chunk[0] == SOCKS_VERSION4) {
        this.socksVersion = SOCKS_VERSION4;
        this.handshake4 = handshake4.bind(this);
        this.handshake4(chunk);
    } else {
        errorLog('handshake: wrong socks version: %d', chunk[0]);
        this.end();
    }
}

// SOCKS5
function handshake5(chunk) {
    var method_count = 0;

    // SOCKS Version 5 is the only support version
    if (chunk[0] != SOCKS_VERSION5) {
        errorLog('socks5 handshake: wrong socks version: %d', chunk[0]);
        this.end();
        return;
    }
    // Number of authentication methods
    method_count = chunk[1];

    this.auth_methods = [];
    // i starts on 2, since we've read chunk 0 & 1 already
    for (var i=2; i < method_count + 2; i++) {
        this.auth_methods.push(chunk[i]);
    }
    log('Supported auth methods: %j', this.auth_methods);

    var resp = new Buffer(2);
    resp[0] = 0x05;

    // user/pass auth
    if (USERPASS) {
        if (this.auth_methods.indexOf(AUTHENTICATION.USERPASS) > -1) {
            log('Handing off to handleAuthRequest');
            this.handleAuthRequest = handleAuthRequest.bind(this);
            this.once('data', this.handleAuthRequest);
            resp[1] = AUTHENTICATION.USERPASS;
            this.write(resp);
        } else {
            errorLog('Unsuported authentication method -- disconnecting');
            resp[1] = 0xFF;
            this.end(resp);
        }
    } else
        // NO Auth
        if (this.auth_methods.indexOf(AUTHENTICATION.NOAUTH) > -1) {
            log('Handing off to handleConnRequest');
            this.handleConnRequest = handleConnRequest.bind(this);
            this.once('data', this.handleConnRequest);
            resp[1] = AUTHENTICATION.NOAUTH;
            this.write(resp);
        } else {
            errorLog('Unsuported authentication method -- disconnecting');
            resp[1] = 0xFF;
            this.end(resp);
        }
}

// SOCKS4/4a
function handshake4(chunk) {
    var cmd = chunk[1],
        address,
        port,
        uid;

    // Wrong version!
    if (chunk[0] !== SOCKS_VERSION4) {
        this.end('%d%d', 0x00, 0x5b);
        errorLog('socks4 handleConnRequest: wrong socks version: %d', chunk[0]);
        return;
    }
    port = chunk.readUInt16BE(2);

    // SOCKS4a
    if ((chunk[4] == 0 && chunk[5] == chunk[6] == 0) && (chunk[7] != 0)) {
        var it = 0;

        uid = '';
        for (it = 0; it < 1024; it++) {
            uid += chunk[8 + it];
            if (chunk[8 + it] == 0x00)
                break;
        }
        address = '';
        if (chunk[8 + it] == 0x00) {
            for (it++; it < 2048; it++) {
                address += chunk[8 + it];
                if (chunk[8 + it] == 0x00)
                    break;
            }
        }
        if (chunk[8 + it] == 0x00) {
            // DNS lookup
            DNS.lookup(address, function (err, ip, family) {
                if (err) {
                    errorLog(err + ',socks4a dns lookup failed');

                    this.end(new Buffer([0x00, 0x5b]));
                    return;
                } else {
                    this.socksAddress = ip;
                    this.socksPort = port;
                    this.socksUid = uid;

                    log('socks4a Request: type: %d -- to: %s:%d:%s', cmd, address, port, uid);

                    if (cmd == REQUEST_CMD.CONNECT) {
                        this.request = chunk;
                        this.on_accept(this, port, ip, proxyReady4.bind(this));
                    } else {
                        this.end(new Buffer([0x00, 0x5b]));
                        return;
                    }
                }
            });
        } else {
            this.end(new Buffer([0x00, 0x5b]));
            return;
        }
    } else {
        // SOCKS4
        address = util.format('%s.%s.%s.%s', chunk[4], chunk[5], chunk[6], chunk[7]);

        uid = '';
        for (it = 0; it < 1024; it++) {
            uid += chunk[8 + it];
            if (chunk[8 + it] == 0x00)
                break;
        }

        this.socksAddress = address;
        this.socksPort = port;
        this.socksUid = uid;

        log('socks4 Request: type: %d -- to: %s:%d:%s', cmd, address, port, uid);

        if (cmd == REQUEST_CMD.CONNECT) {
            this.request = chunk;
            this.on_accept(this, port, address, proxyReady4.bind(this));
        } else {
            this.end(new Buffer([0x00, 0x5b]));
            return;
        }
    }
}

function handlAuthRequest(chunk) {
    var cmd=chunk[1],
        username,
        password;
    // Wrong version!
    if (chunk[0] !== SOCKS_VERSION5) {
        this.end(new Buffer([0x05, x01]));
        errorLog('socks5 handleConnRequest: wrong socks version: %d', chunk[0]);
        return;
    } /* else if (chunk[2] == 0x00) {
        this.end(util.format('%d%d', 0x05, 0x01));
        errorLog('socks5 handleConnRequest: Mangled request. Reserved field is not null: %d', chunk[offset]);
        return;
    } */
    try {
        var na = [],pa=[],ni,pi;
        for (ni=   2;ni<(2+chunk[1]);    ni++) na.push(chunk[ni]);username = new Buffer(na).toString('utf8');
        for (pi=ni+1;pi<(ni+1+chunk[ni]);pi++) pa.push(chunk[pi]);password = new Buffer(pa).toString('utf8');
    } catch (e) {
        errorLog('socks5 handleAuthRequest: username/password '+e);
        return;
    }

    log('socks5 Auth: username:%s,password:%s', username, password);

    // check user:pass
    if (USERPASS && USERPASS.username===username && USERPASS.password===password) {
        log('Handing off to handleConnRequest');
        this.handleConnRequest = handleConnRequest.bind(this);
        this.once('data', this.handleConnRequest);
        this.write(new Buffer([0x05, 0x00]));
    } else {
        this.end(new Buffer([0x05, x01]));
        errorLog('socks5 handleConnRequest: wrong socks version: %d', chunk[0]);
        return;
    }
}

function handleConnRequest(chunk) {
    var cmd=chunk[1],
        address,
        port,
        offset=3;
    // Wrong version!
    if (chunk[0] !== SOCKS_VERSION5) {
        this.end(new Buffer([0x05, x01]));
        errorLog('socks5 handleConnRequest: wrong socks version: %d', chunk[0]);
        return;
    } /* else if (chunk[2] == 0x00) {
        this.end(util.format('%d%d', 0x05, 0x01));
        errorLog('socks5 handleConnRequest: Mangled request. Reserved field is not null: %d', chunk[offset]);
        return;
    } */
    try {
	    address = Address.read(chunk, 3);
	    port = Port.read(chunk, 3);
    } catch (e) {
        errorLog('socks5 handleConnRequest: Address.read '+e);
        return;
    }

    log('socks5 Request: type: %d -- to: %s:%d', chunk[1], address, port);

    if (cmd == REQUEST_CMD.CONNECT) {
        this.request = chunk;
        this.on_accept(this, port, address, proxyReady5.bind(this));
    } else {
        this.end(new Buffer([0x05, x01]));
        return;
    }
}

function proxyReady5() {
    log('Indicating to the client that the proxy is ready');
    // creating response
    var resp = new Buffer(this.request.length);
    this.request.copy(resp);
    // rewrite response header
    resp[0] = SOCKS_VERSION5;
    resp[1] = 0x00;
    resp[2] = 0x00;

    this.write(resp);

    log('socks5 Connected to: %s:%d', Address.read(resp, 3), resp.readUInt16BE(resp.length - 2));
}

function proxyReady4() {
    log('Indicating to the client that the proxy is ready');
    // creating response
    var resp = new Buffer(8);

    // write response header
    resp[0] = 0x00;
    resp[1] = 0x5a;

    // port
    resp.writeUInt16BE(this.socksPort, 2);

    // ip
    var ips = this.socksAddress.split('.');
    resp.writeUInt8(parseInt(ips[0]), 4);
    resp.writeUInt8(parseInt(ips[1]), 5);
    resp.writeUInt8(parseInt(ips[2]), 6);
    resp.writeUInt8(parseInt(ips[3]), 7);

    this.write(resp);

    log('socks4 Connected to: %s:%d:%s', this.socksAddress, this.socksPort, this.socksUid);
}

module.exports = {
    createServer: createSocksServer
};
<|endoftext|>


<commit_before>const debug = require('debug')('solve')
const _ = require('lodash')
const transpose = require('./transpose')

module.exports = function solve (problem) {
  debug('start')
  return findSlicesByCol(problem)
  debug('end')
}

function findSlicesByCol(problem) {
  problem.pizza = transpose(problem.pizza)
  let solve = findSlicesLineByLine(problem)
  return _.map(solve, ({r1, r2, c1, c2}) => { return {"r1":c1, "r2":c2, "c1":r1, "c2":r2}})
}

function cutLineByLine(slice, x, y) {
  return {r1:y, r2:y, c1:x, c2: x+slice.length - 1}
}

function sliceOk(slice, minIngredients) {
  //TODO one line only
  return _.filter(slice, (l) => l === "M").length >= minIngredients
        && _.filter(slice, (l) => l === "T").length >= minIngredients
}

function findSlicesLineByLine(problem) {
  return _(problem.pizza).map((line, y) => {
    let index = 0
    let slice
    if(problem.maxSliceSize > line.length && sliceOk(line, problem.minIngredients)) {
      //FIXME only works with maxSlices > line.length
      return cutLineByLine(line, 0,  y)
    }
    while(index < line.length - 1) {
      slice = _.slice(line, index, Math.min(index + problem.maxSliceSize, line.length))
      if(sliceOk(slice, problem.minIngredients)) {
        return cutLineByLine(slice, index, y)
      } else {
        index++
      }
    }
  }).compact().value()
}
<commit_msg>style(solve): make eslint happy<commit_after>const debug = require('debug')('solve')
const _ = require('lodash')
const transpose = require('./transpose')

module.exports = function solve (problem) {
  debug('start')
  return findSlicesByCol(problem)
  debug('end')
}

function findSlicesByCol (problem) {
  problem.pizza = transpose(problem.pizza)
  let solve = findSlicesLineByLine(problem)
  return _.map(solve, ({r1, r2, c1, c2}) => { return {'r1': c1, 'r2': c2, 'c1': r1, 'c2': r2} })
}

function cutLineByLine (slice, x, y) {
  return {r1: y, r2: y, c1: x, c2: x + slice.length - 1}
}

function sliceOk (slice, minIngredients) {
  // TODO one line only
  return _.filter(slice, (l) => l === 'M').length >= minIngredients &&
        _.filter(slice, (l) => l === 'T').length >= minIngredients
}

function findSlicesLineByLine (problem) {
  return _(problem.pizza).map((line, y) => {
    let index = 0
    let slice
    if (problem.maxSliceSize > line.length && sliceOk(line, problem.minIngredients)) {
      // FIXME only works with maxSlices > line.length
      return cutLineByLine(line, 0, y)
    }
    while (index < line.length - 1) {
      slice = _.slice(line, index, Math.min(index + problem.maxSliceSize, line.length))
      if (sliceOk(slice, problem.minIngredients)) {
        return cutLineByLine(slice, index, y)
      } else {
        index++
      }
    }
  }).compact().value()
}
<|endoftext|>


<commit_before>
$(function () {
  Applet.run({name: 'compile scripts'});
  Applet.run({"logged_in?": false});

  Applet.run({num: {number: 1}});
  Applet.run({num: {number: 2}});
  Applet.run({num: {number: 3}});

  Applet.run({num_name: {word: 'three'}});
  Applet.run({num_name: {word: 'two'}});
  Applet.run({num_name: {word: 'one'}});

  console.log(
    Applet.attrs($('

')[0])
  )

});

describe('attrs:', function () {

  beforeEach(Applet.reset);

  it('returns attrs of node', function () {
    var result = Applet.attrs($('

')[0]);
    expect(result).toEqual({id: "000", img: ".png"});
  }); // === it returns attrs of node

  it('ignores custom attributes', function () {
    var result = Applet.attrs($('

')[0]);
    expect(result).toEqual({id: "111", img: ".png"});
  }); // === it ignores custom attributes

}); // === describe attrs =================
<commit_msg>Specs for: .custom_attrs<commit_after>
$(function () {
  Applet.run({name: 'compile scripts'});
  Applet.run({"logged_in?": false});

  Applet.run({num: {number: 1}});
  Applet.run({num: {number: 2}});
  Applet.run({num: {number: 3}});

  Applet.run({num_name: {word: 'three'}});
  Applet.run({num_name: {word: 'two'}});
  Applet.run({num_name: {word: 'one'}});

});

describe('attrs:', function () {

  beforeEach(Applet.reset);

  it('returns attrs of node', function () {
    var result = Applet.attrs($('

')[0]);
    expect(result).toEqual({id: "000", img: ".png"});
  }); // === it returns attrs of node

  it('ignores custom attributes', function () {
    var result = Applet.attrs($('

')[0]);
    expect(result).toEqual({id: "111", img: ".png"});
  }); // === it ignores custom attributes

}); // === describe attrs =================

describe('custom_attrs:', function () {

  beforeEach(Applet.reset);

  it('returns custom attrs of node', function () {
    Applet.run(function (e) { return 'hide_if'; });

    var result = Applet.custom_attrs($('

')[0]);
    expect(result).toEqual(
      {show_if: "sad?", hide_if: 'happy?'}
    );
  }); // === it returns custom attrs of node

  it('ignores regular attributes', function () {
    var result = Applet.custom_attrs($('

')[0]);
    expect(result).toEqual(
      {show_if: "mellow?"}
    );
  }); // === it ignores regular attributes

}); // === describe custom_attrs =================
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      27.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

/* Available transitions for page changes */
M.TRANSITION = {};
M.TRANSITION.NONE = 'none';
M.TRANSITION.SLIDE = 'slide';
M.TRANSITION.SLIDEUP = 'slideup';
M.TRANSITION.SLIDEDOWN = 'slidedown';
M.TRANSITION.POP = 'pop';
M.TRANSITION.FADE = 'fade';
M.TRANSITION.FLIP = 'flip';

m_require('core/foundation/observable.js');

/**
 * @class
 *
 * The root class for every controller.
 *
 * Controllers, respectively their properties, are observables. Views can observe them.
 *
 * @extends M.Object
 */
M.Controller = M.Object.extend(
/** @scope M.Controller.prototype */ {

    /**
     * The type of this object.
     *
     * @type String
     */
    type: 'M.Controller',

    /**
     * Makes the controller's properties observable.
     */
    observable: M.Observable.extend({}),

    /**
     * Helper function to build the location href for the view to be displayed.
     *
     * @param {String} id The id of the new target.
     */
    buildLocationHref: function(id) {
        return location.pathname + '#' + id;
    },

    /**
     * Returns the class property behind the given key and informs its observers.
     *
     * @param {Object, String} page The page to be displayed or its name.
     * @param {String} transition The transition that should be used. Default: horizontal slide
     * @param {Boolean} isBack YES will cause a reverse-direction transition. Default: NO
     * @param {Boolean} changeLoc Update the browser history. Default: YES
     */
    switchToPage: function(page, transition, isBack, changeLoc) {
        page = page && page.type === 'M.PageView' ? page : M.Application.viewManager.getPage(page);
        var id = page && page.id ? page.id : null;
        var isTabBarViewTopPage = NO;

        if(id) {
            if(page.hasTabBarView) {
                if(page.tabBarView.childViews) {
                    var tabItemViews = $.trim(page.tabBarView.childViews).split(' ');
                    for(var i in tabItemViews) {
                        var tabItemView = page.tabBarView[tabItemViews[i]];
                        if(M.ViewManager.getPage(tabItemView.page) === page) {
                            page.tabBarView.setActiveTab(tabItemView.page, M.Application.viewManager.getIdByView(tabItemView));
                            isTabBarViewTopPage = YES;
                        }
                    }
                }
            }
            /* If the new page is a real tabBarViewPage (has a tabBarView and is no sub view), use no transition. */
            if(isTabBarViewTopPage) {
                transition = page.tabBarView.transition ? page.tabBarView.transition : M.TRANSITION.NONE;
                isBack = NO;
                changeLoc = changeLoc !== undefined ? changeLoc : NO;
            } else {
                transition = transition ? transition : M.TRANSITION.SLIDE;
                isBack = isBack !== undefined ? isBack : NO;
                changeLoc = changeLoc !== undefined ? changeLoc : YES;
            }

            /* Now do the page change by using a jquery mobile method and pass the properties */
            $.mobile.changePage(id, M.Application.useTransitions ? transition : M.TRANSITION.NONE, isBack, changeLoc);

            /* Save the current page in the view manager */
            M.Application.viewManager.setCurrentPage(page);
        } else {
            M.Logger.log('"' + page + '" not found', M.WARN);
        }
    },

    /**
     * Returns the class property behind the given key and informs its observers.
     *
     * @param {String} key The key of the property to be changed.
     * @param {Object, String} value The value to be set.
     */
    set: function(key, value) {
        this[key] = value;
        this.observable.notifyObservers(key);
    }

});<commit_msg>Refactoring: if useTransitions is set to NO, never set isBack-property to YES<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      27.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

/* Available transitions for page changes */
M.TRANSITION = {};
M.TRANSITION.NONE = 'none';
M.TRANSITION.SLIDE = 'slide';
M.TRANSITION.SLIDEUP = 'slideup';
M.TRANSITION.SLIDEDOWN = 'slidedown';
M.TRANSITION.POP = 'pop';
M.TRANSITION.FADE = 'fade';
M.TRANSITION.FLIP = 'flip';

m_require('core/foundation/observable.js');

/**
 * @class
 *
 * The root class for every controller.
 *
 * Controllers, respectively their properties, are observables. Views can observe them.
 *
 * @extends M.Object
 */
M.Controller = M.Object.extend(
/** @scope M.Controller.prototype */ {

    /**
     * The type of this object.
     *
     * @type String
     */
    type: 'M.Controller',

    /**
     * Makes the controller's properties observable.
     */
    observable: M.Observable.extend({}),

    /**
     * Helper function to build the location href for the view to be displayed.
     *
     * @param {String} id The id of the new target.
     */
    buildLocationHref: function(id) {
        return location.pathname + '#' + id;
    },

    /**
     * Returns the class property behind the given key and informs its observers.
     *
     * @param {Object, String} page The page to be displayed or its name.
     * @param {String} transition The transition that should be used. Default: horizontal slide
     * @param {Boolean} isBack YES will cause a reverse-direction transition. Default: NO
     * @param {Boolean} changeLoc Update the browser history. Default: YES
     */
    switchToPage: function(page, transition, isBack, changeLoc) {
        page = page && page.type === 'M.PageView' ? page : M.Application.viewManager.getPage(page);
        var id = page && page.id ? page.id : null;
        var isTabBarViewTopPage = NO;

        if(id) {
            if(page.hasTabBarView) {
                if(page.tabBarView.childViews) {
                    var tabItemViews = $.trim(page.tabBarView.childViews).split(' ');
                    for(var i in tabItemViews) {
                        var tabItemView = page.tabBarView[tabItemViews[i]];
                        if(M.ViewManager.getPage(tabItemView.page) === page) {
                            page.tabBarView.setActiveTab(tabItemView.page, M.Application.viewManager.getIdByView(tabItemView));
                            isTabBarViewTopPage = YES;
                        }
                    }
                }
            }
            /* If the new page is a real tabBarViewPage (has a tabBarView and is no sub view), use no transition. */
            if(isTabBarViewTopPage) {
                transition = page.tabBarView.transition ? page.tabBarView.transition : M.TRANSITION.NONE;
                isBack = NO;
                changeLoc = changeLoc !== undefined ? changeLoc : NO;
            } else {
                transition = transition ? transition : M.TRANSITION.SLIDE;
                isBack = isBack !== undefined ? isBack : NO;
                changeLoc = changeLoc !== undefined ? changeLoc : YES;
            }

            /* Now do the page change by using a jquery mobile method and pass the properties */
            $.mobile.changePage(id, M.Application.useTransitions ? transition : M.TRANSITION.NONE, M.Application.useTransitions ? isBack : NO, changeLoc);

            /* Save the current page in the view manager */
            M.Application.viewManager.setCurrentPage(page);
        } else {
            M.Logger.log('"' + page + '" not found', M.WARN);
        }
    },

    /**
     * Returns the class property behind the given key and informs its observers.
     *
     * @param {String} key The key of the property to be changed.
     * @param {Object, String} value The value to be set.
     */
    set: function(key, value) {
        this[key] = value;
        this.observable.notifyObservers(key);
    }

});<|endoftext|>


<commit_before>/**
 * rest.js
 * REST endpoints
 *
 * @author Amir Malik
 */

var url = require('url');

var connect = require('../../vendor/connect');

var DataStore = require('./datastore').DataStore;

function REST() {
}

REST.prototype.get = function(req, res, next) {
  var collection = req.params.collection,
              id = req.params.id,
           query = url.parse(req.url, true).query;

  var where = query || {}
  var count = 0;

  if(id) {
    where['_id'] = id;
  }

  console.log(JSON.stringify(where));

  DataStore.queryAll(collection, where, function(err, results) {
    if(err) {
      console.log("REST.get error: " + err);
      throw err;
    }

    req.nixus.data = [];

    if(id) {
      if(results.length == 0)
        req.nixus.data = null;
      else
        req.nixus.data = results[0];
    } else {
      req.nixus.data = [];
      for(var i = 0; i < results.length; i++) {
        req.nixus.data.push(req.nixus.process(results[i], req, res));
      }
    }
    next();
  });
};

REST.prototype.put = function(req, res, next) {
  var collection = req.params.collection,
              id = req.params.id;

  var doc = req.body;
  var where = {
    _id: id,
  };

  DataStore.update(collection, where, doc, function(err) {
    if(err) {
      console.log("REST.put error: " + err);
      throw err;
    }

    next();
  });
};

REST.prototype.post = function(req, res, next) {
  var collection = req.params.collection,
              id = req.params.id;

  var doc = req.body;
  doc = req.nixus.process(doc, req, res);

  DataStore.insert(collection, doc, function(err, doc) {
    if(err)
      throw err;

    console.log("REST.post inserted doc with _id: " + doc['_id']);

    req.nixus.data = doc;
    next();
  });
};

REST.prototype.del = function(req, res, next) {
  var collection = req.params.collection,
              id = req.params.id;

  var where = {
    _id: id,
  };

  DataStore.remove(collection, where, function(err) {
    if(err)
      throw err;

    next();
  });
};

exports.REST = global['REST'] || (global['REST'] = new REST());
<commit_msg>Process document if requested by id.<commit_after>/**
 * rest.js
 * REST endpoints
 *
 * @author Amir Malik
 */

var url = require('url');

var connect = require('../../vendor/connect');

var DataStore = require('./datastore').DataStore;

function REST() {
}

REST.prototype.get = function(req, res, next) {
  var collection = req.params.collection,
              id = req.params.id,
           query = url.parse(req.url, true).query;

  var where = query || {}
  var count = 0;

  if(id) {
    where['_id'] = id;
  }

  console.log(JSON.stringify(where));

  DataStore.queryAll(collection, where, function(err, results) {
    if(err) {
      console.log("REST.get error: " + err);
      throw err;
    }

    req.nixus.data = [];

    if(id) {
      if(results.length == 0)
        req.nixus.data = null;
      else
        req.nixus.data = req.nixus.process(results[0], req, res);
    } else {
      req.nixus.data = [];
      for(var i = 0; i < results.length; i++) {
        req.nixus.data.push(req.nixus.process(results[i], req, res));
      }
    }
    next();
  });
};

REST.prototype.put = function(req, res, next) {
  var collection = req.params.collection,
              id = req.params.id;

  var doc = req.body;
  var where = {
    _id: id,
  };

  DataStore.update(collection, where, doc, function(err) {
    if(err) {
      console.log("REST.put error: " + err);
      throw err;
    }

    next();
  });
};

REST.prototype.post = function(req, res, next) {
  var collection = req.params.collection,
              id = req.params.id;

  var doc = req.body;
  doc = req.nixus.process(doc, req, res);

  DataStore.insert(collection, doc, function(err, doc) {
    if(err)
      throw err;

    console.log("REST.post inserted doc with _id: " + doc['_id']);

    req.nixus.data = doc;
    next();
  });
};

REST.prototype.del = function(req, res, next) {
  var collection = req.params.collection,
              id = req.params.id;

  var where = {
    _id: id,
  };

  DataStore.remove(collection, where, function(err) {
    if(err)
      throw err;

    next();
  });
};

exports.REST = global['REST'] || (global['REST'] = new REST());
<|endoftext|>


<commit_before>/* rimo v0.0.1 alpha, @lisence MIT, copyright 2016, miyakogi */

;(function(window, undefined){
  'use strict';
  // Define global object
  var rimo = { version: '0.0.1', settings: {}, log: { level: 0 }}
  var config_prefix = 'RIMO_'

  var log_levels = {
    FATAL: 50,
    CRITICAL: 50,
    ERROR: 40,
    WARNING: 30,
    WARN: 30,
    INFO: 20,
    DEBUG: 10,
    NOTSET: 0,
  }

  function get_log_level(level) {
    if (typeof level === 'number'){
      return level
    }

    if (typeof level === 'string') {
      var s = level.toUpperCase()
      if (s in log_levels) {
        return log_levels[s]
      }
    }

    // Get unknown log level
    console.warn(rimo.settings.LOG_PREFIX + 'unknown log level: ', level)
    return 0
  }

  function set_default(key, defval) {
    if (config_prefix + key in window) {
      rimo.settings[key] = window[config_prefix + key]
    } else {
      rimo.settings[key] = defval
    }
  }

  function get_node(id) {
    return document.getElementById(id)
  }

  function ws_onmessage(e) {
    var msg = JSON.parse(e.data)
    var elm = get_node(msg.id)
    if (!elm) {
      // node may not have been mounted yet. retry 100ms later.
      setTimeout(function() {
        var elm = get_node(msg.id)
        if (!elm) {
          // node not found. send warning.
          rimo.log.console('warn', 'gat message to unknown node.\n Message: ' + msg)
          rimo.log.warn('unknown node: id=' + msg.id + ', tag=' + msg.tag + ', method=' + msg.method)
        } else {
          rimo.exec(elm, msg.method, msg.params)
        }
      }, 100)
    } else {
      rimo.exec(elm, msg.method, msg.params)
    }
  }

  function ws_onclose() {
    function reload(){
      location.reload()
    }

    if (rimo.settings.AUTORELOAD) {
      rimo.log.console('info', 'RootWS closed, reloading page...')
      setTimeout(reload, rimo.settings.RELOAD_WAIT)
    } else {
      rimo.log.console('RootWS CLOSED');
    }
  }

  function initialize() {
    // Define default variables
    var __ws_url = 'ws://' + location.host + '/wdom_ws'
    set_default('DEBUG', false)
    set_default('AUTORELOAD', false)
    set_default('RELOAD_WAIT', 500)
    set_default('LOG_LEVEL', 'WARN')
    set_default('LOG_PREFIX', 'rimo: ')
    set_default('LOG_CONSOLE', false)
    set_default('WS_URL', __ws_url)
    rimo.log.set_level(rimo.settings.LOG_LEVEL)

    // Make root WebScoket connection
    rimo.ws = new WebSocket(rimo.settings.WS_URL)
    rimo.ws.onmessage = ws_onmessage
    rimo.ws.onclose = ws_onclose
  }

  rimo.exec = function(node, method, params) {
    // Execute fucntion with msg
    rimo[method](node, params)
  }

  rimo.eval = function(node, params) {
    // Execute fucntion with msg
    eval(params.script)
  }

  // send response
  rimo.send_response = function(node, reqid, data) {
    rimo.log.debug('send_response')
    var msg = JSON.stringify({
      type: 'response',
      id: node.id,
      reqid: reqid,
      data: data
    })
    rimo.log.debug(msg)
    rimo.ws.send(msg)
  }

  /* Event contrall */
  // emit events to python
  // find better name...
  rimo.send_event = function(node, event, data) {
    var msg = JSON.stringify({
      type: 'event',
      id: node.id,
      event: event,
      data: data
    })
    rimo.log.debug(msg)
    rimo.ws.send(msg)
  }

  /* Event handlers */
  rimo.onclick = function(node) {
    rimo.send_event(node, 'click')
  }

  rimo.onchange = function(node) {
    rimo.send_event(
      node,
      'change',
      {
        checked: node.checked,
        value: node.value,
      }
    )
  }

  rimo.oninput = function(node) {
    rimo.send_event(
      node,
      'input',
      {
        checked: node.checked,
        value: node.value,
      }
    )
  }

  rimo.addEventListener = function(node, params) {
    var e = 'on' + params.event
    node.addEventListener(e, function() { rimo[e](node) })
  }

  /* DOM contrall */
  rimo.insert = function(node, params) {
    var index = Number(params.index)
    if (!node.hasChildNodes() || index >= node.childNodes.length) {
      node.insertAdjacentHTML('beforeend', params.html)
    } else {
      var ref_node = node.childNodes[index]
      if (ref_node.nodeName === '#text') {
        var df = document.createDocumentFragment()
        df.innerHTML = params.html
        ref_node.parentNode.insertBefore(df, ref_node)
      } else {
        ref_node.insertAdjacentHTML('beforebegin', params.html)
      }
    }
  }

  rimo.insertAdjacentHTML = function(node, params) {
    node.insertAdjacentHTML(params.position, params.text)
  }

  rimo.textContent = function(node, params) {
    node.textContent = params.text
  }

  rimo.innerHTML = function(node, params) {
    node.innerHTML = params.html
  }

  rimo.outerHTML = function(node, params) {
    node.outerHTML = params.html
  }

  rimo.removeChild = function(node, params) {
    var child = document.getElementById(params.id)
    if (child){
      node.removeChild(child)
    }
  }

  rimo.replaceChild = function(node, params) {
    var old_child = document.getElementById(params.id)
    if (old_child) {
      old_child.insertAdjacentHTML('beforebegin', params.html)
      old_child.parentNode.removeChild(old_child)
    }
  }

  rimo.removeAttribute = function(node, params) {
    node.removeAttribute(params.attr)
  }

  rimo.setAttribute = function(node, params) {
    var value = params.value
    if (typeof value === 'string'){
      if (value === 'true') {
        value = true
      } else if (value === 'false') {
        value = false
      }
    }
    if (params.attr in node) {
      node[params.attr] = value
    } else {
      node.setAttribute(params.attr, value)
    }
  }

  rimo.addClass = function(node, params) {
    if (node.classList) {
      node.classList.add(params.class)
    } else {
      node.className += ' ' + params.class
    }
  }

  rimo.removeClass = function(node, params) {
    if (node.classList) {
      node.classList.remove(params.class)
    } else {
      node.className = node.className.replace(params.class, '')
    }
  }

  rimo.empty = function(node) {
    node.innerHTML = ''
  }

  rimo.getBoundingClientRect = function(node, params) {
    var reqid = params.reqid
    var rect = node.getBoundingClientRect()
    rimo.send_response(node, reqid, {
      bottom: rect.bottom,
      height: rect.height,
      left: rect.left,
      right: rect.right,
      top: rect.top,
      width: rect.width
    })
  }

  /* Window Control */
  rimo.scroll = function(node, params){
    window.scrollTo(params.x, params.y)
  }

  rimo.scrollTo = function(node, params){
    window.scrollTo(params.x, params.y)
  }

  rimo.scrollBy = function(node, params){
    window.scrollBy(params.x, params.y)
  }

  rimo.scrollX = function(node, params){
    rimo.send_response(node, params.reqid, {x: window.scrollX})
  }

  rimo.scrollY = function(node, params){
    rimo.send_response(node, params.reqid, {y: window.scrollY})
  }

  rimo.log.log = function(level, message, retry) {
    var msg = JSON.stringify({
      type: 'log',
      level: level,
      message: message
    })

    if (rimo.settings.LOG_CONSOLE) {
      rimo.log.console(level, message)
    }

    if (!rimo.ws.OPEN) {
      retry = retry ? retry + 1 : 1
      if (retry < 5) {
        setTimeout(function() { rimo.log.log(level, message, retry) }, 200)
      } else {
        setTimeout(function() { rimo.ws.send(msg) }, 200)
      }
    } else {
      rimo.ws.send(msg)
    }
  }

  rimo.log.console = function(level, message) {
    if (rimo.log.level <= get_log_level(level)) {
      console[level](rimo.settings.LOG_PREFIX + message)
    }
  }

  rimo.log.set_level = function(level) {
    rimo.log.level = get_log_level(level)
  }

  rimo.log.error = function(message) {
    rimo.log.log('error', message)
  }

  rimo.log.warn = function(message) {
    rimo.log.log('warn', message)
  }

  rimo.log.info = function(message) {
    rimo.log.log('info', message)
  }

  rimo.log.debug = function(message) {
    rimo.log.log('debug', message)
  }

  // Register object to global
  window['rimo'] = rimo
  window.addEventListener('load', initialize)

})(typeof window != 'undefined' ? window : void 0);
<commit_msg>Change default ws url<commit_after>/* rimo v0.0.1 alpha, @lisence MIT, copyright 2016, miyakogi */

;(function(window, undefined){
  'use strict';
  // Define global object
  var rimo = { version: '0.0.1', settings: {}, log: { level: 0 }}
  var config_prefix = 'RIMO_'

  var log_levels = {
    FATAL: 50,
    CRITICAL: 50,
    ERROR: 40,
    WARNING: 30,
    WARN: 30,
    INFO: 20,
    DEBUG: 10,
    NOTSET: 0,
  }

  function get_log_level(level) {
    if (typeof level === 'number'){
      return level
    }

    if (typeof level === 'string') {
      var s = level.toUpperCase()
      if (s in log_levels) {
        return log_levels[s]
      }
    }

    // Get unknown log level
    console.warn(rimo.settings.LOG_PREFIX + 'unknown log level: ', level)
    return 0
  }

  function set_default(key, defval) {
    if (config_prefix + key in window) {
      rimo.settings[key] = window[config_prefix + key]
    } else {
      rimo.settings[key] = defval
    }
  }

  function get_node(id) {
    return document.getElementById(id)
  }

  function ws_onmessage(e) {
    var msg = JSON.parse(e.data)
    var elm = get_node(msg.id)
    if (!elm) {
      // node may not have been mounted yet. retry 100ms later.
      setTimeout(function() {
        var elm = get_node(msg.id)
        if (!elm) {
          // node not found. send warning.
          rimo.log.console('warn', 'gat message to unknown node.\n Message: ' + msg)
          rimo.log.warn('unknown node: id=' + msg.id + ', tag=' + msg.tag + ', method=' + msg.method)
        } else {
          rimo.exec(elm, msg.method, msg.params)
        }
      }, 100)
    } else {
      rimo.exec(elm, msg.method, msg.params)
    }
  }

  function ws_onclose() {
    function reload(){
      location.reload()
    }

    if (rimo.settings.AUTORELOAD) {
      rimo.log.console('info', 'RootWS closed, reloading page...')
      setTimeout(reload, rimo.settings.RELOAD_WAIT)
    } else {
      rimo.log.console('RootWS CLOSED');
    }
  }

  function initialize() {
    // Define default variables
    var __ws_url = 'ws://' + location.host + '/rimo_ws'
    set_default('DEBUG', false)
    set_default('AUTORELOAD', false)
    set_default('RELOAD_WAIT', 500)
    set_default('LOG_LEVEL', 'WARN')
    set_default('LOG_PREFIX', 'rimo: ')
    set_default('LOG_CONSOLE', false)
    set_default('WS_URL', __ws_url)
    rimo.log.set_level(rimo.settings.LOG_LEVEL)

    // Make root WebScoket connection
    rimo.ws = new WebSocket(rimo.settings.WS_URL)
    rimo.ws.onmessage = ws_onmessage
    rimo.ws.onclose = ws_onclose
  }

  rimo.exec = function(node, method, params) {
    // Execute fucntion with msg
    rimo[method](node, params)
  }

  rimo.eval = function(node, params) {
    // Execute fucntion with msg
    eval(params.script)
  }

  // send response
  rimo.send_response = function(node, reqid, data) {
    rimo.log.debug('send_response')
    var msg = JSON.stringify({
      type: 'response',
      id: node.id,
      reqid: reqid,
      data: data
    })
    rimo.log.debug(msg)
    rimo.ws.send(msg)
  }

  /* Event contrall */
  // emit events to python
  // find better name...
  rimo.send_event = function(node, event, data) {
    var msg = JSON.stringify({
      type: 'event',
      id: node.id,
      event: event,
      data: data
    })
    rimo.log.debug(msg)
    rimo.ws.send(msg)
  }

  /* Event handlers */
  rimo.onclick = function(node) {
    rimo.send_event(node, 'click')
  }

  rimo.onchange = function(node) {
    rimo.send_event(
      node,
      'change',
      {
        checked: node.checked,
        value: node.value,
      }
    )
  }

  rimo.oninput = function(node) {
    rimo.send_event(
      node,
      'input',
      {
        checked: node.checked,
        value: node.value,
      }
    )
  }

  rimo.addEventListener = function(node, params) {
    var e = 'on' + params.event
    node.addEventListener(e, function() { rimo[e](node) })
  }

  /* DOM contrall */
  rimo.insert = function(node, params) {
    var index = Number(params.index)
    if (!node.hasChildNodes() || index >= node.childNodes.length) {
      node.insertAdjacentHTML('beforeend', params.html)
    } else {
      var ref_node = node.childNodes[index]
      if (ref_node.nodeName === '#text') {
        var df = document.createDocumentFragment()
        df.innerHTML = params.html
        ref_node.parentNode.insertBefore(df, ref_node)
      } else {
        ref_node.insertAdjacentHTML('beforebegin', params.html)
      }
    }
  }

  rimo.insertAdjacentHTML = function(node, params) {
    node.insertAdjacentHTML(params.position, params.text)
  }

  rimo.textContent = function(node, params) {
    node.textContent = params.text
  }

  rimo.innerHTML = function(node, params) {
    node.innerHTML = params.html
  }

  rimo.outerHTML = function(node, params) {
    node.outerHTML = params.html
  }

  rimo.removeChild = function(node, params) {
    var child = document.getElementById(params.id)
    if (child){
      node.removeChild(child)
    }
  }

  rimo.replaceChild = function(node, params) {
    var old_child = document.getElementById(params.id)
    if (old_child) {
      old_child.insertAdjacentHTML('beforebegin', params.html)
      old_child.parentNode.removeChild(old_child)
    }
  }

  rimo.removeAttribute = function(node, params) {
    node.removeAttribute(params.attr)
  }

  rimo.setAttribute = function(node, params) {
    var value = params.value
    if (typeof value === 'string'){
      if (value === 'true') {
        value = true
      } else if (value === 'false') {
        value = false
      }
    }
    if (params.attr in node) {
      node[params.attr] = value
    } else {
      node.setAttribute(params.attr, value)
    }
  }

  rimo.addClass = function(node, params) {
    if (node.classList) {
      node.classList.add(params.class)
    } else {
      node.className += ' ' + params.class
    }
  }

  rimo.removeClass = function(node, params) {
    if (node.classList) {
      node.classList.remove(params.class)
    } else {
      node.className = node.className.replace(params.class, '')
    }
  }

  rimo.empty = function(node) {
    node.innerHTML = ''
  }

  rimo.getBoundingClientRect = function(node, params) {
    var reqid = params.reqid
    var rect = node.getBoundingClientRect()
    rimo.send_response(node, reqid, {
      bottom: rect.bottom,
      height: rect.height,
      left: rect.left,
      right: rect.right,
      top: rect.top,
      width: rect.width
    })
  }

  /* Window Control */
  rimo.scroll = function(node, params){
    window.scrollTo(params.x, params.y)
  }

  rimo.scrollTo = function(node, params){
    window.scrollTo(params.x, params.y)
  }

  rimo.scrollBy = function(node, params){
    window.scrollBy(params.x, params.y)
  }

  rimo.scrollX = function(node, params){
    rimo.send_response(node, params.reqid, {x: window.scrollX})
  }

  rimo.scrollY = function(node, params){
    rimo.send_response(node, params.reqid, {y: window.scrollY})
  }

  rimo.log.log = function(level, message, retry) {
    var msg = JSON.stringify({
      type: 'log',
      level: level,
      message: message
    })

    if (rimo.settings.LOG_CONSOLE) {
      rimo.log.console(level, message)
    }

    if (!rimo.ws.OPEN) {
      retry = retry ? retry + 1 : 1
      if (retry < 5) {
        setTimeout(function() { rimo.log.log(level, message, retry) }, 200)
      } else {
        setTimeout(function() { rimo.ws.send(msg) }, 200)
      }
    } else {
      rimo.ws.send(msg)
    }
  }

  rimo.log.console = function(level, message) {
    if (rimo.log.level <= get_log_level(level)) {
      console[level](rimo.settings.LOG_PREFIX + message)
    }
  }

  rimo.log.set_level = function(level) {
    rimo.log.level = get_log_level(level)
  }

  rimo.log.error = function(message) {
    rimo.log.log('error', message)
  }

  rimo.log.warn = function(message) {
    rimo.log.log('warn', message)
  }

  rimo.log.info = function(message) {
    rimo.log.log('info', message)
  }

  rimo.log.debug = function(message) {
    rimo.log.log('debug', message)
  }

  // Register object to global
  window['rimo'] = rimo
  window.addEventListener('load', initialize)

})(typeof window != 'undefined' ? window : void 0);
<|endoftext|>


<commit_before>/* global require */
var http = require('http');
var fs = require('fs');
var express = require('express');
var app = express();
app.set('port', process.env.PORT || 3001);

app.get('/api/chapters', chapters);
// app.get('/api/chapters/:chapter_name', chapter);
// app.get('/api/chapters/:chapter_name/users', chapter_users);

function chapters(req, res) {
  function callback(err, files) {
    res.json(200, files);
  }

  fs.readdir('chapters', callback);
}

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

// http.createServer(function (req, res) {
//   res.writeHead(200, {'Content-Type': 'text/plain'});

//   function callback(err, files) {
//     res.end(files.toString());
//   }

//   fs.readdir('users', callback)

// }).listen(1337, '127.0.0.1');

// console.log('Server running at http://127.0.0.1:1337/');
<commit_msg>chapter api endpoint<commit_after>/* global require */
var http = require('http');
var fs = require('fs');
var express = require('express');
var app = express();
app.set('port', process.env.PORT || 3001);

app.get('/api/chapters', chapters);
app.get('/api/chapters/:chapter_name', chapter);
// app.get('/api/chapters/:chapter_name/users', chapter_users);

function chapters(req, res) {
  function callback(err, files) {
    res.json(200, files);
  }

  fs.readdir('chapters', callback);
}

function chapter(req, res) {
  function callback(err, files) {
    res.json(200, files);
  }

  fs.readdir('chapters/' + req.params.chapter_name, callback);
}

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

// http.createServer(function (req, res) {
//   res.writeHead(200, {'Content-Type': 'text/plain'});

//   function callback(err, files) {
//     res.end(files.toString());
//   }

//   fs.readdir('users', callback)

// }).listen(1337, '127.0.0.1');

// console.log('Server running at http://127.0.0.1:1337/');
<|endoftext|>


<commit_before>angular.module('rifiuti.controllers.profilo', [])

.controller('ProfiliCtrl', function ($scope, $rootScope) {})

.controller('ModificaProfiloCtrl', function ($scope, $rootScope, $ionicNavBarDelegate, $filter, DataManager, $stateParams, $ionicPopup, $ionicModal, Profili, Raccolta) {
    $scope.searchQuery = {};

    $scope.aree = [];

    $scope.id = $stateParams.id;

    $scope.profilo = {
        name: '',
        utenza: {},
        area: {}
    };

    $scope.updateLocations = function () {
        Raccolta.areeForTipoUtenza($scope.profilo.utenza.tipologiaUtenza).then(function (data) {
            $scope.aree = [];

            for (var i = 0; i < data.length; i++) {
                $scope.aree.push(data[i]);
                if ($scope.profilo.area && data[i].nome == $scope.profilo.area.nome) {
                    $scope.profilo.area = data[i];
                }
            }
        });
    };

    // popola tipi di utenza e relative locations
    Profili.tipidiutenza().then(function (tipi) {
        tipi = tipi.sort(function (a, b) {
            return a.nome.localeCompare(b.nome);
        });
        $scope.tipologiaUtenza = tipi;

        // new profile
        if (!$scope.id) {
            $scope.profilo.utenza = tipi[0];
            $scope.updateLocations();
        } else {
            // get profile
            var p = Profili.byId($scope.id);
            if (!!p) {
                $scope.profilo = angular.copy(p);
                $scope.updateLocations();
            }
        }
        if (!!$rootScope.selectedProfile && $rootScope.selectedProfile.name == $scope.profilo.name) {
            $scope.isCurrentProfile = true;
        } else {
            $scope.isCurrentProfile = false;
        }

    });

    $scope.isCurrentProfile = true;
    $scope.editMode = !$scope.id;

    $scope.edit = function () {
        if (!$scope.editMode) {
            // edit
            $scope.editMode = true;

            for (var i = 0; i < $scope.tipologiaUtenza.length; i++) {
                if ($scope.tipologiaUtenza[i].nome === $scope.profilo.utenza.nome) {
                    $scope.profilo.utenza = $scope.tipologiaUtenza[i];
                }
            }
        } else {
            // save
            if (!!$scope.profilo.name && !!$scope.profilo.area && !!$scope.profilo.area.nome) {
                var newProfile = null;

                if (!!$scope.id) {
                    // update
                    newProfile = Profili.update($scope.id, $scope.profilo.name, $scope.profilo.utenza, $scope.profilo.area);
                } else {
                    // create
                    newProfile = Profili.add($scope.profilo.name, $scope.profilo.utenza, $scope.profilo.area);
                    $scope.back();
                    return;
                }

                if (newProfile == null) {
                    // error: already exists
                    var popup = $ionicPopup.show({
                        title: '<b class="popup-title">Attenzione !<b/>',
                        template: 'Il nome del profilo è già in uso!',
                        buttons: [
                            {
                                text: 'OK'
                            }
                        ]
                    });
                } else {
                    $scope.editMode = false;
                }
            } else {
                // not complete
                $ionicPopup.show({
                    title: '<b class="popup-title">Attenzione !<b/>',
                    template: 'Per completare il tuo profilo devi scegliere un nome e una località!',
                    scope: $scope,
                    buttons: [
                        {
                            text: 'OK'
                        }
                    ]
                });
            }
        }
    };

    $scope.helpTipi = function (area) {
        var popup = $ionicPopup.show({
            title: '<b class="popup-title">Info<b/>',
            templateUrl: 'templates/profiloHelp.html',
            scope: $scope,
            buttons: [
                {
                    text: 'Chiudi'
                }
            ]
        });
        return;
    };

    $scope.help = function (area) {
        var popup = $ionicPopup.show({
            title: '<b class="popup-title">' + area.etichetta + '<b/>',
            //templateUrl: 'templates/profiloHelp.html',
            template: area.descrizione,
            scope: $scope,
            buttons: [
                {
                    text: 'Chiudi'
                }
            ]
        });
        return;
    };

    $scope.click = function () {
        if ($scope.isCurrentProfile) {
            var popup = $ionicPopup.show({
                title: '<b class="popup-title">Avviso<b/>',
                template: 'Non è possibile cancellare il profilo in uso.',
                scope: $scope,
                buttons: [
                    {
                        text: 'OK'
                    }
                ]
            });
            return;
        }

        var popup = $ionicPopup.show({
            title: '<b class="popup-title">Avviso<b/>',
            template: 'Premendo OK cancellerai definitivamente questo profilo. Confermi?',
            //TODO: le note dovrebbero essere legate al profilo??? ora non lo sono!
            //      template: 'Premendo OK cancellerai definitivamente questo profilo, incluse tutte le eventuali note personali. Confermi?',
            scope: $scope,
            buttons: [
                {
                    text: $filter('translate')('cancel')
                },
                {
                    text: 'OK',
                    onTap: function (e) {
                        return true;
                    }
                }
            ]
        }).then(function (res) {
            if (!!res) {
                Profili.remove($scope.id);
                $scope.back();
            }
        });
    };

    /* LOCALITA SELECTOR */
    $ionicModal.fromTemplateUrl('templates/localitaModal.html', {
        scope: $scope,
        animation: 'slide-in-up'
    }).then(function (modal) {
        $scope.localitaModal = modal;
    });

    $scope.openLocalitaSelector = function () {
        $scope.localitaModal.show();
    };

    $scope.closeLocalitaSelector = function () {
        $scope.localitaModal.hide();
    };

    $scope.localitaSelected = function (item) {
        $scope.profilo.area = item;
        $scope.closeLocalitaSelector();
    };

    //Cleanup the modal when we're done with it!
    $scope.$on('$destroy', function () {
        $scope.localitaModal.remove();
    });

    // Execute action on hide modal
    $scope.$on('modal.hidden', function () {
        // Execute action
    });

    // Execute action on remove modal
    $scope.$on('modal.removed', function () {
        // Execute action
    });
});
<commit_msg>Fix for filter<commit_after>angular.module('rifiuti.controllers.profilo', [])

.controller('ProfiliCtrl', function ($scope, $rootScope) {})

.controller('ModificaProfiloCtrl', function ($scope, $rootScope, $ionicNavBarDelegate, $filter, DataManager, $stateParams, $ionicPopup, $ionicModal, Profili, Raccolta) {
    $scope.searchQuery = {};

    $scope.aree = [];

    $scope.id = $stateParams.id;

    $scope.profilo = {
        name: '',
        utenza: {},
        area: {}
    };

    $scope.updateLocations = function () {
        Raccolta.areeForTipoUtenza($scope.profilo.utenza.tipologiaUtenza).then(function (data) {
            $scope.aree = [];

            for (var i = 0; i < data.length; i++) {
                $scope.aree.push(data[i]);
                if ($scope.profilo.area && data[i].nome == $scope.profilo.area.nome) {
                    $scope.profilo.area = data[i];
                }
            }
        });
    };

    // popola tipi di utenza e relative locations
    Profili.tipidiutenza().then(function (tipi) {
        tipi = tipi.sort(function (a, b) {
            return a.nome.localeCompare(b.nome);
        });
        $scope.tipologiaUtenza = tipi;

        // new profile
        if (!$scope.id) {
            $scope.profilo.utenza = tipi[0];
            $scope.updateLocations();
        } else {
            // get profile
            var p = Profili.byId($scope.id);
            if (!!p) {
                $scope.profilo = angular.copy(p);
                $scope.updateLocations();
            }
        }
        if (!!$rootScope.selectedProfile && $rootScope.selectedProfile.name == $scope.profilo.name) {
            $scope.isCurrentProfile = true;
        } else {
            $scope.isCurrentProfile = false;
        }

    });

    $scope.isCurrentProfile = true;
    $scope.editMode = !$scope.id;

    $scope.edit = function () {
        if (!$scope.editMode) {
            // edit
            $scope.editMode = true;

            for (var i = 0; i < $scope.tipologiaUtenza.length; i++) {
                if ($scope.tipologiaUtenza[i].nome === $scope.profilo.utenza.nome) {
                    $scope.profilo.utenza = $scope.tipologiaUtenza[i];
                }
            }
        } else {
            // save
            if (!!$scope.profilo.name && !!$scope.profilo.area && !!$scope.profilo.area.nome) {
                var newProfile = null;

                if (!!$scope.id) {
                    // update
                    newProfile = Profili.update($scope.id, $scope.profilo.name, $scope.profilo.utenza, $scope.profilo.area);
                } else {
                    // create
                    newProfile = Profili.add($scope.profilo.name, $scope.profilo.utenza, $scope.profilo.area);
                    $scope.back();
                    return;
                }

                if (newProfile == null) {
                    // error: already exists
                    var popup = $ionicPopup.show({
                        title: '<b class="popup-title">Attenzione !<b/>',
                        template: 'Il nome del profilo è già in uso!',
                        buttons: [
                            {
                                text: 'OK'
                            }
                        ]
                    });
                } else {
                    $scope.editMode = false;
                }
            } else {
                // not complete
                $ionicPopup.show({
                    title: '<b class="popup-title">Attenzione !<b/>',
                    template: 'Per completare il tuo profilo devi scegliere un nome e una località!',
                    scope: $scope,
                    buttons: [
                        {
                            text: 'OK'
                        }
                    ]
                });
            }
        }
    };

    $scope.helpTipi = function (area) {
        var popup = $ionicPopup.show({
            title: '<b class="popup-title">Info<b/>',
            templateUrl: 'templates/profiloHelp.html',
            scope: $scope,
            buttons: [
                {
                    text: 'Chiudi'
                }
            ]
        });
        return;
    };

    $scope.help = function (area) {
        var popup = $ionicPopup.show({
            title: '<b class="popup-title">' + area.etichetta + '<b/>',
            //templateUrl: 'templates/profiloHelp.html',
            template: area.descrizione,
            scope: $scope,
            buttons: [
                {
                    text: 'Chiudi'
                }
            ]
        });
        return;
    };

    $scope.click = function () {
        if ($scope.isCurrentProfile) {
            var popup = $ionicPopup.show({
                title: '<b class="popup-title">Avviso<b/>',
                template: 'Non è possibile cancellare il profilo in uso.',
                scope: $scope,
                buttons: [
                    {
                        text: 'OK'
                    }
                ]
            });
            return;
        }

        var popup = $ionicPopup.show({
            title: '<b class="popup-title">Avviso<b/>',
            template: 'Premendo OK cancellerai definitivamente questo profilo. Confermi?',
            //TODO: le note dovrebbero essere legate al profilo??? ora non lo sono!
            //      template: 'Premendo OK cancellerai definitivamente questo profilo, incluse tutte le eventuali note personali. Confermi?',
            scope: $scope,
            buttons: [
                {
                    text: $filter('translate')('cancel')
                },
                {
                    text: 'OK',
                    onTap: function (e) {
                        return true;
                    }
                }
            ]
        }).then(function (res) {
            if (!!res) {
                Profili.remove($scope.id);
                $scope.back();
            }
        });
    };

    /* LOCALITA SELECTOR */
    $ionicModal.fromTemplateUrl('templates/localitaModal.html', {
        scope: $scope,
        animation: 'slide-in-up'
    }).then(function (modal) {
        $scope.localitaModal = modal;
    });

    $scope.openLocalitaSelector = function () {
        $scope.localitaModal.show();
    };

    $scope.closeLocalitaSelector = function () {
        $scope.localitaModal.hide();
    };

    $scope.localitaSelected = function (item) {
        $scope.searchQuery['etichetta'] = '';
        $scope.profilo.area = item;
        $scope.closeLocalitaSelector();
    };

    //Cleanup the modal when we're done with it!
    $scope.$on('$destroy', function () {
        $scope.localitaModal.remove();
    });

    // Execute action on hide modal
    $scope.$on('modal.hidden', function () {
        // Execute action
    });

    // Execute action on remove modal
    $scope.$on('modal.removed', function () {
        // Execute action
    });
});
<|endoftext|>


<commit_before>var Say = require('../../utils/say');
var global = require('../../global');

module.exports = function (unitPaymentCorrection) {

    var items = unitPaymentCorrection.items.map((item) => {
        return {
            quantity: item.quantity,
            uom: item.uom,
            product: item.product,
            pricePerUnit: item.pricePerUnit,
            priceTotal: item.priceTotal,
            prNo: item.purchaseRequest.no,
        };
    });

    items = [].concat.apply([], items);

    var currency = unitPaymentCorrection.items.find(r => true).currency.symbol;
    var urDates = unitPaymentCorrection.unitPaymentOrder.items.map(unitPaymentOrderItem => {
        return new Date(unitPaymentOrderItem.unitReceiptNote.date)
    })
    var sjDate = Math.max.apply(null, urDates);

    var locale = global.config.locale;

    var dateFormat = "DD MMMM YYYY";
    var dateFormat2 = "DD/MM/YYYY";

    var moment = require('moment');
    moment.locale(locale.name);

    var numberLocaleOptions = {
        style: 'decimal',
        maximumFractionDigits: 4,

    };
    var header = [
        {
            columns: [{
                width: '50%',
                text: 'DAN LIRIS',
                style: ['size15', 'bold']
            }, {
                    text: 'NOTA DEBET',
                    style: ['size15', 'bold']

                }]
        }, {
            columns: [{
                width: '60%',
                stack: [
                    'INDUSTRIAL & TRADING CO.LTD. ',
                    'Kel. Banaran Kec. Grogol Kab. Sukoharjo',
                    'Telp. (0271) 714400'
                ],
                style: ['size08']
            }, {
                    width: '*',
                    stack: [
                        `SUKOHARJO, ${moment(unitPaymentCorrection.unitPaymentOrder.date).format(dateFormat)}`,
                        `(${unitPaymentCorrection.unitPaymentOrder.supplier.code}) ${unitPaymentCorrection.unitPaymentOrder.supplier.name}`,
                        `${unitPaymentCorrection.unitPaymentOrder.supplier.address}`],
                    alignment: 'right',
                    style: ['size08']

                }]
        }, '\n', {
            columns: [{
                width: '50%',
                text: `Retur/Potongan ${unitPaymentCorrection.unitPaymentOrder.category.name}`,
                style: ['size09']
            }, {
                    width: '40%',
                    text: `NO. ${unitPaymentCorrection.no}`,
                    style: ['size09', 'bold']
                }]
        }, {
            width: '*',
            text: `Untuk : (${unitPaymentCorrection.unitPaymentOrder.unit.code}) ${unitPaymentCorrection.unitPaymentOrder.unit.subDivision}`,
            style: ['size09']
        }, '\n'
    ];

    var thead = [
        {
            text: 'No.',
            style: 'tableHeader'
        }, {
            text: 'Banyak',
            style: 'tableHeader'
        }, {
            text: 'Keterangan',
            style: 'tableHeader'
        }, {
            text: 'Harga',
            style: 'tableHeader'
        }, {
            text: 'Jumlah',
            style: 'tableHeader'
        }, {
            text: 'Nomor Order',
            style: 'tableHeader'
        }
    ];

    var tbody = items.map(function (item,index) {
        return [{
            text: (index+1).toString() || '',
            style: ['size07', 'center']
        }, {
                text: `${item.quantity} ${item.uom.unit}`,
                style: ['size07', 'right']
            }, {
                text: item.product.name,
                style: ['size07', 'left']
            }, {
                text: parseFloat(item.pricePerUnit).toLocaleString(locale, locale.currency),
                style: ['size07', 'right']
            }, {
                text: parseFloat(item.priceTotal).toLocaleString(locale, locale.currency),
                style: ['size07', 'right']
            }, {
                text: item.prNo,
                style: ['size07', 'left']
            }];
    });

    tbody = tbody.length > 0 ? tbody : [
        [{
            text: "tidak ada barang",
            style: ['size08', 'center'],
            colSpan: 6
        }, "", "", "", "", ""]
    ];

    var table = [{
        table: {
            widths: ['5%', '15%', '35%', '15%', '15%', '15%'],
            headerRows: 1,
            body: [].concat([thead], tbody)
        }
    }];

    var initialValue = {
        priceTotal: 0
    };

    var sum = (items.length > 0 ? items : [initialValue])
        .map(item => item.priceTotal)
        .reduce(function (prev, curr, index, arr) {
            return prev + curr;
        }, 0);

    var useIncomeTax = unitPaymentCorrection.unitPaymentOrder.incomeTaxNo.length > 0 ? sum * 0.1 : 0;

    var total = ['\n',
        {
            columns: [{
                width: '30%',
                text: 'Jumlah',
                style: ['size08']
            }, {
                    width: '5%',
                    text: currency,
                    style: ['size08']
                }, {
                    width: '65%',
                    text: parseFloat(sum).toLocaleString(locale, locale.currency),
                    style: ['size08', 'right']
                }],
            margin: [350, 0, 0, 0]
        }, {
            columns: [{
                width: '30%',
                text: 'PPN',
                style: ['size08']
            }, {
                    width: '5%',
                    text: currency,
                    style: ['size08']
                }, {
                    width: '65%',
                    text: parseFloat(useIncomeTax).toLocaleString(locale, locale.currency),
                    style: ['size08', 'right']
                }],
            margin: [350, 0, 0, 0]
        }, {
            columns: [{
                width: '30%',
                text: 'Total',
                style: ['size08']
            }, {
                    width: '5%',
                    text: currency,
                    style: ['size08']
                }, {
                    width: '65%',
                    text: parseFloat(sum + useIncomeTax).toLocaleString(locale, locale.currency),
                    style: ['size08', 'right', 'bold']
                }],
            margin: [350, 0, 0, 0]
        },
        '\n'];

    var terbilang = {
        columns: [{
            width: '10%',
            text: 'Terbilang :',
            style: ['size08']
        }, {
                text: Say(sum + useIncomeTax),
                style: ['size08', 'justify']
            }]
    };

    var footer = ['\n', {
                text: `Perjanjian Pembayaran : ${moment(unitPaymentCorrection.unitPaymentOrder.dueDate).format(dateFormat)}`,
                style: ['size08']
            }, {
            columns: [{
                width: '50%',
                columns: [{
                    width: '10%',
                    text: 'Nota',
                    style: ['size08']
                }, {
                        width: '3%',
                        text: ':',
                        style: ['size08']
                    }, {
                        width: '*',
                        text: `NO ${unitPaymentCorrection.invoiceCorrectionNo} ${moment(unitPaymentCorrection.invoiceCorrectionDate).format(dateFormat2)}`,
                        style: ['size08']
                    }]
            }, {
                    width: '50%',
                    columns: [{
                        width: '15%',
                        text: 'Brg Dtg',
                        style: ['size08']
                    }, {
                            width: '3%',
                            text: ':',
                            style: ['size08']
                        }, {
                            width: '*',
                            text: `${moment(sjDate).format(dateFormat2)} `,
                            style: ['size08']
                        }]
                }]
        }, {
            columns: [{
                width: '50%',
                columns: [{
                    width: '10%',
                    text: 'Ket',
                    style: ['size08']
                }, {
                        width: '3%',
                        text: ':',
                        style: ['size08']
                    }, {
                        width: '*',
                        text: unitPaymentCorrection.remark,
                        style: ['size08']
                    }]
            }, {
                    width: '50%',
                    columns: [{
                        width: '15%',
                        text: 'NT',
                        style: ['size08']
                    }, {
                            width: '3%',
                            text: ':',
                            style: ['size08']
                        }, {
                            width: '*',
                            text: unitPaymentCorrection.unitCoverLetterNo,
                            style: ['size08']
                        }]
                }]
        }, '\n'];

    var signature = [{
            columns: [{
                width: '25%',
                stack: ['Diperiksa,', 'Verifikasi', '\n\n\n\n', '(                               )'],
                style: ['center']
            }, {
                width: '25%',
                stack: ['Mengetahui,', 'Pimpinan Bagian', '\n\n\n\n', '(                               )'],
                style: ['center']
            }, {
                width: '25%',
                stack: ['Tanda Terima,', 'Bagian Pembelian', '\n\n\n\n', '(                               )'],
                style: ['center']
            }, {
                width: '25%',
                stack: ['Dibuat Oleh,', ' ', '\n\n\n\n', `(  ${unitPaymentCorrection._createdBy}  )`],
                style: ['center']
            }],
        style: ['size08']
        }, '\n', {
                text: `Dicetak Oleh ${unitPaymentCorrection._createdBy}`,
                style: ['size08']
        }];

    var dd = {
        pageSize: 'A5',
        pageOrientation: 'landscape',
        pageMargins: 20,
        content: [].concat(header, table, total, terbilang, footer, signature),
        styles: {
            size06: {
                fontSize: 6
            },
            size07: {
                fontSize: 7
            },
            size08: {
                fontSize: 8
            },
            size09: {
                fontSize: 9
            },
            size10: {
                fontSize: 10
            },
            size15: {
                fontSize: 15
            },
            bold: {
                bold: true
            },
            center: {
                alignment: 'center'
            },
            left: {
                alignment: 'left'
            },
            right: {
                alignment: 'right'
            },
            justify: {
                alignment: 'justify'
            },
            tableHeader: {
                bold: true,
                fontSize: 8,
                color: 'black',
                alignment: 'center'
            }
        }
    }

    return dd;
}<commit_msg>change format in unit-payment-corection-note<commit_after>var Say = require('../../utils/say');
var global = require('../../global');

module.exports = function (unitPaymentCorrection) {

    var items = unitPaymentCorrection.items.map((item) => {
        return {
            quantity: item.quantity,
            uom: item.uom,
            product: item.product,
            pricePerUnit: item.pricePerUnit,
            priceTotal: item.priceTotal,
            prNo: item.purchaseRequest.no,
        };
    });

    items = [].concat.apply([], items);

    var currency = unitPaymentCorrection.items.find(r => true).currency.symbol;
    var urDates = unitPaymentCorrection.unitPaymentOrder.items.map(unitPaymentOrderItem => {
        return new Date(unitPaymentOrderItem.unitReceiptNote.date)
    })
    var sjDate = Math.max.apply(null, urDates);

    var locale = global.config.locale;

    var moment = require('moment');
    moment.locale(locale.name);

    var numberLocaleOptions = {
        style: 'decimal',
        maximumFractionDigits: 4,

    };
    var header = [
        {
            columns: [{
                width: '50%',
                text: 'DAN LIRIS',
                style: ['size15', 'bold']
            }, {
                    text: 'NOTA DEBET',
                    style: ['size15', 'bold']

                }]
        }, {
            columns: [{
                width: '60%',
                stack: [
                    'INDUSTRIAL & TRADING CO.LTD. ',
                    'Kel. Banaran Kec. Grogol Kab. Sukoharjo',
                    'Telp. (0271) 714400'
                ],
                style: ['size08']
            }, {
                    width: '*',
                    stack: [
                        `SUKOHARJO, ${moment(unitPaymentCorrection.unitPaymentOrder.date).format(locale.date.format)}`,
                        `(${unitPaymentCorrection.unitPaymentOrder.supplier.code}) ${unitPaymentCorrection.unitPaymentOrder.supplier.name}`,
                        `${unitPaymentCorrection.unitPaymentOrder.supplier.address}`],
                    alignment: 'right',
                    style: ['size08']

                }]
        }, '\n', {
            columns: [{
                width: '50%',
                text: `Retur/Potongan ${unitPaymentCorrection.unitPaymentOrder.category.name}`,
                style: ['size09']
            }, {
                    width: '40%',
                    text: `NO. ${unitPaymentCorrection.no}`,
                    style: ['size09', 'bold']
                }]
        }, {
            width: '*',
            text: `Untuk : (${unitPaymentCorrection.unitPaymentOrder.unit.code}) ${unitPaymentCorrection.unitPaymentOrder.unit.subDivision}`,
            style: ['size09']
        }, '\n'
    ];

    var thead = [
        {
            text: 'No.',
            style: 'tableHeader'
        }, {
            text: 'Banyak',
            style: 'tableHeader'
        }, {
            text: 'Keterangan',
            style: 'tableHeader'
        }, {
            text: 'Harga',
            style: 'tableHeader'
        }, {
            text: 'Jumlah',
            style: 'tableHeader'
        }, {
            text: 'Nomor Order',
            style: 'tableHeader'
        }
    ];

    var tbody = items.map(function (item,index) {
        return [{
            text: (index+1).toString() || '',
            style: ['size07', 'center']
        }, {
                text: `${item.quantity} ${item.uom.unit}`,
                style: ['size07', 'right']
            }, {
                text: item.product.name,
                style: ['size07', 'left']
            }, {
                text: parseFloat(item.pricePerUnit).toLocaleString(locale, locale.currency),
                style: ['size07', 'right']
            }, {
                text: parseFloat(item.priceTotal).toLocaleString(locale, locale.currency),
                style: ['size07', 'right']
            }, {
                text: item.prNo,
                style: ['size07', 'left']
            }];
    });

    tbody = tbody.length > 0 ? tbody : [
        [{
            text: "tidak ada barang",
            style: ['size08', 'center'],
            colSpan: 6
        }, "", "", "", "", ""]
    ];

    var table = [{
        table: {
            widths: ['5%', '15%', '35%', '15%', '15%', '15%'],
            headerRows: 1,
            body: [].concat([thead], tbody)
        }
    }];

    var initialValue = {
        priceTotal: 0
    };

    var sum = (items.length > 0 ? items : [initialValue])
        .map(item => item.priceTotal)
        .reduce(function (prev, curr, index, arr) {
            return prev + curr;
        }, 0);

    var useIncomeTax = unitPaymentCorrection.unitPaymentOrder.incomeTaxNo.length > 0 ? sum * 0.1 : 0;

    var total = ['\n',
        {
            columns: [{
                width: '30%',
                text: 'Jumlah',
                style: ['size08']
            }, {
                    width: '5%',
                    text: currency,
                    style: ['size08']
                }, {
                    width: '65%',
                    text: parseFloat(sum).toLocaleString(locale, locale.currency),
                    style: ['size08', 'right']
                }],
            margin: [350, 0, 0, 0]
        }, {
            columns: [{
                width: '30%',
                text: 'PPN',
                style: ['size08']
            }, {
                    width: '5%',
                    text: currency,
                    style: ['size08']
                }, {
                    width: '65%',
                    text: parseFloat(useIncomeTax).toLocaleString(locale, locale.currency),
                    style: ['size08', 'right']
                }],
            margin: [350, 0, 0, 0]
        }, {
            columns: [{
                width: '30%',
                text: 'Total',
                style: ['size08']
            }, {
                    width: '5%',
                    text: currency,
                    style: ['size08']
                }, {
                    width: '65%',
                    text: parseFloat(sum + useIncomeTax).toLocaleString(locale, locale.currency),
                    style: ['size08', 'right', 'bold']
                }],
            margin: [350, 0, 0, 0]
        },
        '\n'];

    var terbilang = {
        columns: [{
            width: '10%',
            text: 'Terbilang :',
            style: ['size08']
        }, {
                text: Say(sum + useIncomeTax),
                style: ['size08', 'justify']
            }]
    };

    var footer = ['\n', {
                text: `Perjanjian Pembayaran : ${moment(unitPaymentCorrection.unitPaymentOrder.dueDate).format(locale.date.format)}`,
                style: ['size08']
            }, {
            columns: [{
                width: '50%',
                columns: [{
                    width: '10%',
                    text: 'Nota',
                    style: ['size08']
                }, {
                        width: '3%',
                        text: ':',
                        style: ['size08']
                    }, {
                        width: '*',
                        text: `NO ${unitPaymentCorrection.invoiceCorrectionNo} ${moment(unitPaymentCorrection.invoiceCorrectionDate).format(locale.date.format)}`,
                        style: ['size08']
                    }]
            }, {
                    width: '50%',
                    columns: [{
                        width: '15%',
                        text: 'Brg Dtg',
                        style: ['size08']
                    }, {
                            width: '3%',
                            text: ':',
                            style: ['size08']
                        }, {
                            width: '*',
                            text: `${moment(sjDate).format(locale.date.format)} `,
                            style: ['size08']
                        }]
                }]
        }, {
            columns: [{
                width: '50%',
                columns: [{
                    width: '10%',
                    text: 'Ket',
                    style: ['size08']
                }, {
                        width: '3%',
                        text: ':',
                        style: ['size08']
                    }, {
                        width: '*',
                        text: unitPaymentCorrection.remark,
                        style: ['size08']
                    }]
            }, {
                    width: '50%',
                    columns: [{
                        width: '15%',
                        text: 'NT',
                        style: ['size08']
                    }, {
                            width: '3%',
                            text: ':',
                            style: ['size08']
                        }, {
                            width: '*',
                            text: unitPaymentCorrection.unitCoverLetterNo,
                            style: ['size08']
                        }]
                }]
        }, '\n'];

    var signature = [{
            columns: [{
                width: '25%',
                stack: ['Diperiksa,', 'Verifikasi', '\n\n\n\n', '(                               )'],
                style: ['center']
            }, {
                width: '25%',
                stack: ['Mengetahui,', 'Pimpinan Bagian', '\n\n\n\n', '(                               )'],
                style: ['center']
            }, {
                width: '25%',
                stack: ['Tanda Terima,', 'Bagian Pembelian', '\n\n\n\n', '(                               )'],
                style: ['center']
            }, {
                width: '25%',
                stack: ['Dibuat Oleh,', ' ', '\n\n\n\n', `(  ${unitPaymentCorrection._createdBy}  )`],
                style: ['center']
            }],
        style: ['size08']
        }, '\n', {
                text: `Dicetak Oleh ${unitPaymentCorrection._createdBy}`,
                style: ['size08']
        }];

    var dd = {
        pageSize: 'A5',
        pageOrientation: 'landscape',
        pageMargins: 20,
        content: [].concat(header, table, total, terbilang, footer, signature),
        styles: {
            size06: {
                fontSize: 6
            },
            size07: {
                fontSize: 7
            },
            size08: {
                fontSize: 8
            },
            size09: {
                fontSize: 9
            },
            size10: {
                fontSize: 10
            },
            size15: {
                fontSize: 15
            },
            bold: {
                bold: true
            },
            center: {
                alignment: 'center'
            },
            left: {
                alignment: 'left'
            },
            right: {
                alignment: 'right'
            },
            justify: {
                alignment: 'justify'
            },
            tableHeader: {
                bold: true,
                fontSize: 8,
                color: 'black',
                alignment: 'center'
            }
        }
    }

    return dd;
}<|endoftext|>