<commit_before>define([
    "utils",
    "components/vue/dist/vue.min"
], function(utils, Vue) {
    "use strict";

    var resolution_conf_tag = 'resolution';
    var resolution_component = Vue.component(resolution_conf_tag + '-component', {
        // Your configurable must have a "value" property
        props: ['value'],

        template:
            '
' +
            '  Resolution' +
            '  <select class="form-control" v-model="selected_value">' +
            '    <option v-for="resolution_option in resolution_options">' +
            '      {{resolution_option}}' +
            '    </option>' +
            '  </select>' +
            '
',

        data: function() {
            return {
                selected_value: this.value,
                resolution_options: ['Window', '1920x1080', '1280x1024', '1280x800', '1024x768']
            };
        },

        watch: {
            value: function() {this.selected_value = this.value;}, // model -> view update
            selected_value: function() {this.$emit('update:value', this.selected_value);} // view -> model update
        }
    });

    // Your configurable class must implement tag and value attributes and as_config_dict method
    var resolution_model = function() {
        this.tag = resolution_conf_tag;
        this.value = 'Window';
        this.component = resolution_component;
    };
    resolution_model.prototype.as_config_dict = function() {
        var resolution = this.value;

        if (this.value === 'Window') {
            var max_size = utils.max_iframe_size();
            resolution = max_size[0] + 'x' + max_size[1];
        }

        return { 'resolution': resolution };
    };

    // Export all your configurable models here
    return {
        resolution: resolution_model
    };
});
<commit_msg>Renamed resolution_model into ResolutionModel<commit_after>define([
    "utils",
    "components/vue/dist/vue.min"
], function(utils, Vue) {
    "use strict";

    var resolution_conf_tag = 'resolution';
    var resolution_component = Vue.component(resolution_conf_tag + '-component', {
        // Your configurable must have a "value" property
        props: ['value'],

        template:
            '
' +
            '  Resolution' +
            '  <select class="form-control" v-model="selected_value">' +
            '    <option v-for="resolution_option in resolution_options">' +
            '      {{resolution_option}}' +
            '    </option>' +
            '  </select>' +
            '
',

        data: function() {
            return {
                selected_value: this.value,
                resolution_options: ['Window', '1920x1080', '1280x1024', '1280x800', '1024x768']
            };
        },

        watch: {
            value: function() {this.selected_value = this.value;}, // model -> view update
            selected_value: function() {this.$emit('update:value', this.selected_value);} // view -> model update
        }
    });

    // Your configurable class must implement tag and value attributes and as_config_dict method
    var ResolutionModel = function() {
        this.tag = resolution_conf_tag;
        this.value = 'Window';
        this.component = resolution_component;
    };
    ResolutionModel.prototype.as_config_dict = function() {
        var resolution = this.value;

        if (this.value === 'Window') {
            var max_size = utils.max_iframe_size();
            resolution = max_size[0] + 'x' + max_size[1];
        }

        return { 'resolution': resolution };
    };

    // Export all your configurable models here
    return {
        resolution: ResolutionModel
    };
});
<|endoftext|>


<commit_before>var assert = require('assert');

function testPersistence(Persistence) {
  describe('Persistence', function() {
    var store;
    beforeEach(function() {
      return (store = new Persistence());
    });
    afterEach(function() {
      return store.resetChanges();
    });
    it('storing create change adds timestamp and version', function() {
      return store.saveChange({
        type: 'create',
        storeName: 'animals',
        clientId: 1,
        record: {name: 'Thumper', key: 1},
      }).then(function(change) {
        assert.notEqual(change.timestamp, undefined);
        assert.notEqual(change.version, undefined);
      });
    });
    it('can save and get change to store', function() {
      return store.saveChange({
        type: 'create',
        storeName: 'animals',
        clientId: 1,
        record: {name: 'Thumper', key: 1},
      }).then(function() {
        return store.getChanges({
          since: null,
          clientId: 2,
          storeName: 'animals',
        });
      }).then(function(result) {
        assert.equal(result.length, 1);
        assert.notEqual(result[0].timestamp, undefined);
        assert.equal(result[0].record.name, 'Thumper');
      });
    });
    it('only get changes from other clients', function() {
      return store.saveChange({
        type: 'create',
        storeName: 'animals',
        clientId: 1,
        record: {name: 'Thumper', key: 1},
      }).then(function() {
        return store.saveChange({
          type: 'create',
          storeName: 'animals',
          clientId: 2,
          record: {name: 'Cuddley', key: 2},
        });
      }).then(function() {
        return store.getChanges({
          since: null,
          clientId: 2,
          storeName: 'animals',
        });
      }).then(function(result) {
        assert.equal(result.length, 1);
      });
    });
  });
}

exports.testPersistence = testPersistence;
<commit_msg>Add additional persistence test<commit_after>var assert = require('assert');

function testPersistence(Persistence) {
  describe('Persistence', function() {
    var store;
    beforeEach(function() {
      return (store = new Persistence());
    });
    afterEach(function() {
      return store.resetChanges();
    });
    it('storing create change adds timestamp and version', function() {
      return store.saveChange({
        type: 'create',
        storeName: 'animals',
        clientId: 1,
        record: {name: 'Thumper', key: 1},
      }).then(function(change) {
        assert.notEqual(change.timestamp, undefined);
        assert.notEqual(change.version, undefined);
      });
    });
    it('storing update change adds timestamp and new version', function() {
      return store.saveChange({
        type: 'update',
        storeName: 'animals',
        clientId: 1,
        record: {name: 'Thumper', key: 1},
      }).then(function(change) {
        assert.notEqual(change.timestamp, undefined);
        assert.notEqual(change.version, undefined);
      });
    });
    it('can save and get change to store', function() {
      return store.saveChange({
        type: 'create',
        storeName: 'animals',
        clientId: 1,
        record: {name: 'Thumper', key: 1},
      }).then(function() {
        return store.getChanges({
          since: null,
          clientId: 2,
          storeName: 'animals',
        });
      }).then(function(result) {
        assert.equal(result.length, 1);
        assert.notEqual(result[0].timestamp, undefined);
        assert.equal(result[0].record.name, 'Thumper');
      });
    });
    it('only get changes from other clients', function() {
      return store.saveChange({
        type: 'create',
        storeName: 'animals',
        clientId: 1,
        record: {name: 'Thumper', key: 1},
      }).then(function() {
        return store.saveChange({
          type: 'create',
          storeName: 'animals',
          clientId: 2,
          record: {name: 'Cuddley', key: 2},
        });
      }).then(function() {
        return store.getChanges({
          since: null,
          clientId: 2,
          storeName: 'animals',
        });
      }).then(function(result) {
        assert.equal(result.length, 1);
      });
    });
  });
}

exports.testPersistence = testPersistence;
<|endoftext|>


<commit_before><commit_msg>For Bug 52732<commit_after><|endoftext|>


<commit_before>'use strict'

Promise.all([
  _getCollections(),
  _getSubscriptions()
]).then(valueArr => {
  var collections = valueArr[0]
  var subscriptions = valueArr[1]

  template.render('manager-section',{ quantity: Object.keys(collections).length }).then(html => {
    var _getSubscriptionContainer = function() {
      return document.getElementById('subscription-manager-container')
    }

    var elem = document.createElement('div')
    _getSubscriptionContainer().parentNode.insertBefore(elem,_getSubscriptionContainer())
    elem.outerHTML = html

    return document.getElementById('collections-manager-container')
  }).then(node => {
    var form = document.getElementById('add-collection-form')

    node.addEventListener('click',e => {
      if(e.target.hasAttribute('data-collection-id')) {
        var removedId = e.target.dataset.collectionId
        if(window.confirm('Remove collection '+ e.target.closest('tr').querySelector('.subscription-title').getAttribute('title') +'?')) {
          _removeCollection(e.target.dataset.collectionId)
        }
      }
    })

    form.querySelector('input[name="add-collection"]').addEventListener('input',e => {
      e.target.classList.toggle('invalid',!e.target.checkValidity() && e.target.value !== '')
    })

    form.querySelector('input[name="add-collection"]').addEventListener('invalid',e => {
      e.target.classList.add('invalid')
    })

    form.addEventListener('submit',e => {
      _addCollection(form.querySelector('input[name="add-collection"]').value)

      e.preventDefault()
      e.stopPropagation()
      return false
    })

    return document.querySelector('#collection-manager-list tbody')
  }).then(node => {
    return Object.keys(collections).map(id => {
      return template.render('manager-section-item',{
        id: id,
        name: collections[id].name
      }).then(html => {
        var elem = document.createElement('tr')
        node.appendChild(elem)
        elem.outerHTML = html
        return document.getElementById(id+'-manager-collection')
      })
    })
  })

  var buttons

  Promise.all(
    [template.render('manager-subscription-popup-item', { id: '', label: '' })].concat(
    Object.keys(collections).map(k => {
      return template.render('manager-subscription-popup-item', { id: k, label: collections[k].name })
    }))
  ).then(valueArr => {
    buttons = valueArr.join('')
    return Promise.all(Object.keys(collections).map(k => {
      return template.render('manager-subscription-button', { id: k, label: collections[k].name, buttons: buttons }).then(html => {
        return { [collections[k].name]: html }
      })
    }))
  })
  .then(valueArr => {
    return template.render('manager-subscription-button', { id: '', label: '', buttons: buttons }).then(html => {
      valueArr.push({'(none)':html})
      return valueArr.reduce((all,curr) => Object.assign(all,curr),{})
    })
  })
  .then(htmls => {
    let query = '#subscription-manager-list tr.subscription-item td:first-of-type .subscription-title-wrap'
    Array.prototype.slice.call(document.querySelectorAll(query))
    .map(node => {
      var channelId = node.closest('tr').dataset.channelExternalId
      var collection = collections[subscriptions[channelId]]
      var elem = document.createElement('div')
      node.appendChild(elem)

      if(collection === undefined) {
        elem.outerHTML = htmls['(none)']
      } else {
        elem.outerHTML = htmls[collection.name]
      }

      node.querySelector('.add-to-collection ul').setAttribute('data-subscription-id',channelId)
    })
  })
  .then(() => {
    window.addEventListener('click',e => {
      if(e.target.matches('ul[data-subscription-id] li button, ul[data-subscription-id] li button *')) {
        var collectionId = e.target.closest('li').dataset.collectionId
        var subscriptionid = e.target.closest('ul').dataset.subscriptionId

        if(collectionId === '') {
          _removeSubscription(subscriptionid)
        }
        else {
          _addSubscription(subscriptionid,collectionId)
        }
      }
    })
  })
})

_getCollections().then(collections => {
  window.addEventListener('message',e => {
    if (event.source != window) {
      return
    }

    var _getAddSubscriptionButton = function(subId) {
      return document.querySelector('#subscription-manager-list\
        tr[data-channel-external-id="'+subId+'"] .add-to-collection')
    }

    var _setButtonCollectionId = function(subId,collectionId) {
      _getAddSubscriptionButton(subId).setAttribute('data-collection-id',collectionId)
      var label = collectionId === '' ? '' : collections[collectionId].name
      _getAddSubscriptionButton(subId).querySelector('.collection-label-wrapper').textContent = label
    }

    if (event.data.type) {
      switch(event.data.type) {
        case 'SUBSCRIPTION_ADDED':
          _setButtonCollectionId(event.data.subscriptionId,event.data.collectionId)
          break;
        case 'SUBSCRIPTION_REMOVED':
          _setButtonCollectionId(event.data.subscriptionId,'')
          break;
        case 'SUBSCRIPTION_UPDATED':
          _setButtonCollectionId(event.data.subscriptionId,event.data.newValue)
          break;
        case 'COLLECTION_ADDED':
          template.render('manager-section-item',{
            id: event.data.id,
            name: event.data.name
          }).then(html => {
            var elem = document.createElement('tr')
            document.querySelector('#collection-manager-list tbody').appendChild(elem)
            elem.outerHTML = html
          })
          break;
        case 'COLLECTION_REMOVED':
          document.getElementById(event.data.id+'-manager-collection').remove()
          break;
      }
    }
  })
})<commit_msg>Moving popup options html generation to a separate function, leading to cleaner code overall.<commit_after>'use strict'

function _generatePopupOptions() {
  return _getCollections().then(collections => {
    return Promise.all(
      [template.render('manager-subscription-popup-item', { id: '', label: '' })]
      .concat(Object.keys(collections).map(k => {
        return template.render('manager-subscription-popup-item', { id: k, label: collections[k].name })
      }))
    )
  })
  .then(htmls => {
    return htmls.join('')
  })
}

Promise.all([
  _getCollections(),
  _getSubscriptions()
]).then(valueArr => {
  var collections = valueArr[0]
  var subscriptions = valueArr[1]

  template.render('manager-section',{ quantity: Object.keys(collections).length }).then(html => {
    var _getSubscriptionContainer = function() {
      return document.getElementById('subscription-manager-container')
    }

    var elem = document.createElement('div')
    _getSubscriptionContainer().parentNode.insertBefore(elem,_getSubscriptionContainer())
    elem.outerHTML = html

    return document.getElementById('collections-manager-container')
  }).then(node => {
    var form = document.getElementById('add-collection-form')

    node.addEventListener('click',e => {
      if(e.target.hasAttribute('data-collection-id')) {
        var removedId = e.target.dataset.collectionId
        if(window.confirm('Remove collection '+ e.target.closest('tr').querySelector('.subscription-title').getAttribute('title') +'?')) {
          _removeCollection(e.target.dataset.collectionId)
        }
      }
    })

    form.querySelector('input[name="add-collection"]').addEventListener('input',e => {
      e.target.classList.toggle('invalid',!e.target.checkValidity() && e.target.value !== '')
    })

    form.querySelector('input[name="add-collection"]').addEventListener('invalid',e => {
      e.target.classList.add('invalid')
    })

    form.addEventListener('submit',e => {
      _addCollection(form.querySelector('input[name="add-collection"]').value)

      e.preventDefault()
      e.stopPropagation()
      return false
    })

    return document.querySelector('#collection-manager-list tbody')
  }).then(node => {
    return Object.keys(collections).map(id => {
      return template.render('manager-section-item',{
        id: id,
        name: collections[id].name
      }).then(html => {
        var elem = document.createElement('tr')
        node.appendChild(elem)
        elem.outerHTML = html
        return document.getElementById(id+'-manager-collection')
      })
    })
  })

  _generatePopupOptions().then(buttonsHtml => {
    return Promise.all(
      Object.keys(collections).map(k => {
        return template.render('manager-subscription-button', { id: k, label: collections[k].name, buttons: buttonsHtml })
        .then(html => {
          return { [collections[k].name]: html }
        })
      }).concat(template.render('manager-subscription-button', { id: '', label: '', buttons: buttonsHtml })
        .then(html => {
          return { '(none)': html }
        })
      )
    ).then(arr => {
      return arr.reduce((p,c) => Object.assign(p,c),{})
    })
  })
  .then(htmls => {
    let query = '#subscription-manager-list tr.subscription-item td:first-of-type .subscription-title-wrap'
    Array.prototype.slice.call(document.querySelectorAll(query))
    .map(node => {
      var channelId = node.closest('tr').dataset.channelExternalId
      var collection = collections[subscriptions[channelId]]
      var elem = document.createElement('div')
      node.appendChild(elem)

      if(collection === undefined) {
        elem.outerHTML = htmls['(none)']
      } else {
        elem.outerHTML = htmls[collection.name]
      }

      node.querySelector('.add-to-collection ul').setAttribute('data-subscription-id',channelId)
    })
  })
  .then(() => {
    window.addEventListener('click',e => {
      if(e.target.matches('ul[data-subscription-id] li button, ul[data-subscription-id] li button *')) {
        var collectionId = e.target.closest('li').dataset.collectionId
        var subscriptionid = e.target.closest('ul').dataset.subscriptionId

        if(collectionId === '') {
          _removeSubscription(subscriptionid)
        }
        else {
          _addSubscription(subscriptionid,collectionId)
        }
      }
    })
  })
})

_getCollections().then(collections => {
  window.addEventListener('message',e => {
    if (event.source != window) {
      return
    }

    var _getAddSubscriptionButton = function(subId) {
      return document.querySelector('#subscription-manager-list\
        tr[data-channel-external-id="'+subId+'"] .add-to-collection')
    }

    var _setButtonCollectionId = function(subId,collectionId) {
      _getAddSubscriptionButton(subId).setAttribute('data-collection-id',collectionId)
      var label = collectionId === '' ? '' : collections[collectionId].name
      _getAddSubscriptionButton(subId).querySelector('.collection-label-wrapper').textContent = label
    }

    if (event.data.type) {
      switch(event.data.type) {
        case 'SUBSCRIPTION_ADDED':
          _setButtonCollectionId(event.data.subscriptionId,event.data.collectionId)
          break;
        case 'SUBSCRIPTION_REMOVED':
          _setButtonCollectionId(event.data.subscriptionId,'')
          break;
        case 'SUBSCRIPTION_UPDATED':
          _setButtonCollectionId(event.data.subscriptionId,event.data.newValue)
          break;
        case 'COLLECTION_ADDED':
          template.render('manager-section-item',{
            id: event.data.id,
            name: event.data.name
          }).then(html => {
            var elem = document.createElement('tr')
            document.querySelector('#collection-manager-list tbody').appendChild(elem)
            elem.outerHTML = html
          })
          break;
        case 'COLLECTION_REMOVED':
          document.getElementById(event.data.id+'-manager-collection').remove()
          break;
      }
    }
  })
})<|endoftext|>


<commit_before>(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * @private
     * Allows the Roadmap Planning Board CardBoard to be scrolled forwards and backwards
     */
    Ext.define('Rally.apps.roadmapplanningboard.plugin.RoadmapScrollable', {
        alias: 'plugin.rallytimeframescrollablecardboard',
        extend: 'Rally.ui.cardboard.plugin.Scrollable',

        /**
         * @cfg {Number} The number of timeframe columns
         */
        timeframeColumnCount: 4,

        init: function (cmp) {
            var pluginScope = this;
            this.originBuildColumnsFromStore = cmp.buildColumnsFromStore;
            cmp.buildColumnsFromStore = function (store) {
                pluginScope.buildColumnsFromStore(store);
            };
            this.callParent(arguments);
        },

        /**
         *
         * @param store
         */
        buildColumnsFromStore: function (store) {
            var columns = this.originBuildColumnsFromStore.call(this.cmp, store);

            this.backlogColumn = columns[0];
            this.scrollableColumns = columns.slice(1);

            this.cmp.columns = [this.backlogColumn].concat(this._getVisibleColumns(this._getPresentColumns(this.scrollableColumns)));
            return this.cmp.columns;
        },

        _getPresentColumns: function (columns) {
            var now = new Date();

            this.presentColumns = this.presentColumns || _.filter(columns, function (column) {
                return column.timeframeRecord.get('end') >= now;
            }, this);

            return this.presentColumns;
        },

        _getPastColumns: function (columns) {
            var now = new Date();

            this.presentColumns = this.presentColumns || this._getPresentColumns(columns);
            this.pastColumns = this.pastColumns || _.difference(columns, this.presentColumns);

            return this.pastColumns;
        },

        _getVisibleColumns: function (presentColumns) {
            return _.first(presentColumns, this.timeframeColumnCount);
        },

        _isBackwardsButtonHidden: function () {
            return this.scrollableColumns[0].timeframeRecord === this.getFirstVisibleScrollableColumn().timeframeRecord;
        },

        _isForwardsButtonHidden: function () {
            return _.last(this.scrollableColumns).timeframeRecord === this.getLastVisibleScrollableColumn().timeframeRecord;
        },

        _scroll: function (forwards) {
            var insertNextToColumn = this._getInsertNextToColumn(forwards);
            var scrollableColumnRecords = _.pluck(this.scrollableColumns, 'timeframeRecord');
            var newlyVisibleColumn = this.scrollableColumns[_.indexOf(scrollableColumnRecords, insertNextToColumn.timeframeRecord) + (forwards ? 1 : -1)];

            var indexOfNewColumn = _.indexOf(this.cmp.getColumns(), insertNextToColumn);
            this.cmp.destroyColumn(this._getColumnToRemove(forwards));

            var column = this.cmp.addColumn(newlyVisibleColumn, indexOfNewColumn);
            column.on('ready', this._onNewlyAddedColumnReady, this, {single: true});

            var columnEls = this.cmp.createColumnElements(forwards ? 'after' : 'before', insertNextToColumn);
            this.cmp.renderColumn(column, columnEls);

            this.cmp.drawThemeToggle();

            this.cmp.fireEvent('scroll', this.cmp);

            this._afterScroll(forwards);
        },

        _onNewlyAddedColumnReady: function () {
            this.cmp.applyLocalFilters();
        },

        _sizeButtonToColumnHeader: function(button, column){
            var columnHeaderHeight = column.getHeaderTitle().getHeight();

            button.getEl().setHeight(columnHeaderHeight);
        },

        getFirstVisibleScrollableColumn: function () {
            return this.getScrollableColumns()[0];
        },

        getLastVisibleScrollableColumn: function () {
            return _.last(this.getScrollableColumns());
        },

        getScrollableColumns: function () {
            return this.cmp.getColumns().slice(1);
        }
    });
})();<commit_msg>DE18285 - Fixed RoadmapScrollable.js to handle 1 column (insert before delete)<commit_after>(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * @private
     * Allows the Roadmap Planning Board CardBoard to be scrolled forwards and backwards
     */
    Ext.define('Rally.apps.roadmapplanningboard.plugin.RoadmapScrollable', {
        alias: 'plugin.rallytimeframescrollablecardboard',
        extend: 'Rally.ui.cardboard.plugin.Scrollable',

        /**
         * @cfg {Number} The number of timeframe columns
         */
        timeframeColumnCount: 4,

        init: function (cmp) {
            var pluginScope = this;
            this.originBuildColumnsFromStore = cmp.buildColumnsFromStore;
            cmp.buildColumnsFromStore = function (store) {
                pluginScope.buildColumnsFromStore(store);
            };
            this.callParent(arguments);
        },

        /**
         *
         * @param store
         */
        buildColumnsFromStore: function (store) {
            var columns = this.originBuildColumnsFromStore.call(this.cmp, store);

            this.backlogColumn = columns[0];
            this.scrollableColumns = columns.slice(1);

            this.cmp.columns = [this.backlogColumn].concat(this._getVisibleColumns(this._getPresentColumns(this.scrollableColumns)));
            return this.cmp.columns;
        },

        _getPresentColumns: function (columns) {
            var now = new Date();

            this.presentColumns = this.presentColumns || _.filter(columns, function (column) {
                return column.timeframeRecord.get('end') >= now;
            }, this);

            return this.presentColumns;
        },

        _getPastColumns: function (columns) {
            var now = new Date();

            this.presentColumns = this.presentColumns || this._getPresentColumns(columns);
            this.pastColumns = this.pastColumns || _.difference(columns, this.presentColumns);

            return this.pastColumns;
        },

        _getVisibleColumns: function (presentColumns) {
            return _.first(presentColumns, this.timeframeColumnCount);
        },

        _isBackwardsButtonHidden: function () {
            return this.scrollableColumns[0].timeframeRecord === this.getFirstVisibleScrollableColumn().timeframeRecord;
        },

        _isForwardsButtonHidden: function () {
            return _.last(this.scrollableColumns).timeframeRecord === this.getLastVisibleScrollableColumn().timeframeRecord;
        },

        _scroll: function (forwards) {
            var insertNextToColumn = this._getInsertNextToColumn(forwards);
            var scrollableColumnRecords = _.pluck(this.scrollableColumns, 'timeframeRecord');
            var newlyVisibleColumn = this.scrollableColumns[_.indexOf(scrollableColumnRecords, insertNextToColumn.timeframeRecord) + (forwards ? 1 : -1)];

            var indexOfNewColumn = _.indexOf(this.cmp.getColumns(), insertNextToColumn);
            var columnEls = this.cmp.createColumnElements(forwards ? 'after' : 'before', insertNextToColumn);
            this.cmp.destroyColumn(this._getColumnToRemove(forwards));

            var column = this.cmp.addColumn(newlyVisibleColumn, indexOfNewColumn);
            column.on('ready', this._onNewlyAddedColumnReady, this, {single: true});

            this.cmp.renderColumn(column, columnEls);

            this.cmp.drawThemeToggle();

            this.cmp.fireEvent('scroll', this.cmp);

            this._afterScroll(forwards);
        },

        _onNewlyAddedColumnReady: function () {
            this.cmp.applyLocalFilters();
        },

        _sizeButtonToColumnHeader: function(button, column){
            var columnHeaderHeight = column.getHeaderTitle().getHeight();

            button.getEl().setHeight(columnHeaderHeight);
        },

        getFirstVisibleScrollableColumn: function () {
            return this.getScrollableColumns()[0];
        },

        getLastVisibleScrollableColumn: function () {
            return _.last(this.getScrollableColumns());
        },

        getScrollableColumns: function () {
            return this.cmp.getColumns().slice(1);
        }
    });
})();<|endoftext|>


<commit_before>var settings = require("./settings");
var gulp = require("gulp");
var spsave = require("gulp-spsave");
var replace = require("gulp-replace");
var tap = require("gulp-tap");
var gutil = require("gulp-util");
var del = require("del");
var prompt = require("gulp-prompt");
var inquirer = require("inquirer");
var urlParser = require("url");
var runSequence = require("run-sequence");
var merge = require("merge-stream");
var plumber = require("gulp-plumber");
var pathUtil = require("path");
var Cpass = require("cpass");

var _ = require("lodash");

var styleSettings = _.defaults({folder: "Style Library"}, settings);
var catalogSettings = _.defaults({folder: "_catalogs/wp"}, settings);

function setUsername(username){
    styleSettings = _.extend(styleSettings, { username });
    catalogSettings = _.extend(catalogSettings, { username });
}

function setPassword(password){
    styleSettings = _.extend(styleSettings, { password });
    catalogSettings = _.extend(catalogSettings, { password });
}

function setSiteUrl(url){

    var urlObject = urlParser.parse(url);
    var newSite = { siteUrl: urlObject.href, basePath: urlObject.pathname };

    settings = _.extend(settings, newSite);
    styleSettings = _.extend(styleSettings, newSite);
    catalogSettings = _.extend(catalogSettings, newSite);

}

gulp.task("check-site", function(){

    if(!settings.siteUrl || settings.siteUrl == "https://[tenant].sharepoint.com"){

        return inquirer.prompt([{
                type: "text",
                name: "site",
                message: "Deployment site:"
            }])
            .then(function(result){
                    setSiteUrl(result.site);
                });
     }else{
        setSiteUrl(settings.siteUrl);
     }
});

gulp.task("check-user", function(){

    if(settings.username == "[username]"){

        return inquirer.prompt([{
                type: "text",
                name: "user",
                message: "Deployment user:"
            }])
            .then(function(result){
                    setUsername(result.user);
                });
     }
});

gulp.task("check-password", function(){

    if(settings.password == "[password]"){

        return inquirer.prompt([{
                type: "password",
                name: "pass",
                message: "Password:"
            }])
            .then(function(result){
                    setPassword(result.pass);
                });
     }
});

gulp.task("save-password", function(){

    function encrypt(password){
        var cp = new Cpass();
        return cp.encode(password);
    }

    function replacePassword(file, password){
        file.contents = new Buffer(String(file.contents)
            .replace(/pass:\s*['"]\S+['"]/g, 'pass: \"' + encrypt(password) + '\"'));
    }

    return inquirer.prompt([{
                type: "password",
                name: "pass",
                message: "Password:"
            }])
            .then(function(result){

                return gulp.src("./creds.js")
                    .pipe(tap(function(file){return replacePassword(file, result.pass)}))
                    .pipe(gulp.dest("."));
            });
});

gulp.task("clean", function(){
    return del("./dist");
});

gulp.task("build", ["check-site"], function(){

    function replaceTokens(file){
        file.contents = new Buffer(String(file.contents)
            .replace(/_BASEURL_/g, settings.basePath));
    }

    var webparts = gulp.src("./src/_catalogs/wp/**/*.*")
        .pipe(tap(replaceTokens))
        .pipe(gulp.dest("./dist/_catalogs/wp"));

    var templates = gulp.src("./src/Style Library/**/*.*")
        .pipe(tap(replaceTokens))
        .pipe(gulp.dest("./dist/Style Library"));

    return merge(webparts, templates);

});

gulp.task("check-all", function(done){

    return runSequence("check-site", "check-user", "check-password", done);

})

gulp.task("push", ["check-all"], function(){

    var styles = gulp.src("./dist/Style Library/**/*.*")
        .pipe(spsave(styleSettings));

    var webparts = gulp.src("./dist/_catalogs/wp/**/*.*")
        .pipe(spsave(catalogSettings));

    return merge(styles, webparts);

});

gulp.task("deploy", function(done){
    runSequence("clean", "build", "push", done);
});

var onError = function(err){
    gutil.log(err);
    this.emit("end");
}

gulp.task("watch", ["check-all"], function(){

    gulp.watch(["./dist/Style Library/**/*.*"], function(event){

        return gulp.src(event.path, {base: "Style Library"})
            .pipe(plumber({
                errorHandler: onError
            }))
            .pipe(spsave(styleSettings));
    });

    gulp.watch(["./src/Style Library/**/*.*"], function(event){

        function replaceTokens(file){
            file.contents = new Buffer(String(file.contents)
                .replace(/_BASEURL_/g, settings.basePath));
        }

        function buildDest(filepath){

           return [".", "dist", ...filepath.split(pathUtil.sep)
                .filter((val, index, arr) => {
                    return index < arr.length - 1 && index > arr.indexOf('src');
                })].join(pathUtil.sep);
        }

        gutil.log(event.type + ": " + event.path);

        return gulp.src(event.path)
            .pipe(plumber({
                errorHandler: onError
            }))
            .pipe(tap(replaceTokens))
            .pipe(gulp.dest(function(){
                return buildDest(event.path);
            }));
    });
});<commit_msg>password decryption<commit_after>var settings = require("./settings");
var gulp = require("gulp");
var spsave = require("gulp-spsave");
var replace = require("gulp-replace");
var tap = require("gulp-tap");
var gutil = require("gulp-util");
var del = require("del");
var prompt = require("gulp-prompt");
var inquirer = require("inquirer");
var urlParser = require("url");
var runSequence = require("run-sequence");
var merge = require("merge-stream");
var plumber = require("gulp-plumber");
var pathUtil = require("path");
var Cpass = require("cpass");

var _ = require("lodash");

var styleSettings = _.defaults({folder: "Style Library"}, settings);
var catalogSettings = _.defaults({folder: "_catalogs/wp"}, settings);

function setUsername(username){
    styleSettings = _.extend(styleSettings, { username });
    catalogSettings = _.extend(catalogSettings, { username });
}

function setPassword(password){
    styleSettings = _.extend(styleSettings, { password });
    catalogSettings = _.extend(catalogSettings, { password });
}

function setSiteUrl(url){

    var urlObject = urlParser.parse(url);
    var newSite = { siteUrl: urlObject.href, basePath: urlObject.pathname };

    settings = _.extend(settings, newSite);
    styleSettings = _.extend(styleSettings, newSite);
    catalogSettings = _.extend(catalogSettings, newSite);

}

gulp.task("check-site", function(){

    if(!settings.siteUrl || settings.siteUrl == "https://[tenant].sharepoint.com"){

        return inquirer.prompt([{
                type: "text",
                name: "site",
                message: "Deployment site:"
            }])
            .then(function(result){
                    setSiteUrl(result.site);
                });
     }else{
        setSiteUrl(settings.siteUrl);
     }
});

gulp.task("check-user", function(){

    if(!settings.username || settings.username == "[username]"){

        return inquirer.prompt([{
                type: "text",
                name: "user",
                message: "Deployment user:"
            }])
            .then(function(result){
                    setUsername(result.user);
                });
     }
});

gulp.task("check-password", function(){

    function decrypt(pass){
        var cp = new Cpass();
        return cp.decode(pass);
    }

    if(!settings.password || settings.password == "[password]"){

        return inquirer.prompt([{
                type: "password",
                name: "pass",
                message: "Password:"
            }])
            .then(function(result){
                    setPassword(result.pass);
                });
     }else{
        setPassword(decrypt(settings.password));
     }
});

gulp.task("save-password", function(){

    function encrypt(password){
        var cp = new Cpass();
        return cp.encode(password);
    }

    function replacePassword(file, password){
        file.contents = new Buffer(String(file.contents)
            .replace(/pass:\s*['"]\S+['"]/g, 'pass: \"' + encrypt(password) + '\"'));
    }

    return inquirer.prompt([{
                type: "password",
                name: "pass",
                message: "Password:"
            }])
            .then(function(result){

                return gulp.src("./creds.js")
                    .pipe(tap(function(file){return replacePassword(file, result.pass)}))
                    .pipe(gulp.dest("."));
            });
});

gulp.task("clean", function(){
    return del("./dist");
});

gulp.task("build", ["check-site"], function(){

    function replaceTokens(file){
        file.contents = new Buffer(String(file.contents)
            .replace(/_BASEURL_/g, settings.basePath));
    }

    var webparts = gulp.src("./src/_catalogs/wp/**/*.*")
        .pipe(tap(replaceTokens))
        .pipe(gulp.dest("./dist/_catalogs/wp"));

    var templates = gulp.src("./src/Style Library/**/*.*")
        .pipe(tap(replaceTokens))
        .pipe(gulp.dest("./dist/Style Library"));

    return merge(webparts, templates);

});

gulp.task("check-all", function(done){

    return runSequence("check-site", "check-user", "check-password", done);

})

gulp.task("push", ["check-all"], function(){

    var styles = gulp.src("./dist/Style Library/**/*.*")
        .pipe(spsave(styleSettings));

    var webparts = gulp.src("./dist/_catalogs/wp/**/*.*")
        .pipe(spsave(catalogSettings));

    return merge(styles, webparts);

});

gulp.task("deploy", function(done){
    runSequence("clean", "build", "push", done);
});

var onError = function(err){
    gutil.log(err);
    this.emit("end");
}

gulp.task("watch", ["check-all"], function(){

    gulp.watch(["./dist/Style Library/**/*.*"], function(event){

        return gulp.src(event.path, {base: "Style Library"})
            .pipe(plumber({
                errorHandler: onError
            }))
            .pipe(spsave(styleSettings));
    });

    gulp.watch(["./src/Style Library/**/*.*"], function(event){

        function replaceTokens(file){
            file.contents = new Buffer(String(file.contents)
                .replace(/_BASEURL_/g, settings.basePath));
        }

        function buildDest(filepath){

           return [".", "dist", ...filepath.split(pathUtil.sep)
                .filter((val, index, arr) => {
                    return index < arr.length - 1 && index > arr.indexOf('src');
                })].join(pathUtil.sep);
        }

        gutil.log(event.type + ": " + event.path);

        return gulp.src(event.path)
            .pipe(plumber({
                errorHandler: onError
            }))
            .pipe(tap(replaceTokens))
            .pipe(gulp.dest(function(){
                return buildDest(event.path);
            }));
    });
});<|endoftext|>


<commit_before>const GLib = imports.gi.GLib;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Util = imports.misc.util;

function LOG(message) {
	// log("[pixel-saver]: " + message);
}

function WARN(message) {
	log("[pixel-saver]: " + message);
}

/** Guesses the X ID of a window.
 *
 * It is often in the window's title, being `"0x%x %10s".format(XID, window.title)`.
 * (See `mutter/src/core/window-props.c`).
 *
 * If we couldn't find it there, we use `win`'s actor, `win.get_compositor_private()`.
 * The actor's `x-window` property is the X ID of the window *actor*'s frame
 * (as opposed to the window itself).
 *
 * However, the child window of the window actor is the window itself, so by
 * using `xwininfo -children -id [actor's XID]` we can attempt to deduce the
 * window's X ID.
 *
 * It is not always foolproof, but works good enough for now.
 *
 * @param {Meta.Window} win - the window to guess the XID of. You wil get better
 * success if the window's actor (`win.get_compositor_private()`) exists.
 */
function guessWindowXID(win) {
	// We cache the result so we don't need to redetect.
	if (win._pixelSaverWindowID) {
		return win._pixelSaverWindowID;
	}

	/* if window title has non-utf8 characters, get_description() complains
	 * "Failed to convert UTF-8 string to JS string: Invalid byte sequence in conversion input",
	 * event though get_title() works.
	 */
	try {
		let m = win.get_description().match(/0x[0-9a-f]+/);
		if (m && m[0]) {
			return win._pixelSaverWindowID = m[0];
		}
	} catch (err) { }

	// use xwininfo, take first child.
	let act = win.get_compositor_private();
	let xwindow = act && act['x-window'];
	if (xwindow) {
		let xwininfo = GLib.spawn_command_line_sync('xwininfo -children -id 0x%x'.format(xwindow));
		if (xwininfo[0]) {
			let str = xwininfo[1].toString();

			/* The X ID of the window is the one preceding the target window's title.
			 * This is to handle cases where the window has no frame and so
			 * act['x-window'] is actually the X ID we want, not the child.
			 */
			let regexp = new RegExp('(0x[0-9a-f]+) +"%s"'.format(win.title));
			let m = str.match(regexp);
			if (m && m[1]) {
				return win._pixelSaverWindowID = m[1];
			}

			/* Otherwise, just grab the child and hope for the best */
			m = str.split(/child(?:ren)?:/)[1].match(/0x[0-9a-f]+/);
			if (m && m[0]) {
				return win._pixelSaverWindowID = m[0];
			}
		}
	}

	// Try enumerating all available windows and match the title. Note that this
	// may be necessary if the title contains special characters and `x-window`
	// is not available.
	let result = GLib.spawn_command_line_sync('xprop -root _NET_CLIENT_LIST');
	LOG('xprop -root _NET_CLIENT_LIST')
	if (result[0]) {
		let str = result[1].toString();

		// Get the list of window IDs.
		let windowList = str.match(/0x[0-9a-f]+/g);

		// For each window ID, check if the title matches the desired title.
		for (var i = 0; i < windowList.length; ++i) {
			let cmd = 'xprop -id "' + windowList[i] + '" _NET_WM_NAME _PIXEL_SAVER_ORIGINAL_STATE';
			let result = GLib.spawn_command_line_sync(cmd);
			LOG(cmd);

			if (result[0]) {
				let output = result[1].toString();
				let isManaged = output.indexOf("_PIXEL_SAVER_ORIGINAL_STATE(CARDINAL)") > -1;
				if (isManaged) {
					continue;
				}

				let title = output.match(/_NET_WM_NAME(\(\w+\))? = "(([^\\"]|\\"|\\\\)*)"/);
				LOG("Title of XID %s is \"%s\".".format(windowList[i], title[2]));

				// Is this our guy?
				if (title && title[2] == win.title) {
					return windowList[i];
				}
			}
		}
	}

	// debugging for when people find bugs..
	WARN("Could not find XID for window with title %s".format(win.title));

	// if we can't find an atom, assume the titlebar not to be hidden
	return win._pixelSaverOriginalState = false;
}

/**
 * Get the value of _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED before
 * pixel saver did its magic.
 *
 * @param {Meta.Window} win - the window to check the property
 */
function getOriginalState(win) {
	if (win._pixelSaverOriginalState !== undefined) {
		return win._pixelSaverOriginalState;
	}

	let id = guessWindowXID(win);
	let cmd = 'xprop -id ' + id;
	LOG(cmd);

	let xprops = GLib.spawn_command_line_sync(cmd);
	if (!xprops[0]) {
		WARN("xprop failed for " + win.title + " with id " + id);
		return false;
	}

	let str = xprops[1].toString();
	let m = str.match(/^_PIXEL_SAVER_ORIGINAL_STATE\(CARDINAL\) = ([0-9]+)$/m);
	if (m) {
		return win._pixelSaverOriginalState = !!m[1];
	}

	m = str.match(/^_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED(\(CARDINAL\))? = ([0-9]+)$/m);
	if (m) {
		let state = !!m[1];
		cmd = ['xprop', '-id', id,
		      '-f', '_PIXEL_SAVER_ORIGINAL_STATE', '32c',
		      '-set', '_PIXEL_SAVER_ORIGINAL_STATE',
		      (state ? '0x1' : '0x0')];
		LOG(cmd.join(' '));
		Util.spawn(cmd);
		return win._pixelSaverOriginalState = state;
	}

	WARN("Can't find original state for " + win.title + " with id " + id);
	return false;
}

/**
 * Tells the window manager to hide the titlebar on maximised windows.
 *
 * Does this by setting the _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED hint - means
 * I can do it once and forget about it, rather than tracking maximize/unmaximize
 * events.
 *
 * **Caveat**: doesn't work with Ubuntu's Ambiance and Radiance window themes -
 * my guess is they don't respect or implement this property.
 *
 * I don't know how to read the inital value, so I'm not sure how to resore it.
 *
 * @param {Meta.Window} win - window to set the HIDE_TITLEBAR_WHEN_MAXIMIZED property of.
 * @param {boolean} hide - whether to hide the titlebar or not.
 */
function setHideTitlebar(win, hide) {
	LOG('setHideTitlebar: ' + win.get_title() + ': ' + hide);

	// Make sure we save the state before altering it.
	getOriginalState(win);

	/* Undecorate with xprop. Use _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED.
	 * See (eg) mutter/src/window-props.c
	 */
	let cmd = ['xprop', '-id', guessWindowXID(win),
	           '-f', '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED', '32c',
	           '-set', '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED',
	           (hide ? '0x1' : '0x0')];
	LOG(cmd.join(' '));

	// Run xprop
	[success, pid] = GLib.spawn_async(
		null,
		cmd,
		null,
		GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
		null);

	// After xprop completes, unmaximize and remaximize any window
	// that is already maximized. It seems that setting the xprop on
	// a window that is already maximized doesn't actually take
	// effect immediately but it needs a focuse change or other
	// action to force a relayout. Doing unmaximize and maximize
	// here seems to be an uninvasive way to handle this. This needs
	// to happen _after_ xprop completes.
	GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {
		const MAXIMIZED = Meta.MaximizeFlags.BOTH;
		let flags = win.get_maximized();
		if (flags == MAXIMIZED) {
			win.unmaximize(MAXIMIZED);
			win.maximize(MAXIMIZED);
		}
	});
}

/**** Callbacks ****/
/** Callback when a window is added in any of the workspaces.
 * This includes a window switching to another workspace.
 *
 * If it is a window we already know about, we do nothing.
 *
 * Otherwise, we activate the hide title on maximize feature.
 *
 * @param {Meta.Window} win - the window that was added.
 *
 * @see undecorate
 */
function onWindowAdded(ws, win, retry) {
	if (win.window_type === Meta.WindowType.DESKTOP) {
		return false;
	}

	// If the window is simply switching workspaces, it will trigger a
	// window-added signal. We don't want to reprocess it then because we already
	// have.
	if (win._pixelSaverOriginalState !== undefined) {
		return false;
	}

	/**
	 * Newly-created windows are added to the workspace before
	 * the compositor knows about them: get_compositor_private() is null.
	 * Additionally things like .get_maximized() aren't properly done yet.
	 * (see workspace.js _doAddWindow)
	 */
	if (!win.get_compositor_private()) {
		retry = (retry !== undefined) ? retry : 0;
		if (retry > 3) {
			return false;
		}

		Mainloop.idle_add(function () {
			onWindowAdded(ws, win, retry + 1);
			return false;
		});
		return false;
	}

	let retry = 3;
	Mainloop.idle_add(function () {
		let id = guessWindowXID(win);
		if (!id) {
			if (--retry) {
				return true;
			}

			WARN("Finding XID for window %s failed".format(win.title));
			return false;
		}

		LOG('onWindowAdded: ' + win.get_title());
		setHideTitlebar(win, true);
		return false;
	});

	return false;
}

let workspaces = [];

/** Callback whenever the number of workspaces changes.
 *
 * We ensure that we are listening to the 'window-added' signal on each of
 * the workspaces.
 *
 * @see onWindowAdded
 */
function onChangeNWorkspaces() {
	let i = workspaces.length;
	while (i--) {
		let ws = workspaces[i];
		ws.disconnect(ws._pixelSaverWindowAddedId);
	}

	workspaces = [];
	i = global.screen.n_workspaces;
	while (i--) {
		let ws = global.screen.get_workspace_by_index(i);
		workspaces.push(ws);
		// we need to add a Mainloop.idle_add, or else in onWindowAdded the
		// window's maximized state is not correct yet.
		ws._pixelSaverWindowAddedId = ws.connect('window-added', function (ws, win) {
			Mainloop.idle_add(function () { return onWindowAdded(ws, win); });
		});
	}

	return false;
}

/*
 * Subextension hooks
 */
function init() {}

let changeWorkspaceID = 0;
function enable() {
	/* Connect events */
	changeWorkspaceID = global.screen.connect('notify::n-workspaces', onChangeNWorkspaces);

	/* Go through already-maximised windows & undecorate.
	 * This needs a delay as the window list is not yet loaded
	 *  when the extension is loaded.
	 * Also, connect up the 'window-added' event.
	 * Note that we do not connect this before the onMaximise loop
	 *  because when one restarts the gnome-shell, window-added gets
	 *  fired for every currently-existing window, and then
	 *  these windows will have onMaximise called twice on them.
	 */
	Mainloop.idle_add(function () {
		let winList = global.get_window_actors().map(function (w) { return w.meta_window; }),
			i       = winList.length;
		while (i--) {
			let win = winList[i];
			if (win.window_type === Meta.WindowType.DESKTOP) {
				continue;
			}
			onWindowAdded(null, win);
		}

		onChangeNWorkspaces();
		return false;
	});
}

function disable() {
	if (changeWorkspaceID) {
		global.window_manager.disconnect(changeWorkspaceID);
		changeWorkspaceID = 0;
	}

	/* disconnect window-added from workspaces */
	let i = workspaces.length;
	while (i--) {
		workspaces[i].disconnect(workspaces[i]._pixelSaverWindowAddedId);
		delete workspaces[i]._pixelSaverWindowAddedId;
	}
	workspaces = [];

	let winList = global.get_window_actors().map(function (w) { return w.meta_window; }),
		i       = winList.length;
	while (i--) {
		let win = winList[i];
		if (win.window_type === Meta.WindowType.DESKTOP) {
			continue;
		}

		LOG('stopUndecorating: ' + win.title);
		if (getOriginalState(win) === false) {
			setHideTitlebar(win, false);
		}

		delete win._pixelSaverOriginalState;
	}
}

<commit_msg>Move fix to correct method; explicitly handle all possible states<commit_after>const GLib = imports.gi.GLib;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Util = imports.misc.util;

function LOG(message) {
	// log("[pixel-saver]: " + message);
}

function WARN(message) {
	log("[pixel-saver]: " + message);
}

/** Guesses the X ID of a window.
 *
 * It is often in the window's title, being `"0x%x %10s".format(XID, window.title)`.
 * (See `mutter/src/core/window-props.c`).
 *
 * If we couldn't find it there, we use `win`'s actor, `win.get_compositor_private()`.
 * The actor's `x-window` property is the X ID of the window *actor*'s frame
 * (as opposed to the window itself).
 *
 * However, the child window of the window actor is the window itself, so by
 * using `xwininfo -children -id [actor's XID]` we can attempt to deduce the
 * window's X ID.
 *
 * It is not always foolproof, but works good enough for now.
 *
 * @param {Meta.Window} win - the window to guess the XID of. You wil get better
 * success if the window's actor (`win.get_compositor_private()`) exists.
 */
function guessWindowXID(win) {
	// We cache the result so we don't need to redetect.
	if (win._pixelSaverWindowID) {
		return win._pixelSaverWindowID;
	}

	/* if window title has non-utf8 characters, get_description() complains
	 * "Failed to convert UTF-8 string to JS string: Invalid byte sequence in conversion input",
	 * event though get_title() works.
	 */
	try {
		let m = win.get_description().match(/0x[0-9a-f]+/);
		if (m && m[0]) {
			return win._pixelSaverWindowID = m[0];
		}
	} catch (err) { }

	// use xwininfo, take first child.
	let act = win.get_compositor_private();
	let xwindow = act && act['x-window'];
	if (xwindow) {
		let xwininfo = GLib.spawn_command_line_sync('xwininfo -children -id 0x%x'.format(xwindow));
		if (xwininfo[0]) {
			let str = xwininfo[1].toString();

			/* The X ID of the window is the one preceding the target window's title.
			 * This is to handle cases where the window has no frame and so
			 * act['x-window'] is actually the X ID we want, not the child.
			 */
			let regexp = new RegExp('(0x[0-9a-f]+) +"%s"'.format(win.title));
			let m = str.match(regexp);
			if (m && m[1]) {
				return win._pixelSaverWindowID = m[1];
			}

			/* Otherwise, just grab the child and hope for the best */
			m = str.split(/child(?:ren)?:/)[1].match(/0x[0-9a-f]+/);
			if (m && m[0]) {
				return win._pixelSaverWindowID = m[0];
			}
		}
	}

	// Try enumerating all available windows and match the title. Note that this
	// may be necessary if the title contains special characters and `x-window`
	// is not available.
	let result = GLib.spawn_command_line_sync('xprop -root _NET_CLIENT_LIST');
	LOG('xprop -root _NET_CLIENT_LIST')
	if (result[0]) {
		let str = result[1].toString();

		// Get the list of window IDs.
		let windowList = str.match(/0x[0-9a-f]+/g);

		// For each window ID, check if the title matches the desired title.
		for (var i = 0; i < windowList.length; ++i) {
			let cmd = 'xprop -id "' + windowList[i] + '" _NET_WM_NAME _PIXEL_SAVER_ORIGINAL_STATE';
			let result = GLib.spawn_command_line_sync(cmd);
			LOG(cmd);

			if (result[0]) {
				let output = result[1].toString();
				let isManaged = output.indexOf("_PIXEL_SAVER_ORIGINAL_STATE(CARDINAL)") > -1;
				if (isManaged) {
					continue;
				}

				let title = output.match(/_NET_WM_NAME(\(\w+\))? = "(([^\\"]|\\"|\\\\)*)"/);
				LOG("Title of XID %s is \"%s\".".format(windowList[i], title[2]));

				// Is this our guy?
				if (title && title[2] == win.title) {
					return windowList[i];
				}
			}
		}
	}

	// debugging for when people find bugs..
	WARN("Could not find XID for window with title %s".format(win.title));
	return null;
}

const WindowState = {
	DEFAULT: 'default',
	HIDE_TITLEBAR: 'hide_titlebar',
	UNDECORATED: 'undecorated',
	UNKNOWN: 'unknown'
}

/**
 * Get the value of _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED before
 * pixel saver did its magic.
 *
 * @param {Meta.Window} win - the window to check the property
 */
function getOriginalState(win) {
	if (win._pixelSaverOriginalState !== undefined) {
		return win._pixelSaverOriginalState;
	}

	if (!win.decorated) {
		return win._pixelSaverOriginalState = WindowState.UNDECORATED;
	}

	let id = guessWindowXID(win);
	let cmd = 'xprop -id ' + id;
	LOG(cmd);

	let xprops = GLib.spawn_command_line_sync(cmd);
	if (!xprops[0]) {
		WARN("xprop failed for " + win.title + " with id " + id);
		return win._pixelSaverOriginalState = State.UNKNOWN;
	}

	let str = xprops[1].toString();
	let m = str.match(/^_PIXEL_SAVER_ORIGINAL_STATE\(CARDINAL\) = ([0-9]+)$/m);
	if (m) {
		return win._pixelSaverOriginalState = !!m[1] ? WindowState.HIDE_TITLEBAR : WindowState.DEFAULT;
	}

	m = str.match(/^_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED(\(CARDINAL\))? = ([0-9]+)$/m);
	if (m) {
		let state = !!m[1];
		cmd = ['xprop', '-id', id,
		      '-f', '_PIXEL_SAVER_ORIGINAL_STATE', '32c',
		      '-set', '_PIXEL_SAVER_ORIGINAL_STATE',
		      (state ? '0x1' : '0x0')];
		LOG(cmd.join(' '));
		Util.spawn(cmd);
		return win._pixelSaverOriginalState = state ? WindowState.HIDE_TITLEBAR : WindowState.DEFAULT;
	}

	WARN("Can't find original state for " + win.title + " with id " + id);

	// if we can't find an atom, assume the titlebar not to be hidden
	return win._pixelSaverOriginalState = WindowState.DEFAULT;
}

/**
 * Tells the window manager to hide the titlebar on maximised windows.
 *
 * Does this by setting the _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED hint - means
 * I can do it once and forget about it, rather than tracking maximize/unmaximize
 * events.
 *
 * **Caveat**: doesn't work with Ubuntu's Ambiance and Radiance window themes -
 * my guess is they don't respect or implement this property.
 *
 * I don't know how to read the inital value, so I'm not sure how to resore it.
 *
 * @param {Meta.Window} win - window to set the HIDE_TITLEBAR_WHEN_MAXIMIZED property of.
 * @param {boolean} hide - whether to hide the titlebar or not.
 */
function setHideTitlebar(win, hide) {
	LOG('setHideTitlebar: ' + win.get_title() + ': ' + hide);

	// Make sure we save the state before altering it.
	getOriginalState(win);

	/* Undecorate with xprop. Use _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED.
	 * See (eg) mutter/src/window-props.c
	 */
	let cmd = ['xprop', '-id', guessWindowXID(win),
	           '-f', '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED', '32c',
	           '-set', '_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED',
	           (hide ? '0x1' : '0x0')];
	LOG(cmd.join(' '));

	// Run xprop
	[success, pid] = GLib.spawn_async(
		null,
		cmd,
		null,
		GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
		null);

	// After xprop completes, unmaximize and remaximize any window
	// that is already maximized. It seems that setting the xprop on
	// a window that is already maximized doesn't actually take
	// effect immediately but it needs a focuse change or other
	// action to force a relayout. Doing unmaximize and maximize
	// here seems to be an uninvasive way to handle this. This needs
	// to happen _after_ xprop completes.
	GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {
		const MAXIMIZED = Meta.MaximizeFlags.BOTH;
		let flags = win.get_maximized();
		if (flags == MAXIMIZED) {
			win.unmaximize(MAXIMIZED);
			win.maximize(MAXIMIZED);
		}
	});
}

/**** Callbacks ****/
/** Callback when a window is added in any of the workspaces.
 * This includes a window switching to another workspace.
 *
 * If it is a window we already know about, we do nothing.
 *
 * Otherwise, we activate the hide title on maximize feature.
 *
 * @param {Meta.Window} win - the window that was added.
 *
 * @see undecorate
 */
function onWindowAdded(ws, win, retry) {
	if (win.window_type === Meta.WindowType.DESKTOP) {
		return false;
	}

	// If the window is simply switching workspaces, it will trigger a
	// window-added signal. We don't want to reprocess it then because we already
	// have.
	if (win._pixelSaverOriginalState !== undefined) {
		return false;
	}

	/**
	 * Newly-created windows are added to the workspace before
	 * the compositor knows about them: get_compositor_private() is null.
	 * Additionally things like .get_maximized() aren't properly done yet.
	 * (see workspace.js _doAddWindow)
	 */
	if (!win.get_compositor_private()) {
		retry = (retry !== undefined) ? retry : 0;
		if (retry > 3) {
			return false;
		}

		Mainloop.idle_add(function () {
			onWindowAdded(ws, win, retry + 1);
			return false;
		});
		return false;
	}

	let retry = 3;
	Mainloop.idle_add(function () {
		let id = guessWindowXID(win);
		if (!id) {
			if (--retry) {
				return true;
			}

			WARN("Finding XID for window %s failed".format(win.title));
			return false;
		}

		LOG('onWindowAdded: ' + win.get_title());
		setHideTitlebar(win, true);
		return false;
	});

	return false;
}

let workspaces = [];

/** Callback whenever the number of workspaces changes.
 *
 * We ensure that we are listening to the 'window-added' signal on each of
 * the workspaces.
 *
 * @see onWindowAdded
 */
function onChangeNWorkspaces() {
	let i = workspaces.length;
	while (i--) {
		let ws = workspaces[i];
		ws.disconnect(ws._pixelSaverWindowAddedId);
	}

	workspaces = [];
	i = global.screen.n_workspaces;
	while (i--) {
		let ws = global.screen.get_workspace_by_index(i);
		workspaces.push(ws);
		// we need to add a Mainloop.idle_add, or else in onWindowAdded the
		// window's maximized state is not correct yet.
		ws._pixelSaverWindowAddedId = ws.connect('window-added', function (ws, win) {
			Mainloop.idle_add(function () { return onWindowAdded(ws, win); });
		});
	}

	return false;
}

/*
 * Subextension hooks
 */
function init() {}

let changeWorkspaceID = 0;
function enable() {
	/* Connect events */
	changeWorkspaceID = global.screen.connect('notify::n-workspaces', onChangeNWorkspaces);

	/* Go through already-maximised windows & undecorate.
	 * This needs a delay as the window list is not yet loaded
	 *  when the extension is loaded.
	 * Also, connect up the 'window-added' event.
	 * Note that we do not connect this before the onMaximise loop
	 *  because when one restarts the gnome-shell, window-added gets
	 *  fired for every currently-existing window, and then
	 *  these windows will have onMaximise called twice on them.
	 */
	Mainloop.idle_add(function () {
		let winList = global.get_window_actors().map(function (w) { return w.meta_window; }),
			i       = winList.length;
		while (i--) {
			let win = winList[i];
			if (win.window_type === Meta.WindowType.DESKTOP) {
				continue;
			}
			onWindowAdded(null, win);
		}

		onChangeNWorkspaces();
		return false;
	});
}

function disable() {
	if (changeWorkspaceID) {
		global.window_manager.disconnect(changeWorkspaceID);
		changeWorkspaceID = 0;
	}

	/* disconnect window-added from workspaces */
	let i = workspaces.length;
	while (i--) {
		workspaces[i].disconnect(workspaces[i]._pixelSaverWindowAddedId);
		delete workspaces[i]._pixelSaverWindowAddedId;
	}
	workspaces = [];

	let winList = global.get_window_actors().map(function (w) { return w.meta_window; }),
		i       = winList.length;
	while (i--) {
		let win = winList[i];
		if (win.window_type === Meta.WindowType.DESKTOP) {
			continue;
		}

		let state = getOriginalState(win);
		LOG('stopUndecorating: ' + win.title + ' original=' + state);
		if (state == WindowState.DEFAULT) {
			setHideTitlebar(win, false);
		}

		delete win._pixelSaverOriginalState;
	}
}

<|endoftext|>


<commit_before>import endsWith from 'lodash/endsWith';
import mapKeys from 'lodash/mapKeys';
import sha1 from 'sha1';

const root = window.root;

console.assert(typeof root.app.config === 'object', 'root.app.config is not an object');

const settings = {
    version: root.app.config.version,
    webroot: root.app.config.webroot,
    name: 'cnc',
    log: {
        level: 'warn', // trace, debug, info, warn, error
        logger: 'console', // console
        prefix: ''
    },
    i18next: {
        lowerCaseLng: true,

        // logs out more info (console)
        debug: false,

        // language to lookup key if not found on set language
        fallbackLng: 'en',

        // string or array of namespaces
        ns: [
            'locale', // locale: language, timezone, ...
            'resource' // default
        ],
        // default namespace used if not passed to translation function
        defaultNS: 'resource',

        whitelist: [
            'en', // default language
            'de',
            'es',
            'fr',
            'it',
            'ja',
            'zh-cn',
            'zh-tw'
        ],

        // array of languages to preload
        preload: [],

        // language codes to lookup, given set language is 'en-US':
        // 'all' --> ['en-US', 'en', 'dev']
        // 'currentOnly' --> 'en-US'
        // 'languageOnly' --> 'en'
        load: 'currentOnly',

        // char to separate keys
        keySeparator: '.',

        // char to split namespace from key
        nsSeparator: ':',

        interpolation: {
            prefix: '{{',
            suffix: '}}'
        },

        // options for language detection
        // https://github.com/i18next/i18next-browser-languageDetector
        detection: {
            // order and from where user language should be detected
            order: ['querystring', 'cookie', 'localStorage'],

            // keys or params to lookup language from
            lookupQuerystring: 'lang',
            lookupCookie: 'lang',
            lookupLocalStorage: 'lang',

            // cache user language on
            caches: ['localStorage', 'cookie']
        },
        // options for backend
        // https://github.com/i18next/i18next-xhr-backend
        backend: {
            // path where resources get loaded from
            loadPath: root.app.config.webroot + 'i18n/{{lng}}/{{ns}}.json',

            // path to post missing resources
            addPath: 'api/i18n/sendMissing/{{lng}}/{{ns}}',

            // your backend server supports multiloading
            // /locales/resources.json?lng=de+en&ns=ns1+ns2
            allowMultiLoading: false,

            parse: function(data, url) {
                if (endsWith(url, 'resource.json')) {
                    data = mapKeys(data, (value, key) => {
                        return sha1(key);
                    });
                }

                return data;
            },

            // allow cross domain requests
            crossDomain: false
        }
    }
};

export default settings;
<commit_msg>Modify translation keys once data have been fetched<commit_after>import endsWith from 'lodash/endsWith';
import mapKeys from 'lodash/mapKeys';
import sha1 from 'sha1';
import log from '../lib/log';

const root = window.root;

console.assert(typeof root.app.config === 'object', 'root.app.config is not an object');

const settings = {
    version: root.app.config.version,
    webroot: root.app.config.webroot,
    name: 'cnc',
    log: {
        level: 'warn', // trace, debug, info, warn, error
        logger: 'console', // console
        prefix: ''
    },
    i18next: {
        lowerCaseLng: true,

        // logs out more info (console)
        debug: false,

        // language to lookup key if not found on set language
        fallbackLng: 'en',

        // string or array of namespaces
        ns: [
            'locale', // locale: language, timezone, ...
            'resource' // default
        ],
        // default namespace used if not passed to translation function
        defaultNS: 'resource',

        whitelist: [
            'en', // default language
            'de',
            'es',
            'fr',
            'it',
            'ja',
            'zh-cn',
            'zh-tw'
        ],

        // array of languages to preload
        preload: [],

        // language codes to lookup, given set language is 'en-US':
        // 'all' --> ['en-US', 'en', 'dev']
        // 'currentOnly' --> 'en-US'
        // 'languageOnly' --> 'en'
        load: 'currentOnly',

        // char to separate keys
        keySeparator: '.',

        // char to split namespace from key
        nsSeparator: ':',

        interpolation: {
            prefix: '{{',
            suffix: '}}'
        },

        // options for language detection
        // https://github.com/i18next/i18next-browser-languageDetector
        detection: {
            // order and from where user language should be detected
            order: ['querystring', 'cookie', 'localStorage'],

            // keys or params to lookup language from
            lookupQuerystring: 'lang',
            lookupCookie: 'lang',
            lookupLocalStorage: 'lang',

            // cache user language on
            caches: ['localStorage', 'cookie']
        },
        // options for backend
        // https://github.com/i18next/i18next-xhr-backend
        backend: {
            // path where resources get loaded from
            loadPath: root.app.config.webroot + 'i18n/{{lng}}/{{ns}}.json',

            // path to post missing resources
            addPath: 'api/i18n/sendMissing/{{lng}}/{{ns}}',

            // your backend server supports multiloading
            // /locales/resources.json?lng=de+en&ns=ns1+ns2
            allowMultiLoading: false,

            parse: function(data, url) {
                if (endsWith(url, '/resource.json')) {
                    const source = JSON.parse(data);
                    const target = mapKeys(source, (value, key) => sha1(key));
                    data = JSON.stringify(target, null, 2);
                }

                log.trace(`Loading resource: url="${url}"`);

                return data;
            },

            // allow cross domain requests
            crossDomain: false
        }
    }
};

export default settings;
<|endoftext|>


<commit_before>/**
 * @author Serge Babayan
 * @module views/ThrottleView
 * @requires models/Commands
 * @requires models/TelemetryData
 * @requires util/Template
 * @requires util/Logger
 * @requires util/Validator
 * @requires electron
 * @listens models/TelemetryData~TelemetryData:data_received
 * @copyright Waterloo Aerial Robotics Group 2016
 * @licence https://raw.githubusercontent.com/UWARG/WARG-Ground-Station/master/LICENSE
 * @description View that displays the aircraft's throttle, flap, and attitude rate values
 */

var remote = require('electron').remote;
var Logger = remote.require('./app/util/Logger');
var TelemetryData = remote.require('./app/models/TelemetryData');
var Validator = require('../util/Validator');
var Commands = remote.require('./app/models/Commands');
var Template = require('../util/Template');

module.exports = function (Marionette) {

  return Marionette.ItemView.extend({
    template: Template('ThrottleView'),
    className: 'throttleView',

    ui: {
      throttle: '.throttle-value',
      yaw: '.yaw-value',
      yaw_setpoint: '.yaw-setpoint-value',
      flap: '.flap-value',
      roll_rate_rad: '.roll-rate-value-rad',
      pitch_rate_rad: '.pitch-rate-value-rad',
      yaw_rate_rad: '.yaw-rate-value-rad',
      roll_rate_deg: '.roll-rate-value-deg',
      pitch_rate_deg: '.pitch-rate-value-deg',
      yaw_rate_deg: '.yaw-rate-value-deg',
      throttle_input: '.throttle-form input',
      flap_input: '.flap-form input'
    },
    events: {
      'submit .flap-form': 'sendSetFlapCommand',
      'submit .throttle-form': 'sendSetThrottleCommand'
    },
    initialize: function () {
      this.aircraft_setpoints_callback = this.aircraftSetpointsCallback.bind(this);
      this.aircraft_position_callback = this.aircraftPositionCallback.bind(this);
      TelemetryData.addListener('aircraft_setpoints', this.aircraft_setpoints_callback);
      TelemetryData.addListener('aircraft_position', this.aircraft_position_callback);
    },

    aircraftSetpointsCallback: function(data){
      this.setThrottle(data.throttle_setpoint);
      // this.setFlap(data.flap_setpoint);
    },

    aircraftPositionCallback: function(data){
      this.setRollRate(data.roll_rate);
      this.setYawRate(data.yaw_rate);
      this.setPitchRate(data.pitch_rate);
    },

    onBeforeDestroy: function(){
      TelemetryData.removeListener('aircraft_setpoints', this.aircraft_setpoints_callback);
      TelemetryData.removeListener('aircraft_position', this.aircraft_position_callback);
    },

    setThrottle: function (throttle) {
      if (throttle !== null) {
        this.ui.throttle.text(((throttle + 1024) * 100 / 2048).toFixed(1));//-1024 represents 0%
      }
    },

    setRollRate: function (val) {
      if (val !== null) {
        this.ui.roll_rate_rad.text(Number(val).toFixed(2));
        this.ui.roll_rate_deg.text((Number(val)*180/Math.PI).toFixed(2));
      }
    },

    setPitchRate: function (val) {
      if (val !== null) {
        this.ui.pitch_rate_rad.text(Number(val).toFixed(2));
        this.ui.pitch_rate_deg.text((Number(val)*180/Math.PI).toFixed(2));
      }
    },

    setYawRate: function (val) {
      if (val !== null) {
        this.ui.yaw_rate_rad.text(Number(val).toFixed(2));
        this.ui.yaw_rate_deg.text((Number(val)*180/Math.PI).toFixed(2));
      }
    },

    setFlap: function (flap) {
      if (flap !== null) {
        this.ui.flap.text((flap + 1024) * 100 / 2048).toFixed(1);//-1024 represents 0%
      }
    },

    setFlap: function (flap) {
      if (flap !== null) {
        this.ui.flap.text((flap + 1024) * 100 / 2048).toFixed(1);//-1024 represents 0%
      }
    },

    setFlap: function (flap) {
      if (flap !== null) {
        this.ui.flap.text((flap + 1024) * 100 / 2048).toFixed(1);//-1024 represents 0%
      }
    },

    setFlap: function (flap) {
      if (flap !== null) {
        this.ui.flap.text((flap + 1024) * 100 / 2048).toFixed(1);//-1024 represents 0%
      }
    },

    sendSetThrottleCommand: function (e) {
      e.preventDefault();
      Commands.sendThrottle(this.ui.throttle_input.val());
      this.ui.throttle_input.val('');
    },
    sendSetFlapCommand: function (e) {
      e.preventDefault();
      Commands.sendFlap(this.ui.flap_input.val());
      this.ui.flap_input.val('');
    }
  });
};<commit_msg>Fixed attitude rates being incorrect<commit_after>/**
 * @author Serge Babayan
 * @module views/ThrottleView
 * @requires models/Commands
 * @requires models/TelemetryData
 * @requires util/Template
 * @requires util/Logger
 * @requires util/Validator
 * @requires electron
 * @listens models/TelemetryData~TelemetryData:data_received
 * @copyright Waterloo Aerial Robotics Group 2016
 * @licence https://raw.githubusercontent.com/UWARG/WARG-Ground-Station/master/LICENSE
 * @description View that displays the aircraft's throttle, flap, and attitude rate values
 */

var remote = require('electron').remote;
var Logger = remote.require('./app/util/Logger');
var TelemetryData = remote.require('./app/models/TelemetryData');
var Validator = require('../util/Validator');
var Commands = remote.require('./app/models/Commands');
var Template = require('../util/Template');

module.exports = function (Marionette) {

  return Marionette.ItemView.extend({
    template: Template('ThrottleView'),
    className: 'throttleView',

    ui: {
      throttle: '.throttle-value',
      yaw: '.yaw-value',
      yaw_setpoint: '.yaw-setpoint-value',
      flap: '.flap-value',
      roll_rate_rad: '.roll-rate-value-rad',
      pitch_rate_rad: '.pitch-rate-value-rad',
      yaw_rate_rad: '.yaw-rate-value-rad',
      roll_rate_deg: '.roll-rate-value-deg',
      pitch_rate_deg: '.pitch-rate-value-deg',
      yaw_rate_deg: '.yaw-rate-value-deg',
      throttle_input: '.throttle-form input',
      flap_input: '.flap-form input'
    },
    events: {
      'submit .flap-form': 'sendSetFlapCommand',
      'submit .throttle-form': 'sendSetThrottleCommand'
    },
    initialize: function () {
      this.aircraft_setpoints_callback = this.aircraftSetpointsCallback.bind(this);
      this.aircraft_position_callback = this.aircraftPositionCallback.bind(this);
      TelemetryData.addListener('aircraft_setpoints', this.aircraft_setpoints_callback);
      TelemetryData.addListener('aircraft_position', this.aircraft_position_callback);
    },

    aircraftSetpointsCallback: function(data){
      this.setThrottle(data.throttle_setpoint);
      // this.setFlap(data.flap_setpoint);
    },

    aircraftPositionCallback: function(data){
      this.setRollRate(data.roll_rate);
      this.setYawRate(data.yaw_rate);
      this.setPitchRate(data.pitch_rate);
    },

    onBeforeDestroy: function(){
      TelemetryData.removeListener('aircraft_setpoints', this.aircraft_setpoints_callback);
      TelemetryData.removeListener('aircraft_position', this.aircraft_position_callback);
    },

    setThrottle: function (throttle) {
      if (throttle !== null) {
        this.ui.throttle.text(((throttle + 1024) * 100 / 2048).toFixed(1));//-1024 represents 0%
      }
    },

    setRollRate: function (val) {
      if (val !== null) {
        this.ui.roll_rate_deg.text(Number(val).toFixed(2));
        this.ui.roll_rate_rad.text((Number(val)/180*Math.PI).toFixed(2));
      }
    },

    setPitchRate: function (val) {
      if (val !== null) {
        this.ui.pitch_rate_deg.text(Number(val).toFixed(2));
        this.ui.pitch_rate_rad.text((Number(val)/180*Math.PI).toFixed(2));
      }
    },

    setYawRate: function (val) {
      if (val !== null) {
        this.ui.yaw_rate_deg.text(Number(val).toFixed(2));
        this.ui.yaw_rate_rad.text((Number(val)/180*Math.PI).toFixed(2));
      }
    },

    setFlap: function (flap) {
      if (flap !== null) {
        this.ui.flap.text((flap + 1024) * 100 / 2048).toFixed(1);//-1024 represents 0%
      }
    },

    setFlap: function (flap) {
      if (flap !== null) {
        this.ui.flap.text((flap + 1024) * 100 / 2048).toFixed(1);//-1024 represents 0%
      }
    },

    setFlap: function (flap) {
      if (flap !== null) {
        this.ui.flap.text((flap + 1024) * 100 / 2048).toFixed(1);//-1024 represents 0%
      }
    },

    setFlap: function (flap) {
      if (flap !== null) {
        this.ui.flap.text((flap + 1024) * 100 / 2048).toFixed(1);//-1024 represents 0%
      }
    },

    sendSetThrottleCommand: function (e) {
      e.preventDefault();
      Commands.sendThrottle(this.ui.throttle_input.val());
      this.ui.throttle_input.val('');
    },
    sendSetFlapCommand: function (e) {
      e.preventDefault();
      Commands.sendFlap(this.ui.flap_input.val());
      this.ui.flap_input.val('');
    }
  });
};<|endoftext|>


<commit_before><commit_msg>Refactor: combine all places `doneUserLine` is set<commit_after><|endoftext|>


<commit_before><commit_msg>Guard against missing divApplab...?<commit_after><|endoftext|>


<commit_before><commit_msg>hoc2015: paused clouds cleanup.<commit_after><|endoftext|>


<commit_before><commit_msg>fix canvasDrawRect() by adding beginPath()<commit_after><|endoftext|>


<commit_before>/**
 * A ping federate example of how to use `hapi-auth-saml`
 */
var Hapi = require('hapi');

var port = 80;
var server = Hapi.createServer(port);

var SamlAuth = require('../lib');

var options = require('./secrets');

server.pack.register(SamlAuth, function (err) {
  var samlOptions = {
    path: options.path,
    protocol: options.protocol,
    entryPoint: options.entryPoint,
    additionalEntryPointParams: options.additionalEntryPointParams,
    cert: options.cert,
    /**
     * Check whether profile returned contains the
     * correct information
     *
     * @param  {Object}   profile
     * @param  {function(err, profile, info)} done
     * @return {function} `done` function
     */
    verifyFunc: function(profile, done) {
      // Can check profile contains the correct
      // information here
      server.log(['debug', 'verifyFunc'], profile);

      return done(null, profile);
    }
  };

  if (options.issuer) {
    samlOptions.issuer = options.issuer;
  }

  server.auth.strategy('ping', 'saml', samlOptions);

  server.route({
    method: 'GET',
    path: '/',
    config: {
      handler: function(request, reply) {
        reply("
Homepage (no auth)
Login");
      }
    }
  });

  server.route({
    method: 'GET',
    path: '/login',
    config: {
      auth: 'ping',
      handler: function(request, reply) {
        reply(request.auth.credentials);
      }
    }
  });

  server.start(function(err) {
    console.log('Server started at:', server.info.uri);
  });

});
<commit_msg>Show all auth in example reply.<commit_after>/**
 * A ping federate example of how to use `hapi-auth-saml`
 */
var Hapi = require('hapi');

var port = 80;
var server = Hapi.createServer(port);

var SamlAuth = require('../lib');

var options = require('./secrets');

server.pack.register(SamlAuth, function (err) {
  var samlOptions = {
    path: options.path,
    protocol: options.protocol,
    entryPoint: options.entryPoint,
    additionalEntryPointParams: options.additionalEntryPointParams,
    cert: options.cert,
    /**
     * Check whether profile returned contains the
     * correct information
     *
     * @param  {Object}   profile
     * @param  {function(err, profile, info)} done
     * @return {function} `done` function
     */
    verifyFunc: function(profile, done) {
      // Can check profile contains the correct
      // information here
      server.log(['debug', 'verifyFunc'], profile);

      return done(null, profile);
    }
  };

  if (options.issuer) {
    samlOptions.issuer = options.issuer;
  }

  server.auth.strategy('ping', 'saml', samlOptions);

  server.route({
    method: 'GET',
    path: '/',
    config: {
      handler: function(request, reply) {
        reply("
Homepage (no auth)
Login");
      }
    }
  });

  server.route({
    method: 'GET',
    path: '/login',
    config: {
      auth: 'ping',
      handler: function(request, reply) {
        reply(request.auth);
      }
    }
  });

  server.start(function(err) {
    console.log('Server started at:', server.info.uri);
  });

});
<|endoftext|>


<commit_before>'use strict'

const common = require('./webpack.common')

const webpack = require('webpack')
const merge = require('webpack-merge')
const ExtractTextPlugin = require('extract-text-webpack-plugin')

let branchName = ''
if (process.platform === 'darwin') {
  branchName = process.env.TRAVIS_BRANCH
} else if (process.platform === 'win32') {
  branchName = process.env.APPVEYOR_REPO_BRANCH
}

let environment = 'production'
if (branchName && branchName.length > 0) {
  const matches = branchName.match(/^__release-([a-zA-Z]+)-.*/)
  if (matches && matches.length === 2) {
    environment = matches[1]
  }
}

const config = {
  devtool: 'cheap-module-source-map',
  plugins: [
  ],
}

const mainConfig = merge({}, common.main, config)
const sharedConfig = merge({}, common.shared, config)
const askPassConfig = merge({}, common.askPass, config)

const rendererConfig = merge({}, common.renderer, config, {
  module: {
    rules: [
      // This will cause the compiled CSS to be output to a
      // styles.css and a <link rel="stylesheet"> tag to be
      // appended to the index.html HEAD at compile time
      {
        test: /\.(scss|css)$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [ 'css-loader', 'sass-loader' ]
        })
      },
    ],
  },
  plugins: [
    // Necessary to be able to use ExtractTextPlugin as a loader.
    new ExtractTextPlugin('styles.css')
  ]
})

module.exports = [ mainConfig, sharedConfig, rendererConfig, askPassConfig ]
<commit_msg>:art: trailing comma<commit_after>'use strict'

const common = require('./webpack.common')

const webpack = require('webpack')
const merge = require('webpack-merge')
const ExtractTextPlugin = require('extract-text-webpack-plugin')

let branchName = ''
if (process.platform === 'darwin') {
  branchName = process.env.TRAVIS_BRANCH
} else if (process.platform === 'win32') {
  branchName = process.env.APPVEYOR_REPO_BRANCH
}

let environment = 'production'
if (branchName && branchName.length > 0) {
  const matches = branchName.match(/^__release-([a-zA-Z]+)-.*/)
  if (matches && matches.length === 2) {
    environment = matches[1]
  }
}

const config = {
  devtool: 'cheap-module-source-map',
  plugins: [
  ],
}

const mainConfig = merge({}, common.main, config)
const sharedConfig = merge({}, common.shared, config)
const askPassConfig = merge({}, common.askPass, config)

const rendererConfig = merge({}, common.renderer, config, {
  module: {
    rules: [
      // This will cause the compiled CSS to be output to a
      // styles.css and a <link rel="stylesheet"> tag to be
      // appended to the index.html HEAD at compile time
      {
        test: /\.(scss|css)$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [ 'css-loader', 'sass-loader' ]
        })
      },
    ],
  },
  plugins: [
    // Necessary to be able to use ExtractTextPlugin as a loader.
    new ExtractTextPlugin('styles.css'),
  ]
})

module.exports = [ mainConfig, sharedConfig, rendererConfig, askPassConfig ]
<|endoftext|>