<commit_before>(function(ext) {

    //The variable that will hold the json to be read from
    var jsonObject = null;

    //The scale applied to the kinect data to make it map to the canvas better.
    var xScale = 280;
    var yScale = 210;
    var zScale = 200;

    //The status of the kinect
    var status = 0;

    //alert letting the user know what needs to be done before loading the extension.
    alert("BEFORE CLICKING OK: Make sure the kinect is connected and your JSON websocket server has started");

    console.log("connecting to server ..");

    // create a new websocket and connect
    window.ws = new WebSocket('ws://localhost:8181/');

    // when data is comming from the server, this method is called
    ws.onmessage = function (evt) {
        jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };

    // Cleanup function when the extension is unloaded
    ext._shutdown = function()
    {
    window.ws.close();
    };

    // Reports status of kinect
    ext._getStatus = function() {
        if(status == 0)
        {
        return {status: 0, msg: 'Kinect is not connected to Scratch'};
        }
        if(status == 1)
        {
            return {status: 1, msg: 'Kinect is connected, but is not detecting any bodies'};
        }
        if(status == 2)
        {
            return {status: 2, msg: 'Kinect is sending body data'};
        }
    };

        // Block and block menu descriptions
    var descriptor = {
        blocks: [
            ['r', '%m.b %m.j %m.c', 'joints', 'Body 1', 'Head', 'x'],
            ['r', '%m.b %m.d Handstate', 'handdebug', 'Body 1', 'Left'],
            ['r', '%m.b id', 'bodyid', 'Body 1'],
            ['b', '%m.b %m.d Handstate is %m.h', 'handstate', 'Body 1', 'Left', 'Closed'],
            ['b', '%m.b tracked', 'tracked', 'Body 1'],
            ['b', 'connected', 'connected'],
            ['', 'Basic body check', 'basic_body_check'],
            ['', 'restart local connection', 'restart'],
            ['', 'Create connection to %s', 'ipconnect', '0.0.0.0'],
            ['', 'Close connection', 'closeconn'],
            ['', 'console.log %n', 'write'],
            ['', 'bad only %n', 'writeB']
        ],

        menus: {
	    j: ['Left Ankle', 'Right Ankle', 'Left Elbow', 'Right Elbow', 'Left Foot', 'Right Foot', 'Left Hand', 'Right Hand', 'Left Hand Tip', 'Right Hand Tip', 'Head', 'Left Hip', 'Right Hip', 'Left Knee', 'Right Knee', 'Neck', 'Left Shoulder', 'Right Shoulder', 'Spine Base', 'Spine Middle', 'Spine Shoulder', 'Left Thumb', 'Right Thumb', 'Left Wrist', 'Right Wrist'],
        b: ['Body 1', 'Body 2', 'Body 3', 'Body 4', 'Body 5', 'Body 6'],
        h: ['Unknown', 'Not Tracked', 'Open', 'Closed', 'Lasso'],
        c: ['x', 'y', 'z'],
        d: ['Left', 'Right']
    }
    };

    //restarts the local connection
    ext.restart = function() {
        window.ws.close();
        console.log("connecting to local server ..");
        window.ws = new WebSocket('ws://localhost:8181/');

        // when data is comming from the server, this method is called
        ws.onmessage = function (evt) {
            jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };
    };

    //s: a string containing the ip the user wishes to connect to.
    //Creates a remote connection to s.
    ext.ipconnect = function(string) {
        window.ws.close();
        console.log("connecting to "+string+' ..');
        window.ws = new WebSocket('ws://'+string+':8181/');

        // when data is comming from the server, this method is called
        ws.onmessage = function (evt) {
            jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
        };

        // when the connection is established, this method is called
        ws.onopen = function () {
        console.log('.. connection open');
        };

        // when the connection is closed, this method is called
        ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
        };
    }

    //Closes the current connection
    ext.closeconn = function()
    {
        window.ws.close();
    }

    //m: the number to be written to the console
    //Outputs numeric content to console
    ext.write = function(number){
        console.log(number);
    };

    //m: input to be compared to 0
    //Writes "bad" in console if the input is 0
    ext.writeB = function(number){
        if(number == 0)
        {
            console.log("bad");
        }
    };

    //Checks the body 1 head x coordinate
    //Good for check if any data is getting in from the kinect
    ext.basic_body_check = function() {
        console.log(jsonObject.bodies[0].joints[3].x*xScale);
    };

    //m: the body chosen (Body 1-6)
    //Gives the id of the selected body
    ext.bodyid = function(body)
    {
        switch(body){
            case 'Body 1': return jsonObject.bodies[0].id;
            case 'Body 2': return jsonObject.bodies[1].id;
            case 'Body 3': return jsonObject.bodies[2].id;
            case 'Body 4': return jsonObject.bodies[3].id;
            case 'Body 5': return jsonObject.bodies[4].id;
            case 'Body 6': return jsonObject.bodies[5].id;
        }
    }

        //True if scratch is receiving the kinect (but not necessarily data)
    ext.connected = function()
    {
        if(status == 0){
            return false;
        }

        if(status == 1 || 2){
            return true;
        }
    };

    //m: the body chosen (Body 1-6)
    //True if scratch is receiving the chosen body data
    ext.tracked = function(body)
    {
        var i = -1;
        switch(body){
            case 'Body 1': i = 0;
                break;
            case 'Body 2': i = 1;
                break;
            case 'Body 3': i = 2;
                break;
            case 'Body 4': i = 3;
                break;
            case 'Body 5': i = 4;
                break;
            case 'Body 6': i = 5;
                break;
        }

        return jsonObject.bodies[i].id != 0;
    };

    //l: the body chosen (Body 1-6)
    //d: which handstate (left or right)
    //Outputs the left handstate of the selected body
    ext.handdebug = function(body,direction)
    {
        var i;
        switch(body){
            case 'Body 1': i=0;
                break;
            case 'Body 2': i=1;
                break;
            case 'Body 3': i=2;
                break;
            case 'Body 4': i=3;
                break;
            case 'Body 5': i=4;
                break;
            case 'Body 6': i=5;
                break;
        }

        switch(direction)
        {
            case 'Left': return jsonObject.bodies[i].lhandstate;
            case 'Right': return jsonObject.bodies[i].rhandstate;
        }
    }

    //l: The selected body (Body 1-6)
    //d: Which handstate (left or right)
    //n: The selected handstate (Unknown, Not Tracked, Open, Closed, Lasso)
    //Returns true if the selected bodies left handstate is the same as block selected one.
    ext.handstate = function(body,direction,handstate)
    {
        var i;
        var j;
        switch(body){
            case 'Body 1': i=0;
                break;
            case 'Body 2': i=1;
                break;
            case 'Body 3': i=2;
                break;
            case 'Body 4': i=3;
                break;
            case 'Body 5': i=4;
                break;
            case 'Body 6': i=5;
                break;
        }

        switch(handstate)
        {
            case 'Unknown': j = 0;
                break;
            case 'Not Tracked': j = 1;
                break;
            case 'Open': j = 2;
                break;
            case 'Closed': j = 3;
                break;
            case 'Lasso': j = 4;
                break;
        }

        switch(direction)
        {
            case 'Left': return jsonObject.bodies[i].lhandstate == j;
            case 'Right': return jsonObject.bodies[i].rhandstate == j;
        }
    }

    //l: The body chosen (Body 1-6).
    //k1: The joint chosen (All joint the kinect v2 tracks).
    //x: The chosen coordinate (x, y, or z).
    //Gets the coordinate chosen from the joint chosen from the body chosen
    ext.joints = function(l,k1,x)
    {
        var a;
        var b;
        switch(k1){
            case 'Left Ankle': a=14;
                break;
            case 'Right Ankle': a=18;
                break;
            case 'Left Elbow': a=5;
                break;
            case 'Right Elbow': a=9;
                break;
            case 'Left Foot': a=15;
                break;
            case 'Right Foot': a=19;
                break;
            case 'Left Hand': a=7;
                break;
            case 'Right Hand': a=11;
                break;
            case 'Left Hand Tip': a=21;
                break;
            case 'Right Hand Tip': a=23;
                break;
            case 'Head': a=3;
                break;
            case 'Left Hip': a=12;
                break;
            case 'Right Hip': a=16;
                break;
            case 'Left Knee': a=13;
                break;
            case 'Right Knee': a=17;
                break;
            case 'Neck': a=2;
                break;
            case 'Left Shoulder': a=4;
                break;
            case 'Right Shoulder': a=8;
                break;
            case 'Spine Base': a=0;
                break;
            case 'Spine Middle': a=1;
                break;
            case 'Spine Shoulder': a=20;
                break;
            case 'Left Thumb': a=22;
                break;
            case 'Right Thumb': a=24;
                break;
            case 'Left Wrist': a=6;
                break;
            case 'Right Wrist': a=10;
                break;
        }

        switch(l){
            case 'Body 1': b=0;
                break;
            case 'Body 2': b=1;
                break;
            case 'Body 3': b=2;
                break;
            case 'Body 4': b=3;
                break;
            case 'Body 5': b=4;
                break;
            case 'Body 6': b=5;
                break;
        }

        switch(x){
            case 'x': return jsonObject.bodies[b].joints[a].x*xScale;
            case 'y': return jsonObject.bodies[b].joints[a].y*yScale;
            case 'z': return jsonObject.bodies[b].joints[a].z*zScale;
        }
    }

    // Register the extension
    ScratchExtensions.register('SkelScratch', descriptor, ext);
})({});<commit_msg>Clean up extension<commit_after>(function(ext) {

    //The variable that will hold the json to be read from
    var jsonObject = null;

    //The scale applied to the kinect data to make it map to the canvas better.
    var xScale = 280;
    var yScale = 210;
    var zScale = 200;

    //The status of the kinect
    var status = 0;

    //alert letting the user know what needs to be done before loading the extension.
    alert("BEFORE CLICKING OK: Make sure the kinect is connected and your JSON websocket server has started");

    console.log("connecting to server ..");

    // create a new websocket and connect
    window.ws = new WebSocket('ws://localhost:8181/');

    // when data is comming from the server, this method is called
    ws.onmessage = function (evt) {
        jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };

    // Cleanup function when the extension is unloaded
    ext._shutdown = function()
    {
    window.ws.close();
    };

    // Reports status of kinect
    ext._getStatus = function() {
        if(status == 0)
        {
        return {status: 0, msg: 'Kinect is not connected to Scratch'};
        }
        if(status == 1)
        {
            return {status: 1, msg: 'Kinect is connected, but is not detecting any bodies'};
        }
        if(status == 2)
        {
            return {status: 2, msg: 'Kinect is sending body data'};
        }
    };

        // Block and block menu descriptions
    var descriptor = {
        blocks: [
            ['r', '%m.b %m.j %m.c', 'joints', 'Body 1', 'Head', 'x'],
            ['r', '%m.b %m.d Handstate', 'handdebug', 'Body 1', 'Left'],
            ['r', '%m.b id', 'bodyid', 'Body 1'],
            ['b', '%m.b %m.d Handstate is %m.h', 'handstate', 'Body 1', 'Left', 'Closed'],
            ['b', '%m.b tracked', 'tracked', 'Body 1'],
            ['b', 'connected', 'connected'],
            ['', 'Basic body check', 'basic_body_check'],
            ['', 'restart local connection', 'restart'],
            ['', 'Create connection to %s', 'ipconnect', '0.0.0.0'],
            ['', 'Close connection', 'closeconn'],
            ['', 'console.log %n', 'write'],
            ['', 'bad only %n', 'writeB']
        ],

        menus: {
	    j: ['Left Ankle', 'Right Ankle', 'Left Elbow', 'Right Elbow', 'Left Foot', 'Right Foot', 'Left Hand', 'Right Hand', 'Left Hand Tip', 'Right Hand Tip', 'Head', 'Left Hip', 'Right Hip', 'Left Knee', 'Right Knee', 'Neck', 'Left Shoulder', 'Right Shoulder', 'Spine Base', 'Spine Middle', 'Spine Shoulder', 'Left Thumb', 'Right Thumb', 'Left Wrist', 'Right Wrist'],
        b: ['Body 1', 'Body 2', 'Body 3', 'Body 4', 'Body 5', 'Body 6'],
        h: ['Unknown', 'Not Tracked', 'Open', 'Closed', 'Lasso'],
        c: ['x', 'y', 'z'],
        d: ['Left', 'Right']
    }
    };

    //restarts the local connection
    ext.restart = function() {
        window.ws.close();
        console.log("connecting to local server ..");
        window.ws = new WebSocket('ws://localhost:8181/');

        // when data is comming from the server, this method is called
        ws.onmessage = function (evt) {
            jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };
    };

    //s: a string containing the ip the user wishes to connect to.
    //Creates a remote connection to s.
    ext.ipconnect = function(string) {
        window.ws.close();
        console.log("connecting to "+string+' ..');
        window.ws = new WebSocket('ws://'+string+':8181/');

        // when data is comming from the server, this method is called
        ws.onmessage = function (evt) {
            jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
        };

        // when the connection is established, this method is called
        ws.onopen = function () {
        console.log('.. connection open');
        };

        // when the connection is closed, this method is called
        ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
        };
    }

    //Closes the current connection
    ext.closeconn = function()
    {
        window.ws.close();
    }

    //m: the number to be written to the console
    //Outputs numeric content to console
    ext.write = function(number){
        console.log(number);
    };

    //m: input to be compared to 0
    //Writes "bad" in console if the input is 0
    ext.writeB = function(number){
        if(number == 0)
        {
            console.log("bad");
        }
    };

    //Checks the body 1 head x coordinate
    //Good for check if any data is getting in from the kinect
    ext.basic_body_check = function() {
        console.log(jsonObject.bodies[0].joints[3].x*xScale);
    };

    //m: the body chosen (Body 1-6)
    //Gives the id of the selected body
    ext.bodyid = function(body)
    {
        switch(body){
            case 'Body 1': return jsonObject.bodies[0].id;
            case 'Body 2': return jsonObject.bodies[1].id;
            case 'Body 3': return jsonObject.bodies[2].id;
            case 'Body 4': return jsonObject.bodies[3].id;
            case 'Body 5': return jsonObject.bodies[4].id;
            case 'Body 6': return jsonObject.bodies[5].id;
        }
    }

        //True if scratch is receiving the kinect (but not necessarily data)
    ext.connected = function()
    {
        if(status == 0){
            return false;
        }

        if(status == 1 || 2){
            return true;
        }
    };

    //m: the body chosen (Body 1-6)
    //True if scratch is receiving the chosen body data
    ext.tracked = function(body)
    {
        var i = -1;
        switch(body){
            case 'Body 1': i = 0;
                break;
            case 'Body 2': i = 1;
                break;
            case 'Body 3': i = 2;
                break;
            case 'Body 4': i = 3;
                break;
            case 'Body 5': i = 4;
                break;
            case 'Body 6': i = 5;
                break;
        }

        return jsonObject.bodies[i].id != 0;
    };

    //l: the body chosen (Body 1-6)
    //d: which handstate (left or right)
    //Outputs the left handstate of the selected body
    ext.handdebug = function(body,direction)
    {
        var i;
        switch(body){
            case 'Body 1': i=0;
                break;
            case 'Body 2': i=1;
                break;
            case 'Body 3': i=2;
                break;
            case 'Body 4': i=3;
                break;
            case 'Body 5': i=4;
                break;
            case 'Body 6': i=5;
                break;
        }

        switch(direction)
        {
            case 'Left': return jsonObject.bodies[i].lhandstate;
            case 'Right': return jsonObject.bodies[i].rhandstate;
        }
    }

    //l: The selected body (Body 1-6)
    //d: Which handstate (left or right)
    //n: The selected handstate (Unknown, Not Tracked, Open, Closed, Lasso)
    //Returns true if the selected bodies left handstate is the same as block selected one.
    ext.handstate = function(body,direction,handstate)
    {
        var i;
        var j;
        switch(body){
            case 'Body 1': i=0;
                break;
            case 'Body 2': i=1;
                break;
            case 'Body 3': i=2;
                break;
            case 'Body 4': i=3;
                break;
            case 'Body 5': i=4;
                break;
            case 'Body 6': i=5;
                break;
        }

        switch(handstate)
        {
            case 'Unknown': j = 0;
                break;
            case 'Not Tracked': j = 1;
                break;
            case 'Open': j = 2;
                break;
            case 'Closed': j = 3;
                break;
            case 'Lasso': j = 4;
                break;
        }

        switch(direction)
        {
            case 'Left': return jsonObject.bodies[i].lhandstate == j;
            case 'Right': return jsonObject.bodies[i].rhandstate == j;
        }
    }

    //l: The body chosen (Body 1-6).
    //k1: The joint chosen (All joint the kinect v2 tracks).
    //x: The chosen coordinate (x, y, or z).
    //Gets the coordinate chosen from the joint chosen from the body chosen
    ext.joints = function(body,joint,coordinate)
    {
        var a;
        var b;

        switch(joint){
            case 'Left Ankle': a=14;
                break;
            case 'Right Ankle': a=18;
                break;
            case 'Left Elbow': a=5;
                break;
            case 'Right Elbow': a=9;
                break;
            case 'Left Foot': a=15;
                break;
            case 'Right Foot': a=19;
                break;
            case 'Left Hand': a=7;
                break;
            case 'Right Hand': a=11;
                break;
            case 'Left Hand Tip': a=21;
                break;
            case 'Right Hand Tip': a=23;
                break;
            case 'Head': a=3;
                break;
            case 'Left Hip': a=12;
                break;
            case 'Right Hip': a=16;
                break;
            case 'Left Knee': a=13;
                break;
            case 'Right Knee': a=17;
                break;
            case 'Neck': a=2;
                break;
            case 'Left Shoulder': a=4;
                break;
            case 'Right Shoulder': a=8;
                break;
            case 'Spine Base': a=0;
                break;
            case 'Spine Middle': a=1;
                break;
            case 'Spine Shoulder': a=20;
                break;
            case 'Left Thumb': a=22;
                break;
            case 'Right Thumb': a=24;
                break;
            case 'Left Wrist': a=6;
                break;
            case 'Right Wrist': a=10;
                break;
        }

        switch(body){
            case 'Body 1': b=0;
                break;
            case 'Body 2': b=1;
                break;
            case 'Body 3': b=2;
                break;
            case 'Body 4': b=3;
                break;
            case 'Body 5': b=4;
                break;
            case 'Body 6': b=5;
                break;
        }

        switch(coordinate){
            case 'x': return jsonObject.bodies[b].joints[a].x*xScale;
            case 'y': return jsonObject.bodies[b].joints[a].y*yScale;
            case 'z': return jsonObject.bodies[b].joints[a].z*zScale;
        }
    }

    // Register the extension
    ScratchExtensions.register('SkelScratch', descriptor, ext);
})({});<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

var app = {
  // Application Constructor
  initialize: function() {
    this.bindEvents();
  },
  // Bind Event Listeners
  //
  // Bind any events that are required on startup. Common events are:
  // 'load', 'deviceready', 'offline', and 'online'.
  bindEvents: function() {
    document.addEventListener('deviceready', this.onDeviceReady, false);
  },
  // deviceready Event Handler
  //
  // The scope of 'this' is the event. In order to call the 'receivedEvent'
  // function, we must explicity call 'app.receivedEvent(...);'
  onDeviceReady: function() {

      // Getting OpenTokRTC's room's credentials.
      // To use your own room in opentokrtc, change cordova to room of your choice
      //   -> ie: https://opentokrtc.com/myroom.json
      // To use your own credentials
      //  replace data.apiKey, data.sid, and data.token with your own
      var xmlhttp=new XMLHttpRequest();
      xmlhttp.open("GET", "https://opentokrtc.com/cordova.json", false);
      xmlhttp.send();
      var data = JSON.parse( xmlhttp.response );

      // Very simple OpenTok Code for group video chat
      var publisher = TB.initPublisher(data.apiKey,'myPublisherDiv');

      var session = TB.initSession( data.apiKey, data.sid );
      session.on({
        'streamCreated': function( event ){
            var div = document.createElement('div');
            div.setAttribute('id', 'stream' + event.stream.streamId);
            document.body.appendChild(div);
            session.subscribe( event.stream, div.id, {subscribeToAudio: false} );
        }
      });
      session.connect(data.token, function(){
        session.publish( publisher );
      });

  },
  // Update DOM on a Received Event
  receivedEvent: function(id) {
  }
};
<commit_msg>resolve #141<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

var app = {
  // Application Constructor
  initialize: function() {
    this.bindEvents();
  },
  // Bind Event Listeners
  //
  // Bind any events that are required on startup. Common events are:
  // 'load', 'deviceready', 'offline', and 'online'.
  bindEvents: function() {
    document.addEventListener('deviceready', this.onDeviceReady, false);
  },
  // deviceready Event Handler
  //
  // The scope of 'this' is the event. In order to call the 'receivedEvent'
  // function, we must explicity call 'app.receivedEvent(...);'
  onDeviceReady: function() {

      // Sign up for an OpenTok API Key at: https://tokbox.com/signup
      // Then generate a sessionId and token at: https://dashboard.tokbox.com
      var apiKey = ""; // INSERT YOUR API Key
      var sessionId = ""; // INSERT YOUR SESSION ID
      var token = ""; // INSERT YOUR TOKEN

      // Very simple OpenTok Code for group video chat
      var publisher = TB.initPublisher(apiKey,'myPublisherDiv');

      var session = TB.initSession( apiKey, sessionId );
      session.on({
        'streamCreated': function( event ){
            var div = document.createElement('div');
            div.setAttribute('id', 'stream' + event.stream.streamId);
            document.body.appendChild(div);
            session.subscribe( event.stream, div.id, {subscribeToAudio: false} );
        }
      });
      session.connect(token, function(){
        session.publish( publisher );
      });

  },
  // Update DOM on a Received Event
  receivedEvent: function(id) {
  }
};
<|endoftext|>


<commit_before>import app from 'app';

import {getAvailableDictionaries} from 'browser/utils/spellchecker';
import platform from 'common/utils/platform';

const availableLanguages = getAvailableDictionaries();
const defaults = {
  'analytics-track': true,
  'analytics-uid': null,
  'launch-startup': false,
  'launch-startup-hidden': true,
  'launch-quit': false,
  'links-in-browser': true,
  'close-with-esc': false,
  'quit-behaviour-taught': false,
  'raffle-code': null,
  'show-notifications-badge': true,
  'show-tray': platform.isWindows,
  'show-dock': true,
  'spell-checker-check': false,
  'spell-checker-auto-correct': false,
  'spell-checker-language': defaultSpellCheckerLanguage,
  'theme': 'default',
  'updates-auto-check': true,
  'updates-channel': 'beta',
  'window-bounds': {
    width: 800,
    height: 600
  },
  'window-full-screen': false,
  'zoom-level': 0
};

function get(key) {
  if (key === 'spell-checker-language') {
    const valueFn = defaults[key];
    if (typeof valueFn === 'function') {
      if (global.ready) {
        defaults[key] = valueFn();
        return defaults[key];
      } else {
        return valueFn();
      }
    }
  }

  return defaults[key];
}

function defaultSpellCheckerLanguage() {
  let defaultLanguage = null;

  // Try to get it from app
  if (global.ready) {
    defaultLanguage = app.getLocale();
    if (typeof defaultLanguage === 'string') {
      defaultLanguage = defaultLanguage.replace('-', '_');
      defaultLanguage = validateLanguage(defaultLanguage);
      if (defaultLanguage) {
        return defaultLanguage;
      }
    }
    defaultLanguage = null;
  }

  // Try to get it from env
  if (typeof process.env.LANG === 'string') {
    defaultLanguage = process.env.LANG.split('.')[0];
    defaultLanguage = defaultLanguage.replace('-', '_');
    defaultLanguage = validateLanguage(defaultLanguage);
    if (defaultLanguage) {
      return defaultLanguage;
    }
    defaultLanguage = null;
  }

  // Try to use the first available language
  if (availableLanguages.length) {
    return availableLanguages[0];
  }

  // Use the default
  return 'en_US';
}

function validateLanguage(lang) {
  if (availableLanguages.includes(lang)) {
    return lang;
  } else {
    lang = lang.split('_')[0];
    if (availableLanguages.includes(lang)) {
      return lang;
    }
  }
  return null;
}

export default {
  get
};
<commit_msg>Updates channel is by default the existing one<commit_after>import app from 'app';

import {getAvailableDictionaries} from 'browser/utils/spellchecker';
import platform from 'common/utils/platform';

const availableLanguages = getAvailableDictionaries();
const defaults = {
  'analytics-track': true,
  'analytics-uid': null,
  'launch-startup': false,
  'launch-startup-hidden': true,
  'launch-quit': false,
  'links-in-browser': true,
  'close-with-esc': false,
  'quit-behaviour-taught': false,
  'raffle-code': null,
  'show-notifications-badge': true,
  'show-tray': platform.isWindows,
  'show-dock': true,
  'spell-checker-check': false,
  'spell-checker-auto-correct': false,
  'spell-checker-language': defaultSpellCheckerLanguage,
  'theme': 'default',
  'updates-auto-check': true,
  'updates-channel': global.manifest.versionChannel,
  'window-bounds': {
    width: 800,
    height: 600
  },
  'window-full-screen': false,
  'zoom-level': 0
};

function get(key) {
  if (key === 'spell-checker-language') {
    const valueFn = defaults[key];
    if (typeof valueFn === 'function') {
      if (global.ready) {
        defaults[key] = valueFn();
        return defaults[key];
      } else {
        return valueFn();
      }
    }
  }

  return defaults[key];
}

function defaultSpellCheckerLanguage() {
  let defaultLanguage = null;

  // Try to get it from app
  if (global.ready) {
    defaultLanguage = app.getLocale();
    if (typeof defaultLanguage === 'string') {
      defaultLanguage = defaultLanguage.replace('-', '_');
      defaultLanguage = validateLanguage(defaultLanguage);
      if (defaultLanguage) {
        return defaultLanguage;
      }
    }
    defaultLanguage = null;
  }

  // Try to get it from env
  if (typeof process.env.LANG === 'string') {
    defaultLanguage = process.env.LANG.split('.')[0];
    defaultLanguage = defaultLanguage.replace('-', '_');
    defaultLanguage = validateLanguage(defaultLanguage);
    if (defaultLanguage) {
      return defaultLanguage;
    }
    defaultLanguage = null;
  }

  // Try to use the first available language
  if (availableLanguages.length) {
    return availableLanguages[0];
  }

  // Use the default
  return 'en_US';
}

function validateLanguage(lang) {
  if (availableLanguages.includes(lang)) {
    return lang;
  } else {
    lang = lang.split('_')[0];
    if (availableLanguages.includes(lang)) {
      return lang;
    }
  }
  return null;
}

export default {
  get
};
<|endoftext|>


<commit_before>transporter.module.create('transporter/module_morph', function(requires) {

requires('lk_ext/rows_and_columns');
requires('transporter/transporter');

}, function(thisModule) {

thisModule.addSlots(transporter.module, function(add) {

  add.method('newMorph', function () {
    return new this.Morph(this);
  }, {category: ['user interface']});

  add.method('Morph', function Morph() { Class.initializer.apply(this, arguments); }, {category: ['user interface']});

});

thisModule.addSlots(transporter.module.Morph, function(add) {

  add.data('superclass', RowMorph);

  add.creator('prototype', Object.create(RowMorph.prototype));

  add.data('type', 'transporter.module.Morph');

  add.method('doneUpload', function (name) {
    if (name.substr(-3) === '.js') { name = name.substr(0, name.length - 3); }
    transporter.fileIn(name, function() {
      new MessageNotifierMorph(name + " has been loaded.", Color.green).showTemporarilyInCenterOfWorld(WorldMorph.current());
    });
  });

});

thisModule.addSlots(transporter.module.Morph.prototype, function(add) {

  add.data('constructor', transporter.module.Morph);

  add.method('initialize', function ($super, module) {
    $super();
    this._module = module;

    this.setPadding({top: 2, bottom: 2, left: 4, right: 4, between: 3});
    this.setFill(lively.paint.defaultFillWithColor(Color.red.lighter()));
    this.shape.roundEdgesBy(10);

    this._nameLabel = TextMorph.createLabel(function() { return module.name(); });

    var fileOutButton = ButtonMorph.createButton('Save as .js file', this.fileOut.bind(this), 2);
    var optionalFileOutButton  = Morph.createOptionalMorph(fileOutButton, function() { return this._module.canBeFiledOut(); }.bind(this));
    optionalFileOutButton.refreshContent();

    this._changeIndicator = TextMorph.createLabel(function() { return this._module.hasChangedSinceLastFileOut() ? ' has changed ' : ''; }.bind(this));
    this._changeIndicator.setTextColor(Color.green.darker());

    this.setColumns([this._nameLabel, this._changeIndicator, optionalFileOutButton, this.createDismissButton()]);

    this.startPeriodicallyUpdating();
  }, {category: ['creating']});

  add.method('inspect', function () { return this._module.name(); }, {category: ['printing']});

  add.method('rename', function (evt) {
    evt.hand.world().prompt("New name?", function(newName) {
      MessageNotifierMorph.showIfErrorDuring(function () {
        this._module.rename(newName);
        this.updateAppearance();
      }.bind(this), evt);
    }.bind(this), this._module.name());
  }, {category: ['commands']});

  add.method('fileOut', function (evt) {
    this.fileOutPlural([{morph: this}], evt);
  }, {category: ['commands']});

  add.method('fileOutPlural', function (morphsAndCommands, evt, repo) {
    transporter.prepareToFileStuffOut();
    morphsAndCommands.each(function(morphAndCommand) {
      var m = morphAndCommand.morph;
      m._module.fileOut(null,
			repo,
                        function() {m.refreshContentOfMeAndSubmorphs();},
                        function(errorMessage) {
                          if (errorMessage.mirrorWithoutCreatorSlot) {
                            var world = evt.hand.world();
                            world.morphFor(errorMessage.mirrorWithoutCreatorSlot).grabMe(evt);
                          }
                          MessageNotifierMorph.showError("Error filing out " + m._module + ": " + errorMessage, evt);
                        });
    });
  }, {category: ['commands']});

  add.method('emailTheSource', function (evt) {
    var repo = Object.newChildOf(transporter.repositories.httpWithSavingScript,
				 this._module.repository().url(),
				 "http://" + document.domain + "/cgi-bin/emailSource.cgi");
    this.fileOutPlural([{morph: this}], evt, repo);
  }, {category: ['commands']});

  add.method('fileOutWithoutAnnotations', function (evt) {
    MessageNotifierMorph.showIfErrorDuring(function() { this._module.fileOutWithoutAnnotations(); }.bind(this), evt);
    this.refreshContentOfMeAndSubmorphs();
  }, {category: ['commands']});

  add.method('mockFileOut', function (evt) {
    console.log(this._module.codeOfMockFileOut());
  }, {category: ['commands']});

  add.method('printToConsole', function (evt) {
      this._module.fileOut(Object.newChildOf(transporter.module.annotationlessFilerOuter),
			   transporter.repositories.console,
			   function() {},
			   function(errorMessage) { MessageNotifierMorph.showError("Error printing out " + this._module + ": " + errorMessage, evt); }.bind(this));

  }, {category: ['commands']});

  add.method('forgetIWasChanged', function (evt) {
    this._module.markAsUnchanged();
    this.refreshContentOfMeAndSubmorphs();
  }, {category: ['commands']});

  add.method('getModuleObject', function (evt) {
    evt.hand.world().morphFor(reflect(this._module)).grabMe(evt);
  }, {category: ['commands']});

  add.method('getAllObjects', function (evt) {
    var w = evt.hand.world();
    var objectsInPose = this._module.objectsThatMightContainSlotsInMe().map(function(o) { return reflect(o); });
    objectsInPose.unshift(this._module); // aaa - should really put it in a special place on the screen
    w.assumePose(w.listPoseOfMorphsFor(objectsInPose, "objects in module " + this._module.name()));
  }, {category: ['commands']});

  add.method('addCommandsTo', function (cmdList) {
    if (this._module.canBeFiledOut()) {
      cmdList.addItem({label: 'save as .js file', pluralLabel: 'save modules as .js files', go: this.fileOut.bind(this), pluralGo: this.fileOutPlural.bind(this)});
      // aaa - not working yet: cmdList.addItem({label: 'email me the source', go: this.emailTheSource.bind(this)});
    }

    cmdList.addItem({label: 'print to console', go: this.printToConsole.bind(this)});

    if (avocado.debugMode) {
      cmdList.addItem({label: 'print mock fileout', go: this.mockFileOut.bind(this)});
    }

    if (this._module.hasChangedSinceLastFileOut()) {
      cmdList.addItem({label: 'forget I was changed', go: this.forgetIWasChanged.bind(this)});
    }

    cmdList.addLine();

    cmdList.addItem({label: 'rename',            go: this.rename.bind(this)});
    cmdList.addItem({label: 'get module object', go: this.getModuleObject.bind(this)});

    cmdList.addLine();

    cmdList.addItem({label: 'all objects', go: this.getAllObjects.bind(this)});
  }, {category: ['menu']});

});

thisModule.addSlots(transporter, function(add) {

  add.method('chooseARepository', function (evt, targetMorph, menuCaption, callback) {
    if (transporter.availableRepositories.length === 1) { callback(transporter.availableRepositories[0], evt); return; }

    var repoMenu = new MenuMorph([], targetMorph);
    transporter.availableRepositories.each(function(repo) {
      repoMenu.addItem([repo.toString(), function() { callback(repo, evt); }])
    });
    repoMenu.openIn(evt.hand.world(), evt.point(), false, menuCaption);
  }, {category: ['menu']});

  add.method('createAModule', function (evt, targetMorph, callback) {
    this.chooseARepository(evt, targetMorph, 'Which server should the new module live on?', function(repo, evt) {
      evt.hand.world().prompt("Module name?", function(name) {
        if (name) {
	  if (lobby.modules[name]) {
	    throw "There is already a module named " + name;
	  }
	  var module = lobby.transporter.module.named(name);
	  module._repository = repo;
	  if (modules.thisProject) { modules.thisProject.addRequirement(name); }
	  callback(module, evt);
	}
      });
    });
  }, {category: ['menu']});

  add.method('modulePathDictionary', function () {
    var modulePathDictionary = dictionary.copyRemoveAll();
    transporter.module.eachModule(function(m) {
      var nameParts = m.name().split('/');
      var currentDictionary = modulePathDictionary;
      while (nameParts.length > 1) {
        var part = nameParts.shift();
        currentDictionary = currentDictionary.getOrIfAbsentPut(part, function() {return dictionary.copyRemoveAll();});
      }
      currentDictionary.put(nameParts.shift(), m);
    });
    return modulePathDictionary;
  }, {category: ['menu']});

  add.method('menuItemsForModulePathDictionary', function (modulePathDictionary, evt, callback) {
    if (modulePathDictionary.keys) { // aaa is there a better way to do a type test?
      return modulePathDictionary.keys().sort().map(function(dirName) {
          return [dirName, this.menuItemsForModulePathDictionary(modulePathDictionary.get(dirName), evt, callback)];
      }.bind(this));
    } else {
      // the leaves of the tree are the modules
      var module = modulePathDictionary;
      return function(evt) { callback(module, evt); };
    }
  }, {category: ['menu']});

  add.method('chooseOrCreateAModule', function (evt, likelyModules, targetMorph, menuCaption, callback) {
    var modulesMenu = new MenuMorph([], targetMorph);
    modulesMenu.addItem(["new module...", function(evt) { this.createAModule(evt, targetMorph, callback); }.bind(this)]);
    modulesMenu.addLine();
    if (likelyModules.length > 0 && likelyModules.length < 8) {
      likelyModules.each(function(likelyModule) {
        if (likelyModule) {
          modulesMenu.addItem([likelyModule.name(), function(evt) { callback(likelyModule, evt); }]);
        }
      }.bind(this));
      modulesMenu.addLine();
    }
    modulesMenu.addItems(this.menuItemsForModulePathDictionary(this.modulePathDictionary(), evt, callback));
    modulesMenu.openIn(targetMorph.world(), evt.point(), false, menuCaption);
  }, {category: ['menu']});

  add.method('addGlobalCommandsTo', function (menu, evt) {
    menu.addLine();

    var snapshottingWorks = false; // aaa - turn this on once it works.
    if (snapshottingWorks) {
    menu.addItem(["save snapshot", function(evt) {
      var snapshotter = snapshotter.create();
      snapshotter.walk(lobby);
      var snapshot = snapshotter.completeSnapshotText();

      var baseDirURL = URL.source.getDirectory().withRelativePath("javascripts/snapshots/");
      var fileName = "snapshot_" + snapshotter._number + ".js";
      var url = baseDirURL.withFilename(fileName);
      var status = new Resource(Record.newPlainInstance({URL: url})).store(snapshot, true).getStatus();
      if (! status.isSuccess()) {
        throw "failed to write " + fileName + ", status is " + status.code();
      }
    }]);
    }

    menu.addItem(["all modules", function(evt) {
      var world = evt.hand.world();
      world.assumePose(world.listPoseOfMorphsFor(Object.newChildOf(enumerator, transporter.module, 'eachModule'), "all modules"));
    }]);

    menu.addItem(["changed modules", function(evt) {
      var world = evt.hand.world();
      world.assumePose(world.listPoseOfMorphsFor(transporter.module.changedOnes(), "all modules"));
    }]);

    /* Not working yet.
      menu.addItem(["aaa upload file...", function(evt) {
        var form = document.getElementById('uploadForm');
        var fileInput = form.fileToUpload;
        fileInput.click();
      }.bind(this)]);
    */

    // aaa - hack because I haven't managed to get WebDAV working on adamspitz.com yet
    var shouldBeAbleToLoadJSFiles = avocado.debugMode;
    if (shouldBeAbleToLoadJSFiles) {
      menu.addItem(["load JS file...", function(evt) {
        var world = evt.hand.world();
        var modulesMenu = new MenuMorph([], world);
        transporter.availableRepositories.each(function(repo) {
          modulesMenu.addItem([repo.toString(), repo.menuItemsForLoadMenu()]);
        });
        modulesMenu.openIn(world, evt.point(), false, "From where?");
      }.bind(this)]);
    }

  }, {category: ['menu']});

});

thisModule.addSlots(transporter.repositories.http, function(add) {

  add.method('menuItemsForLoadMenu', function () {
    return this.menuItemsForLoadMenuForDir(new FileDirectory(new URL(this._url)), "");
  }, {category: ['menu']});

  add.method('menuItemsForLoadMenuForDir', function (dir, pathFromModuleSystemRootDir) {
    var menuItems = [];

    var subdirURLs = this.subdirectoriesIn(dir);
    subdirURLs.each(function(subdirURL) {
      var subdir = new FileDirectory(subdirURL);
      var subdirName = subdirURL.filename().withoutSuffix('/');
      menuItems.push([subdirName, this.menuItemsForLoadMenuForDir(subdir, pathFromModuleSystemRootDir ? pathFromModuleSystemRootDir + "/" + subdirName : subdirName)]);
    }.bind(this));

    var jsFileNames = this.filenamesIn(dir).select(function(n) {return n.endsWith(".js");});
    jsFileNames.each(function(n) {
      menuItems.push([n, function(evt) {
        var moduleName = n.substring(0, n.length - 3);
        MessageNotifierMorph.showIfErrorDuring(function() {
          this.fileIn(pathFromModuleSystemRootDir ? (pathFromModuleSystemRootDir + '/' + moduleName) : moduleName);
        }.bind(this), evt);
      }.bind(this)]);
    }.bind(this));

    return menuItems;
  }, {category: ['menu']});

});

thisModule.addSlots(transporter.repositories.httpWithWebDAV, function(add) {

  add.method('subdirectoriesIn', function (dir) {
    return dir.subdirectories();
  }, {category: ['directories']});

  add.method('filenamesIn', function (dir) {
    return dir.filenames();
  }, {category: ['directories']});

});

thisModule.addSlots(transporter.repositories.httpWithSavingScript, function(add) {

  add.method('subdirectoriesIn', function (dir) {
    return []; // aaa;
  }, {category: ['directories']});

  add.method('filenamesIn', function (dir) {
    return []; // aaa;
  }, {category: ['directories']});

});

});
<commit_msg>When printing a module to the console, show the mirrors for objects without a single creator slot.<commit_after>transporter.module.create('transporter/module_morph', function(requires) {

requires('lk_ext/rows_and_columns');
requires('transporter/transporter');

}, function(thisModule) {

thisModule.addSlots(transporter.module, function(add) {

  add.method('newMorph', function () {
    return new this.Morph(this);
  }, {category: ['user interface']});

  add.method('Morph', function Morph() { Class.initializer.apply(this, arguments); }, {category: ['user interface']});

});

thisModule.addSlots(transporter.module.Morph, function(add) {

  add.data('superclass', RowMorph);

  add.creator('prototype', Object.create(RowMorph.prototype));

  add.data('type', 'transporter.module.Morph');

  add.method('doneUpload', function (name) {
    if (name.substr(-3) === '.js') { name = name.substr(0, name.length - 3); }
    transporter.fileIn(name, function() {
      new MessageNotifierMorph(name + " has been loaded.", Color.green).showTemporarilyInCenterOfWorld(WorldMorph.current());
    });
  });

});

thisModule.addSlots(transporter.module.Morph.prototype, function(add) {

  add.data('constructor', transporter.module.Morph);

  add.method('initialize', function ($super, module) {
    $super();
    this._module = module;

    this.setPadding({top: 2, bottom: 2, left: 4, right: 4, between: 3});
    this.setFill(lively.paint.defaultFillWithColor(Color.red.lighter()));
    this.shape.roundEdgesBy(10);

    this._nameLabel = TextMorph.createLabel(function() { return module.name(); });

    var fileOutButton = ButtonMorph.createButton('Save as .js file', this.fileOut.bind(this), 2);
    var optionalFileOutButton  = Morph.createOptionalMorph(fileOutButton, function() { return this._module.canBeFiledOut(); }.bind(this));
    optionalFileOutButton.refreshContent();

    this._changeIndicator = TextMorph.createLabel(function() { return this._module.hasChangedSinceLastFileOut() ? ' has changed ' : ''; }.bind(this));
    this._changeIndicator.setTextColor(Color.green.darker());

    this.setColumns([this._nameLabel, this._changeIndicator, optionalFileOutButton, this.createDismissButton()]);

    this.startPeriodicallyUpdating();
  }, {category: ['creating']});

  add.method('inspect', function () { return this._module.name(); }, {category: ['printing']});

  add.method('rename', function (evt) {
    evt.hand.world().prompt("New name?", function(newName) {
      MessageNotifierMorph.showIfErrorDuring(function () {
        this._module.rename(newName);
        this.updateAppearance();
      }.bind(this), evt);
    }.bind(this), this._module.name());
  }, {category: ['commands']});

  add.method('fileOut', function (evt) {
    this.fileOutPlural([{morph: this}], evt);
  }, {category: ['commands']});

  add.method('fileOutPlural', function (morphsAndCommands, evt, repo) {
    transporter.prepareToFileStuffOut();
    morphsAndCommands.each(function(morphAndCommand) {
      var m = morphAndCommand.morph;
      m._module.fileOut(null,
                        repo,
                        function() { m.refreshContentOfMeAndSubmorphs(); },
                        function(err) { m.errorFilingOut(err, evt); });
    });
  }, {category: ['commands']});

  add.method('errorFilingOut', function (err, evt) {
    if (err.mirrorWithoutCreatorSlot) {
      var world = evt.hand.world();
      world.morphFor(err.mirrorWithoutCreatorSlot).grabMe(evt);
    }
    MessageNotifierMorph.showError("Error filing out " + this._module + ": " + err, evt);
  }, {category: ['commands']});

  add.method('emailTheSource', function (evt) {
    var repo = Object.newChildOf(transporter.repositories.httpWithSavingScript,
				 this._module.repository().url(),
				 "http://" + document.domain + "/cgi-bin/emailSource.cgi");
    this.fileOutPlural([{morph: this}], evt, repo);
  }, {category: ['commands']});

  add.method('fileOutWithoutAnnotations', function (evt) {
    MessageNotifierMorph.showIfErrorDuring(function() { this._module.fileOutWithoutAnnotations(); }.bind(this), evt);
    this.refreshContentOfMeAndSubmorphs();
  }, {category: ['commands']});

  add.method('mockFileOut', function (evt) {
    console.log(this._module.codeOfMockFileOut());
  }, {category: ['commands']});

  add.method('printToConsole', function (evt) {
    this._module.fileOut(Object.newChildOf(transporter.module.annotationlessFilerOuter),
			   transporter.repositories.console,
			   function() {},
			   function(err) { this.errorFilingOut(err, evt); }.bind(this));
  }, {category: ['commands']});

  add.method('forgetIWasChanged', function (evt) {
    this._module.markAsUnchanged();
    this.refreshContentOfMeAndSubmorphs();
  }, {category: ['commands']});

  add.method('getModuleObject', function (evt) {
    evt.hand.world().morphFor(reflect(this._module)).grabMe(evt);
  }, {category: ['commands']});

  add.method('getAllObjects', function (evt) {
    var w = evt.hand.world();
    var objectsInPose = this._module.objectsThatMightContainSlotsInMe().map(function(o) { return reflect(o); });
    objectsInPose.unshift(this._module); // aaa - should really put it in a special place on the screen
    w.assumePose(w.listPoseOfMorphsFor(objectsInPose, "objects in module " + this._module.name()));
  }, {category: ['commands']});

  add.method('addCommandsTo', function (cmdList) {
    if (this._module.canBeFiledOut()) {
      cmdList.addItem({label: 'save as .js file', pluralLabel: 'save modules as .js files', go: this.fileOut.bind(this), pluralGo: this.fileOutPlural.bind(this)});
      // aaa - not working yet: cmdList.addItem({label: 'email me the source', go: this.emailTheSource.bind(this)});
    }

    cmdList.addItem({label: 'print to console', go: this.printToConsole.bind(this)});

    if (avocado.debugMode) {
      cmdList.addItem({label: 'print mock fileout', go: this.mockFileOut.bind(this)});
    }

    if (this._module.hasChangedSinceLastFileOut()) {
      cmdList.addItem({label: 'forget I was changed', go: this.forgetIWasChanged.bind(this)});
    }

    cmdList.addLine();

    cmdList.addItem({label: 'rename',            go: this.rename.bind(this)});
    cmdList.addItem({label: 'get module object', go: this.getModuleObject.bind(this)});

    cmdList.addLine();

    cmdList.addItem({label: 'all objects', go: this.getAllObjects.bind(this)});
  }, {category: ['menu']});

});

thisModule.addSlots(transporter, function(add) {

  add.method('chooseARepository', function (evt, targetMorph, menuCaption, callback) {
    if (transporter.availableRepositories.length === 1) { callback(transporter.availableRepositories[0], evt); return; }

    var repoMenu = new MenuMorph([], targetMorph);
    transporter.availableRepositories.each(function(repo) {
      repoMenu.addItem([repo.toString(), function() { callback(repo, evt); }])
    });
    repoMenu.openIn(evt.hand.world(), evt.point(), false, menuCaption);
  }, {category: ['menu']});

  add.method('createAModule', function (evt, targetMorph, callback) {
    this.chooseARepository(evt, targetMorph, 'Which server should the new module live on?', function(repo, evt) {
      evt.hand.world().prompt("Module name?", function(name) {
        if (name) {
	  if (lobby.modules[name]) {
	    throw "There is already a module named " + name;
	  }
	  var module = lobby.transporter.module.named(name);
	  module._repository = repo;
	  if (modules.thisProject) { modules.thisProject.addRequirement(name); }
	  callback(module, evt);
	}
      });
    });
  }, {category: ['menu']});

  add.method('modulePathDictionary', function () {
    var modulePathDictionary = dictionary.copyRemoveAll();
    transporter.module.eachModule(function(m) {
      var nameParts = m.name().split('/');
      var currentDictionary = modulePathDictionary;
      while (nameParts.length > 1) {
        var part = nameParts.shift();
        currentDictionary = currentDictionary.getOrIfAbsentPut(part, function() {return dictionary.copyRemoveAll();});
      }
      currentDictionary.put(nameParts.shift(), m);
    });
    return modulePathDictionary;
  }, {category: ['menu']});

  add.method('menuItemsForModulePathDictionary', function (modulePathDictionary, evt, callback) {
    if (modulePathDictionary.keys) { // aaa is there a better way to do a type test?
      return modulePathDictionary.keys().sort().map(function(dirName) {
          return [dirName, this.menuItemsForModulePathDictionary(modulePathDictionary.get(dirName), evt, callback)];
      }.bind(this));
    } else {
      // the leaves of the tree are the modules
      var module = modulePathDictionary;
      return function(evt) { callback(module, evt); };
    }
  }, {category: ['menu']});

  add.method('chooseOrCreateAModule', function (evt, likelyModules, targetMorph, menuCaption, callback) {
    var modulesMenu = new MenuMorph([], targetMorph);
    modulesMenu.addItem(["new module...", function(evt) { this.createAModule(evt, targetMorph, callback); }.bind(this)]);
    modulesMenu.addLine();
    if (likelyModules.length > 0 && likelyModules.length < 8) {
      likelyModules.each(function(likelyModule) {
        if (likelyModule) {
          modulesMenu.addItem([likelyModule.name(), function(evt) { callback(likelyModule, evt); }]);
        }
      }.bind(this));
      modulesMenu.addLine();
    }
    modulesMenu.addItems(this.menuItemsForModulePathDictionary(this.modulePathDictionary(), evt, callback));
    modulesMenu.openIn(targetMorph.world(), evt.point(), false, menuCaption);
  }, {category: ['menu']});

  add.method('addGlobalCommandsTo', function (menu, evt) {
    menu.addLine();

    var snapshottingWorks = false; // aaa - turn this on once it works.
    if (snapshottingWorks) {
    menu.addItem(["save snapshot", function(evt) {
      var snapshotter = snapshotter.create();
      snapshotter.walk(lobby);
      var snapshot = snapshotter.completeSnapshotText();

      var baseDirURL = URL.source.getDirectory().withRelativePath("javascripts/snapshots/");
      var fileName = "snapshot_" + snapshotter._number + ".js";
      var url = baseDirURL.withFilename(fileName);
      var status = new Resource(Record.newPlainInstance({URL: url})).store(snapshot, true).getStatus();
      if (! status.isSuccess()) {
        throw "failed to write " + fileName + ", status is " + status.code();
      }
    }]);
    }

    menu.addItem(["all modules", function(evt) {
      var world = evt.hand.world();
      world.assumePose(world.listPoseOfMorphsFor(Object.newChildOf(enumerator, transporter.module, 'eachModule'), "all modules"));
    }]);

    menu.addItem(["changed modules", function(evt) {
      var world = evt.hand.world();
      world.assumePose(world.listPoseOfMorphsFor(transporter.module.changedOnes(), "all modules"));
    }]);

    /* Not working yet.
      menu.addItem(["aaa upload file...", function(evt) {
        var form = document.getElementById('uploadForm');
        var fileInput = form.fileToUpload;
        fileInput.click();
      }.bind(this)]);
    */

    // aaa - hack because I haven't managed to get WebDAV working on adamspitz.com yet
    var shouldBeAbleToLoadJSFiles = avocado.debugMode;
    if (shouldBeAbleToLoadJSFiles) {
      menu.addItem(["load JS file...", function(evt) {
        var world = evt.hand.world();
        var modulesMenu = new MenuMorph([], world);
        transporter.availableRepositories.each(function(repo) {
          modulesMenu.addItem([repo.toString(), repo.menuItemsForLoadMenu()]);
        });
        modulesMenu.openIn(world, evt.point(), false, "From where?");
      }.bind(this)]);
    }

  }, {category: ['menu']});

});

thisModule.addSlots(transporter.repositories.http, function(add) {

  add.method('menuItemsForLoadMenu', function () {
    return this.menuItemsForLoadMenuForDir(new FileDirectory(new URL(this._url)), "");
  }, {category: ['menu']});

  add.method('menuItemsForLoadMenuForDir', function (dir, pathFromModuleSystemRootDir) {
    var menuItems = [];

    var subdirURLs = this.subdirectoriesIn(dir);
    subdirURLs.each(function(subdirURL) {
      var subdir = new FileDirectory(subdirURL);
      var subdirName = subdirURL.filename().withoutSuffix('/');
      menuItems.push([subdirName, this.menuItemsForLoadMenuForDir(subdir, pathFromModuleSystemRootDir ? pathFromModuleSystemRootDir + "/" + subdirName : subdirName)]);
    }.bind(this));

    var jsFileNames = this.filenamesIn(dir).select(function(n) {return n.endsWith(".js");});
    jsFileNames.each(function(n) {
      menuItems.push([n, function(evt) {
        var moduleName = n.substring(0, n.length - 3);
        MessageNotifierMorph.showIfErrorDuring(function() {
          this.fileIn(pathFromModuleSystemRootDir ? (pathFromModuleSystemRootDir + '/' + moduleName) : moduleName);
        }.bind(this), evt);
      }.bind(this)]);
    }.bind(this));

    return menuItems;
  }, {category: ['menu']});

});

thisModule.addSlots(transporter.repositories.httpWithWebDAV, function(add) {

  add.method('subdirectoriesIn', function (dir) {
    return dir.subdirectories();
  }, {category: ['directories']});

  add.method('filenamesIn', function (dir) {
    return dir.filenames();
  }, {category: ['directories']});

});

thisModule.addSlots(transporter.repositories.httpWithSavingScript, function(add) {

  add.method('subdirectoriesIn', function (dir) {
    return []; // aaa;
  }, {category: ['directories']});

  add.method('filenamesIn', function (dir) {
    return []; // aaa;
  }, {category: ['directories']});

});

});
<|endoftext|>


<commit_before>/**
* classes to manage maps
*/

/**
* Map layer, could be tiled or whatever
*/
cdb.geo.MapLayer = Backbone.Model.extend({

  defaults: {
    visible: true,
    type: 'Tiled'
  }
});

// Good old fashioned tile layer
cdb.geo.TileLayer = cdb.geo.MapLayer.extend({
  getTileLayer: function () {
    return new L.TileLayer(this.get('urlTemplate'));
  }
});

// CartoDB layer
cdb.geo.CartoDBLayer = cdb.geo.MapLayer.extend({
  defaults: {
    type:           'CartoDB',
    query:          "SELECT * FROM {{table_name}}",
    opacity:        0.99,
    auto_bound:     false,
    debug:          false,
    visible:        true,
    tiler_domain:   "cartodb.com",
    tiler_port:     "80",
    tiler_protocol: "http",
    sql_domain:     "cartodb.com",
    sql_port:       "80",
    sql_protocol:   "http",
    extra_params:   {},
    cdn_url:        null
  },

  initialize: function() {
    _.bindAll(this, 'getTileLayer', '_getInteractiveLayer', '_getStaticTileLayer', '_bindWaxEvents');
  },

  _generateURL: function(type){

    // Check if we are using a CDN and in that case, return the provided URL
    if ( this.get("cdn_url") ) {
      return this.get("cdn_url");
    }

    var // let's build the URL
    username     = this.get("user_name"),
    domain       = this.get("sql_domain"),
    port         = this.get("sql_port"),
    protocol     = this.get("sql_protocol");

    if (type != "sql") {
      protocol = this.get("tiler_protocol");
    }

    return protocol + "://" + ( username ? username + "." : "" ) + domain + ( port != "" ? (":" + port) : "" );

  },

  /**
  * Appends callback to the urls
  *
  * @params {String} Tile url
  * @params {String} Tile data
  * @return {String} Tile url parsed
  */
  _addUrlData: function (url, data) {
    url += this._parseUri(url).query ? '&' : '?';
    return url += data;
  },

  /**
  * Parse URI
  *
  * @params {String} Tile url
  * @return {String} URI parsed
  */
  _parseUri: function (str) {
    var o = {
      strictMode: false,
      key: ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"],
      q:   {
        name:   "queryKey",
        parser: /(?:^|&)([^&=]*)=?([^&]*)/g
      },
      parser: {
        strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
        loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
      }
    },
    mode   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
    uri = {},
    i   = 14;

    while (i--) uri[o.key[i]] = mode[i] || "";

    uri[o.q.name] = {};

    uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
      if ($1) uri[o.q.name][$1] = $2;
    });

    return uri;
  },

  /**
  * Generate tilejson for wax
  *
  * @return {Object} Options for L.TileLayer
  */
  _generateTileJson: function () {
    var
    core_url = this._generateURL("tiler"),
    base_url = core_url + '/tiles/' + this.get("table_name") + '/{z}/{x}/{y}',
    tile_url = base_url + '.png',
    grid_url = base_url + '.grid.json';

    var
    query         = this.get("query"),
    tableName     = this.get("table_name"),
    tileStyle     = this.get("tile_style"),
    interactivity = this.get("interactivity");
    extraParams   = this.get("extra_params");

    if (query) {
      var query = 'sql=' + encodeURIComponent(query.replace(/\{\{table_name\}\}/g, tableName));
      tile_url = this._addUrlData(tile_url, query);
      grid_url = this._addUrlData(grid_url, query);
    }

    _.each(extraParams, function(value, name) {
      tile_url = this._addUrlData(tile_url, name + "=" + value);
      grid_url = this._addUrlData(grid_url, name + "=" + value);
    });

    if (tileStyle) {
      var style = 'style=' + encodeURIComponent(tileStyle.replace(/\{\{table_name\}\}/g, tableName));
      tile_url = this._addUrlData(tile_url, style);
      grid_url = this._addUrlData(grid_url, style);
    }

    if (interactivity) {
      var interactivity = 'interactivity=' + encodeURIComponent(interactivity.replace(/ /g,''));
      tile_url = this._addUrlData(tile_url, interactivity);
      grid_url = this._addUrlData(grid_url, interactivity);
    }

    // Build up the tileJSON
    return {
      blankImage: '../img/blank_tile.png',
      tilejson: '1.0.0',
      scheme: 'xyz',
      tiles: [tile_url],
      grids: [grid_url],
      tiles_base: tile_url,
      grids_base: grid_url,
      opacity: this.get("opacity"),
      formatter: function(options, data) {
        return data
      }
    };
  },

  /**
  * Get the point of the event in the map
  *
  * @params {Object} Map object
  * @params {Object} Wax event object
  */
  _findPos: function (map,o) {
    var
    curleft = curtop = 0,
    obj     = map._container;

    if (obj.offsetParent) {

      do { // Modern browsers
        curleft += obj.offsetLeft;
        curtop += obj.offsetTop;
      } while (obj = obj.offsetParent);

      return map.containerPointToLayerPoint(new L.Point(o.pos.x - curleft,o.pos.y - curtop))

    } else { // IE
      return map.mouseEventToLayerPoint(o.e)
    }
  },

  /**
  * Bind events for wax interaction
  *
  * @param {Object} Layer map object
  * @param {Event} Wax event
  */
  _bindWaxEvents: function(map, o) {

    var
    layer_point = this._findPos(map, o),
    latlng      = map.layerPointToLatLng(layer_point);

    var featureOver  = this.get("featureOver");
    var featureClick = this.get("featureClick");

    switch (o.e.type) {
      case 'mousemove':
        if (featureOver) {
          return featureOver(o.e,latlng,o.pos,o.data);
        } else {
          if (this.get("debug")) throw('featureOver function not defined');
        }
      break;
    case 'click':
      if (featureClick) {
        featureClick(o.e,latlng,o.pos,o.data);
      } else {
        if (this.get("debug")) throw('featureClick function not defined');
      }
    break;
  case 'touched':
    if (featureClick) {
      featureClick(o.e,latlng,o.pos,o.data);
    } else {
      if (this.get("debug")) throw('featureClick function not defined');
    }
    break;
  default: break;
    }
  },

  getTileLayer: function() {

    if (this.get("interactivity")) {
      return this._getInteractiveLayer();
    }

    return this._getStaticTileLayer();
  },

  _getInteractiveLayer: function() {

    var self = this;

    this.tilejson = this._generateTileJson();
    this.layer    = new wax.leaf.connector(this.tilejson);

    var featureOver = function(o) { self._bindWaxEvents(self.mapView.map_leaflet, o)};
    var featureOut  = function() {

      var featureOut = self.get("featureOut");

      if (featureOut) {
        return featureOut && featureOut();
      } else {
        if (self.get("debug")) {
          throw('featureOut function not defined');
        }
      }
    };

    this.interaction = this.mapView.addInteraction(this.tilejson, featureOver, featureOut);

    return this.layer;
  },

  _getStaticTileLayer: function() {

    var // add the cartodb tiles
    style     = this.get("tile_style"),
    tableName = this.get("table_name"),
    query     = this.get("query");

    tileStyle  = (style) ? encodeURIComponent(style.replace(/\{\{table_name\}\}/g, tableName )) : '';
    query      = encodeURIComponent(query.replace(/\{\{table_name\}\}/g, tableName ));

    var cartodb_url = this._generateURL("tiler") + '/tiles/' + tableName + '/{z}/{x}/{y}.png?sql=' + query +'&style=' + tileStyle;

    _.each(this.attributes.extra_params, function(value, name) {
      cartodb_url += "&" + name + "=" + value;
    });

    return new L.TileLayer(cartodb_url, { attribution:'CartoDB', opacity: this.get("opacity") });
  }

});

cdb.geo.MapLayers = Backbone.Collection.extend({
  model: cdb.geo.MapLayer
  });

  /**
  * map model itself
  */
  cdb.geo.Map = Backbone.Model.extend({

    defaults: {
      center: [0, 0],
      zoom: 9
    },

    initialize: function() {
      this.layers = new cdb.geo.MapLayers();
    },

    setZoom: function(z) {
      this.set({zoom:  z});
    },

    getZoom: function() {
      return this.get('zoom');
    },

    setCenter: function(latlng) {
      this.set({center: latlng});
    },

    /**
    * add a layer to the map
    */
    addLayer: function(layer) {
      this.layers.add(layer);
    }

  });

  /**
  * base view for all impl
  */
  cdb.geo.MapView = cdb.core.View.extend({

    initialize: function() {
      if(this.options.map === undefined) {
        throw new Exception("you should specify a map model");
      }
      this.map = this.options.map;
      this.add_related_model(this.map);
    }

  });

  /**
  * leatlef impl
  */
  cdb.geo.LeafletMapView = cdb.geo.MapView.extend({

    initialize: function() {

      _.bindAll(this, '_addLayer', '_setZoom', '_setCenter');

      cdb.geo.MapView.prototype.initialize.call(this);

      var self = this;

      this.map_leaflet = new L.Map(this.el, {
        zoomControl: false
      });

      this.map.layers.bind('add', this._addLayer);

      this._bindModel();

      //set options
      this._setCenter(this.map, this.map.get('center'));
      this._setZoom(this.map, this.map.get('zoom'));

      this.map_leaflet.on('zoomend', function() {
        self._setModelProperty({zoom: self.map_leaflet.getZoom()});
      }, this);

      this.map_leaflet.on('drag', function () {
        var c = self.map_leaflet.getCenter();
        self._setModelProperty({center: [c.lat, c.lng]});
      }, this);
    },

    /** bind model properties */
    _bindModel: function() {
      this.map.bind('change:zoom', this._setZoom, this);
      this.map.bind('change:center', this._setCenter, this);
    },

    /** unbind model properties */
    _unbindModel: function() {
      this.map.unbind('change:zoom', this._setZoom, this);
      this.map.unbind('change:center', this._setCenter, this);
    },

    /**
    * set model property but unbind changes first in order to not create an infinite loop
    */
    _setModelProperty: function(prop) {
      this._unbindModel();
      this.map.set(prop);
      this._bindModel();
    },

    _setZoom: function(model, z) {
      this.map_leaflet.setZoom(z);
    },

    _setCenter: function(model, center) {
      this.map_leaflet.panTo(new L.LatLng(center[0], center[1]));
    },

    /**
    * Adds interactivity to a layer
    *
    * @params {String} tileJSON
    * @params {String} featureOver
    * @return {String} featureOut
    */
    addInteraction: function(tileJSON, featureOver, featureOut) {

      return wax.leaf.interaction()
      .map(this.map_leaflet)
      .tilejson(tileJSON)
      .on('on',  featureOver)
      .on('off', featureOut);

    },

    _addLayer: function(layer) {
      var lyr;

      // Adds reference to the parent mapView
      layer.mapView = this;

      if ( layer.get('type') == "Tiled" ) {
        lyr = layer.getTileLayer();
      }

      if ( layer.get('type') == 'CartoDB') {
        lyr = layer.getTileLayer();
      }

      if (lyr) {
        this.map_leaflet.addLayer(lyr);
      } else {
        cdb.log.error("layer type not supported");
      }
    }
  });

<commit_msg>added render method<commit_after>/**
* classes to manage maps
*/

/**
* Map layer, could be tiled or whatever
*/
cdb.geo.MapLayer = Backbone.Model.extend({

  defaults: {
    visible: true,
    type: 'Tiled'
  }
});

// Good old fashioned tile layer
cdb.geo.TileLayer = cdb.geo.MapLayer.extend({
  getTileLayer: function () {
    return new L.TileLayer(this.get('urlTemplate'));
  }
});

// CartoDB layer
cdb.geo.CartoDBLayer = cdb.geo.MapLayer.extend({
  defaults: {
    type:           'CartoDB',
    query:          "SELECT * FROM {{table_name}}",
    opacity:        0.99,
    auto_bound:     false,
    debug:          false,
    visible:        true,
    tiler_domain:   "cartodb.com",
    tiler_port:     "80",
    tiler_protocol: "http",
    sql_domain:     "cartodb.com",
    sql_port:       "80",
    sql_protocol:   "http",
    extra_params:   {},
    cdn_url:        null
  },

  initialize: function() {
    _.bindAll(this, 'getTileLayer', '_getInteractiveLayer', '_getStaticTileLayer', '_bindWaxEvents');
  },

  _generateURL: function(type){

    // Check if we are using a CDN and in that case, return the provided URL
    if ( this.get("cdn_url") ) {
      return this.get("cdn_url");
    }

    var // let's build the URL
    username     = this.get("user_name"),
    domain       = this.get("sql_domain"),
    port         = this.get("sql_port"),
    protocol     = this.get("sql_protocol");

    if (type != "sql") {
      protocol = this.get("tiler_protocol");
    }

    return protocol + "://" + ( username ? username + "." : "" ) + domain + ( port != "" ? (":" + port) : "" );

  },

  /**
  * Appends callback to the urls
  *
  * @params {String} Tile url
  * @params {String} Tile data
  * @return {String} Tile url parsed
  */
  _addUrlData: function (url, data) {
    url += this._parseUri(url).query ? '&' : '?';
    return url += data;
  },

  /**
  * Parse URI
  *
  * @params {String} Tile url
  * @return {String} URI parsed
  */
  _parseUri: function (str) {
    var o = {
      strictMode: false,
      key: ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"],
      q:   {
        name:   "queryKey",
        parser: /(?:^|&)([^&=]*)=?([^&]*)/g
      },
      parser: {
        strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
        loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
      }
    },
    mode   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
    uri = {},
    i   = 14;

    while (i--) uri[o.key[i]] = mode[i] || "";

    uri[o.q.name] = {};

    uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
      if ($1) uri[o.q.name][$1] = $2;
    });

    return uri;
  },

  /**
  * Generate tilejson for wax
  *
  * @return {Object} Options for L.TileLayer
  */
  _generateTileJson: function () {
    var
    core_url = this._generateURL("tiler"),
    base_url = core_url + '/tiles/' + this.get("table_name") + '/{z}/{x}/{y}',
    tile_url = base_url + '.png',
    grid_url = base_url + '.grid.json';

    var
    query         = this.get("query"),
    tableName     = this.get("table_name"),
    tileStyle     = this.get("tile_style"),
    interactivity = this.get("interactivity");
    extraParams   = this.get("extra_params");

    if (query) {
      var query = 'sql=' + encodeURIComponent(query.replace(/\{\{table_name\}\}/g, tableName));
      tile_url = this._addUrlData(tile_url, query);
      grid_url = this._addUrlData(grid_url, query);
    }

    _.each(extraParams, function(value, name) {
      tile_url = this._addUrlData(tile_url, name + "=" + value);
      grid_url = this._addUrlData(grid_url, name + "=" + value);
    });

    if (tileStyle) {
      var style = 'style=' + encodeURIComponent(tileStyle.replace(/\{\{table_name\}\}/g, tableName));
      tile_url = this._addUrlData(tile_url, style);
      grid_url = this._addUrlData(grid_url, style);
    }

    if (interactivity) {
      var interactivity = 'interactivity=' + encodeURIComponent(interactivity.replace(/ /g,''));
      tile_url = this._addUrlData(tile_url, interactivity);
      grid_url = this._addUrlData(grid_url, interactivity);
    }

    // Build up the tileJSON
    return {
      blankImage: '../img/blank_tile.png',
      tilejson: '1.0.0',
      scheme: 'xyz',
      tiles: [tile_url],
      grids: [grid_url],
      tiles_base: tile_url,
      grids_base: grid_url,
      opacity: this.get("opacity"),
      formatter: function(options, data) {
        return data
      }
    };
  },

  /**
  * Get the point of the event in the map
  *
  * @params {Object} Map object
  * @params {Object} Wax event object
  */
  _findPos: function (map,o) {
    var
    curleft = curtop = 0,
    obj     = map._container;

    if (obj.offsetParent) {

      do { // Modern browsers
        curleft += obj.offsetLeft;
        curtop += obj.offsetTop;
      } while (obj = obj.offsetParent);

      return map.containerPointToLayerPoint(new L.Point(o.pos.x - curleft,o.pos.y - curtop))

    } else { // IE
      return map.mouseEventToLayerPoint(o.e)
    }
  },

  /**
  * Bind events for wax interaction
  *
  * @param {Object} Layer map object
  * @param {Event} Wax event
  */
  _bindWaxEvents: function(map, o) {

    var
    layer_point = this._findPos(map, o),
    latlng      = map.layerPointToLatLng(layer_point);

    var featureOver  = this.get("featureOver");
    var featureClick = this.get("featureClick");

    switch (o.e.type) {
      case 'mousemove':
        if (featureOver) {
          return featureOver(o.e,latlng,o.pos,o.data);
        } else {
          if (this.get("debug")) throw('featureOver function not defined');
        }
      break;
    case 'click':
      if (featureClick) {
        featureClick(o.e,latlng,o.pos,o.data);
      } else {
        if (this.get("debug")) throw('featureClick function not defined');
      }
    break;
  case 'touched':
    if (featureClick) {
      featureClick(o.e,latlng,o.pos,o.data);
    } else {
      if (this.get("debug")) throw('featureClick function not defined');
    }
    break;
  default: break;
    }
  },

  getTileLayer: function() {

    if (this.get("interactivity")) {
      return this._getInteractiveLayer();
    }

    return this._getStaticTileLayer();
  },

  _getInteractiveLayer: function() {

    var self = this;

    this.tilejson = this._generateTileJson();
    this.layer    = new wax.leaf.connector(this.tilejson);

    var featureOver = function(o) { self._bindWaxEvents(self.mapView.map_leaflet, o)};
    var featureOut  = function() {

      var featureOut = self.get("featureOut");

      if (featureOut) {
        return featureOut && featureOut();
      } else {
        if (self.get("debug")) {
          throw('featureOut function not defined');
        }
      }
    };

    this.interaction = this.mapView.addInteraction(this.tilejson, featureOver, featureOut);

    return this.layer;
  },

  _getStaticTileLayer: function() {

    var // add the cartodb tiles
    style     = this.get("tile_style"),
    tableName = this.get("table_name"),
    query     = this.get("query");

    tileStyle  = (style) ? encodeURIComponent(style.replace(/\{\{table_name\}\}/g, tableName )) : '';
    query      = encodeURIComponent(query.replace(/\{\{table_name\}\}/g, tableName ));

    var cartodb_url = this._generateURL("tiler") + '/tiles/' + tableName + '/{z}/{x}/{y}.png?sql=' + query +'&style=' + tileStyle;

    _.each(this.attributes.extra_params, function(value, name) {
      cartodb_url += "&" + name + "=" + value;
    });

    return new L.TileLayer(cartodb_url, { attribution:'CartoDB', opacity: this.get("opacity") });
  }

});

cdb.geo.MapLayers = Backbone.Collection.extend({
  model: cdb.geo.MapLayer
  });

  /**
  * map model itself
  */
  cdb.geo.Map = Backbone.Model.extend({

    defaults: {
      center: [0, 0],
      zoom: 9
    },

    initialize: function() {
      this.layers = new cdb.geo.MapLayers();
    },

    setZoom: function(z) {
      this.set({zoom:  z});
    },

    getZoom: function() {
      return this.get('zoom');
    },

    setCenter: function(latlng) {
      this.set({center: latlng});
    },

    /**
    * add a layer to the map
    */
    addLayer: function(layer) {
      this.layers.add(layer);
    }

  });

  /**
  * base view for all impl
  */
  cdb.geo.MapView = cdb.core.View.extend({

    initialize: function() {
      if(this.options.map === undefined) {
        throw new Exception("you should specify a map model");
      }
      this.map = this.options.map;
      this.add_related_model(this.map);
    },

    render: function() {
      return this;
    }

  });

  /**
  * leatlef impl
  */
  cdb.geo.LeafletMapView = cdb.geo.MapView.extend({

    initialize: function() {

      _.bindAll(this, '_addLayer', '_setZoom', '_setCenter');

      cdb.geo.MapView.prototype.initialize.call(this);

      var self = this;

      this.map_leaflet = new L.Map(this.el, {
        zoomControl: false
      });

      this.map.layers.bind('add', this._addLayer);

      this._bindModel();

      //set options
      this._setCenter(this.map, this.map.get('center'));
      this._setZoom(this.map, this.map.get('zoom'));

      this.map_leaflet.on('zoomend', function() {
        self._setModelProperty({zoom: self.map_leaflet.getZoom()});
      }, this);

      this.map_leaflet.on('drag', function () {
        var c = self.map_leaflet.getCenter();
        self._setModelProperty({center: [c.lat, c.lng]});
      }, this);
    },

    /** bind model properties */
    _bindModel: function() {
      this.map.bind('change:zoom', this._setZoom, this);
      this.map.bind('change:center', this._setCenter, this);
    },

    /** unbind model properties */
    _unbindModel: function() {
      this.map.unbind('change:zoom', this._setZoom, this);
      this.map.unbind('change:center', this._setCenter, this);
    },

    /**
    * set model property but unbind changes first in order to not create an infinite loop
    */
    _setModelProperty: function(prop) {
      this._unbindModel();
      this.map.set(prop);
      this._bindModel();
    },

    _setZoom: function(model, z) {
      this.map_leaflet.setZoom(z);
    },

    _setCenter: function(model, center) {
      this.map_leaflet.panTo(new L.LatLng(center[0], center[1]));
    },

    /**
    * Adds interactivity to a layer
    *
    * @params {String} tileJSON
    * @params {String} featureOver
    * @return {String} featureOut
    */
    addInteraction: function(tileJSON, featureOver, featureOut) {

      return wax.leaf.interaction()
      .map(this.map_leaflet)
      .tilejson(tileJSON)
      .on('on',  featureOver)
      .on('off', featureOut);

    },

    _addLayer: function(layer) {
      var lyr;

      // Adds reference to the parent mapView
      layer.mapView = this;

      if ( layer.get('type') == "Tiled" ) {
        lyr = layer.getTileLayer();
      }

      if ( layer.get('type') == 'CartoDB') {
        lyr = layer.getTileLayer();
      }

      if (lyr) {
        this.map_leaflet.addLayer(lyr);
      } else {
        cdb.log.error("layer type not supported");
      }
    }
  });

<|endoftext|>


<commit_before>import React from 'react';

import { Putro } from 'MAINTAINERS';
import Wrapper from 'common/Wrapper';
import SpellLink from 'common/SpellLink';
import SPELLS from 'common/SPELLS';
import ITEMS from 'common/ITEMS';
import ItemLink from 'common/ItemLink';

export default [
  {
    date: new Date('2018-02-11'),
    changes: <Wrapper>Added a preliminary Talents and Traits list which will include damage information about various talents and traits as they get implemented. Implemented modules for <SpellLink id={SPELLS.STEEL_TRAP_TALENT.id} icon />, <SpellLink id={SPELLS.EXPLOSIVE_TRAP_CAST.id} icon />, <SpellLink id={SPELLS.CALTROPS_TALENT.id} icon /> and added prepull handling for all three. </Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-02-05'),
    changes: <Wrapper>Added additional information to the <ItemLink id={ITEMS.CALL_OF_THE_WILD.id} icon /> module, to show cooldown reduction on the various affected spells. </Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-02-02'),
    changes: <Wrapper>Added a module for tracking <SpellLink id={SPELLS.SPITTING_COBRA_TALENT.id} icon />, and ensure cast efficiency works properly for the talent even if precast. </Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-02-02'),
    changes: <Wrapper>Added support for <ItemLink id={ITEMS.BUTCHERS_BONE_APRON.id} icon />, <ItemLink id={ITEMS.FRIZZOS_FINGERTRAP.id} icon />, <ItemLink id={ITEMS.HELBRINE_ROPE_OF_THE_MIST_MARAUDER.id} icon />, <ItemLink id={ITEMS.NESINGWARYS_TRAPPING_TREADS.id} icon />, <ItemLink id={ITEMS.UNSEEN_PREDATORS_CLOAK.id} icon />.</Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-31'),
    changes: <Wrapper>Added a module for tracking <SpellLink id={SPELLS.WAY_OF_THE_MOKNATHAL_TALENT.id} icon />. </Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-30'),
    changes: <Wrapper>Added two statistic modules for <SpellLink id={SPELLS.MONGOOSE_FURY.id} icon /></Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-30'),
    changes: 'Added a focus usage chart to track what you\'re spending your focus on',
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-18'),
    changes: <Wrapper>Added support for <SpellLink id={SPELLS.HUNTER_SV_T20_2P_BONUS.id} icon />, <SpellLink id={SPELLS.HUNTER_SV_T20_4P_BONUS.id} icon />, <SpellLink id={SPELLS.HUNTER_SV_T21_2P_BONUS.id} icon />, <SpellLink id={SPELLS.HUNTER_SV_T21_4P_BONUS.id} icon />.</Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-17'),
    changes: 'Initial support of survival.',
    contributors: [Putro],
  },
];
<commit_msg>update changelog<commit_after>import React from 'react';

import { Putro } from 'MAINTAINERS';
import Wrapper from 'common/Wrapper';
import SpellLink from 'common/SpellLink';
import SPELLS from 'common/SPELLS';
import ITEMS from 'common/ITEMS';
import ItemLink from 'common/ItemLink';

export default [
  {
    date: new Date('2018-02-11'),
    changes: <Wrapper>Added support for <SpellLink id={SPELLS.ASPECT_OF_THE_BEAST_TALENT.id} icon />, <SpellLink id={SPELLS.SERPENT_STING_TALENT.id} icon />, <SpellLink id={SPELLS.A_MURDER_OF_CROWS_TALENT_SURVIVAL.id} icon />, <SpellLink id={SPELLS.DRAGONSFIRE_GRENADE_TALENT.id} icon />, <SpellLink id={SPELLS.THROWING_AXES_TALENT.id} icon /> into the Talents/Trait listbox.</Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-02-11'),
    changes: <Wrapper>Added a preliminary Talents and Traits list which will include damage information about various talents and traits as they get implemented. Implemented modules for <SpellLink id={SPELLS.STEEL_TRAP_TALENT.id} icon />, <SpellLink id={SPELLS.EXPLOSIVE_TRAP_CAST.id} icon />, <SpellLink id={SPELLS.CALTROPS_TALENT.id} icon /> and added prepull handling for all three. </Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-02-05'),
    changes: <Wrapper>Added additional information to the <ItemLink id={ITEMS.CALL_OF_THE_WILD.id} icon /> module, to show cooldown reduction on the various affected spells. </Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-02-02'),
    changes: <Wrapper>Added a module for tracking <SpellLink id={SPELLS.SPITTING_COBRA_TALENT.id} icon />, and ensure cast efficiency works properly for the talent even if precast. </Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-02-02'),
    changes: <Wrapper>Added support for <ItemLink id={ITEMS.BUTCHERS_BONE_APRON.id} icon />, <ItemLink id={ITEMS.FRIZZOS_FINGERTRAP.id} icon />, <ItemLink id={ITEMS.HELBRINE_ROPE_OF_THE_MIST_MARAUDER.id} icon />, <ItemLink id={ITEMS.NESINGWARYS_TRAPPING_TREADS.id} icon />, <ItemLink id={ITEMS.UNSEEN_PREDATORS_CLOAK.id} icon />.</Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-31'),
    changes: <Wrapper>Added a module for tracking <SpellLink id={SPELLS.WAY_OF_THE_MOKNATHAL_TALENT.id} icon />. </Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-30'),
    changes: <Wrapper>Added two statistic modules for <SpellLink id={SPELLS.MONGOOSE_FURY.id} icon /></Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-30'),
    changes: 'Added a focus usage chart to track what you\'re spending your focus on',
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-18'),
    changes: <Wrapper>Added support for <SpellLink id={SPELLS.HUNTER_SV_T20_2P_BONUS.id} icon />, <SpellLink id={SPELLS.HUNTER_SV_T20_4P_BONUS.id} icon />, <SpellLink id={SPELLS.HUNTER_SV_T21_2P_BONUS.id} icon />, <SpellLink id={SPELLS.HUNTER_SV_T21_4P_BONUS.id} icon />.</Wrapper>,
    contributors: [Putro],
  },
  {
    date: new Date('2018-01-17'),
    changes: 'Initial support of survival.',
    contributors: [Putro],
  },
];
<|endoftext|>


<commit_before>import Link from "next/link";
import { useRouter } from "next/router";
import { useState, useEffect } from "react";
import classnames from "classnames";
import path from "path";
import MenuTray from "../components/MenuTray";
import Section from "../components/Section";
import { capitalize } from "../lib/lib";

function ActiveLink({ children, href, className, currentPath }) {
  const firstCrumb = currentPath.split("/")[1];

  const activeClassName = classnames({
    "text-wall-600": "/" + firstCrumb === href,
    "text-wall-500": "/" + firstCrumb !== href,
  });

  return (
    <Link href={href}>
      <a className={`${className} ${activeClassName}`}>{children}
    </Link>
  );
}

export default function Header(props) {
  const [isOpen, setTray] = useState(false);
  const [shortcut, setShortcut] = useState("");

  const currentPath = useRouter().asPath;

  const routeDepth = currentPath.split("/").length;

  const firstCrumb = currentPath.split("/")[1];

  const detectOS = () => {
    const agent = window.navigator.appVersion;
    if (agent.includes("Win")) {
      return "Ctrl+K";
    } else if (agent.includes("Mac")) {
      return "⌘K";
    } else if (agent.includes("Linux")) {
      return "Ctrl+K";
    }
  };

  useEffect(() => {
    setShortcut(detectOS());
  }, []);

  return (

        <Link href="/">
          Urbit
        </Link>
        {routeDepth > 2 ? (
          <Link href={`/${firstCrumb}`}>

              {capitalize(firstCrumb)}

          </Link>
        ) : null}

      {
        // Large screen header
      }

        <ActiveLink
          currentPath={currentPath}
          className="mr-5 type-ui"
          href="/docs"
        >
          Docs
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 type-ui"
          href="/using"
        >
          Operator's Manual
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 type-ui"
          href="/blog"
        >
          Blog
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 type-ui"
          href="/events"
        >
          Events
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 text-green-400 type-ui button-text"
          href="/getting-started"
        >
          Get Started
        </ActiveLink>
        <button
          onClick={(e) => {
            e.stopPropagation();
            props.search.toggleSearch(e);
          }}
          className="bg-wall-100 text-wall-500 flex px-4 py-1 rounded-lg type-ui"
        >

Search

{shortcut}

        </button>

      {
        // Small screen header
      }
      <MenuTray isOpen={isOpen} setTray={setTray} search={props.search}>
        <Link href="/">
          Urbit
        </Link>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 mb-4 type-h3"
          href="/docs"
        >
          Docs
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 mb-4 type-h3"
          href="/blog"
        >
          Blog
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 mb-4 type-h3"
          href="/events"
        >
          Events
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 mb-4 type-h3"
          href="/grants"
        >
          Grants
        </ActiveLink>
      </MenuTray>

  );
}
<commit_msg>rename to "Manual"<commit_after>import Link from "next/link";
import { useRouter } from "next/router";
import { useState, useEffect } from "react";
import classnames from "classnames";
import path from "path";
import MenuTray from "../components/MenuTray";
import Section from "../components/Section";
import { capitalize } from "../lib/lib";

function ActiveLink({ children, href, className, currentPath }) {
  const firstCrumb = currentPath.split("/")[1];

  const activeClassName = classnames({
    "text-wall-600": "/" + firstCrumb === href,
    "text-wall-500": "/" + firstCrumb !== href,
  });

  return (
    <Link href={href}>
      <a className={`${className} ${activeClassName}`}>{children}
    </Link>
  );
}

export default function Header(props) {
  const [isOpen, setTray] = useState(false);
  const [shortcut, setShortcut] = useState("");

  const currentPath = useRouter().asPath;

  const routeDepth = currentPath.split("/").length;

  const firstCrumb = currentPath.split("/")[1];

  const detectOS = () => {
    const agent = window.navigator.appVersion;
    if (agent.includes("Win")) {
      return "Ctrl+K";
    } else if (agent.includes("Mac")) {
      return "⌘K";
    } else if (agent.includes("Linux")) {
      return "Ctrl+K";
    }
  };

  useEffect(() => {
    setShortcut(detectOS());
  }, []);

  return (

        <Link href="/">
          Urbit
        </Link>
        {routeDepth > 2 ? (
          <Link href={`/${firstCrumb}`}>

              {capitalize(firstCrumb)}

          </Link>
        ) : null}

      {
        // Large screen header
      }

        <ActiveLink
          currentPath={currentPath}
          className="mr-5 type-ui"
          href="/docs"
        >
          Docs
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 type-ui"
          href="/using"
        >
          Manual
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 type-ui"
          href="/blog"
        >
          Blog
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 type-ui"
          href="/events"
        >
          Events
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 text-green-400 type-ui button-text"
          href="/getting-started"
        >
          Get Started
        </ActiveLink>
        <button
          onClick={(e) => {
            e.stopPropagation();
            props.search.toggleSearch(e);
          }}
          className="bg-wall-100 text-wall-500 flex px-4 py-1 rounded-lg type-ui"
        >

Search

{shortcut}

        </button>

      {
        // Small screen header
      }
      <MenuTray isOpen={isOpen} setTray={setTray} search={props.search}>
        <Link href="/">
          Urbit
        </Link>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 mb-4 type-h3"
          href="/docs"
        >
          Docs
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 mb-4 type-h3"
          href="/blog"
        >
          Blog
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 mb-4 type-h3"
          href="/events"
        >
          Events
        </ActiveLink>
        <ActiveLink
          currentPath={currentPath}
          className="mr-5 mb-4 type-h3"
          href="/grants"
        >
          Grants
        </ActiveLink>
      </MenuTray>

  );
}
<|endoftext|>