<commit_before>/**
 * Optional monad for Javascript.
 * @type {{EMPTY: Object, empty: Optional.empty, of: Optional.of}}
 */
var Optional = {
    EMPTY: Object.freeze(of(null)),
    /**
     * An empty optional
     * @returns {*}
     */
    empty: function () {
        return EMPTY;
    },
    /**
     * Creates an optional of the specified value. The value may be undefined or null.
     * @param value
     *  the value of the otional
     * @returns {{get: get, orElse: orElse, ifPresent: ifPresent, isPresent: isPresent, filter: filter, map: map, flatMap: flatMap}}
     */
    of: function (value) {

        function nullOrUndefined(value) {
            return value == undefined || value == null;
        }

        return {
            /**
             * The value of the optional
             * @returns {*}
             *  the value if it is not null or throws an Exception if the value is undefined or null
             */
            get: function () {
                if (nullOrUndefined(value)) {
                    throw "Optional value is undefined or null";
                }
                return value;
            },
            /**
             * Checks if the optional contains a value.
             * @param elseValue
             *  the value to be returned if the optional contains no value
             * @returns {*}
             */
            orElse: function (elseValue) {
                if (nullOrUndefined(value)) {
                    return elseValue;
                }
                return value;
            },
            /**
             * Applies the function if the optional value is present.
             * @param func
             *  the function to be executed. Must accept a single parameter
             */
            ifPresent: function (func) {
                if (!nullOrUndefined(value)) {
                    func(value);
                }
            },
            /**
             * Checks if the Optional contains a value.
             * @returns {boolean}
             *  true if the value is defined and not null
             */
            isPresent: function () {
                return !nullOrUndefined(value);
            },
            /**
             * Applies a filter function to this Optional.
             * @param filterFunction
             *  the filter function must accept a single parameter (the value to test) must return a boolean value
             *  indicating whether the test was successful or not
             * @returns {*}
             *  this optional if the filter test succeeded or empty if not
             */
            filter: function (filterFunction) {
                if (nullOrUndefined(value)) {
                    return this;
                } else if (filterFunction(value)) {
                    return this;
                } else {
                    return Optional.EMPTY;
                }
            },
            /**
             * Maps the value of the optional onto another optional with another value. The mapping is done by the
             * supplied mapping function. The resulting value is wrapped in an Optional
             * @param mapperFunction
             *  the mapping function used to map the value. The function must accept a single parameter (the value)
             * @returns {*}
             *  an optional of the mapped value
             */
            map: function (mapperFunction) {
                if (nullOrUndefined(value)) {
                    return Optional.EMPTY;
                } else {
                    return Optional.of(mapperFunction(value));
                }
            },
            /**
             * Similar to the map method except that the value of the mapperFunction is returned directly.
             * @param mapperFunction
             *  the mapping function used to map the value. The function must accept a single parameter (the value)
             * @returns {*}
             *  the mapped value
             */
            flatMap: function (mapperFunction) {
                if (nullOrUndefined(value)) {
                    return Optional.EMPTY;
                } else {
                    return mapperFunction(value);
                }
            }
        }
    }
}
<commit_msg>minor fixes<commit_after>/**
 * Optional monad for Javascript.
 * @type {{EMPTY: Object, empty: Optional.empty, of: Optional.of}}
 */
var Optional = {
    EMPTY: Object.freeze(of(null)),
    /**
     * An empty optional
     * @returns {*}
     */
    empty: function () {
        return EMPTY;
    },
    /**
     * Creates an optional of the specified value. The value may be undefined or null.
     * @param value
     *  the value of the otional
     * @returns {{get: get, orElse: orElse, ifPresent: ifPresent, isPresent: isPresent, filter: filter, map: map, flatMap: flatMap}}
     */
    of: function (value) {

        function nullOrUndefined(value) {
            return value == undefined || value == null;
        }

        return {
            /**
             * The value of the optional
             * @returns {*}
             *  the value if it is not null or throws an Exception if the value is undefined or null
             */
            get: function () {
                if (nullOrUndefined(value)) {
                    throw "Optional value is undefined or null";
                }
                return value;
            },
            /**
             * Checks if the optional contains a value.
             * @param elseValue
             *  the value to be returned if the optional contains no value
             * @returns {*}
             */
            orElse: function (elseValue) {
                if (nullOrUndefined(value)) {
                    return elseValue;
                }
                return value;
            },
            /**
             * Applies the function if the optional value is present.
             * @param func
             *  the function to be executed. Must accept a single parameter
             */
            ifPresent: function (func) {
                if (!nullOrUndefined(value)) {
                    func(value);
                }
            },
            /**
             * Checks if the Optional contains a value.
             * @returns {boolean}
             *  true if the value is defined and not null
             */
            isPresent: function () {
                return !nullOrUndefined(value);
            },
            /**
             * Applies a filter function to this Optional.
             * @param filterFunction
             *  the filter function must accept a single parameter (the value to test) must return a boolean value
             *  indicating whether the test was successful or not
             * @returns {*}
             *  this optional if the filter test succeeded or empty if not
             */
            filter: function (filterFunction) {
                if (nullOrUndefined(value)) {
                    return this;
                } else if (filterFunction(value)) {
                    return this;
                } else {
                    return Optional.EMPTY;
                }
            },
            /**
             * Maps the value of the optional onto another optional with another value. The mapping is done by the
             * supplied mapping function. The resulting value is wrapped in an Optional
             * @param mapperFunction
             *  the mapping function used to map the value. The function must accept a single parameter (the value)
             * @returns {*}
             *  an optional of the mapped value or the empty optional if the value is null or undefined
             */
            map: function (mapperFunction) {
                if (nullOrUndefined(value)) {
                    return Optional.EMPTY;
                } else {
                    return Optional.of(mapperFunction(value));
                }
            },
            /**
             * Similar to the map method except that the value of the mapperFunction is returned directly.
             * @param mapperFunction
             *  the mapping function used to map the value. The function must accept a single parameter (the value)
             * @returns {*}
             *  the mapped value
             */
            flatMap: function (mapperFunction) {
                return mapperFunction(value);
            }
        }
    }
}
<|endoftext|>


<commit_before>Ext.ns('Vpc.Shop.Cart.Checkout');
Vpc.Shop.Cart.Checkout.OrdersPanel = Ext.extend(Ext.Panel, {
    layout: 'border',
    initComponent: function()
    {
        var order = new Vps.Auto.FormPanel({
            region: 'center',
            controllerUrl:  this.orderControllerUrl,
            baseParams: Vps.clone(this.baseParams)
        });
        var orderProducts = new Vps.Auto.GridPanel({
            xtype: 'vps.autogrid',
            region: 'south',
            height: 150,
            split: true,
            controllerUrl: this.orderProductsControllerUrl,
            baseParams: Vps.clone(this.baseParams)
        });
        var orders = new Vps.Auto.GridPanel({
            xtype: 'vps.autogrid',
            region: 'center',
            controllerUrl: this.ordersControllerUrl,
            baseParams: Vps.clone(this.baseParams),
            bindings: [ order, { item: orderProducts, queryParam: 'shop_order_id' } ],
            columnsConfig: {
                invoice: {
                    clickHandler: function(grid, index, button, event) {
                        var row = grid.getStore().getAt(index);
                        window.open(this.ordersControllerUrl+'/pdf?'+Ext.urlEncode(this.baseParams)+'&id='+row.id);
                        (function() {
                            order.reload(); //invoice_date wurde wom�glich gesetzt
                        }).defer(500);
                    },
                    renderer: function(value, p, record, rowIndex, colIndex, store, column) {
                        p.css += 'vps-cell-button';
                        var icon = '/assets/silkicons/page_white.png';
                        if (record.get('invoice_number')) {
                            icon = '/assets/silkicons/page_white_star.png';
                        }
                        p.attr += 'style="background-image:url('+icon+');" ';
                    },
                    scope: this
                },
                shipped: {
                    renderer: function(value, p, record, rowIndex, colIndex, store, column) {
                        if (!record.get('shipped')) {
                            return Ext.util.Format.cellButton.apply(this, arguments);
                        }
                    },
                    clickHandler: function(grid, index, button, event) {
                        var row = grid.getStore().getAt(index);
                        if (row.get('shipped')) return;
                        var p = Vps.clone(this.baseParams);
                        p.id = row.id;
                        Ext.Ajax.request({
                            url: this.ordersControllerUrl+'/json-shipped',
                            params: p,
                            scope: this,
                            mask: this.getEl(),
                            success: function() {
                                orders.reload();
                                order.reload();
                            }
                        });
                    },
                    scope: this
                }
            }
        });
        this.items = [orders, {
            layout: 'border',
            region: 'east',
            width: 500,
            split: true,
            items: [order, orderProducts]
        }];

        Ext.TaskMgr.start({
            run: function() {
                orders.reload();
            },
            interval: 1000*60*5
        });

        Vpc.Shop.Cart.Checkout.OrdersPanel.superclass.initComponent.call(this);
    }
});
Ext.reg('vpc.shop.cart.checkout.orders', Vpc.Shop.Cart.Checkout.OrdersPanel);

<commit_msg>etwas mehr hoehe vom produkte grid<commit_after>Ext.ns('Vpc.Shop.Cart.Checkout');
Vpc.Shop.Cart.Checkout.OrdersPanel = Ext.extend(Ext.Panel, {
    layout: 'border',
    initComponent: function()
    {
        var order = new Vps.Auto.FormPanel({
            region: 'center',
            controllerUrl:  this.orderControllerUrl,
            baseParams: Vps.clone(this.baseParams)
        });
        var orderProducts = new Vps.Auto.GridPanel({
            xtype: 'vps.autogrid',
            region: 'south',
            height: 180,
            split: true,
            controllerUrl: this.orderProductsControllerUrl,
            baseParams: Vps.clone(this.baseParams)
        });
        var orders = new Vps.Auto.GridPanel({
            xtype: 'vps.autogrid',
            region: 'center',
            controllerUrl: this.ordersControllerUrl,
            baseParams: Vps.clone(this.baseParams),
            bindings: [ order, { item: orderProducts, queryParam: 'shop_order_id' } ],
            columnsConfig: {
                invoice: {
                    clickHandler: function(grid, index, button, event) {
                        var row = grid.getStore().getAt(index);
                        window.open(this.ordersControllerUrl+'/pdf?'+Ext.urlEncode(this.baseParams)+'&id='+row.id);
                        (function() {
                            order.reload(); //invoice_date wurde wom�glich gesetzt
                        }).defer(500);
                    },
                    renderer: function(value, p, record, rowIndex, colIndex, store, column) {
                        p.css += 'vps-cell-button';
                        var icon = '/assets/silkicons/page_white.png';
                        if (record.get('invoice_number')) {
                            icon = '/assets/silkicons/page_white_star.png';
                        }
                        p.attr += 'style="background-image:url('+icon+');" ';
                    },
                    scope: this
                },
                shipped: {
                    renderer: function(value, p, record, rowIndex, colIndex, store, column) {
                        if (!record.get('shipped')) {
                            return Ext.util.Format.cellButton.apply(this, arguments);
                        }
                    },
                    clickHandler: function(grid, index, button, event) {
                        var row = grid.getStore().getAt(index);
                        if (row.get('shipped')) return;
                        var p = Vps.clone(this.baseParams);
                        p.id = row.id;
                        Ext.Ajax.request({
                            url: this.ordersControllerUrl+'/json-shipped',
                            params: p,
                            scope: this,
                            mask: this.getEl(),
                            success: function() {
                                orders.reload();
                                order.reload();
                            }
                        });
                    },
                    scope: this
                }
            }
        });
        this.items = [orders, {
            layout: 'border',
            region: 'east',
            width: 500,
            split: true,
            items: [order, orderProducts]
        }];

        Ext.TaskMgr.start({
            run: function() {
                orders.reload();
            },
            interval: 1000*60*5
        });

        Vpc.Shop.Cart.Checkout.OrdersPanel.superclass.initComponent.call(this);
    }
});
Ext.reg('vpc.shop.cart.checkout.orders', Vpc.Shop.Cart.Checkout.OrdersPanel);

<|endoftext|>


<commit_before>//////////////////////////////////
//           SWOOP JS           //
//////////////////////////////////
// Get data from backend        //
// Get requests from frontend   //
// Match up data                //
// Send to front end            //
//////////////////////////////////
var http = require('http'); // http protocol
var express = require('express'); // web server
var bodyParser = require('body-parser'); // http body parser
var mongodb = require('mongodb');
var socketio = require('socket.io');
var request = require('request');
var fs = require('fs');
var Mongo = mongodb.MongoClient;
var ObjectID = mongodb.ObjectID;
var http = require('http').Server(app);
const MONGO_URL = 'mongodb://localhost:27017/swoop';
///////////////
// MONGO OPs //
///////////////
Mongo.connect(MONGO_URL, function (err, db) {
    if (err) log('error');
    else log('good to go');
    Mongo.ops = {};
    // TODO: Add needed Functions
    Mongo.ops.upsert = function (collection, query, json, callback) {
        db.collection(collection).updateOne(query, {
            $set: json
        }, {
            upsert: true
        }, function (err, result) {
            // TODO: handle err
            if (callback) callback(err, result);
        });
    };
    Mongo.ops.insert = function (collection, json, callback) {
        db.collection(collection).insert(json, function (err, result) {
            if (callback) callback(err, result);
        });
    };
});
////////////////////
// Cross Domains  //
////////////////////
/*function allowCrossDomain(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Authorization');
    // end pre flights
}
//
var app = express();
// use middlewares
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: false
}));
app.use(allowCrossDomain);
*/
///////////////
//  NodeJS   //
///////////////
var app = express();
// use middlewares
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: false
}));
app.post('/car1', function (req, res, next) {
    log('/car1 req.body =', req.body);
    var payload = req.body
    io.sockets.emit('addcar1', req.body);
    Mongo.ops.upsert('car1-current', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
    Mongo.ops.insert('car1-all', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
});
app.post('/car2', function (req, res, next) {
    log('/car2 req.body =', req.body);
    var payload = req.body
    io.sockets.emit('addcar2', req.body);
    Mongo.ops.upsert('car2-current', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
    Mongo.ops.insert('car2-all', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
});
app.post('/car3', function (req, res, next) {
    log('/car3 req.body =', req.body);
    var payload = req.body
    io.sockets.emit('addcar3', req.body);
    Mongo.ops.upsert('car3-current', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
    Mongo.ops.insert('car3-all', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
});
app.listen(3000, function () {
    log('listening on port 3000');
});
///////////////
// SOCKET iO //
///////////////
var server = http.listen(3000, function () {
    console.log('server listening on http://localhost:3000/');
});
var io = require('socket.io').listen(server);

io.sockets.on('connection', function (socket) {
    log('new socket client: ', socket.id);
    socket.on('disconnect', function () {
        log('socket client disconnected: ', socket.id);
    });
    socket.on('addcar1', function (data) {
        log('car lat and long: ' + data.lat + ", " + data.long);
        socket.broadcast.emit('car1', data);
    })
    socket.on('addcar2', function (data) {
        log('car lat and long: ' + data.lat + ", " + data.long);
        socket.broadcast.emit('car2', data);
    })
    socket.on('addcar3', function (data) {
        log('car lat and long: ' + data.lat + ", " + data.long);
        socket.broadcast.emit('car3', data);
    })
});
///////////////
//    LOG    //
///////////////
function log(msg) {
    console.log(msg);
}<commit_msg>Fixed port conflict<commit_after>//////////////////////////////////
//           SWOOP JS           //
//////////////////////////////////
// Get data from backend        //
// Get requests from frontend   //
// Match up data                //
// Send to front end            //
//////////////////////////////////
var http = require('http'); // http protocol
var express = require('express'); // web server
var bodyParser = require('body-parser'); // http body parser
var mongodb = require('mongodb');
var socketio = require('socket.io');
var request = require('request');
var fs = require('fs');
var Mongo = mongodb.MongoClient;
var ObjectID = mongodb.ObjectID;
var http = require('http').Server(app);
const MONGO_URL = 'mongodb://localhost:27017/swoop';
///////////////
// MONGO OPs //
///////////////
Mongo.connect(MONGO_URL, function (err, db) {
    if (err) log('error');
    else log('good to go');
    Mongo.ops = {};
    // TODO: Add needed Functions
    Mongo.ops.upsert = function (collection, query, json, callback) {
        db.collection(collection).updateOne(query, {
            $set: json
        }, {
            upsert: true
        }, function (err, result) {
            // TODO: handle err
            if (callback) callback(err, result);
        });
    };
    Mongo.ops.insert = function (collection, json, callback) {
        db.collection(collection).insert(json, function (err, result) {
            if (callback) callback(err, result);
        });
    };
});
////////////////////
// Cross Domains  //
////////////////////
/*function allowCrossDomain(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Authorization');
    // end pre flights
}
//
var app = express();
// use middlewares
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: false
}));
app.use(allowCrossDomain);
*/
///////////////
//  NodeJS   //
///////////////
var app = express();
// use middlewares
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: false
}));
app.post('/car1', function (req, res, next) {
    log('/car1 req.body =', req.body);
    var payload = req.body
    io.sockets.emit('addcar1', req.body);
    Mongo.ops.upsert('car1-current', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
    Mongo.ops.insert('car1-all', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
});
app.post('/car2', function (req, res, next) {
    log('/car2 req.body =', req.body);
    var payload = req.body
    io.sockets.emit('addcar2', req.body);
    Mongo.ops.upsert('car2-current', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
    Mongo.ops.insert('car2-all', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
});
app.post('/car3', function (req, res, next) {
    log('/car3 req.body =', req.body);
    var payload = req.body
    io.sockets.emit('addcar3', req.body);
    Mongo.ops.upsert('car3-current', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
    Mongo.ops.insert('car3-all', payload, function (err, response) {
        if (err) {
            console.log(err);
        }
        else {
            res.status(201).send('ok');
        }
    });
});
app.listen(3000, function () {
    log('listening on port 3000');
});
///////////////
// SOCKET iO //
///////////////
var server = http.listen(8080, function () {
    console.log('server listening on http://localhost:3000/');
});
var io = require('socket.io').listen(server);

io.sockets.on('connection', function (socket) {
    log('new socket client: ', socket.id);
    socket.on('disconnect', function () {
        log('socket client disconnected: ', socket.id);
    });
    socket.on('addcar1', function (data) {
        log('car lat and long: ' + data.lat + ", " + data.long);
        socket.broadcast.emit('car1', data);
    })
    socket.on('addcar2', function (data) {
        log('car lat and long: ' + data.lat + ", " + data.long);
        socket.broadcast.emit('car2', data);
    })
    socket.on('addcar3', function (data) {
        log('car lat and long: ' + data.lat + ", " + data.long);
        socket.broadcast.emit('car3', data);
    })
});
///////////////
//    LOG    //
///////////////
function log(msg) {
    console.log(msg);
}<|endoftext|>


<commit_before>
// Configuration settings

window.lj_conf = {
    number : 10,
    count : 10,
    date : null,
    expanded : false,
    journal : null,
    reset: function () {
        this.number = 10;
        this.count = 10;
		this.date = '';
//        this.expanded = true;
//        this.journal = 'toronto-ru';
    },
    setJournal: function(journal) {
        this.number = 10;
        this.count = 10;
		this.date = '';
//		this.expanded = true;
        this.journal = journal;
    }
};

<commit_msg>Fix initial date<commit_after>
// Configuration settings

window.lj_conf = {
    format : 'yyyy-MM-dd HH:mm:ss',
    number : 10,
    count : 10,
    date : null,
    expanded : false,
    journal : null,
    setCurrentDate: function() {
        this.date = $.format.date(new Date(), this.format);
    },
    reset: function () {
        this.setCurrentDate();
        this.number = 10;
        this.count = 10;
    },
    setJournal: function(journal) {
        this.reset();
        this.journal = journal;
    }
};

<|endoftext|>


<commit_before>(function() {

  /**
  *
  * Backbone Game Engine - An elementary HTML5 canvas game engine using Backbone.
  *
  * Copyright (c) 2014 Martin Drapeau
  * https://github.com/martindrapeau/backbone-game-engine
  *
  */

  // Ensures the canvas is always full size and/or centered.
  //
  // On mobile:
  // Works in conjunction with meta tag viewport where width is set to the canvas width.
  // <meta name="viewport" content="width=960, user-scalable=no"/>
  // Will modify the canvas height to fit the device aspect ratio, never exceeding the
  // origin canvas height.
  // Set keepRatio to true to maintain your aspect ratio. In such a case, the viewport
  // is adjusted to the height of the canvas. The canvas is kept centered on screen (with
  // black bars left and right to fill empty space).
  //
  // On Desktop:
  // The viewport meta tag is ignored. Instead, the canvas is kept centered. The height
  // may be reduced if the window height is less than the canvas (to avoid scrolling).
  // Set keepRatio to maintain the canvas height.

  function adjustViewport(canvas, keepRatio) {

    var viewport = document.querySelector("meta[name=viewport]"),
        mobile = "onorientationchange" in window ||
          window.navigator.msMaxTouchPoints ||
          window.navigator.isCocoonJS;

    function onResize() {
      if (window.innerWidth > window.innerHeight) {
        // Landscape
        canvas.style.left = _.max([0, (window.innerWidth - canvas.width) / 2]) + "px";
        if (mobile && viewport)
          viewport.setAttribute("content", "width=" + Math.ceil(canvas.height * window.innerWidth / window.innerHeight) + ",user-scalable=no");
      } else {
        // Portrait
        canvas.style.left = "0px";
        if (mobile && viewport)
          viewport.setAttribute("content", "width=" + canvas.width + ",user-scalable=no");
      }
    }

    if (mobile && !keepRatio) {
      canvas.height = Math.round(Math.min(canvas.height, canvas.width * Math.min(window.innerHeight, window.innerWidth) / Math.max(window.innerHeight, window.innerWidth) ));
    } else {
      if (!keepRatio)
        canvas.height = Math.round(Math.min(canvas.height, window.innerHeight));
      window.addEventListener("resize", _.debounce(onResize, 300));
      setTimeout(onResize, 10);
    }

  }

  _.extend(window, {
    adjustViewport: adjustViewport
  });

}).call(this);<commit_msg>viewport bug on CocoonJS<commit_after>(function() {

  /**
  *
  * Backbone Game Engine - An elementary HTML5 canvas game engine using Backbone.
  *
  * Copyright (c) 2014 Martin Drapeau
  * https://github.com/martindrapeau/backbone-game-engine
  *
  */

  // Ensures the canvas is always full size and/or centered.
  //
  // On mobile:
  // Works in conjunction with meta tag viewport where width is set to the canvas width.
  // <meta name="viewport" content="width=960, user-scalable=no"/>
  // Will modify the canvas height to fit the device aspect ratio, never exceeding the
  // origin canvas height.
  // Set keepRatio to true to maintain your aspect ratio. In such a case, the viewport
  // is adjusted to the height of the canvas. The canvas is kept centered on screen (with
  // black bars left and right to fill empty space).
  //
  // On Desktop:
  // The viewport meta tag is ignored. Instead, the canvas is kept centered. The height
  // may be reduced if the window height is less than the canvas (to avoid scrolling).
  // Set keepRatio to maintain the canvas height.

  function adjustViewport(canvas, keepRatio) {

    var viewport = !window.navigator.isCocoonJS ? document.querySelector("meta[name=viewport]") : null,
        mobile = "onorientationchange" in window ||
          window.navigator.msMaxTouchPoints ||
          window.navigator.isCocoonJS;

    function onResize() {
      if (window.innerWidth > window.innerHeight) {
        // Landscape
        canvas.style.left = _.max([0, (window.innerWidth - canvas.width) / 2]) + "px";
        if (mobile && viewport)
          viewport.setAttribute("content", "width=" + Math.ceil(canvas.height * window.innerWidth / window.innerHeight) + ",user-scalable=no");
      } else {
        // Portrait
        canvas.style.left = "0px";
        if (mobile && viewport)
          viewport.setAttribute("content", "width=" + canvas.width + ",user-scalable=no");
      }
    }

    if (mobile && !keepRatio) {
      canvas.height = Math.round(Math.min(canvas.height, canvas.width * Math.min(window.innerHeight, window.innerWidth) / Math.max(window.innerHeight, window.innerWidth) ));
    } else {
      if (!keepRatio)
        canvas.height = Math.round(Math.min(canvas.height, window.innerHeight));
      window.addEventListener("resize", _.debounce(onResize, 300));
      setTimeout(onResize, 10);
    }

  }

  _.extend(window, {
    adjustViewport: adjustViewport
  });

}).call(this);<|endoftext|>


<commit_before>(function() {
'use strict';

angular.module('ionic.ui.popup', [])

/**
 * @private
 */
.directive('ionPopupBackdrop', function() {
  return {
    restrict: 'E',
    replace: true,
    template: '

'
  }
})

/**
 * @private
 */
.directive('ionPopup', ['$ionicBind', function($ionicBind) {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    scope: true,
    template:
      '
' +
        '
' +
          '

' +
          '

' +
        '
' +
        '
' +
        '
' +
        '
' +
          '<button ng-repeat="button in buttons" ng-click="_buttonTapped(button, $event)" class="button col" ng-class="button.type || \'button-default\'" ng-bind-html="button.text"></button>' +
        '
' +
      '
',
    link: function($scope, $element, $attr) {
      $ionicBind($scope, $attr, {
        title: '@',
        buttons: '=',
        $onButtonTap: '&onButtonTap',
        $onClose: '&onClose'
      });

      $scope._buttonTapped = function(button, event) {
        var result = button.onTap && button.onTap(event);

        // A way to return false
        if(event.defaultPrevented) {
          return $scope.$onClose({button: button, result: false, event: event });
        }

        // Truthy test to see if we should close the window
        if(result) {
          return $scope.$onClose({button: button, result: result, event: event });
        }
        $scope.$onButtonTap({button: button, event: event});
      }
    }
  };
}]);

})();
<commit_msg>fix($ionicPopup): make it work if jquery is included<commit_after>(function() {
'use strict';

angular.module('ionic.ui.popup', [])

/**
 * @private
 */
.directive('ionPopupBackdrop', function() {
  return {
    restrict: 'E',
    replace: true,
    template: '

'
  }
})

/**
 * @private
 */
.directive('ionPopup', ['$ionicBind', function($ionicBind) {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    scope: true,
    template:
      '
' +
        '
' +
          '

' +
          '

' +
        '
' +
        '
' +
        '
' +
        '
' +
          '<button ng-repeat="button in buttons" ng-click="_buttonTapped(button, $event)" class="button col" ng-class="button.type || \'button-default\'" ng-bind-html="button.text"></button>' +
        '
' +
      '
',
    link: function($scope, $element, $attr) {
      $ionicBind($scope, $attr, {
        title: '@',
        buttons: '=',
        $onButtonTap: '&onButtonTap',
        $onClose: '&onClose'
      });

      $scope._buttonTapped = function(button, event) {
        var result = button.onTap && button.onTap(event);

        // A way to return false
        if((event.originalEvent || event).defaultPrevented) {
          return $scope.$onClose({button: button, result: false, event: event });
        }

        // Truthy test to see if we should close the window
        if(result) {
          return $scope.$onClose({button: button, result: result, event: event });
        }
        $scope.$onButtonTap({button: button, event: event});
      }
    }
  };
}]);

})();
<|endoftext|>


<commit_before>import Component from 'flarum/component';
import ItemList from 'flarum/utils/item-list';
import DiscussionList from 'flarum/components/discussion-list';
import DiscussionHero from 'flarum/components/discussion-hero';
import PostStream from 'flarum/components/post-stream';
import PostScrubber from 'flarum/components/post-scrubber';
import ReplyComposer from 'flarum/components/reply-composer';
import ActionButton from 'flarum/components/action-button';
import LoadingIndicator from 'flarum/components/loading-indicator';
import DropdownSplit from 'flarum/components/dropdown-split';
import Separator from 'flarum/components/separator';
import listItems from 'flarum/helpers/list-items';
import mixin from 'flarum/utils/mixin';
import evented from 'flarum/utils/evented';

export default class DiscussionPage extends mixin(Component, evented) {
  /**

   */
  constructor(props) {
    super(props);

    this.discussion = m.prop();
    this.refresh();

    if (app.cache.discussionList) {
      if (!(app.current instanceof DiscussionPage)) {
        app.cache.discussionList.subtrees.map(subtree => subtree.invalidate());
      } else {
        m.redraw.strategy('diff'); // otherwise pane redraws (killing retained subtrees) and mouseenter event is triggered so it doesn't hide
      }
      app.pane.enable();
      app.pane.hide();
    }

    app.history.push('discussion');
    app.current = this;
    app.session.on('loggedIn', this.loggedInHandler = this.refresh.bind(this));
  }

  refresh() {
    this.currentNear = m.route.param('near') || 0;
    this.discussion(null);

    var params = this.params();
    params.include = params.include.join(',');

    var discussion;
    if (app.preload.response) {
      // We must wrap this in a setTimeout because if we are mounting this
      // component for the first time on page load, then any calls to m.redraw
      // will be ineffective and thus any configs (scroll code) will be run
      // before stuff is drawn to the page.
      setTimeout(() => {
        var discussion = app.store.pushPayload(app.preload.response);
        app.preload.response = null;
        this.setupDiscussion(discussion);
      });
    } else {
      app.store.find('discussions', m.route.param('id'), params).then(this.setupDiscussion.bind(this));
    }

    // Trigger a redraw only if we're not already in a computation (e.g. route change)
    m.startComputation();
    m.endComputation();
  }

  params() {
    return {
      near: this.currentNear,
      include: ['posts', 'posts.user', 'posts.user.groups']
    };
  }

  /*

   */
  setupDiscussion(discussion) {
    // Hold up there skippy! If the slug in the URL doesn't match up, we'll
    // redirect so we have the correct one.
    // Waiting on https://github.com/lhorie/mithril.js/issues/539
    // if (m.route.param('id') === discussion.id() && m.route.param('slug') !== discussion.slug()) {
    //   var params = m.route.param();
    //   params.slug = discussion.slug();
    //   params.near = params.near || '';
    //   m.route(app.route('discussion.near', params), null, true);
    //   return;
    // }

    this.discussion(discussion);
    app.setTitle(discussion.title());

    var includedPosts = [];
    if (discussion.payload && discussion.payload.included) {
      discussion.payload.included.forEach(record => {
        if (record.type === 'posts' && record.links && record.links.discussion) {
          includedPosts.push(app.store.getById('posts', record.id));
        }
      });
      includedPosts.sort((a, b) => a.id() - b.id());
    }

    this.stream = new PostStream({ discussion, includedPosts });
    this.stream.on('positionChanged', this.positionChanged.bind(this));
    this.stream.goToNumber(m.route.param('near') || 1, true);

    this.trigger('loaded', discussion);
  }

  onload(element, isInitialized, context) {
    if (isInitialized) { return; }

    context.retain = true;

    $('body').addClass('discussion-page');
    context.onunload = function() {
      $('body').removeClass('discussion-page');
    }
  }

  /**

   */
  onunload(e) {
    // If we have routed to the same discussion as we were viewing previously,
    // cancel the unloading of this controller and instead prompt the post
    // stream to jump to the new 'near' param.
    var discussion = this.discussion();
    if (discussion) {
      if (m.route.param('id') == discussion.id()) {
        e.preventDefault();
        if (m.route.param('near') != this.currentNear) {
          this.stream.goToNumber(m.route.param('near') || 1);
        }
        this.currentNear = null;
        return;
      }
    }

    app.pane.disable();
    app.composer.minimize();
    app.session.off('loggedIn', this.loggedInHandler);
  }

  /**

   */
  view() {
    var discussion = this.discussion();

    return m('div', {config: this.onload.bind(this)}, [
      app.cache.discussionList ? m('div.index-area.paned', {config: this.configIndex.bind(this)}, app.cache.discussionList.view()) : '',
      m('div.discussion-area', discussion ? [
        DiscussionHero.component({discussion}),
        m('div.container', [
          m('nav.discussion-nav', [
            m('ul', listItems(this.sidebarItems().toArray()))
          ]),
          this.stream.view()
        ])
      ] : LoadingIndicator.component({className: 'loading-indicator-block'}))
    ]);
  }

  /**

   */
  configIndex(element, isInitialized, context) {
    if (isInitialized) { return; }

    context.retain = true;

    var $index = $(element);

    // When viewing a discussion (for which the discussions route is the
    // parent,) the discussion list is still rendered but it becomes a
    // pane hidden on the side of the screen. When the mouse enters and
    // leaves the discussions pane, we want to show and hide the pane
    // respectively. We also create a 10px 'hot edge' on the left of the
    // screen to activate the pane.
    var pane = app.pane;
    $index.hover(pane.show.bind(pane), pane.onmouseleave.bind(pane));

    var hotEdge = function(e) {
      if (e.pageX < 10) { pane.show(); }
    };
    $(document).on('mousemove', hotEdge);
    context.onunload = function() {
      $(document).off('mousemove', hotEdge);
    };

    var $discussion = $index.find('.discussion-summary.active');
    if ($discussion.length) {
      var indexTop = $index.offset().top;
      var discussionTop = $discussion.offset().top;
      if (discussionTop < indexTop || discussionTop + $discussion.outerHeight() > indexTop + $index.outerHeight()) {
        $index.scrollTop($index.scrollTop() - indexTop + discussionTop);
      }
    }
  }

  /**

   */
  sidebarItems() {
    var items = new ItemList();

    items.add('controls',
      DropdownSplit.component({
        items: this.discussion().controls(this).toArray(),
        icon: 'ellipsis-v',
        className: 'primary-control',
        buttonClass: 'btn btn-primary'
      })
    );

    items.add('scrubber',
      PostScrubber.component({
        stream: this.stream,
        className: 'title-control'
      })
    );

    return items;
  }

  /**

   */
  positionChanged(startNumber, endNumber) {
    var discussion = this.discussion();

    var url = app.route('discussion.near', {
      id: discussion.id(),
      slug: discussion.slug(),
      near: this.currentNear = startNumber
    });

    // https://github.com/lhorie/mithril.js/issues/559
    m.route(url, true);
    window.history.replaceState(null, document.title, (m.route.mode === 'hash' ? '#' : '')+url);

    app.history.push('discussion');

    if (app.session.user() && endNumber > discussion.readNumber()) {
      discussion.save({readNumber: endNumber});
      m.redraw();
    }
  }
}
<commit_msg>Only display the first page of posts<commit_after>import Component from 'flarum/component';
import ItemList from 'flarum/utils/item-list';
import DiscussionList from 'flarum/components/discussion-list';
import DiscussionHero from 'flarum/components/discussion-hero';
import PostStream from 'flarum/components/post-stream';
import PostScrubber from 'flarum/components/post-scrubber';
import ReplyComposer from 'flarum/components/reply-composer';
import ActionButton from 'flarum/components/action-button';
import LoadingIndicator from 'flarum/components/loading-indicator';
import DropdownSplit from 'flarum/components/dropdown-split';
import Separator from 'flarum/components/separator';
import listItems from 'flarum/helpers/list-items';
import mixin from 'flarum/utils/mixin';
import evented from 'flarum/utils/evented';

export default class DiscussionPage extends mixin(Component, evented) {
  /**

   */
  constructor(props) {
    super(props);

    this.discussion = m.prop();
    this.refresh();

    if (app.cache.discussionList) {
      if (!(app.current instanceof DiscussionPage)) {
        app.cache.discussionList.subtrees.map(subtree => subtree.invalidate());
      } else {
        m.redraw.strategy('diff'); // otherwise pane redraws (killing retained subtrees) and mouseenter event is triggered so it doesn't hide
      }
      app.pane.enable();
      app.pane.hide();
    }

    app.history.push('discussion');
    app.current = this;
    app.session.on('loggedIn', this.loggedInHandler = this.refresh.bind(this));
  }

  refresh() {
    this.currentNear = m.route.param('near') || 0;
    this.discussion(null);

    var params = this.params();
    params.include = params.include.join(',');

    var discussion;
    if (app.preload.response) {
      // We must wrap this in a setTimeout because if we are mounting this
      // component for the first time on page load, then any calls to m.redraw
      // will be ineffective and thus any configs (scroll code) will be run
      // before stuff is drawn to the page.
      setTimeout(() => {
        var discussion = app.store.pushPayload(app.preload.response);
        app.preload.response = null;
        this.setupDiscussion(discussion);
      });
    } else {
      app.store.find('discussions', m.route.param('id'), params).then(this.setupDiscussion.bind(this));
    }

    // Trigger a redraw only if we're not already in a computation (e.g. route change)
    m.startComputation();
    m.endComputation();
  }

  params() {
    return {
      near: this.currentNear,
      include: ['posts', 'posts.user', 'posts.user.groups']
    };
  }

  /*

   */
  setupDiscussion(discussion) {
    // Hold up there skippy! If the slug in the URL doesn't match up, we'll
    // redirect so we have the correct one.
    // Waiting on https://github.com/lhorie/mithril.js/issues/539
    // if (m.route.param('id') === discussion.id() && m.route.param('slug') !== discussion.slug()) {
    //   var params = m.route.param();
    //   params.slug = discussion.slug();
    //   params.near = params.near || '';
    //   m.route(app.route('discussion.near', params), null, true);
    //   return;
    // }

    this.discussion(discussion);
    app.setTitle(discussion.title());

    var includedPosts = [];
    if (discussion.payload && discussion.payload.included) {
      discussion.payload.included.forEach(record => {
        if (record.type === 'posts' && record.links && record.links.discussion) {
          includedPosts.push(app.store.getById('posts', record.id));
        }
      });
      includedPosts.sort((a, b) => a.id() - b.id()).splice(20);
    }

    this.stream = new PostStream({ discussion, includedPosts });
    this.stream.on('positionChanged', this.positionChanged.bind(this));
    this.stream.goToNumber(m.route.param('near') || 1, true);

    this.trigger('loaded', discussion);
  }

  onload(element, isInitialized, context) {
    if (isInitialized) { return; }

    context.retain = true;

    $('body').addClass('discussion-page');
    context.onunload = function() {
      $('body').removeClass('discussion-page');
    }
  }

  /**

   */
  onunload(e) {
    // If we have routed to the same discussion as we were viewing previously,
    // cancel the unloading of this controller and instead prompt the post
    // stream to jump to the new 'near' param.
    var discussion = this.discussion();
    if (discussion) {
      if (m.route.param('id') == discussion.id()) {
        e.preventDefault();
        if (m.route.param('near') != this.currentNear) {
          this.stream.goToNumber(m.route.param('near') || 1);
        }
        this.currentNear = null;
        return;
      }
    }

    app.pane.disable();
    app.composer.minimize();
    app.session.off('loggedIn', this.loggedInHandler);
  }

  /**

   */
  view() {
    var discussion = this.discussion();

    return m('div', {config: this.onload.bind(this)}, [
      app.cache.discussionList ? m('div.index-area.paned', {config: this.configIndex.bind(this)}, app.cache.discussionList.view()) : '',
      m('div.discussion-area', discussion ? [
        DiscussionHero.component({discussion}),
        m('div.container', [
          m('nav.discussion-nav', [
            m('ul', listItems(this.sidebarItems().toArray()))
          ]),
          this.stream.view()
        ])
      ] : LoadingIndicator.component({className: 'loading-indicator-block'}))
    ]);
  }

  /**

   */
  configIndex(element, isInitialized, context) {
    if (isInitialized) { return; }

    context.retain = true;

    var $index = $(element);

    // When viewing a discussion (for which the discussions route is the
    // parent,) the discussion list is still rendered but it becomes a
    // pane hidden on the side of the screen. When the mouse enters and
    // leaves the discussions pane, we want to show and hide the pane
    // respectively. We also create a 10px 'hot edge' on the left of the
    // screen to activate the pane.
    var pane = app.pane;
    $index.hover(pane.show.bind(pane), pane.onmouseleave.bind(pane));

    var hotEdge = function(e) {
      if (e.pageX < 10) { pane.show(); }
    };
    $(document).on('mousemove', hotEdge);
    context.onunload = function() {
      $(document).off('mousemove', hotEdge);
    };

    var $discussion = $index.find('.discussion-summary.active');
    if ($discussion.length) {
      var indexTop = $index.offset().top;
      var discussionTop = $discussion.offset().top;
      if (discussionTop < indexTop || discussionTop + $discussion.outerHeight() > indexTop + $index.outerHeight()) {
        $index.scrollTop($index.scrollTop() - indexTop + discussionTop);
      }
    }
  }

  /**

   */
  sidebarItems() {
    var items = new ItemList();

    items.add('controls',
      DropdownSplit.component({
        items: this.discussion().controls(this).toArray(),
        icon: 'ellipsis-v',
        className: 'primary-control',
        buttonClass: 'btn btn-primary'
      })
    );

    items.add('scrubber',
      PostScrubber.component({
        stream: this.stream,
        className: 'title-control'
      })
    );

    return items;
  }

  /**

   */
  positionChanged(startNumber, endNumber) {
    var discussion = this.discussion();

    var url = app.route('discussion.near', {
      id: discussion.id(),
      slug: discussion.slug(),
      near: this.currentNear = startNumber
    });

    // https://github.com/lhorie/mithril.js/issues/559
    m.route(url, true);
    window.history.replaceState(null, document.title, (m.route.mode === 'hash' ? '#' : '')+url);

    app.history.push('discussion');

    if (app.session.user() && endNumber > discussion.readNumber()) {
      discussion.save({readNumber: endNumber});
      m.redraw();
    }
  }
}
<|endoftext|>


<commit_before>define([
    "zepto",
    "modules/hashTable",
    "modules/channels/channel",
    "modules/channels/tokens",
    "modules/channels/channelExtensions",
    "modules/channels/tlkeChannel",
    "modules/channels/remoteChannel",
    "modules/channels/tlChannel",
    "modules/data-types/hex",
    "tools/urandom"
], function ($, HashTable, Channel, tokens, extensions, TlkeChannel, RemoteChannel, TlChannel, Hex, urandom) {
    "use strict";

    function ContactChannelGroup() {

        // new RemoteChannel() will call this._notifyDirty but the dirtyNotifier is not yet set
        // just don't forget to set the dirtyNotifier after calling new ContactChannelGroup()
        this.setDirtyNotifier({notify: function () { }});

        this.channels = new HashTable();
        this.remoteChannels = new HashTable();
        this.tlkeChannel = null;
        // alice generates offer, bob accepts
        this.iAmAlice = null;

        // mirror of the contact's ContactChannelGroup to send tokens
        this.remoteChannelGroup = new RemoteChannel();
        this._addRemoteChannel(this.remoteChannelGroup, 0);
        this.channels.setItem(this, {ref: 0});

        this._setTokenHandler(tokens.ContactChannelGroup.GenerateTlkeToken, this.onTokenGenerateTlke);
        this._setTokenHandler(tokens.ContactChannelGroup.OfferToken, this.onTokenOffer);
        this._setTokenHandler(tokens.ContactChannelGroup.AuthToken, this.onTokenAuth);
        this._setTokenHandler(tokens.ContactChannelGroup.GenerateOverTlkeToken, this.requestCreateExtraTlChannel);
    }

    ContactChannelGroup.prototype = new Channel();

    $.extend(ContactChannelGroup.prototype, {
        setMsgProcessor: function (iMsgProcessor) { this.msgProcessor = iMsgProcessor; },

        ////////////////////
        //  User comms    //
        ////////////////////
        // user calls enterToken with ContactChannelGroup.GenerateTlkeToken argument
        onTokenGenerateTlke: function (token, context) {
            this.iAmAlice = true;
            this.tlkeChannel = new TlkeChannel();
            this._addChannel(this.tlkeChannel);
            this.tlkeChannel.enterToken(new tokens.TlkeChannel.GenerateToken());
        },
        // user calls enterToken with ContactChannelGroup.OfferToken argument
        onTokenOffer: function (token, context) {
            this.iAmAlice = false;
            this.tlkeChannel = new TlkeChannel();
            this._addChannel(this.tlkeChannel);
            this.tlkeChannel.enterToken(new tokens.TlkeChannel.OfferToken(token.offer));
        },
        // user calls enterToken with ContactChannelGroup.AuthToken argument
        onTokenAuth: function (token, context) {
            if (!this.tlkeChannel) {
                throw new Error("Tlke channel is not ready");
            }
            this.tlkeChannel.enterToken(new tokens.TlkeChannel.AuthToken(token.auth));
        },
        // transport calls processPacket. Careful to the structure: { receiver: "BEEF", data: "1FAA..." }
        processPacket: function (packet) {
            var receiverTuple = this.channels.first(function (value) {
                return value.inId && value.inId.as(Hex).isEqualTo(packet.receiver);
            });
            if (receiverTuple) {
                receiverTuple.key.processPacket(packet.data);
            } else {
                throw new Error("Could not find the receiver for packet ", packet, " Check packet.receiver property");
            }
        },

        // handled by extensions, configured by this._setTokenHandler()
        enterToken: function (token, context) {
            this._enterToken(token, context);
        },

        // simply send the user message to the contact. data should be plain object
        sendMessage: function (data) {
            this._sendMessage(new ChannelGroupMessage(ChannelGroupMessage.MSG_TYPE_USER, data));
        },

        //////////////////////////////
        //  Regular channels comms.
        //  (regular channels communicate via packetSender that uses onChannelSendPacket())
        //////////////////////////////
        // a message received from generic channel
        onChannelMessage: function (channel, data) {
            var message = ChannelGroupMessage.deserialize(data);
            if (message.type === ChannelGroupMessage.MSG_TYPE_USER) {
                this._emitUserMessage(message.data);
            } else if (message.type === ChannelGroupMessage.MSG_TYPE_WRAPPER) {
                this.onPacketForRemoteChannel(message.data, message.ref);
            } else {
                console.warn("Received a strange message: ", message);
            }
        },
        // one of regular channels has issued a token
        onChannelToken: function (isOverChannel, channel, token, context) {

            if (token instanceof tokens.TlkeChannel.TlkeChannelGeneratedToken) {
                // learn new ids
                this.onChannelNewIds(channel, token);
            } else if (token instanceof tokens.TlkeChannel.ChangeStateToken) {
                // just mirror tlke change state token
                if (isOverChannel) {
                    this._emitPrompt(new tokens.ContactChannelGroup.OverChannelChangeStateToken(token.state));
                } else {
                    this._emitPrompt(new tokens.ContactChannelGroup.ChangeStateToken(token.state));
                }
            } else if (token instanceof tokens.TlkeChannel.GenericChannelGeneratedToken) {
                // create new generic channel
                this.onNewTlChannelKeysReady(token);
            } else if (channel === this.tlkeChannel && token instanceof tokens.TlkeChannel.OfferToken) {
                // just mirror tlke offer token
                this._emitPrompt(new tokens.ContactChannelGroup.OfferToken(token.offer));
            } else if (channel === this.tlkeChannel && token instanceof tokens.TlkeChannel.AuthToken) {
                // just mirror tlke auth token
                this._emitPrompt(new tokens.ContactChannelGroup.AuthToken(token.auth));
            }

            // handle additional overChannel tokens
            if (isOverChannel) {
                this.onOverChannelToken(channel, token, context);
            }
        },

        // new channel ids learned, add to routing
        onChannelNewIds: function (channel, token) {
            var info = this.channels.getItem(channel);
            info.inId = token.inId;
            info.outId = token.outId;
            this.channels.setItem(channel, info);
            // notify the owner that it should listen more channelIds
            this._emitPrompt(new tokens.ContactChannelGroup.ChannelAddedToken(token.inId));
            this._notifyDirty();
        },
        // tlke channel has generated new keys for generic channel
        onNewTlChannelKeysReady: function (token) {
            // todo remove tlke from lists and clear this.tlkeChannel
            var newGeneric = new TlChannel();
            this._addChannel(newGeneric, null, true);
            this.onChannelNewIds(newGeneric, token);
            newGeneric.enterToken(token);
        },
        // channel sends a packet. Careful to the structure of the resulting packet: { receiver: "BEEF", data: "1FAA..." }
        onChannelSendPacket: function (channel, data) {
            var sender = this.channels.getItem(channel);
            if (!sender.outId) {
                throw new Error("The channel did not provide it's channel ids yet");
            }
            var packet = {
                receiver: sender.outId,
                data: data
            };
            this._sendPacket(packet);
        },
        // channel notifies it has changed it's state
        onChannelNotifyDirty: function (channel) {
            this._notifyDirty();
        },

        //////////////////////////////
        //  Remote channels comms   //
        //////////////////////////////
        // RemoteChannel wants to send the token
        onRemoteChannelSendPacket: function (channel, packet) {
            var sender = this.remoteChannels.getItem(channel);
            this._sendMessage(new ChannelGroupMessage(ChannelGroupMessage.MSG_TYPE_WRAPPER, packet, sender.ref));
        },
        // the remote channel has issued the token
        onRemoteChannelToken: function (channel, token, context) {
            var remoteChannelInfo = this.remoteChannels.getItem(channel);
            var ref = remoteChannelInfo.ref;
            var overChannelItem = this.channels.first(function (value) {
                return value.ref === remoteChannelInfo.ref;
            });
            var refChannel = overChannelItem ? overChannelItem.key : null;

            if ((token instanceof tokens.ContactChannelGroup.OfferToken) && ref === 0) {
                // remote ContactChannelGroup has provided an offer to accept
                this.onRemoteTokenOffer(token, refChannel);
            } else if (token instanceof tokens.ContactChannelGroup.AuthToken) {
                // remote ContactChannelGroup has provided an offer to accept
                refChannel.enterToken(new tokens.TlkeChannel.AuthToken(token.auth));
            }
        },
        // the packet received in a wrapper message from generic channel
        onPacketForRemoteChannel: function (packet, ref) {
            var remoteChannelTuple = this.remoteChannels.first(function (value) {
                return value.ref === ref;
            });
            if (remoteChannelTuple) {
                remoteChannelTuple.key.processPacket(packet);
            } else {
                console.warn("Remote channel with ref " + ref + " not found");
            }
        },

        // received the remote token to create new remote channel and accept offer
        onRemoteTokenOffer: function (token) {
            var overTlke = new TlkeChannel();
            this._addChannel(overTlke, token.ref);
            var remoteTlke = new RemoteChannel();
            this._addRemoteChannel(remoteTlke, token.ref);
            overTlke.enterToken(new tokens.TlkeChannel.OfferToken(token.offer));
        },

        //////////////////////////////
        //  OverChannels (channels that communicate via remote channels)
        //////////////////////////////
        // create additional generic channel
        requestCreateExtraTlChannel: function () {
            var overTlkeChannel = new TlkeChannel();
            var ref = urandom.int(1, 0xffffff);
            var remoteTlke = new RemoteChannel();
            this._addChannel(overTlkeChannel, ref);
            this._addRemoteChannel(remoteTlke, ref);
            console.info((this.iAmAlice ? "Alice" : "Bob") + " created remote tlke");
            overTlkeChannel.enterToken(new tokens.TlkeChannel.GenerateToken());
        },

        // token from overChannel
        onOverChannelToken: function (channel, token, context) {
            var info = this.channels.getItem(channel);
            var ref = info.ref;
            if (token instanceof tokens.TlkeChannel.OfferToken && token.offer) {
                // overTlkeChannel has generated an offer
                // ask remote contact to create channel and accept the offer
                this.remoteChannelGroup.enterToken(new tokens.ContactChannelGroup.OfferToken(token.offer, ref));
            } else if (token instanceof tokens.TlkeChannel.AuthToken && token.auth) {
                // overTlkeChannel has generated an auth
                // ask remote channel to accept it
                var remoteChannelInfo = this.remoteChannels.first(function (value) { return value.ref === ref; });
                if (!remoteChannelInfo) {
                    throw new Error("Cannot route the token over remote channel");
                }
                remoteChannelInfo.key.enterToken(new tokens.ContactChannelGroup.AuthToken(token.auth));
            }
        },

        //////////////////////////////
        //  Sync
        //////////////////////////////
        // just add new channels if don't have ones (distinguished by inId/outId)
        //
        updateChannels: function (updateChannels) {
            if (!updateChannels) { return; }
            updateChannels.forEach(this._importChannel.bind(this, false));
        },

        getChannelInfos: function () {
            var infos = [];
            this.channels.each(function (key, value) {
                if (key instanceof TlChannel) {
                    // TODO if state == established || state == synced
                    // export only established ones
                    infos.push({
                        keyData: key.serialize(),
                        valueData: {
                            inId: value.inId ? value.inId.as(Hex).serialize() : null,
                            outId: value.outId ? value.outId.as(Hex).serialize() : null,
                            canStart: value.canStart
                        }
                    });
                }
            });
            return infos;
        },

        _importChannel: function (canStart, channelInfo) {
            var inId = Hex.deserialize(channelInfo.valueData.inId);
            var outId = Hex.deserialize(channelInfo.valueData.outId);
            var found = this.channels.first(function (itemInfo) {
                return inId && itemInfo.inId && inId.isEqualTo(itemInfo.inId.as(Hex)) &&
                    outId && itemInfo.outId && outId.isEqualTo(itemInfo.outId.as(Hex));
            });
            if (!found) {
                var newChannel = TlChannel.deserialize(channelInfo.keyData);
                this._addChannel(newChannel, null, canStart);
                this.onChannelNewIds(newChannel, {
                    inId: inId,
                    outId: outId
                });
            }
            this._notifyDirty();
        },

        //
        createChannels: function (defaultChannel, updateChannels) {
            this._importChannel(true, defaultChannel);
            this.updateChannels(updateChannels);
            // todo create some overchannels here
            this._emitPrompt(new tokens.ContactChannelGroup.ChangeStateToken(TlkeChannel.STATE_CONNECTION_SYNCED));
            this._notifyDirty();
        },

        getYellowChannelInfo: function () {
            var channel = this._getChannelToStart();
            var channelInfo = this.channels.getItem(channel);
            channelInfo.canStart = false;
            this.channels.setItem(channel, channelInfo);
            this._notifyDirty();
            return {
                keyData: channel.serialize(),
                valueData: {
                    inId: channelInfo.inId ? channelInfo.inId.as(Hex).serialize() : null,
                    outId: channelInfo.outId ? channelInfo.outId.as(Hex).serialize() : null,
                }
            };
        },

        //////////////////////////////
        //  Internal
        //////////////////////////////
        // add remote channel and bind handlers
        _addRemoteChannel: function (channel, reference) {
            this._setPacketSender(channel, this.onRemoteChannelSendPacket);
            this._setTokenPrompter(channel, this.onRemoteChannelToken);
            this.remoteChannels.setItem(channel, {ref: reference});
            this._notifyDirty();
        },

        // add regular channel and bind handlers
        _addChannel: function (channel, reference, canStart) {
            var isOverChannel = !!reference;
            this._setPacketSender(channel, this.onChannelSendPacket);
            this._setTokenPrompter(channel, this.onChannelToken.bind(this, isOverChannel));
            this._setDirtyNotifier(channel, this.onChannelNotifyDirty);
            if (channel instanceof TlChannel) {
                this._setMsgProcessor(channel, this.onChannelMessage);
            }
            channel.setRng(this.random);
            this.channels.setItem(channel, {
                inId: null,
                outId: null,
                ref: reference,
                canStart: canStart
            });
            this._notifyDirty();
        },

        // get one of not-started channels that i can start
        _getChannelToStart: function () {
            var channel = null;
            this.channels.each(function (key, value) {
                if (key instanceof TlChannel && !value.isActive && value.canStart) {
                    channel = key;
                }
            });
            if (!channel) {
                throw new Error("Out of channels");
            }
            return channel;
        },

        _sendMessage: function (message, channel) {
            if (!channel) {
                this.channels.each(function (key, value) {
                    // channel.isActive later
                    if (key instanceof TlChannel) {
                        channel = key;
                    }
                });
            }
            if (!channel) { throw new Error("Didn't found channel to send a message"); }
            if (!(message instanceof ChannelGroupMessage)) {
                throw new Error("Argument exception");
            }
            channel.sendMessage(message.serialize());
        },

        _emitUserMessage: function (message) {
            this._check("msgProcessor");
            this.msgProcessor.processMessage(this, message);
        }

    }, extensions);

    // the message type to communicate between ChannelGroups via TlChannels
    // it can wrap a user message or the RemoteChannelList packet
    function ChannelGroupMessage(type, data, ref) {
        if (!$.isPlainObject(data)) {
            var msg = "Could not create ChannelGroupMessage message from " + JSON.stringify(data) + ". ";
            msg += "Only plain-object data is supported now";
            throw new Error(msg);
        }
        this.type = type;
        this.data = data;
        if (ref === 0 || ref) {
            this.ref = parseInt(ref, 10);
        }
    }
    ChannelGroupMessage.prototype.serialize = function () {
        var dto = {
            t: this.type,
            d: this.data
        };
        if (this.ref === 0 || this.ref) {
            dto.r = this.ref;
        }
        return dto;
    };
    ChannelGroupMessage.deserialize = function (dto) {
        return new ChannelGroupMessage(dto.t, dto.d, dto.r);
    };

    ChannelGroupMessage.MSG_TYPE_USER = "u";
    ChannelGroupMessage.MSG_TYPE_WRAPPER = "w";

    return ContactChannelGroup;
});<commit_msg>became modules/channels/contact.js<commit_after><|endoftext|>


<commit_before>// Copyright 2018, University of Colorado Boulder

/**
 *  This script searches babel for all translation credits based on history and adds them to the website database
 *  if not previously added.
 *
 *  @author Matt Pennington
 **/
/* eslint-env node */
'use strict';

const buildLocal = require( '../common/buildLocal' );
const fetch = require( 'node-fetch' ); //eslint-disable-line
const fs = require( 'fs' );

const translatorAuthCode = buildLocal.translatorAuthCode;
if ( !translatorAuthCode ) {
  console.log( 'ERROR: translatorAuthCode required in build-local.json' );
  return;
}

let repos;
try {
  repos = fs.readFileSync( '../perennial/data/active-sims' )
    .toString()
    .split( '\r\n' )
    .filter( e => { return e !== ''; } );
}
catch (e) {
  console.log( e );
  console.log( 'Error processing data/active-sims, this script must be run from the perennial directory' );
  return;
}

const usermap = {};

// FIND ALL TRANSLATION CREDITS
repos.forEach( repo => {
  try {
    const repoPath = '../babel/' + repo + '/'
    fs.readdirSync( repoPath ).forEach( localizedFilename => {
      const locale = localizedFilename.slice( ( repo + '-strings_' ).length, localizedFilename.indexOf( '.' ) );
      const content = JSON.parse( fs.readFileSync( repoPath + localizedFilename ).toString() );
      for ( let stringKey in content ) {
        if ( content.hasOwnProperty( stringKey ) && content[ stringKey ].history ) {
          content[ stringKey ].history.forEach( entry => {
            if ( !usermap[ entry.userId ] ) {
              usermap[ entry.userId ] = {};
            }
            if ( !usermap[ entry.userId ][ locale ] ) {
              usermap[ entry.userId ][ locale ] = [];
            }
            if ( !usermap[ entry.userId ][ locale ].includes( repo ) ) {
              usermap[ entry.userId ][ locale ].push( repo );
            }
          } );
        }
      }

    } );
  }
  catch( e ) {
    // We expect unpublished or test repos to have no translations
    if ( e.code === 'ENOENT' ) {
      console.log( 'INFO: no localized files found for ' + repo );
    }
    // Catch-all
    else {
      console.log( 'WARN: ', e );
    }
  }
} );

// PREPARE QUEUE
const urlPath = 'https://phet.colorado.edu/services/add-html-translator?';
const requests = [];
for ( let user in usermap ) {
  if ( usermap.hasOwnProperty( user ) ) {
    for ( let locale in usermap[ user ] ) {
      if ( usermap[ user ].hasOwnProperty( locale ) ) {
        usermap[ user ][ locale ].forEach( async repo => {
          const paramString = 'simName=' + repo
                              + '&locale=' + locale
                              + '&userId=' + user
                              + '&authorizationCode=' + translatorAuthCode;
          requests.push( urlPath + paramString );
        } );
      }
    }
  }
}

// SEND HTTP REQUESTS
let i = 0;
const get = async () => {
  console.log( 'Fetching ' + requests[ i ] );
  const response = await fetch( requests[ i ] );
  if ( response.status < 200 || response.status > 299 ) {
    console.log( 'ERROR: ' + response.status + ' ' + response.statusText );
  }
  else {
    console.log( 'SUCCESS: ' + response.status );
  }
  i += 1;
  if ( i < requests.length ) {
    get();
  }
  else {
    console.log( 'FINISHED!' );
  }
};
try {
  get();
}
catch( e ) {
  console.log( 'ERROR: ', e );
}<commit_msg>Added ;s<commit_after>// Copyright 2018, University of Colorado Boulder

/**
 *  This script searches babel for all translation credits based on history and adds them to the website database
 *  if not previously added.
 *
 *  @author Matt Pennington
 **/
/* eslint-env node */
'use strict';

const buildLocal = require( '../common/buildLocal' );
const fetch = require( 'node-fetch' ); //eslint-disable-line
const fs = require( 'fs' );

const translatorAuthCode = buildLocal.translatorAuthCode;
if ( !translatorAuthCode ) {
  console.log( 'ERROR: translatorAuthCode required in build-local.json' );
  return;
}

let repos;
try {
  repos = fs.readFileSync( '../perennial/data/active-sims' )
    .toString()
    .split( '\r\n' )
    .filter( e => { return e !== ''; } );
}
catch (e) {
  console.log( e );
  console.log( 'Error processing data/active-sims, this script must be run from the perennial directory' );
  return;
}

const usermap = {};

// FIND ALL TRANSLATION CREDITS
repos.forEach( repo => {
  try {
    const repoPath = '../babel/' + repo + '/';
    fs.readdirSync( repoPath ).forEach( localizedFilename => {
      const locale = localizedFilename.slice( ( repo + '-strings_' ).length, localizedFilename.indexOf( '.' ) );
      const content = JSON.parse( fs.readFileSync( repoPath + localizedFilename ).toString() );
      for ( let stringKey in content ) {
        if ( content.hasOwnProperty( stringKey ) && content[ stringKey ].history ) {
          content[ stringKey ].history.forEach( entry => {
            if ( !usermap[ entry.userId ] ) {
              usermap[ entry.userId ] = {};
            }
            if ( !usermap[ entry.userId ][ locale ] ) {
              usermap[ entry.userId ][ locale ] = [];
            }
            if ( !usermap[ entry.userId ][ locale ].includes( repo ) ) {
              usermap[ entry.userId ][ locale ].push( repo );
            }
          } );
        }
      }

    } );
  }
  catch( e ) {
    // We expect unpublished or test repos to have no translations
    if ( e.code === 'ENOENT' ) {
      console.log( 'INFO: no localized files found for ' + repo );
    }
    // Catch-all
    else {
      console.log( 'WARN: ', e );
    }
  }
} );

// PREPARE QUEUE
const urlPath = 'https://phet.colorado.edu/services/add-html-translator?';
const requests = [];
for ( let user in usermap ) {
  if ( usermap.hasOwnProperty( user ) ) {
    for ( let locale in usermap[ user ] ) {
      if ( usermap[ user ].hasOwnProperty( locale ) ) {
        usermap[ user ][ locale ].forEach( async repo => {
          const paramString = 'simName=' + repo
                              + '&locale=' + locale
                              + '&userId=' + user
                              + '&authorizationCode=' + translatorAuthCode;
          requests.push( urlPath + paramString );
        } );
      }
    }
  }
}

// SEND HTTP REQUESTS
let i = 0;
const get = async () => {
  console.log( 'Fetching ' + requests[ i ] );
  const response = await fetch( requests[ i ] );
  if ( response.status < 200 || response.status > 299 ) {
    console.log( 'ERROR: ' + response.status + ' ' + response.statusText );
  }
  else {
    console.log( 'SUCCESS: ' + response.status );
  }
  i += 1;
  if ( i < requests.length ) {
    get();
  }
  else {
    console.log( 'FINISHED!' );
  }
};
try {
  get();
}
catch( e ) {
  console.log( 'ERROR: ', e );
}<|endoftext|>