<commit_before>/**
 * A steady drip of Khan Academy culture, straight into HipChat's veins.
 *
 * "@CultureCow culture us" to get your hit of culture on demand.
 */

var culturalMsgs = [
    "Shipping beats perfection.",
    "Iterate on ideas before diving into code. Design sprints are being organized by Jason and others and work well for both huge projects and small features.",
    "Concerned about the hacks in our code? Upset that the product's not good enough? Have no fear, we're getting better fast. Our site used to look like this and it was generated by one big main.py file.",
    "Our core company values.",
    "Have anything to demo at the next Monday all-hands? Everything that's shipped to real users is eligible. Show off.",
    "Be open, share your work.",
    "It's ok to leave (or simply not attend) any meeting that you don't feel is important for you.",
    "Email transparency makes it easy for anybody to follow the goings on of teams they're interested in. Join any list.",
    "As a cow, I am fairly proud of having written our Career Development doc. Hard to do w/ just hooves.",
    "Keep learning — we'll send you to conferences to do so.",
    "Anybody can fix anything. (And anybody can run a FIXIT for themselves or their team.)",
    "Wading into some old code that's really disgusting compared to your brilliant new feature? You don't have to fix everything all at once. \"Leave it better\" and use # TODOs liberally. (Ben says he's sorry for the old code.)",
    "Wanna teach the team about anything? Spread good habits? Show off what you're building? Sign up for an Exalted Speaker slot during next Wednesday's dev sitdown.",
    "Will just leave these users stories here.",
    "Do you need anything to do your job well? Hardware? Software? Food? Coach K bobblehead for your desk? It's easy to get whatever you need, and if you have any trouble ping Kamens quickly.",
    "Shipping anything sizable? Dog food it! Schedule a dogfooding hour, ping in hipchat to gather friendly eaters of dog food, profit.",
    "Performance is a feature and is everyone's job. Unsure how to profile your code? No worries, just ask, we have some perf nuts on the team.",
    "Anybody can own a deploy. If you've got big changes going out, you're probably that anybody. I (Culture Cow), may one day even keep track of a deploy count leaderboard and spit it out here!",
    "Write code with your reviewer in mind.",
    "Recruiting is everyone's job. Blogging about recruiting being everyone's job is Marcia's job.",
    ],
    morningCultureHour = 10  // hour of morning (pacific time) at which to send

module.exports = function(robot) {

    var msPerDay = 1000 * 60 * 60 * 24,
        msgIndex = randInt(0, culturalMsgs.length - 1);

    /**
     * Send a single culture tidbit and queue up the next one.
     */
    function sendCultureMessage() {
        var urlCultureCowEmoticon = "https://dujrsrsgsd3nh.cloudfront.net/img/emoticons/6574/culture-1376771657.png",
            s = (" " +
                    culturalMsgs[msgIndex] + " Moooo.");

        robot.messageHipchat(s);

        msgIndex++;
        if (msgIndex >= culturalMsgs.length) {
            msgIndex = 0;
        }
    };

    /**
     * Start dripping culture tidbits now and forever, once per day.
     */
    function startCultureDrip() {
        // Send one culture message every day
        setInterval(sendCultureMessage, msPerDay);
        // And send one right now.
        sendCultureMessage();
    }

    // Send one culture message whenever requested
    robot.respond(/culture us$/i, function(msg) {
        sendCultureMessage();
    });

    setTimeout(startCultureDrip, msUntilMorning());
}

/**
 * Rand int generation, inclusive of min/max
 */
function randInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

/**
 * Return milliseconds between now and sometime (10/11am PST) the next morning.
 */
function msUntilMorning() {
    var now = new Date(),
        later = new Date(),
        pacificUTCOffset = 7;  // not worrying about DST for now

    later.setUTCHours(morningCultureHour + pacificUTCOffset);
    later.setUTCMinutes(0);

    return Math.abs(later - now);
}
<commit_msg>Fix 'milliseconds until morning' calculation when script is started after 10am<commit_after>/**
 * A steady drip of Khan Academy culture, straight into HipChat's veins.
 *
 * "@CultureCow culture us" to get your hit of culture on demand.
 */

var culturalMsgs = [
    "Shipping beats perfection.",
    "Iterate on ideas before diving into code. Design sprints are being organized by Jason and others and work well for both huge projects and small features.",
    "Concerned about the hacks in our code? Upset that the product's not good enough? Have no fear, we're getting better fast. Our site used to look like this and it was generated by one big main.py file.",
    "Our core company values.",
    "Have anything to demo at the next Monday all-hands? Everything that's shipped to real users is eligible. Show off.",
    "Be open, share your work.",
    "It's ok to leave (or simply not attend) any meeting that you don't feel is important for you.",
    "Email transparency makes it easy for anybody to follow the goings on of teams they're interested in. Join any list.",
    "As a cow, I am fairly proud of having written our Career Development doc. Hard to do w/ just hooves.",
    "Keep learning — we'll send you to conferences to do so.",
    "Anybody can fix anything. (And anybody can run a FIXIT for themselves or their team.)",
    "Wading into some old code that's really disgusting compared to your brilliant new feature? You don't have to fix everything all at once. \"Leave it better\" and use # TODOs liberally. (Ben says he's sorry for the old code.)",
    "Wanna teach the team about anything? Spread good habits? Show off what you're building? Sign up for an Exalted Speaker slot during next Wednesday's dev sitdown.",
    "Will just leave these users stories here.",
    "Do you need anything to do your job well? Hardware? Software? Food? Coach K bobblehead for your desk? It's easy to get whatever you need, and if you have any trouble ping Kamens quickly.",
    "Shipping anything sizable? Dog food it! Schedule a dogfooding hour, ping in hipchat to gather friendly eaters of dog food, profit.",
    "Performance is a feature and is everyone's job. Unsure how to profile your code? No worries, just ask, we have some perf nuts on the team.",
    "Anybody can own a deploy. If you've got big changes going out, you're probably that anybody. I (Culture Cow), may one day even keep track of a deploy count leaderboard and spit it out here!",
    "Write code with your reviewer in mind.",
    "Recruiting is everyone's job. Blogging about recruiting being everyone's job is Marcia's job.",
    ],
    morningCultureHour = 10  // hour of morning (pacific time) at which to send

module.exports = function(robot) {

    var msPerDay = 1000 * 60 * 60 * 24,
        msgIndex = randInt(0, culturalMsgs.length - 1);

    /**
     * Send a single culture tidbit and queue up the next one.
     */
    function sendCultureMessage() {
        var urlCultureCowEmoticon = "https://dujrsrsgsd3nh.cloudfront.net/img/emoticons/6574/culture-1376771657.png",
            s = (" " +
                    culturalMsgs[msgIndex] + " Moooo.");

        robot.messageHipchat(s);

        msgIndex++;
        if (msgIndex >= culturalMsgs.length) {
            msgIndex = 0;
        }
    };

    /**
     * Start dripping culture tidbits now and forever, once per day.
     */
    function startCultureDrip() {
        // Send one culture message every day
        setInterval(sendCultureMessage, msPerDay);
        // And send one right now.
        sendCultureMessage();
    }

    // Send one culture message whenever requested
    robot.respond(/culture us$/i, function(msg) {
        sendCultureMessage();
    });

    setTimeout(startCultureDrip, msUntilMorning());
}

/**
 * Rand int generation, inclusive of min/max
 */
function randInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

/**
 * Return milliseconds between now and sometime (10/11am PST) the next morning.
 */
function msUntilMorning() {
    var now = new Date(),
        later = new Date(),
        pacificUTCOffset = 7;  // not worrying about DST for now

    later.setUTCHours(morningCultureHour + pacificUTCOffset);
    later.setUTCMinutes(0);

    if (later < now) {
        later.setUTCDate(later.getUTCDate() + 1);
    }

    return Math.abs(later - now);
}
<|endoftext|>


<commit_before>/*globals fdom:true */
/*jslint indent:2,sloppy:true */

fdom.apis.set("core", {
  'createChannel': {type: "method", value: [], ret: {
    channel: "proxy",
    identifier: "string"
  }},
  'bindChannel': {type: "method", value: ["string"], ret: "proxy"},
  'getId': {type: "method", value: [], ret: ["array", "string"]}
});

fdom.apis.set("core.view", {
  'open': {type: "method", value: ["string", {
    'file': "string",
    'code': "string"
  }]},
  'show': {type: "method", value: []},
  'close': {type: "method", value: []},
  'postMessage': {type: "method", value: ["object"]},

  'message': {type: "event", value: "object"},
  'onClose': {type: "event", value: []}
});

fdom.apis.set("core.storage", {
  'keys': {type: "method", value: [], ret: ["array", "string"]},
  'get': {type: "method", value: ["string"], ret: "string"},
  'set': {type: "method", value: ["string", "string"], ret: "string"},
  'remove': {type: "method", value: ["string"], ret: "string"},
  'clear': {type: "method", value: []}
});

// A TCP Socket.
fdom.apis.set("core.tcpsocket", {
  // Sockets may be constructed bound to a pre-existing id, as in the case of
  // interacting with a socket accpeted by a server.  If no Id is specified, a
  // new socket will be created, which can be either connect'ed or listen'ed.
  'constructor': {
    value: ["number"]
  },

  // Get info about a socket.  Tells you whether the socket is active and
  // available host information.
  'getInfo': {
    type: "method",
    value: [],
    ret: {
      "connected": "boolean",
      "localAddress": "string",
      "localPort": "number",
      "peerAddress": "string",
      "peerPort": "number"
    }
  },

  // Close a socket. Will Fail if the socket is not connected or already
  // closed.
  'close': {
    type: "method",
    value: [],
    err: {
      "errcode": "string",
      "message": "string"
    }
  },

  // Receive notification that the socket has disconnected.
  'onDisconnect': {type: "event", value: {
    "errcode": "string",
    "message": "string"
  }},

  // Connect to a host and port.
  // Fails with an error if connection fails.
  'connect': {
    type: "method",
    value: ["string", "number"],
    err: {
      "errcode": "string",
      "message": "string"
    }
  },

  // Write buffer data to a socket.
  // Fails with an error if write fails.
  'write': {
    type: "method",
    value: ["buffer"],
    err: {
      "errcode": "string",
      "message": "string"
    }
  },

  // Receive data on a connected socket.
  'onData': {
    type: "event",
    value: {"data": "buffer"}
  },

  // Listen as a server at a specified host and port.
  // After calling listen the client should listen for 'onConnection' events.
  // Fails with an error if errors occur while binding or listening.
  'listen': {
    type: "method",
    value: ["string", "number"],
    err: {
      "errcode": "string",
      "message": "string"
    }
  },

  // Receive a connection.
  // The socket parameter may be used to construct a new socket.
  // Host and port information provide information about the remote peer.
  'onConnection': {type: "event", value: {
    "socket": "number",
    "host": "string",
    "port": "number"
  }}
});

// A UDP socket.
// Generally, to use you just need to call bind() at which point onData
// events will start to flow. Note that bind() should only be called
// once per instance.
fdom.apis.set('core.udpsocket', {
  // Creates a socket, binds it to an interface and port and listens for
  // messages, dispatching each message as on onData event.
  // Returns an integer, with zero meaning success and any other value
  // being implementation-dependant.
  'bind': {
    type: 'method',
    value: [
      // Interface (address) on which to bind.
      'string',
      // Port on which to bind.
      'number'
    ],
    ret: 'number'
  },

  // Retrieves the state of the socket.
  // Returns an object with the following properties:
  //  - localAddress: the socket's local address, if bound
  //  - localPort: the socket's local port, if bound
  'getInfo': {type: 'method', value: [], ret: {
    'localAddress': 'string',
    'localPort': 'number'
  }},

  // Sends data to a server.
  // The socket must be bound.
  // Returns an integer indicating the number of bytes written, with no
  // guarantee that the remote side received the data.
  'sendTo': {
    type: 'method',
    value: [
      // Data to send.
      'buffer',
      // Destination address.
      'string',
      // Destination port.
      'number'
    ],
    ret: 'number'
  },

  // Releases all resources associated with this socket.
  // No-op if the socket is not bound.
  'destroy': {type: 'method', value: []},

  // Called once for each message received on this socket, once it's
  // been successfully bound.
  'onData': {
    type: 'event',
    value: {
      // Zero means success, any other value is implementation-dependent.
      'resultCode': 'number',
      // Address from which data was received.
      'address': 'string',
      // Port from which data was received.
      'port': 'number',
      // Data received.
      'data': 'buffer'
    }
  }
});

fdom.apis.set("core.runtime", {
  'createApp': {type: "method", value: ["string", "proxy"]},
  'resolve': {type: "method", value: ["string", "string"]},
  'needFile': {type: 'event', value: ["string", "string"]}
});

fdom.apis.set('core.echo', {
  'setup': {type: "method", value: ["string"]},
  'send': {type: "method", value: ["string"]},
  'message': {type: "event", value: "string"}
});

fdom.apis.set('core.peerconnection', {
  // Setup the link to the peer and options for this peer connection.
  'setup': {
    type: "method",
    value: [
      // The freedom.js channel identifier used to setup a signalling chanel.
      "string",
      // The peerName, used debugging and console messages.
      "string",
      // The list of STUN servers to use.
      // The format of a single entry is stun:HOST:PORT, where HOST
      // and PORT are a stun server hostname and port, respectively.
      ["array", "string"]
    ]
  },

  // Send a message to the peer.
  'send': {type: "method", value: [{
    // Data channel id. If provided, will be used as the channel label.
    // The behavior is undefined if the channel label doesn't exist.
    "channelLabel": "string",
    // One of the bellow should be defined; this is the data to send.
    "text": "string",
    "binary": "blob",
    "buffer": "buffer"
  }]},

  // Called when we get a message from the peer.
  'onReceived': {type: "event", value: {
    // The label/id of the data channel.
    "channelLabel": "string",
    // One the below will be specified.
    "text": "string",
    "binary": "blob",
    "buffer": "buffer"
  }},

  // Open the data channel with this label.
  'openDataChannel': {type: "method", value: ["string"]},
  // Close the data channel with this label.
  'closeDataChannel': {type: "method", value: ["string"]},

  // A channel with this id has been opened.
  'onOpenDataChannel': {type: "event", value: {"channelId": "string"}},
  // The channale with this id has been closed.
  'onCloseDataChannel': {type: "event", value: {"channelId": "string"}},

  // Returns the number of bytes that have queued using "send", but not
  // yet sent out. Currently just exposes:
  // http://www.w3.org/TR/webrtc/#widl-RTCDataChannel-bufferedAmount
  "getBufferedAmount": {type: "method",
                        value: ["string"],
                        ret: "number"},

  // Close the peer connection.
  'close': {type: "method", value: []},
  // The peer connection has been closed.
  'onClose': {type: "event", value: {}}
});

fdom.apis.set("core.websocket", {
  'constructor': {value:
                  // URL to connect through
                  ["string",
                   // Protocols
                   ["array", "string"]]},
  'open': {type: "method",
              value: [],
              err: {
                "errcode": "string",
                "message": "string"
              }},
  // Send the data to the other side of this connection. Only one of
  // the entries in the dictionary that is passed will be sent.
  'send': {type: "method",
           value: [{
             "text": "string",
             "binary": "blob",
             "buffer": "buffer"
           }],
           err:{
             "errcode": "string",
             "message": "string"
           }},
  'getReadyState': {type: "method",
               value: [],
               // 0 -> CONNECTING
               // 1 -> OPEN
               // 2 -> CLOSING
               // 3 -> CLOSED
               ret: "number"
              },
  'close': {type: "method",
            value: []},
  'onMessage': { type: 'event',
                 // The data will be stored in one of the keys,
                 // corresponding with the type received
                 value: [{
                   "text": "string",
                   "binary": "blob",
                   "buffer": "buffer"
                 }]
               },
  'onOpen': { type: 'event',
              value: []
            },
  'onError': { type: 'event',
               value: [{
                 "errcode": "string",
                 "message": "string"
               }]
             },
  'onClose': { type: 'event',
               value: []
             }
});
<commit_msg>Indenting<commit_after>/*globals fdom:true */
/*jslint indent:2,sloppy:true */

fdom.apis.set("core", {
  'createChannel': {type: "method", value: [], ret: {
    channel: "proxy",
    identifier: "string"
  }},
  'bindChannel': {type: "method", value: ["string"], ret: "proxy"},
  'getId': {type: "method", value: [], ret: ["array", "string"]}
});

fdom.apis.set("core.view", {
  'open': {type: "method", value: ["string", {
    'file': "string",
    'code': "string"
  }]},
  'show': {type: "method", value: []},
  'close': {type: "method", value: []},
  'postMessage': {type: "method", value: ["object"]},

  'message': {type: "event", value: "object"},
  'onClose': {type: "event", value: []}
});

fdom.apis.set("core.storage", {
  'keys': {type: "method", value: [], ret: ["array", "string"]},
  'get': {type: "method", value: ["string"], ret: "string"},
  'set': {type: "method", value: ["string", "string"], ret: "string"},
  'remove': {type: "method", value: ["string"], ret: "string"},
  'clear': {type: "method", value: []}
});

// A TCP Socket.
fdom.apis.set("core.tcpsocket", {
  // Sockets may be constructed bound to a pre-existing id, as in the case of
  // interacting with a socket accpeted by a server.  If no Id is specified, a
  // new socket will be created, which can be either connect'ed or listen'ed.
  'constructor': {
    value: ["number"]
  },

  // Get info about a socket.  Tells you whether the socket is active and
  // available host information.
  'getInfo': {
    type: "method",
    value: [],
    ret: {
      "connected": "boolean",
      "localAddress": "string",
      "localPort": "number",
      "peerAddress": "string",
      "peerPort": "number"
    }
  },

  // Close a socket. Will Fail if the socket is not connected or already
  // closed.
  'close': {
    type: "method",
    value: [],
    err: {
      "errcode": "string",
      "message": "string"
    }
  },

  // Receive notification that the socket has disconnected.
  'onDisconnect': {type: "event", value: {
    "errcode": "string",
    "message": "string"
  }},

  // Connect to a host and port.
  // Fails with an error if connection fails.
  'connect': {
    type: "method",
    value: ["string", "number"],
    err: {
      "errcode": "string",
      "message": "string"
    }
  },

  // Write buffer data to a socket.
  // Fails with an error if write fails.
  'write': {
    type: "method",
    value: ["buffer"],
    err: {
      "errcode": "string",
      "message": "string"
    }
  },

  // Receive data on a connected socket.
  'onData': {
    type: "event",
    value: {"data": "buffer"}
  },

  // Listen as a server at a specified host and port.
  // After calling listen the client should listen for 'onConnection' events.
  // Fails with an error if errors occur while binding or listening.
  'listen': {
    type: "method",
    value: ["string", "number"],
    err: {
      "errcode": "string",
      "message": "string"
    }
  },

  // Receive a connection.
  // The socket parameter may be used to construct a new socket.
  // Host and port information provide information about the remote peer.
  'onConnection': {type: "event", value: {
    "socket": "number",
    "host": "string",
    "port": "number"
  }}
});

// A UDP socket.
// Generally, to use you just need to call bind() at which point onData
// events will start to flow. Note that bind() should only be called
// once per instance.
fdom.apis.set('core.udpsocket', {
  // Creates a socket, binds it to an interface and port and listens for
  // messages, dispatching each message as on onData event.
  // Returns an integer, with zero meaning success and any other value
  // being implementation-dependant.
  'bind': {
    type: 'method',
    value: [
      // Interface (address) on which to bind.
      'string',
      // Port on which to bind.
      'number'
    ],
    ret: 'number'
  },

  // Retrieves the state of the socket.
  // Returns an object with the following properties:
  //  - localAddress: the socket's local address, if bound
  //  - localPort: the socket's local port, if bound
  'getInfo': {type: 'method', value: [], ret: {
    'localAddress': 'string',
    'localPort': 'number'
  }},

  // Sends data to a server.
  // The socket must be bound.
  // Returns an integer indicating the number of bytes written, with no
  // guarantee that the remote side received the data.
  'sendTo': {
    type: 'method',
    value: [
      // Data to send.
      'buffer',
      // Destination address.
      'string',
      // Destination port.
      'number'
    ],
    ret: 'number'
  },

  // Releases all resources associated with this socket.
  // No-op if the socket is not bound.
  'destroy': {type: 'method', value: []},

  // Called once for each message received on this socket, once it's
  // been successfully bound.
  'onData': {
    type: 'event',
    value: {
      // Zero means success, any other value is implementation-dependent.
      'resultCode': 'number',
      // Address from which data was received.
      'address': 'string',
      // Port from which data was received.
      'port': 'number',
      // Data received.
      'data': 'buffer'
    }
  }
});

fdom.apis.set("core.runtime", {
  'createApp': {type: "method", value: ["string", "proxy"]},
  'resolve': {type: "method", value: ["string", "string"]},
  'needFile': {type: 'event', value: ["string", "string"]}
});

fdom.apis.set('core.echo', {
  'setup': {type: "method", value: ["string"]},
  'send': {type: "method", value: ["string"]},
  'message': {type: "event", value: "string"}
});

fdom.apis.set('core.peerconnection', {
  // Setup the link to the peer and options for this peer connection.
  'setup': {
    type: "method",
    value: [
      // The freedom.js channel identifier used to setup a signalling chanel.
      "string",
      // The peerName, used debugging and console messages.
      "string",
      // The list of STUN servers to use.
      // The format of a single entry is stun:HOST:PORT, where HOST
      // and PORT are a stun server hostname and port, respectively.
      ["array", "string"]
    ]
  },

  // Send a message to the peer.
  'send': {type: "method", value: [{
    // Data channel id. If provided, will be used as the channel label.
    // The behavior is undefined if the channel label doesn't exist.
    "channelLabel": "string",
    // One of the bellow should be defined; this is the data to send.
    "text": "string",
    "binary": "blob",
    "buffer": "buffer"
  }]},

  // Called when we get a message from the peer.
  'onReceived': {type: "event", value: {
    // The label/id of the data channel.
    "channelLabel": "string",
    // One the below will be specified.
    "text": "string",
    "binary": "blob",
    "buffer": "buffer"
  }},

  // Open the data channel with this label.
  'openDataChannel': {type: "method", value: ["string"]},
  // Close the data channel with this label.
  'closeDataChannel': {type: "method", value: ["string"]},

  // A channel with this id has been opened.
  'onOpenDataChannel': {type: "event", value: {"channelId": "string"}},
  // The channale with this id has been closed.
  'onCloseDataChannel': {type: "event", value: {"channelId": "string"}},

  // Returns the number of bytes that have queued using "send", but not
  // yet sent out. Currently just exposes:
  // http://www.w3.org/TR/webrtc/#widl-RTCDataChannel-bufferedAmount
  "getBufferedAmount": {type: "method",
                        value: ["string"],
                        ret: "number"},

  // Close the peer connection.
  'close': {type: "method", value: []},
  // The peer connection has been closed.
  'onClose': {type: "event", value: {}}
});

fdom.apis.set("core.websocket", {
  'constructor': {value:
    // URL to connect through
    ["string",
    // Protocols
    ["array", "string"]]},
  'open': {type: "method",
    value: [],
    err: {
      "errcode": "string",
      "message": "string"
    }},
  // Send the data to the other side of this connection. Only one of
  // the entries in the dictionary that is passed will be sent.
  'send': {type: "method",
    value: [{
      "text": "string",
      "binary": "blob",
      "buffer": "buffer"
    }],
    err:{
      "errcode": "string",
      "message": "string"
    }},
    'getReadyState': {type: "method",
      value: [],
      // 0 -> CONNECTING
      // 1 -> OPEN
      // 2 -> CLOSING
      // 3 -> CLOSED
      ret: "number"
     },
  'close': {type: "method",
    value: []},
  'onMessage': { type: 'event',
     // The data will be stored in one of the keys,
     // corresponding with the type received
     value: [{
       "text": "string",
       "binary": "blob",
       "buffer": "buffer"
     }]
   },
  'onOpen': { type: 'event',
     value: []
   },
  'onError': { type: 'event',
     value: [{
       "errcode": "string",
       "message": "string"
     }]
  },
  'onClose': { type: 'event',
     value: []
  }
});
<|endoftext|>


<commit_before>const childProcess = require('child_process')
const rimraf = require('rimraf')
const path = require('path')
const zlib = require('zlib')
const fs = require('fs')
const os = require('os')

const repoDir = path.dirname(__dirname)
const npmDir = path.join(repoDir, 'npm', 'esbuild')
const version = fs.readFileSync(path.join(repoDir, 'version.txt'), 'utf8').trim()

exports.buildNativeLib = (esbuildPath) => {
  const libDir = path.join(npmDir, 'lib')
  fs.mkdirSync(libDir, { recursive: true })

  // Generate "npm/esbuild/install.js"
  childProcess.execFileSync(esbuildPath, [
    path.join(repoDir, 'lib', 'install.ts'),
    '--outfile=' + path.join(npmDir, 'install.js'),
    '--target=es2015',
    '--define:ESBUILD_VERSION=' + JSON.stringify(version),
    '--platform=node',
  ], { cwd: repoDir })

  // Generate "npm/esbuild/lib/main.js"
  childProcess.execFileSync(esbuildPath, [
    path.join(repoDir, 'lib', 'node.ts'),
    '--outfile=' + path.join(libDir, 'main.js'),
    '--bundle',
    '--target=es2015',
    '--format=cjs',
    '--define:WASM=false',
    '--define:ESBUILD_VERSION=' + JSON.stringify(version),
    '--platform=node',
  ], { cwd: repoDir })

  // Generate "npm/esbuild/lib/main.d.ts"
  const types_ts = fs.readFileSync(path.join(repoDir, 'lib', 'types.ts'), 'utf8')
  fs.writeFileSync(path.join(libDir, 'main.d.ts'), types_ts)
}

exports.buildWasmLib = async (esbuildPath) => {
  // Asynchronously start building the WebAssembly module
  const npmWasmDir = path.join(repoDir, 'npm', 'esbuild-wasm')
  const goBuildPromise = new Promise((resolve, reject) => childProcess.execFile('go',
    ['build', '-o', path.join(npmWasmDir, 'esbuild.wasm'), path.join(repoDir, 'cmd', 'esbuild')],
    { cwd: repoDir, stdio: 'inherit', env: { ...process.env, GOOS: 'js', GOARCH: 'wasm' } },
    err => err ? reject(err) : resolve()))

  const libDir = path.join(npmWasmDir, 'lib')
  const esmDir = path.join(npmWasmDir, 'esm')
  fs.mkdirSync(libDir, { recursive: true })
  fs.mkdirSync(esmDir, { recursive: true })

  // Generate "npm/esbuild-wasm/wasm_exec.js"
  const toReplace = 'global.fs = fs;';
  const GOROOT = childProcess.execFileSync('go', ['env', 'GOROOT']).toString().trim();
  let wasm_exec_js = fs.readFileSync(path.join(GOROOT, 'misc', 'wasm', 'wasm_exec.js'), 'utf8');
  let index = wasm_exec_js.indexOf(toReplace);
  if (index === -1) throw new Error(`Failed to find ${JSON.stringify(toReplace)} in Go JS shim code`);
  wasm_exec_js = wasm_exec_js.replace(toReplace, `
    global.fs = Object.assign({}, fs, {
      // Hack around a Unicode bug in node: https://github.com/nodejs/node/issues/24550
      write(fd, buf, offset, length, position, callback) {
        if (offset === 0 && length === buf.length && position === null) {
          if (fd === process.stdout.fd) {
            try {
              process.stdout.write(buf, err => err ? callback(err, 0, null) : callback(null, length, buf));
            } catch (err) {
              callback(err, 0, null);
            }
            return;
          }
          if (fd === process.stderr.fd) {
            try {
              process.stderr.write(buf, err => err ? callback(err, 0, null) : callback(null, length, buf));
            } catch (err) {
              callback(err, 0, null);
            }
            return;
          }
        }
        fs.write(fd, buf, offset, length, position, callback);
      },
    });
  `);
  fs.writeFileSync(path.join(npmWasmDir, 'wasm_exec.js'), wasm_exec_js);

  // Generate "npm/esbuild-wasm/lib/main.js"
  childProcess.execFileSync(esbuildPath, [
    path.join(repoDir, 'lib', 'node.ts'),
    '--outfile=' + path.join(libDir, 'main.js'),
    '--bundle',
    '--target=es2015',
    '--format=cjs',
    '--define:WASM=true',
    '--define:ESBUILD_VERSION=' + JSON.stringify(version),
    '--platform=node',
  ], { cwd: repoDir })

  // Generate "npm/esbuild-wasm/lib/main.d.ts" and "npm/esbuild-wasm/lib/browser.d.ts"
  const types_ts = fs.readFileSync(path.join(repoDir, 'lib', 'types.ts'), 'utf8')
  fs.writeFileSync(path.join(libDir, 'main.d.ts'), types_ts)
  fs.writeFileSync(path.join(libDir, 'browser.d.ts'), types_ts)
  fs.writeFileSync(path.join(esmDir, 'browser.d.ts'), types_ts)

  for (const minify of [false, true]) {
    const minifyFlags = minify ? ['--minify'] : []

    // Process "npm/esbuild-wasm/wasm_exec.js"
    let wasmExecCode = wasm_exec_js;
    if (minify) {
      const wasmExecMin = childProcess.execFileSync(esbuildPath, [
        '--target=es2015',
      ].concat(minifyFlags), { cwd: repoDir, input: wasmExecCode }).toString()
      const commentLines = wasmExecCode.split('\n')
      const firstNonComment = commentLines.findIndex(line => !line.startsWith('//'))
      wasmExecCode = '\n' + commentLines.slice(0, firstNonComment).concat(wasmExecMin).join('\n')
    }

    // Process "lib/worker.ts"
    const workerCode = childProcess.execFileSync(esbuildPath, [
      path.join(repoDir, 'lib', 'worker.ts'),
      '--target=es2015',
      '--define:ESBUILD_VERSION=' + JSON.stringify(version),
    ].concat(minifyFlags), { cwd: repoDir }).toString().trim()

    // Generate "npm/esbuild-wasm/lib/browser.*"
    const umdPrefix = `(exports=>{`
    const umdSuffix = `})(typeof exports==="object"?exports:(typeof self!=="undefined"?self:this).esbuild={});`
    const browserCJS = childProcess.execFileSync(esbuildPath, [
      path.join(repoDir, 'lib', 'browser.ts'),
      '--bundle',
      '--target=es2015',
      '--format=cjs',
      '--define:ESBUILD_VERSION=' + JSON.stringify(version),
      '--define:WEB_WORKER_SOURCE_CODE=' + JSON.stringify(wasmExecCode + workerCode),
      '--banner=' + umdPrefix,
      '--footer=' + umdSuffix,
    ].concat(minifyFlags), { cwd: repoDir }).toString()
    fs.writeFileSync(path.join(libDir, minify ? 'browser.min.js' : 'browser.js'), browserCJS)

    // Generate "npm/esbuild-wasm/esm/browser.min.js"
    const browserESM = childProcess.execFileSync(esbuildPath, [
      path.join(repoDir, 'lib', 'browser.ts'),
      '--bundle',
      '--target=es2017',
      '--format=esm',
      '--define:ESBUILD_VERSION=' + JSON.stringify(version),
      '--define:WEB_WORKER_SOURCE_CODE=' + JSON.stringify(wasmExecCode + workerCode),
    ].concat(minifyFlags), { cwd: repoDir }).toString()
    fs.writeFileSync(path.join(esmDir, minify ? 'browser.min.js' : 'browser.js'), browserESM)
  }

  // Generate the "exit0" stubs
  const exit0Map = {};
  const exit0Dir = path.join(__dirname, '..', 'lib', 'exit0');
  for (const entry of fs.readdirSync(exit0Dir)) {
    if (entry.endsWith('.node')) {
      const absPath = path.join(exit0Dir, entry);
      const compressed = zlib.deflateRawSync(fs.readFileSync(absPath), { level: 9 });
      exit0Map[entry] = compressed.toString('base64');
    }
  }
  fs.writeFileSync(path.join(npmWasmDir, 'exit0.js'), `
// Each of these is a native module that calls "exit(0)". This is a workaround
// for https://github.com/nodejs/node/issues/36616. These native modules are
// stored in a string both to make them smaller and to hide them from Yarn 2,
// since they make Yarn 2 unzip this package.

module.exports = ${JSON.stringify(exit0Map, null, 2)};
`);

  // Join with the asynchronous WebAssembly build
  await goBuildPromise;
}

// Writing a file atomically is important for watch mode tests since we don't
// want to read the file after it has been truncated but before the new contents
// have been written.
exports.writeFileAtomic = (where, contents) => {
  // Note: Can't use "os.tmpdir()" because that doesn't work on Windows. CI runs
  // tests on D:\ and the temporary directory is on C:\ or the other way around.
  // And apparently it's impossible to move files between C:\ and D:\ or something.
  // So we have to write the file in the same directory as the destination. This is
  // unfortunate because it will unnecessarily trigger extra watch mode rebuilds.
  // So we have to make our tests extra robust so they can still work with random
  // extra rebuilds thrown in.
  const file = path.join(path.dirname(where), '.esbuild-atomic-file-' + Math.random().toString(36).slice(2))
  fs.writeFileSync(file, contents)
  fs.renameSync(file, where)
}

exports.buildBinary = () => {
  childProcess.execFileSync('go', ['build', '-ldflags=-s -w', './cmd/esbuild'], { cwd: repoDir, stdio: 'ignore' })
  return path.join(repoDir, process.platform === 'win32' ? 'esbuild.exe' : 'esbuild')
}

exports.removeRecursiveSync = path => {
  try {
    // Strangely node doesn't have a function to remove a directory tree.
    // Using "rm -fr" will never work on Windows because the "rm" command
    // doesn't exist. Using the "rimraf" should be cross-platform and even
    // works on Windows some of the time.
    rimraf.sync(path, { disableGlob: true })
  } catch (e) {
    // Removing stuff on Windows is flaky and unreliable. Don't fail tests
    // on CI if Windows is just being a pain. Common causes of flakes include
    // random EPERM and ENOTEMPTY errors.
    //
    // The general "solution" to this is to try asking Windows to redo the
    // failing operation repeatedly until eventually giving up after a
    // timeout. But that doesn't guarantee that flakes will be fixed so we
    // just give up instead. People that want reasonable file system
    // behavior on Windows should use WSL instead.
  }
}

exports.installForTests = () => {
  // Build the "esbuild" binary and library
  const esbuildPath = exports.buildBinary()
  exports.buildNativeLib(esbuildPath)

  // Install the "esbuild" package to a temporary directory. On Windows, it's
  // sometimes randomly impossible to delete this installation directory. My
  // best guess is that this is because the esbuild process is kept alive until
  // the process exits for "buildSync" and "transformSync", and that sometimes
  // prevents Windows from deleting the directory it's in. The call in tests to
  // "rimraf.sync()" appears to hang when this happens. Other operating systems
  // don't have a problem with this. This has only been a problem on the Windows
  // VM in GitHub CI. I cannot reproduce this issue myself.
  const installDir = path.join(os.tmpdir(), 'esbuild-' + Math.random().toString(36).slice(2))
  const env = { ...process.env, ESBUILD_BIN_PATH_FOR_TESTS: esbuildPath }
  fs.mkdirSync(installDir)
  fs.writeFileSync(path.join(installDir, 'package.json'), '{}')
  childProcess.execSync(`npm pack --silent "${npmDir}"`, { cwd: installDir, stdio: 'inherit' })
  childProcess.execSync(`npm install --silent --no-audit --progress=false esbuild-${version}.tgz`, { cwd: installDir, env, stdio: 'inherit' })

  // Evaluate the code
  const ESBUILD_PACKAGE_PATH = path.join(installDir, 'node_modules', 'esbuild')
  const mod = require(ESBUILD_PACKAGE_PATH)
  mod.ESBUILD_PACKAGE_PATH = ESBUILD_PACKAGE_PATH
  return mod
}

// This is helpful for ES6 modules which don't have access to __dirname
exports.dirname = __dirname

// The main Makefile invokes this script before publishing
if (require.main === module) {
  if (process.argv.indexOf('--wasm') >= 0) {
    exports.buildWasmLib(process.argv[2])
  } else {
    exports.buildNativeLib(process.argv[2])
  }
}
<commit_msg>pass "-s -w" to go linker, removes 0.1mb (#836)<commit_after>const childProcess = require('child_process')
const rimraf = require('rimraf')
const path = require('path')
const zlib = require('zlib')
const fs = require('fs')
const os = require('os')

const repoDir = path.dirname(__dirname)
const npmDir = path.join(repoDir, 'npm', 'esbuild')
const version = fs.readFileSync(path.join(repoDir, 'version.txt'), 'utf8').trim()

exports.buildNativeLib = (esbuildPath) => {
  const libDir = path.join(npmDir, 'lib')
  fs.mkdirSync(libDir, { recursive: true })

  // Generate "npm/esbuild/install.js"
  childProcess.execFileSync(esbuildPath, [
    path.join(repoDir, 'lib', 'install.ts'),
    '--outfile=' + path.join(npmDir, 'install.js'),
    '--target=es2015',
    '--define:ESBUILD_VERSION=' + JSON.stringify(version),
    '--platform=node',
  ], { cwd: repoDir })

  // Generate "npm/esbuild/lib/main.js"
  childProcess.execFileSync(esbuildPath, [
    path.join(repoDir, 'lib', 'node.ts'),
    '--outfile=' + path.join(libDir, 'main.js'),
    '--bundle',
    '--target=es2015',
    '--format=cjs',
    '--define:WASM=false',
    '--define:ESBUILD_VERSION=' + JSON.stringify(version),
    '--platform=node',
  ], { cwd: repoDir })

  // Generate "npm/esbuild/lib/main.d.ts"
  const types_ts = fs.readFileSync(path.join(repoDir, 'lib', 'types.ts'), 'utf8')
  fs.writeFileSync(path.join(libDir, 'main.d.ts'), types_ts)
}

exports.buildWasmLib = async (esbuildPath) => {
  // Asynchronously start building the WebAssembly module
  const npmWasmDir = path.join(repoDir, 'npm', 'esbuild-wasm')
  const goBuildPromise = new Promise((resolve, reject) => childProcess.execFile('go',
    [
      'build',
      '-o', path.join(npmWasmDir, 'esbuild.wasm'),
      '-ldflags=-s -w', // This removes ~0.14mb of unnecessary WebAssembly code
      path.join(repoDir, 'cmd', 'esbuild'),
    ],
    { cwd: repoDir, stdio: 'inherit', env: { ...process.env, GOOS: 'js', GOARCH: 'wasm' } },
    err => err ? reject(err) : resolve()))

  const libDir = path.join(npmWasmDir, 'lib')
  const esmDir = path.join(npmWasmDir, 'esm')
  fs.mkdirSync(libDir, { recursive: true })
  fs.mkdirSync(esmDir, { recursive: true })

  // Generate "npm/esbuild-wasm/wasm_exec.js"
  const toReplace = 'global.fs = fs;';
  const GOROOT = childProcess.execFileSync('go', ['env', 'GOROOT']).toString().trim();
  let wasm_exec_js = fs.readFileSync(path.join(GOROOT, 'misc', 'wasm', 'wasm_exec.js'), 'utf8');
  let index = wasm_exec_js.indexOf(toReplace);
  if (index === -1) throw new Error(`Failed to find ${JSON.stringify(toReplace)} in Go JS shim code`);
  wasm_exec_js = wasm_exec_js.replace(toReplace, `
    global.fs = Object.assign({}, fs, {
      // Hack around a Unicode bug in node: https://github.com/nodejs/node/issues/24550
      write(fd, buf, offset, length, position, callback) {
        if (offset === 0 && length === buf.length && position === null) {
          if (fd === process.stdout.fd) {
            try {
              process.stdout.write(buf, err => err ? callback(err, 0, null) : callback(null, length, buf));
            } catch (err) {
              callback(err, 0, null);
            }
            return;
          }
          if (fd === process.stderr.fd) {
            try {
              process.stderr.write(buf, err => err ? callback(err, 0, null) : callback(null, length, buf));
            } catch (err) {
              callback(err, 0, null);
            }
            return;
          }
        }
        fs.write(fd, buf, offset, length, position, callback);
      },
    });
  `);
  fs.writeFileSync(path.join(npmWasmDir, 'wasm_exec.js'), wasm_exec_js);

  // Generate "npm/esbuild-wasm/lib/main.js"
  childProcess.execFileSync(esbuildPath, [
    path.join(repoDir, 'lib', 'node.ts'),
    '--outfile=' + path.join(libDir, 'main.js'),
    '--bundle',
    '--target=es2015',
    '--format=cjs',
    '--define:WASM=true',
    '--define:ESBUILD_VERSION=' + JSON.stringify(version),
    '--platform=node',
  ], { cwd: repoDir })

  // Generate "npm/esbuild-wasm/lib/main.d.ts" and "npm/esbuild-wasm/lib/browser.d.ts"
  const types_ts = fs.readFileSync(path.join(repoDir, 'lib', 'types.ts'), 'utf8')
  fs.writeFileSync(path.join(libDir, 'main.d.ts'), types_ts)
  fs.writeFileSync(path.join(libDir, 'browser.d.ts'), types_ts)
  fs.writeFileSync(path.join(esmDir, 'browser.d.ts'), types_ts)

  for (const minify of [false, true]) {
    const minifyFlags = minify ? ['--minify'] : []

    // Process "npm/esbuild-wasm/wasm_exec.js"
    let wasmExecCode = wasm_exec_js;
    if (minify) {
      const wasmExecMin = childProcess.execFileSync(esbuildPath, [
        '--target=es2015',
      ].concat(minifyFlags), { cwd: repoDir, input: wasmExecCode }).toString()
      const commentLines = wasmExecCode.split('\n')
      const firstNonComment = commentLines.findIndex(line => !line.startsWith('//'))
      wasmExecCode = '\n' + commentLines.slice(0, firstNonComment).concat(wasmExecMin).join('\n')
    }

    // Process "lib/worker.ts"
    const workerCode = childProcess.execFileSync(esbuildPath, [
      path.join(repoDir, 'lib', 'worker.ts'),
      '--target=es2015',
      '--define:ESBUILD_VERSION=' + JSON.stringify(version),
    ].concat(minifyFlags), { cwd: repoDir }).toString().trim()

    // Generate "npm/esbuild-wasm/lib/browser.*"
    const umdPrefix = `(exports=>{`
    const umdSuffix = `})(typeof exports==="object"?exports:(typeof self!=="undefined"?self:this).esbuild={});`
    const browserCJS = childProcess.execFileSync(esbuildPath, [
      path.join(repoDir, 'lib', 'browser.ts'),
      '--bundle',
      '--target=es2015',
      '--format=cjs',
      '--define:ESBUILD_VERSION=' + JSON.stringify(version),
      '--define:WEB_WORKER_SOURCE_CODE=' + JSON.stringify(wasmExecCode + workerCode),
      '--banner=' + umdPrefix,
      '--footer=' + umdSuffix,
    ].concat(minifyFlags), { cwd: repoDir }).toString()
    fs.writeFileSync(path.join(libDir, minify ? 'browser.min.js' : 'browser.js'), browserCJS)

    // Generate "npm/esbuild-wasm/esm/browser.min.js"
    const browserESM = childProcess.execFileSync(esbuildPath, [
      path.join(repoDir, 'lib', 'browser.ts'),
      '--bundle',
      '--target=es2017',
      '--format=esm',
      '--define:ESBUILD_VERSION=' + JSON.stringify(version),
      '--define:WEB_WORKER_SOURCE_CODE=' + JSON.stringify(wasmExecCode + workerCode),
    ].concat(minifyFlags), { cwd: repoDir }).toString()
    fs.writeFileSync(path.join(esmDir, minify ? 'browser.min.js' : 'browser.js'), browserESM)
  }

  // Generate the "exit0" stubs
  const exit0Map = {};
  const exit0Dir = path.join(__dirname, '..', 'lib', 'exit0');
  for (const entry of fs.readdirSync(exit0Dir)) {
    if (entry.endsWith('.node')) {
      const absPath = path.join(exit0Dir, entry);
      const compressed = zlib.deflateRawSync(fs.readFileSync(absPath), { level: 9 });
      exit0Map[entry] = compressed.toString('base64');
    }
  }
  fs.writeFileSync(path.join(npmWasmDir, 'exit0.js'), `
// Each of these is a native module that calls "exit(0)". This is a workaround
// for https://github.com/nodejs/node/issues/36616. These native modules are
// stored in a string both to make them smaller and to hide them from Yarn 2,
// since they make Yarn 2 unzip this package.

module.exports = ${JSON.stringify(exit0Map, null, 2)};
`);

  // Join with the asynchronous WebAssembly build
  await goBuildPromise;
}

// Writing a file atomically is important for watch mode tests since we don't
// want to read the file after it has been truncated but before the new contents
// have been written.
exports.writeFileAtomic = (where, contents) => {
  // Note: Can't use "os.tmpdir()" because that doesn't work on Windows. CI runs
  // tests on D:\ and the temporary directory is on C:\ or the other way around.
  // And apparently it's impossible to move files between C:\ and D:\ or something.
  // So we have to write the file in the same directory as the destination. This is
  // unfortunate because it will unnecessarily trigger extra watch mode rebuilds.
  // So we have to make our tests extra robust so they can still work with random
  // extra rebuilds thrown in.
  const file = path.join(path.dirname(where), '.esbuild-atomic-file-' + Math.random().toString(36).slice(2))
  fs.writeFileSync(file, contents)
  fs.renameSync(file, where)
}

exports.buildBinary = () => {
  childProcess.execFileSync('go', ['build', '-ldflags=-s -w', './cmd/esbuild'], { cwd: repoDir, stdio: 'ignore' })
  return path.join(repoDir, process.platform === 'win32' ? 'esbuild.exe' : 'esbuild')
}

exports.removeRecursiveSync = path => {
  try {
    // Strangely node doesn't have a function to remove a directory tree.
    // Using "rm -fr" will never work on Windows because the "rm" command
    // doesn't exist. Using the "rimraf" should be cross-platform and even
    // works on Windows some of the time.
    rimraf.sync(path, { disableGlob: true })
  } catch (e) {
    // Removing stuff on Windows is flaky and unreliable. Don't fail tests
    // on CI if Windows is just being a pain. Common causes of flakes include
    // random EPERM and ENOTEMPTY errors.
    //
    // The general "solution" to this is to try asking Windows to redo the
    // failing operation repeatedly until eventually giving up after a
    // timeout. But that doesn't guarantee that flakes will be fixed so we
    // just give up instead. People that want reasonable file system
    // behavior on Windows should use WSL instead.
  }
}

exports.installForTests = () => {
  // Build the "esbuild" binary and library
  const esbuildPath = exports.buildBinary()
  exports.buildNativeLib(esbuildPath)

  // Install the "esbuild" package to a temporary directory. On Windows, it's
  // sometimes randomly impossible to delete this installation directory. My
  // best guess is that this is because the esbuild process is kept alive until
  // the process exits for "buildSync" and "transformSync", and that sometimes
  // prevents Windows from deleting the directory it's in. The call in tests to
  // "rimraf.sync()" appears to hang when this happens. Other operating systems
  // don't have a problem with this. This has only been a problem on the Windows
  // VM in GitHub CI. I cannot reproduce this issue myself.
  const installDir = path.join(os.tmpdir(), 'esbuild-' + Math.random().toString(36).slice(2))
  const env = { ...process.env, ESBUILD_BIN_PATH_FOR_TESTS: esbuildPath }
  fs.mkdirSync(installDir)
  fs.writeFileSync(path.join(installDir, 'package.json'), '{}')
  childProcess.execSync(`npm pack --silent "${npmDir}"`, { cwd: installDir, stdio: 'inherit' })
  childProcess.execSync(`npm install --silent --no-audit --progress=false esbuild-${version}.tgz`, { cwd: installDir, env, stdio: 'inherit' })

  // Evaluate the code
  const ESBUILD_PACKAGE_PATH = path.join(installDir, 'node_modules', 'esbuild')
  const mod = require(ESBUILD_PACKAGE_PATH)
  mod.ESBUILD_PACKAGE_PATH = ESBUILD_PACKAGE_PATH
  return mod
}

// This is helpful for ES6 modules which don't have access to __dirname
exports.dirname = __dirname

// The main Makefile invokes this script before publishing
if (require.main === module) {
  if (process.argv.indexOf('--wasm') >= 0) {
    exports.buildWasmLib(process.argv[2])
  } else {
    exports.buildNativeLib(process.argv[2])
  }
}
<|endoftext|>


<commit_before>var fs = require('fs');
var os = require('os');
var spawn = require('child_process').spawn;
var path = require('path');
var request = require('request');

var PLATFORM = os.platform();
var ROOT = process.cwd();
var ARCH = os.arch();
var URL = 'http://cide.cc:8080/webrtc/';
var NODEVER = process.version.split('.');

NODEVER[2] = 'x';
NODEVER = NODEVER.join('.');

URL += 'webrtc-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node';

function build() {
  console.log('Building module...');

  var nodegyp = path.resolve(ROOT, 'node_modules', 'node-gyp', 'bin', 'node-gyp.js');

  var res = spawn('node', [ nodegyp, 'rebuild' ], {
    cwd: ROOT,
    env: process.env,
    stdio: 'inherit',
  });

  res.on('error', function(error) {
    var res = spawn('iojs', [ nodegyp, 'rebuild' ], {
      cwd: ROOT,
      env: process.env,
      stdio: 'inherit',
    });
  });
}

function test() {
  console.log('Loading module...');

  try {
    var WebRTC = require(path.resolve(ROOT, 'build', 'Release', 'webrtc.node'));

    console.log('Done! :)');
  } catch (ignored) {
    if (PLATFORM == 'win32') {
      throw new Error('prebuilt module not working. "set BUILD_WEBRTC=true" and rerun "npm install" to begin to build from source.');
    } else {
      throw new Error('prebuilt module not working. "export BUILD_WEBRTC=true" and rerun "npm install" to begin to build from source.');
    }

    console.log('Install Failed! :(');
  }
}

if (process.env['BUILD_WEBRTC'] == 'true') {
  return build();
}

console.log('Downloading module...');

if (!fs.existsSync(path.resolve(ROOT, 'build', 'Release'))) {
  if (!fs.existsSync(path.resolve(ROOT, 'build'))) {
    fs.mkdirSync(path.resolve(ROOT, 'build'));
  }

  fs.mkdirSync(path.resolve(ROOT, 'build', 'Release'));
}

request.get(URL, function (error, response, body) {
  if (!error && response.statusCode == 200) {
    setTimeout(test, 200);
  } else {
    if (os.platform() == 'win32') {
      throw new Error('prebuilt module not found. "set BUILD_WEBRTC=true" and rerun "npm install" to begin to build from source.');
    } else {
      throw new Error('prebuilt module not found. "export BUILD_WEBRTC=true" and rerun "npm install" to begin to build from source.');
    }

    process.exit(1);
  }
}).pipe(fs.createWriteStream(path.resolve(ROOT, 'build', 'Release', 'webrtc.node')));
<commit_msg>Update install<commit_after>var fs = require('fs');
var os = require('os');
var spawn = require('child_process').spawn;
var path = require('path');
var request = require('request');

var PLATFORM = os.platform();
var ROOT = process.cwd();
var ARCH = os.arch();
var URL = 'http://cide.cc:8080/webrtc/';
var NODEVER = process.version.split('.');

NODEVER[2] = 'x';
NODEVER = NODEVER.join('.');

URL += 'webrtc-' + PLATFORM + '-' + ARCH + '-' + NODEVER + '.node';

function build() {
  console.log('Building module...');

  var nodegyp = path.resolve(ROOT, 'node_modules', 'node-gyp', 'bin', 'node-gyp.js');

  var res = spawn('node', [ nodegyp, 'rebuild' ], {
    cwd: ROOT,
    env: process.env,
    stdio: 'inherit',
  });

  res.on('error', function(error) {
    var res = spawn('iojs', [ nodegyp, 'rebuild' ], {
      cwd: ROOT,
      env: process.env,
      stdio: 'inherit',
    });
  });
}

function test() {
  console.log('Loading module...');

  try {
    var WebRTC = require(path.resolve(ROOT, 'build', 'Release', 'webrtc.node'));

    console.log('Done! :)');
  } catch (ignored) {
    if (PLATFORM == 'win32') {
      throw new Error('prebuilt module not working. See the instructions from https://github.com/vmolsa/webrtc-native#build-from-source for building module from source.');
    } else {
      throw new Error('prebuilt module not working. See the instructions from https://github.com/vmolsa/webrtc-native#build-from-source for building module from source.');
    }

    console.log('Install Failed! :(');
  }
}

if (process.env['BUILD_WEBRTC'] == 'true') {
  return build();
}

console.log('Downloading module...');

if (!fs.existsSync(path.resolve(ROOT, 'build', 'Release'))) {
  if (!fs.existsSync(path.resolve(ROOT, 'build'))) {
    fs.mkdirSync(path.resolve(ROOT, 'build'));
  }

  fs.mkdirSync(path.resolve(ROOT, 'build', 'Release'));
}

request.get(URL, function (error, response, body) {
  if (!error && response.statusCode == 200) {
    setTimeout(test, 200);
  } else {
    if (os.platform() == 'win32') {
      throw new Error('prebuilt module not found. See the instructions from https://github.com/vmolsa/webrtc-native#build-from-source for building module from source.');
    } else {
      throw new Error('prebuilt module not found. See the instructions from https://github.com/vmolsa/webrtc-native#build-from-source for building module from source.');
    }

    process.exit(1);
  }
}).pipe(fs.createWriteStream(path.resolve(ROOT, 'build', 'Release', 'webrtc.node')));
<|endoftext|>


<commit_before>const fs = require( 'fs' );
const path = require( 'path' );

const DEFAULT_CONFIG = {
    extends: 'kokarn'
};
const DEFAULT_TEST_COMMAND = 'eslint *.js';
const DEFAULT_ENGINE = '^6.9.4';
const PACKAGE_PATH = path.join( __dirname, '../../../', 'package.json' );

const packageData = JSON.parse( fs.readFileSync( PACKAGE_PATH, 'utf8' ) );

if( !packageData.scripts ){
    packageData.scripts = {
        pretest: DEFAULT_TEST_COMMAND
    };
} else if ( packageData.scripts && !packageData.scripts.pretest ){
    packageData.scripts.pretest = DEFAULT_TEST_COMMAND;
}

if ( !packageData.engines ){
    packageData.engines = {
        node: DEFAULT_ENGINE
    };
}

packageData.eslintConfig = DEFAULT_CONFIG;

fs.writeFileSync( PACKAGE_PATH, JSON.stringify( packageData, null, 2 ) );
<commit_msg>Be a bit more cleaver when we run install<commit_after>const fs = require( 'fs' );
const path = require( 'path' );

const DEFAULT_CONFIG = {
    extends: 'kokarn'
};
const DEFAULT_TEST_COMMAND = 'eslint *.js';
const DEFAULT_ENGINE = '^6.9.4';
const PACKAGE_PATH = path.join( __dirname, '../../../', 'package.json' );

try {
    const packageData = JSON.parse( fs.readFileSync( PACKAGE_PATH, 'utf8' ) );
} catch ( error ) {
    console.log( `Failed to load package.json in ${ PACKAGE_PATH }, skipping setup` );
    process.exit( 0 );
}

if( !packageData.scripts ){
    packageData.scripts = {
        pretest: DEFAULT_TEST_COMMAND
    };
} else if ( packageData.scripts && !packageData.scripts.pretest ){
    packageData.scripts.pretest = DEFAULT_TEST_COMMAND;
}

if ( !packageData.engines ){
    packageData.engines = {
        node: DEFAULT_ENGINE
    };
}

packageData.eslintConfig = DEFAULT_CONFIG;

fs.writeFileSync( PACKAGE_PATH, JSON.stringify( packageData, null, 2 ) );
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var googleapis = require('googleapis');
var qs = require('querystring');
var request = require('request');
var async = require('async');
var httpStatus = require('http-status');
var userAuth = require('./user-auth.js');
var config = require('../config.js');
var OAuth2 = googleapis.auth.OAuth2;
var googleKeys = require('../config.js').googleKeys;

// google drive specific constants
var ROOT_URL = 'https://www.googleapis.com/';
var DRIVE_API_PATH = 'upload/drive/v2/files';
var DRIVE_ABOUT_PATH = 'drive/v2/about';

function createOauth2Client(tokens) {
  var oauth2Client = new OAuth2(googleKeys.clientId, googleKeys.clientSecret, googleKeys.redirectUri);
  if (arguments.length === 1) {
    oauth2Client.credentials = tokens;
  }

  return oauth2Client;
}

function constructUrl(root, path, params) {
  var paramsString = '';
  if (params) {
    paramsString = '?' + qs.stringify(params);
  }
  path = (path.charAt(0) === '/') ? path.substr(1) : path;
  return root + path + paramsString;
}

function getAvailableCapacity(accessToken, callback) {
  var options = {
    url: constructUrl(ROOT_URL, DRIVE_ABOUT_PATH, null),
    method: 'GET',
    headers: {
      'Authorization': 'Bearer ' + accessToken
    },
  };

  request(options, function (err, res, test) {
    // for some reason it recieves unparsed res.body
    var body = JSON.parse(res.body);

    if (err) {
      console.error('request for capacity error', err);
      return callback(err, null);
    }

    if (res.statusCode !== httpStatus.OK) {
      console.error('request error body: ', body);
      var errorMessage = 'Cannot retrieve Google Drive capacity: ' +
                          body.error.code + ' ' +
                          body.error.messsage;
      return callback(new Error(errorMessage), null);
    }

    var totalQuota = parseInt(body.quotaBytesTotal, 10);
    var usedQuota = parseInt(body.quotaBytesUsedAggregate, 10);
    callback(null, totalQuota - usedQuota);
  });
}

// returns id of the folder
function createFolder(accessToken, callback) {

  var oauth2Client = createOauth2Client();

  oauth2Client.setCredentials({
    access_token: accessToken
  });

  var folder = {
    title: 'Wix Send Files',
    mimeType: 'application/vnd.google-apps.folder'
  };

  googleapis.discover('drive', 'v2').execute(function (err, client) {
    if (err) {
      return callback(err, null);
    }
    client
      .drive.files.insert(folder)
      .withAuthClient(oauth2Client)
      .execute(function (err, result) {
        if (err) {
          return callback(err, null);
        }

        callback(null, result.id);
      });
  });
}

function getUploadUrl(file, folderId, accessToken, callback) {
  var fileDesc = {
    title: file.originalname,
    mimeType: file.mimetype,
    parents: [{
      kind: 'drive#fileLink',
      id: folderId
    }]
  };

  var params = { uploadType: 'resumable' };

  var options = {
    url: constructUrl(ROOT_URL, DRIVE_API_PATH, params),
    method: 'POST',
    headers: {
      'X-Upload-Content-Type': file.mimetype,
      'X-Upload-Content-Length': file.size,
      'Authorization': 'Bearer ' + accessToken
    },
    body: fileDesc,
    json: true
  };

  request(options, function (err, res) {

    var body = res.body;

    if (err) {
      console.error('request error', err);
      return callback(err, null);
    }

    if (res.statusCode !== httpStatus.OK) {
      console.error('request error body: ', body);
      var errorMessage = 'Cannot retrieve Google Drive upload URL: ' +
                          body.error.code + ' ' +
                          body.error.messsage;
      return callback(new Error(errorMessage), null);
    }

    var uploadUrl = res.headers.location;
    callback(null, uploadUrl);
  });
}

function getStartUploadFrom(range) {
  var startFrom = 0;
  if (range) {
    startFrom = parseInt(range.split('-')[1], 10) + 1;
  }
  return startFrom;
}

function requestUploadStatus(file, uploadUrl, accessToken, waitFor, callback) {
  var options = {
    url: uploadUrl,
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + accessToken,
      'Content-Range': 'bytes */' + file.size
    }
  };

  console.log('requesting upload status, waiting for ' + waitFor);

  setTimeout(function () {
    request(options, function (err, res) {

      if (err) {
        console.error('requestUploadStatus error:', err);
        return callback(err, 0, res.statusCode);
      }
      console.log('upload status headers: ', res.headers);
      var rangeHeader = res.headers['range'];

      if (res.statusCode === 308 && rangeHeader) { // Resume Incomplete
        callback(null, getStartUploadFrom(rangeHeader), res.statusCode);
      } else {
        // restart upload from zero
        callback(null, 0, res.statusCode);
      }
    });
  }, waitFor);
}

function recoverUpload(file, uploadUrl, accessToken, callback) {
  var watingTimes = [0, 1000, 2000, 4000, 8000, 16000];
  var startFrom = 0;
  var requestCount = 0;
  var statusCode = httpStatus.SERVICE_UNAVAILABLE;
  var isError = false;
  async.whilst(
    function () {
      return statusCode !== 308 && requestCount < watingTimes.length && !isError;
    },
    function (callback) {
      requestUploadStatus(file, uploadUrl, accessToken, watingTimes[requestCount], function (err, restartFrom, newStatusCode) {
        if (err) {
          isError = true;
          return callback(err);
        }
        startFrom = restartFrom;
        statusCode = newStatusCode;
        requestCount++;
        callback(null);
      });
    },
    function (err) {
      if (err) {
        return callback(err, 0);
      }
      if (statusCode === 308) {
        callback(null, startFrom);
      } else {
        callback(new Error('cannot recover upload to Google Drive'), 0);
      }
    }
  );
}

// returns error, response body, and a boolean of whether it should be recovered
function uploadFile(file, uploadUrl, accessToken, start, callback) {

  var options = {
    url: uploadUrl,
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + accessToken,
    }
  };

  var readStream;
  if (start > 0) { // don't start from zeros byte
    readStream = fs.createReadStream(file.path, { start: start, end: file.size - 1 });
    options.headers['Content-Range'] = 'bytes ' + start + '-' + (file.size - 1) + '/' + file.size - 1;
  } else { // start from zeros byte
    readStream = fs.createReadStream(file.path);
  }

  readStream.on('open', function () {
    readStream.pipe(request(options, function (err, res) {
      var body = res.body;

      if (err) {
        console.error('request for upload to Google Drive error: ', err);
        return callback(err, null, false); // might also set to true, should monitor this
      }

      if (res.statusCode === httpStatus.OK || res.statusCode === httpStatus.CREATED) {
        return callback(null, body, false);
      }

      console.log('google uploaded status code: ', res.statusCode);

      // might be an issue with 308 status code, hasn't been able to replicate

      var recoverWhenStatus = [500, 501, 502, 503];

      var shouldRecover = recoverWhenStatus.indexOf(res.statusCode) > -1;

      if (shouldRecover) {
        callback(new Error('upload to Google Drive was interrupted'), null, true);
      } else {
        callback(new Error('cannot upload to google drive'), null, false);
      }
    }));
  });

  readStream.on('error', function (err) {
    callback(err, null, false);
  });
}

// returns error and parsed result of insertion
function insertFile(file, folderId, accessToken, callback) {

  console.log('insering file to google');
  getUploadUrl(file, folderId, accessToken, function (err, uploadUrl) {
    if (err) {
      console.error('google request for upload url error: ', err);
      return callback(err, null);
    }

    uploadFile(file, uploadUrl, accessToken, 0, function (err, result, isRecoverable) {

      if (result) {
        return callback(null, result);
      }

      if (!isRecoverable) {
        console.error('cannot recover on the first try');
        return callback(new Error('upload to Google Drive is not recoverable'), null);
      }

      console.log('recovering google upload');

      // otherwise try to recover
      var shouldRecover = true;
      var numRecoversTries = 0;
      var responseBody = result;
      async.whilst(
        function () {
          return shouldRecover && numRecoversTries < config.MAX_UPLOAD_RECOVERS;
        },
        function (callback) {
          recoverUpload(file, uploadUrl, accessToken, function (err, startUploadFrom) {
            if (err) {
              return callback(err);
            }
            uploadFile(file, uploadUrl, accessToken, startUploadFrom, function (err, result, isRecoverable) {
              responseBody = result;
              shouldRecover = isRecoverable;
              numRecoversTries++;
              callback(null);
            });
          });
        },
        function (err) {
          if (err) {
            console.error('google recover upload error: ', err);
            return callback(err, null);
          }

          if (responseBody) {
            console.log('successfully recovered google upload: ', responseBody);
            callback(null, responseBody);
          } else if (shouldRecover) {
            console.error('exceeded number of recovers to google');
            callback(new Error('cannot upload to google drive, exceeded number of recovers'), null);
          } else {
            callback(new Error('cannot upload to google drive'), null);
          }
        }
      );
    });
  });
}

module.exports = {
  insertFile: insertFile,
  getAvailableCapacity: getAvailableCapacity,
  createFolder: createFolder,
  createOauth2Client: createOauth2Client
};
<commit_msg>removes dummy variable<commit_after>'use strict';

var fs = require('fs');
var googleapis = require('googleapis');
var qs = require('querystring');
var request = require('request');
var async = require('async');
var httpStatus = require('http-status');
var userAuth = require('./user-auth.js');
var config = require('../config.js');
var OAuth2 = googleapis.auth.OAuth2;
var googleKeys = require('../config.js').googleKeys;

// google drive specific constants
var ROOT_URL = 'https://www.googleapis.com/';
var DRIVE_API_PATH = 'upload/drive/v2/files';
var DRIVE_ABOUT_PATH = 'drive/v2/about';

function createOauth2Client(tokens) {
  var oauth2Client = new OAuth2(googleKeys.clientId, googleKeys.clientSecret, googleKeys.redirectUri);
  if (arguments.length === 1) {
    oauth2Client.credentials = tokens;
  }

  return oauth2Client;
}

function constructUrl(root, path, params) {
  var paramsString = '';
  if (params) {
    paramsString = '?' + qs.stringify(params);
  }
  path = (path.charAt(0) === '/') ? path.substr(1) : path;
  return root + path + paramsString;
}

function getAvailableCapacity(accessToken, callback) {
  var options = {
    url: constructUrl(ROOT_URL, DRIVE_ABOUT_PATH, null),
    method: 'GET',
    headers: {
      'Authorization': 'Bearer ' + accessToken
    },
  };

  request(options, function (err, res) {
    // for some reason it recieves unparsed res.body
    var body = JSON.parse(res.body);

    if (err) {
      console.error('request for capacity error', err);
      return callback(err, null);
    }

    if (res.statusCode !== httpStatus.OK) {
      console.error('request error body: ', body);
      var errorMessage = 'Cannot retrieve Google Drive capacity: ' +
                          body.error.code + ' ' +
                          body.error.messsage;
      return callback(new Error(errorMessage), null);
    }

    var totalQuota = parseInt(body.quotaBytesTotal, 10);
    var usedQuota = parseInt(body.quotaBytesUsedAggregate, 10);
    callback(null, totalQuota - usedQuota);
  });
}

// returns id of the folder
function createFolder(accessToken, callback) {

  var oauth2Client = createOauth2Client();

  oauth2Client.setCredentials({
    access_token: accessToken
  });

  var folder = {
    title: 'Wix Send Files',
    mimeType: 'application/vnd.google-apps.folder'
  };

  googleapis.discover('drive', 'v2').execute(function (err, client) {
    if (err) {
      return callback(err, null);
    }
    client
      .drive.files.insert(folder)
      .withAuthClient(oauth2Client)
      .execute(function (err, result) {
        if (err) {
          return callback(err, null);
        }

        callback(null, result.id);
      });
  });
}

function getUploadUrl(file, folderId, accessToken, callback) {
  var fileDesc = {
    title: file.originalname,
    mimeType: file.mimetype,
    parents: [{
      kind: 'drive#fileLink',
      id: folderId
    }]
  };

  var params = { uploadType: 'resumable' };

  var options = {
    url: constructUrl(ROOT_URL, DRIVE_API_PATH, params),
    method: 'POST',
    headers: {
      'X-Upload-Content-Type': file.mimetype,
      'X-Upload-Content-Length': file.size,
      'Authorization': 'Bearer ' + accessToken
    },
    body: fileDesc,
    json: true
  };

  request(options, function (err, res) {

    var body = res.body;

    if (err) {
      console.error('request error', err);
      return callback(err, null);
    }

    if (res.statusCode !== httpStatus.OK) {
      console.error('request error body: ', body);
      var errorMessage = 'Cannot retrieve Google Drive upload URL: ' +
                          body.error.code + ' ' +
                          body.error.messsage;
      return callback(new Error(errorMessage), null);
    }

    var uploadUrl = res.headers.location;
    callback(null, uploadUrl);
  });
}

function getStartUploadFrom(range) {
  var startFrom = 0;
  if (range) {
    startFrom = parseInt(range.split('-')[1], 10) + 1;
  }
  return startFrom;
}

function requestUploadStatus(file, uploadUrl, accessToken, waitFor, callback) {
  var options = {
    url: uploadUrl,
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + accessToken,
      'Content-Range': 'bytes */' + file.size
    }
  };

  console.log('requesting upload status, waiting for ' + waitFor);

  setTimeout(function () {
    request(options, function (err, res) {

      if (err) {
        console.error('requestUploadStatus error:', err);
        return callback(err, 0, res.statusCode);
      }
      console.log('upload status headers: ', res.headers);
      var rangeHeader = res.headers['range'];

      if (res.statusCode === 308 && rangeHeader) { // Resume Incomplete
        callback(null, getStartUploadFrom(rangeHeader), res.statusCode);
      } else {
        // restart upload from zero
        callback(null, 0, res.statusCode);
      }
    });
  }, waitFor);
}

function recoverUpload(file, uploadUrl, accessToken, callback) {
  var watingTimes = [0, 1000, 2000, 4000, 8000, 16000];
  var startFrom = 0;
  var requestCount = 0;
  var statusCode = httpStatus.SERVICE_UNAVAILABLE;
  var isError = false;
  async.whilst(
    function () {
      return statusCode !== 308 && requestCount < watingTimes.length && !isError;
    },
    function (callback) {
      requestUploadStatus(file, uploadUrl, accessToken, watingTimes[requestCount], function (err, restartFrom, newStatusCode) {
        if (err) {
          isError = true;
          return callback(err);
        }
        startFrom = restartFrom;
        statusCode = newStatusCode;
        requestCount++;
        callback(null);
      });
    },
    function (err) {
      if (err) {
        return callback(err, 0);
      }
      if (statusCode === 308) {
        callback(null, startFrom);
      } else {
        callback(new Error('cannot recover upload to Google Drive'), 0);
      }
    }
  );
}

// returns error, response body, and a boolean of whether it should be recovered
function uploadFile(file, uploadUrl, accessToken, start, callback) {

  var options = {
    url: uploadUrl,
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer ' + accessToken,
    }
  };

  var readStream;
  if (start > 0) { // don't start from zeros byte
    readStream = fs.createReadStream(file.path, { start: start, end: file.size - 1 });
    options.headers['Content-Range'] = 'bytes ' + start + '-' + (file.size - 1) + '/' + file.size - 1;
  } else { // start from zeros byte
    readStream = fs.createReadStream(file.path);
  }

  readStream.on('open', function () {
    readStream.pipe(request(options, function (err, res) {
      var body = res.body;

      if (err) {
        console.error('request for upload to Google Drive error: ', err);
        return callback(err, null, false); // might also set to true, should monitor this
      }

      if (res.statusCode === httpStatus.OK || res.statusCode === httpStatus.CREATED) {
        return callback(null, body, false);
      }

      console.log('google uploaded status code: ', res.statusCode);

      // might be an issue with 308 status code, hasn't been able to replicate

      var recoverWhenStatus = [500, 501, 502, 503];

      var shouldRecover = recoverWhenStatus.indexOf(res.statusCode) > -1;

      if (shouldRecover) {
        callback(new Error('upload to Google Drive was interrupted'), null, true);
      } else {
        callback(new Error('cannot upload to google drive'), null, false);
      }
    }));
  });

  readStream.on('error', function (err) {
    callback(err, null, false);
  });
}

// returns error and parsed result of insertion
function insertFile(file, folderId, accessToken, callback) {

  console.log('insering file to google');
  getUploadUrl(file, folderId, accessToken, function (err, uploadUrl) {
    if (err) {
      console.error('google request for upload url error: ', err);
      return callback(err, null);
    }

    uploadFile(file, uploadUrl, accessToken, 0, function (err, result, isRecoverable) {

      if (result) {
        return callback(null, result);
      }

      if (!isRecoverable) {
        console.error('cannot recover on the first try');
        return callback(new Error('upload to Google Drive is not recoverable'), null);
      }

      console.log('recovering google upload');

      // otherwise try to recover
      var shouldRecover = true;
      var numRecoversTries = 0;
      var responseBody = result;
      async.whilst(
        function () {
          return shouldRecover && numRecoversTries < config.MAX_UPLOAD_RECOVERS;
        },
        function (callback) {
          recoverUpload(file, uploadUrl, accessToken, function (err, startUploadFrom) {
            if (err) {
              return callback(err);
            }
            uploadFile(file, uploadUrl, accessToken, startUploadFrom, function (err, result, isRecoverable) {
              responseBody = result;
              shouldRecover = isRecoverable;
              numRecoversTries++;
              callback(null);
            });
          });
        },
        function (err) {
          if (err) {
            console.error('google recover upload error: ', err);
            return callback(err, null);
          }

          if (responseBody) {
            console.log('successfully recovered google upload: ', responseBody);
            callback(null, responseBody);
          } else if (shouldRecover) {
            console.error('exceeded number of recovers to google');
            callback(new Error('cannot upload to google drive, exceeded number of recovers'), null);
          } else {
            callback(new Error('cannot upload to google drive'), null);
          }
        }
      );
    });
  });
}

module.exports = {
  insertFile: insertFile,
  getAvailableCapacity: getAvailableCapacity,
  createFolder: createFolder,
  createOauth2Client: createOauth2Client
};
<|endoftext|>


<commit_before>/**
  Transcoder Configuration File
*/
var transcoderOptions = {
  video: {
    active: 'iphone',
    iphone: {
      width: '640',
      height: '640',
      format: 'mp4',
      videoBitrate: '1200000',
      videoCodec: 'libx264',
      audioBitrate: '128000',
      audioCodec: 'acc',
      extension: 'mp4',
      extra: []
    }
  },
  audio: {
    active: 'oga',
    oga: {
      format: 'ogg',
      audioBitrate: '128000',
      audioCodec: 'libvorbis',
      extension: 'oga',
      extra: []
    }
  },
  image: {
    active: 'png',
    png: {
      width: '800',
      height: '800',
      format: 'png',
      extension: 'png'
    }
  }
};

var VideoPresets = {
  'ppt':{
    width: '720',
    height: '720',
    format: 'mp4',
    videoBitrate: '700000',
    videoCodec: 'libx264',
    skipAudio: true,
    default: 'mp4',
    extra: []
  },
  '1080p':{
    width: '1080',
    height: '1080',
    format: 'mp4',
    videoBitrate: '1850k',
    videoCodec: 'libx264',
    audioBitrate: '128000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  },
  '720p':{
    width: '720',
    height: '720',
    format: 'mp4',
    videoBitrate: '1400k',
    videoCodec: 'libx264',
    audioBitrate: '128000',
    audioCodec: 'acc',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    default: 'mp4',
    extra: []
  },
  '480p':{
    width: '480',
    height: '480',
    format: 'mp4',
    videoBitrate: '750k',
    videoCodec: 'libx264',
    audioBitrate: '96000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  },
  '360p':{
    width: '360',
    height: '360',
    format: 'mp4',
    videoBitrate: '450k',
    videoCodec: 'libx264',
    audioBitrate: '80000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  },
  '320p':{
    width: '320',
    height: '320',
    format: 'mp4',
    videoBitrate: '250k',
    videoCodec: 'libx264',
    audioBitrate: '60000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  },
  '240p':{
    width: '240',
    height: '240',
    format: 'mp4',
    videoBitrate: '250k',
    videoCodec: 'libx264',
    audioBitrate: '60000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 22,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  }
}

var ImagePresets = {
  '1080p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '1080',
    height: '1080',
    format: 'jpg'
  },
  '720p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '720',
    height: '720',
    format: 'jpg'
  },
  '480p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '480',
    height: '480',
    format: 'jpg'
  },
  '360p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '360',
    height: '360',
    format: 'jpg'
  },
  '320p':{
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '320',
    height: '320',
    format: 'jpg',
  },
  '240p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '720',
    height: '720',
    format: 'jpg'
  }
}

var AudioPresets = {
  'high': {
    audioBitrate: '128000',
    audioCodec: 'libmp3lame',
    format: 'mp3',
    default: 'mp3',
  },
}

module.exports = {
  video: VideoPresets,
  image: ImagePresets,
  audio: AudioPresets,
};

<commit_msg>upgraded resolution for ppt<commit_after>/**
  Transcoder Configuration File
*/
var transcoderOptions = {
  video: {
    active: 'iphone',
    iphone: {
      width: '640',
      height: '640',
      format: 'mp4',
      videoBitrate: '1200000',
      videoCodec: 'libx264',
      audioBitrate: '128000',
      audioCodec: 'acc',
      extension: 'mp4',
      extra: []
    }
  },
  audio: {
    active: 'oga',
    oga: {
      format: 'ogg',
      audioBitrate: '128000',
      audioCodec: 'libvorbis',
      extension: 'oga',
      extra: []
    }
  },
  image: {
    active: 'png',
    png: {
      width: '800',
      height: '800',
      format: 'png',
      extension: 'png'
    }
  }
};

var VideoPresets = {
  'ppt':{
    width: '1080',
    height: '1080',
    format: 'mp4',
    videoBitrate: '700000',
    videoCodec: 'libx264',
    skipAudio: true,
    default: 'mp4',
    extra: []
  },
  '1080p':{
    width: '1080',
    height: '1080',
    format: 'mp4',
    videoBitrate: '1850k',
    videoCodec: 'libx264',
    audioBitrate: '128000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  },
  '720p':{
    width: '720',
    height: '720',
    format: 'mp4',
    videoBitrate: '1400k',
    videoCodec: 'libx264',
    audioBitrate: '128000',
    audioCodec: 'acc',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    default: 'mp4',
    extra: []
  },
  '480p':{
    width: '480',
    height: '480',
    format: 'mp4',
    videoBitrate: '750k',
    videoCodec: 'libx264',
    audioBitrate: '96000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  },
  '360p':{
    width: '360',
    height: '360',
    format: 'mp4',
    videoBitrate: '450k',
    videoCodec: 'libx264',
    audioBitrate: '80000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  },
  '320p':{
    width: '320',
    height: '320',
    format: 'mp4',
    videoBitrate: '250k',
    videoCodec: 'libx264',
    audioBitrate: '60000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 20,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  },
  '240p':{
    width: '240',
    height: '240',
    format: 'mp4',
    videoBitrate: '250k',
    videoCodec: 'libx264',
    audioBitrate: '60000',
    audioCodec: 'acc',
    default: 'mp4',
    crf: 22,
    preset: 'medium',
    videoProfile: 'high',
    extra: []
  }
}

var ImagePresets = {
  '1080p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '1080',
    height: '1080',
    format: 'jpg'
  },
  '720p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '720',
    height: '720',
    format: 'jpg'
  },
  '480p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '480',
    height: '480',
    format: 'jpg'
  },
  '360p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '360',
    height: '360',
    format: 'jpg'
  },
  '320p':{
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '320',
    height: '320',
    format: 'jpg',
  },
  '240p': {
    formats: ['png','gif','jpg','jpeg'],
    default:'jpg',
    width: '720',
    height: '720',
    format: 'jpg'
  }
}

var AudioPresets = {
  'high': {
    audioBitrate: '128000',
    audioCodec: 'libmp3lame',
    format: 'mp3',
    default: 'mp3',
  },
}

module.exports = {
  video: VideoPresets,
  image: ImagePresets,
  audio: AudioPresets,
};

<|endoftext|>