<commit_before>//
//   Copyright 2009-2014 Ilkka Oksanen <iao@iki.fi>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing,
//   software distributed under the License is distributed on an "AS
//   IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//   express or implied.  See the License for the specific language
//   governing permissions and limitations under the License.
//

'use strict';

Mas.WindowView = Ember.View.extend({
    classNames: ['window', 'flex-grow-column'],
    classNameBindings: ['expanded:expanded:', 'visible:visible:hidden'],
    attributeBindings: ['row:data-row', 'draggable'],

    row: Ember.computed.alias('controller.model.row'),
    visible: Ember.computed.alias('controller.model.visible'),
    expanded: false,
    initial: true,

    draggable: function() {
        return 'true';
    }.property(),

    visibilityChanged: function() {
        this.get('parentView').windowAdded(true);
    }.observes('controller.model.visible'),

    $messagePanel: null,
    $images: null,

    actions: {
        expand: function() {
            this.set('expanded', true);
            this.get('parentView').windowAdded(true);
        },

        compress: function() {
            this.set('expanded', false);
            this.get('parentView').windowAdded(true);
        }
    },

    layoutDone: function() {
        this._goToBottom();

        if (this.get('initial')) {
            this._addScrollHandler();
            this.set('initial', false);
        }
    },

    didInsertElement: function() {
        var that = this;

        this.$messagePanel = this.$('.window-messages');

        var observer = new MutationObserver(Ember.run.bind(this, function() {
            that._goToBottom();
            that._updateImages();
        }));
        observer.observe(this.$messagePanel[0], { childList: true });

        this.$('.window-caption').tooltip();
        this.$messagePanel.tooltip({
            selector: '.timestamp',
            placement: 'right'
        });

        var selectedNick;

        this.$('.window-members').contextmenu({
            target: '#window-contextMenu',
            before: function(e) {
                var $target = $(e.target);

                if ($target.hasClass('window-members')) {
                    return false;
                }

                e.preventDefault();
                selectedNick = $target.text();
                this.getMenu().find('li').eq(0).text(selectedNick);
                return true;
            },
            onItem: function(context, e) {
                var action = $(e.target).data('action');
                that.get('controller').send(action, selectedNick);
            }
        });

        this.$('.window-members').click(function(e) {
            $(this).contextmenu('show', e);
            e.preventDefault();
            return false;
        });

        var emojisList = $.map(emojify.emojiNames, function(value, i) {
            return { id: i, name: value };
        });

        var emojiListTemplate =
            '
' +
            '${name}' +
            '
';

        this.$('.form-control').atwho({
            at: ':',
            tpl: emojiListTemplate,
            data: emojisList
        });

        this.$messagePanel.magnificPopup({
            type: 'image',
            delegate: '.user-img',
            closeOnContentClick: true,
            image: {
                verticalFit: false,
                titleSrc: function(item) {
                    var href = item.el.attr('href');

                    return 'Link to the original image:' + href + '';
                }
            }
        });

        this.get('parentView').windowAdded(false);
    },

    _goToBottom: function() {
        if (this.get('controller.model.scrollLock')) {
            return;
        }

        var scrollPos = this.$messagePanel.scrollTop();
        var bottom = this.$messagePanel.prop('scrollHeight');
        var height = this.$messagePanel.height();

        if (bottom - scrollPos > 2 * height) {
            this._moveTo(bottom);
        } else {
            this._scrollTo(bottom);
        }
    },

    _scrollTo: function(pos) {
        this.$messagePanel.stop();
        this.$messagePanel.css('overflow-y', 'hidden');

        this.$messagePanel.animate({
            scrollTop: pos
        }, 500, function() {
            this.$messagePanel.css('overflow-y', 'auto');
        }.bind(this));
    },

    _moveTo: function(pos) {
        this.$messagePanel.css('overflow-y', 'hidden');
        this.$messagePanel.scrollTop(pos);
        this.$messagePanel.css('overflow-y', 'auto');
    },

    _addScrollHandler: function() {
        var prevScrollPos = 0;

        this.$messagePanel.on('scroll', Ember.run.bind(this, function() {
            var $panel = this.$messagePanel;
            var scrollPos = $panel.scrollTop();

            if (prevScrollPos > scrollPos) {
                this.get('controller').send('scrollUp');
            } else if (scrollPos + $panel.innerHeight() >= $panel.prop('scrollHeight')) {
                this.get('controller').send('scrollBottom');
            }

            prevScrollPos = scrollPos;
            this.set('controller.model.deletedLine', false); // Hack

            this._showImages();
        }));

        this._showImages();
    },

    _updateImages: function() {
        if (this.$images === null) {
            this.$images = $([]);
        }

        this.$images = this.$images.add(this.$('img[data-src]'));
    },

    _showImages: function() {
        var placeHolderHeight = 31;
        var panelHeight = this.$messagePanel.height();
        var that = this;

        this.$images = this.$images.filter(function() {
            var $img = $(this);

            // We want to know image's position in .window-messages container div. For position()
            // to work correctly, .window-messages has to have position set to 'relative'. See
            // jQuery offsetParent() documentation for details.
            var pos = $img.position().top;

            if (pos + placeHolderHeight >= 0 && pos <= panelHeight) {
                $img.attr('src', $img.data('src'));
                $img.one('load error', function() {
                    $img.removeAttr('data-src');
                    that._goToBottom();
                });

                return false;
            }

            return true;
        });
    }
});
<commit_msg>Improve client lazy image loading logic<commit_after>//
//   Copyright 2009-2014 Ilkka Oksanen <iao@iki.fi>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing,
//   software distributed under the License is distributed on an "AS
//   IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//   express or implied.  See the License for the specific language
//   governing permissions and limitations under the License.
//

'use strict';

Mas.WindowView = Ember.View.extend({
    classNames: ['window', 'flex-grow-column'],
    classNameBindings: ['expanded:expanded:', 'visible:visible:hidden'],
    attributeBindings: ['row:data-row', 'draggable'],

    row: Ember.computed.alias('controller.model.row'),
    visible: Ember.computed.alias('controller.model.visible'),
    expanded: false,
    initial: true,

    draggable: function() {
        return 'true';
    }.property(),

    visibilityChanged: function() {
        this.get('parentView').windowAdded(true);
    }.observes('controller.model.visible'),

    $messagePanel: null,
    $images: null,

    actions: {
        expand: function() {
            this.set('expanded', true);
            this.get('parentView').windowAdded(true);
        },

        compress: function() {
            this.set('expanded', false);
            this.get('parentView').windowAdded(true);
        }
    },

    layoutDone: function() {
        this._goToBottom();

        if (this.get('initial')) {
            this._updateImages();
            this._addScrollHandler();
            this.set('initial', false);
        }

        this._showImages();
    },

    didInsertElement: function() {
        var that = this;

        this.$messagePanel = this.$('.window-messages');

        var observer = new MutationObserver(Ember.run.bind(this, function() {
            that._goToBottom();
            that._updateImages();
            that._showImages();
        }));
        observer.observe(this.$messagePanel[0], { childList: true });

        this.$('.window-caption').tooltip();
        this.$messagePanel.tooltip({
            selector: '.timestamp',
            placement: 'right'
        });

        var selectedNick;

        this.$('.window-members').contextmenu({
            target: '#window-contextMenu',
            before: function(e) {
                var $target = $(e.target);

                if ($target.hasClass('window-members')) {
                    return false;
                }

                e.preventDefault();
                selectedNick = $target.text();
                this.getMenu().find('li').eq(0).text(selectedNick);
                return true;
            },
            onItem: function(context, e) {
                var action = $(e.target).data('action');
                that.get('controller').send(action, selectedNick);
            }
        });

        this.$('.window-members').click(function(e) {
            $(this).contextmenu('show', e);
            e.preventDefault();
            return false;
        });

        var emojisList = $.map(emojify.emojiNames, function(value, i) {
            return { id: i, name: value };
        });

        var emojiListTemplate =
            '
' +
            '${name}' +
            '
';

        this.$('.form-control').atwho({
            at: ':',
            tpl: emojiListTemplate,
            data: emojisList
        });

        this.$messagePanel.magnificPopup({
            type: 'image',
            delegate: '.user-img',
            closeOnContentClick: true,
            image: {
                verticalFit: false,
                titleSrc: function(item) {
                    var href = item.el.attr('href');

                    return 'Link to the original image:' + href + '';
                }
            }
        });

        this.get('parentView').windowAdded(false);
    },

    _goToBottom: function() {
        if (this.get('controller.model.scrollLock')) {
            return;
        }

        var scrollPos = this.$messagePanel.scrollTop();
        var bottom = this.$messagePanel.prop('scrollHeight');
        var height = this.$messagePanel.height();

        if (bottom - scrollPos > 2 * height) {
            this._moveTo(bottom);
        } else {
            this._scrollTo(bottom);
        }
    },

    _scrollTo: function(pos) {
        this.$messagePanel.stop();
        this.$messagePanel.css('overflow-y', 'hidden');

        this.$messagePanel.animate({
            scrollTop: pos
        }, 500, function() {
            this.$messagePanel.css('overflow-y', 'auto');
        }.bind(this));
    },

    _moveTo: function(pos) {
        this.$messagePanel.css('overflow-y', 'hidden');
        this.$messagePanel.scrollTop(pos);
        this.$messagePanel.css('overflow-y', 'auto');
    },

    _addScrollHandler: function() {
        var prevScrollPos = 0;

        this.$messagePanel.on('scroll', Ember.run.bind(this, function() {
            var $panel = this.$messagePanel;
            var scrollPos = $panel.scrollTop();

            if (prevScrollPos > scrollPos) {
                this.get('controller').send('scrollUp');
            } else if (scrollPos + $panel.innerHeight() >= $panel.prop('scrollHeight')) {
                this.get('controller').send('scrollBottom');
            }

            prevScrollPos = scrollPos;
            this.set('controller.model.deletedLine', false); // Hack

            this._showImages();
        }));
    },

    _updateImages: function() {
        if (this.$images === null) {
            this.$images = $([]);
        }

        this.$images = this.$images.add(this.$('img[data-src]'));
    },

    _showImages: function() {
        var placeHolderHeight = 31;
        var panelHeight = this.$messagePanel.height();
        var that = this;

        this.$images = this.$images.filter(function() {
            var $img = $(this);

            // We want to know image's position in .window-messages container div. For position()
            // to work correctly, .window-messages has to have position set to 'relative'. See
            // jQuery offsetParent() documentation for details.
            var pos = $img.position().top;

            if (pos + placeHolderHeight >= 0 && pos <= panelHeight) {
                $img.attr('src', $img.data('src'));
                $img.one('load error', function() {
                    $img.removeAttr('data-src');
                    that._goToBottom();
                });

                return false;
            }

            return true;
        });
    }
});
<|endoftext|>


<commit_before>/*
 OpenBeerMap OSMAPI.js | noemie.lehuby(at)gmail.com | MIT Licensed
*/

function basic_auth(){
        return "Basic " + btoa("OpenBeerMapContributor" + ":" + "FtHwuH8w1RDjQpOr0y0gF3AWm8sRsRzncK3hHh9");
}

function get_node(id){
        var xhr = new XMLHttpRequest();

        xhr.open("GET", "http://api.openstreetmap.org/api/0.6/node/"+id, false);
        xhr.setRequestHeader("Authorization", basic_auth());
        xhr.send();

        console.log("GET node/ : " + xhr.status);
        var xmlDocument = xhr.responseXML;

        var tous_les_tags = xmlDocument.documentElement.getElementsByTagName("tag");
        for (var i = 0; i < tous_les_tags.length; i++) {
        console.log(tous_les_tags[i].getAttribute("k") +" : "+ tous_les_tags[i].getAttribute("v"))

        }
        return xmlDocument;

}

function edit_tag(xml,key, value){
        var tous_les_tags = xml.documentElement.getElementsByTagName("tag");
        /*modifier la valeur d'un tag, s'il existe déjà */
        for (var i = 0; i < tous_les_tags.length; i++) {
          if (tous_les_tags[i].getAttribute("k") === key)
                {
                //console.log(tous_les_tags[i].getAttribute("v"))
                tous_les_tags[i].setAttribute("v",value);
                return
                }
         }
        /*sinon, créer un nouveau tag */
        newel=xml.createElement("tag");
        x=xml.getElementsByTagName("node")[0];
        x.appendChild(newel);
        newel.setAttribute("k",key);
        newel.setAttribute("v", value);
        return

        //debug
        for (var i = 0; i < tous_les_tags.length; i++) {
        console.log(tous_les_tags[i].getAttribute("k") +" : "+ tous_les_tags[i].getAttribute("v"))
        }
        //return

}

function get_tag(xml,key){
      var tous_les_tags = xml.documentElement.getElementsByTagName("tag");
      /*modifier la valeur d'un tag*/
      for (var i = 0; i < tous_les_tags.length; i++) {
        if (tous_les_tags[i].getAttribute("k") === key)
                {
                //console.log(tous_les_tags[i].getAttribute("v"));
                return tous_les_tags[i].getAttribute("v");
                }
        }
      return "non_fourni"
}

function del_tag(xml,key){
      var tous_les_tags = xml.documentElement.getElementsByTagName("tag");
      /*modifier la valeur d'un tag*/
      for (var i = 0; i < tous_les_tags.length; i++) {
        if (tous_les_tags[i].getAttribute("k") === key)
                {
                //supprimer le tag
                tous_les_tags[i].parentNode.removeChild(tous_les_tags[i]);
                }
        }
        return
}

function put_node(xml, changeset_id, id){
        var node = xml.documentElement.getElementsByTagName("node");
        console.log(node[0].getAttribute('changeset'))
        node[0].setAttribute('changeset', changeset_id);

        var tous_les_tags = xml.documentElement.getElementsByTagName("tag");
        for (var i = 0; i < tous_les_tags.length; i++) {
        console.log(tous_les_tags[i].getAttribute("k") +" : "+ tous_les_tags[i].getAttribute("v"))

        }

        var xhr = new XMLHttpRequest();
        xhr.open("PUT", "http://api.openstreetmap.org/api/0.6/node/"+id, false);
        xhr.setRequestHeader("Authorization", basic_auth());
        xhr.send(xml);

        console.log("PUT node/ : " + xhr.status);
        console.log(xhr.responseText);

}

function close_changeset(id){

        var xhr = new XMLHttpRequest();
        xhr.open("PUT", "http://api.openstreetmap.org/api/0.6/changeset/"+id+"/close", false);
        xhr.setRequestHeader("Authorization", basic_auth());
        xhr.send();

        console.log("PUT changeset/close : " + xhr.status);
        console.log(xhr.responseText);
        return xhr.responseText ;

}

function put_changeset(){
        xml = "<osm> <changeset> <tag k='created_by' v='OpenBeerMap javascript editor'/> <tag k='comment' v='OpenBeerMar - Modification de bar'/> </changeset></osm>";
// TODO : passer le nom du bar modifié (ou son id si pas de nom) ?

        var xhr = new XMLHttpRequest();
        xhr.open("PUT", "http://api.openstreetmap.org/api/0.6/changeset/create", false);
        xhr.setRequestHeader("Authorization", basic_auth());
        xhr.send(xml);

        console.log("PUT changeset : " + xhr.status);
        console.log(xhr.responseText);
        return xhr.responseText ;

}

function edit_node(id){
        // récupérer le node initial
        OSMxml = get_node(id)

        //ici, faire les changements nécessaires
        edit_tag(OSMxml,"internet_acces","wlan")

        //ouvrir un changeset
        changeset_id = put_changeset()

        //envoyer le nouveau node
        put_node(OSMxml, changeset_id, id)

        //fermer le changeset
        close_changeset(changeset_id);

}

<commit_msg>Correction commentaire changeset<commit_after>/*
 OpenBeerMap OSMAPI.js | noemie.lehuby(at)gmail.com | MIT Licensed
*/

function basic_auth(){
        return "Basic " + btoa("OpenBeerMapContributor" + ":" + "FtHwuH8w1RDjQpOr0y0gF3AWm8sRsRzncK3hHh9");
}

function get_node(id){
        var xhr = new XMLHttpRequest();

        xhr.open("GET", "http://api.openstreetmap.org/api/0.6/node/"+id, false);
        xhr.setRequestHeader("Authorization", basic_auth());
        xhr.send();

        console.log("GET node/ : " + xhr.status);
        var xmlDocument = xhr.responseXML;

        var tous_les_tags = xmlDocument.documentElement.getElementsByTagName("tag");
        for (var i = 0; i < tous_les_tags.length; i++) {
        console.log(tous_les_tags[i].getAttribute("k") +" : "+ tous_les_tags[i].getAttribute("v"))

        }
        return xmlDocument;

}

function edit_tag(xml,key, value){
        var tous_les_tags = xml.documentElement.getElementsByTagName("tag");
        /*modifier la valeur d'un tag, s'il existe déjà */
        for (var i = 0; i < tous_les_tags.length; i++) {
          if (tous_les_tags[i].getAttribute("k") === key)
                {
                //console.log(tous_les_tags[i].getAttribute("v"))
                tous_les_tags[i].setAttribute("v",value);
                return
                }
         }
        /*sinon, créer un nouveau tag */
        newel=xml.createElement("tag");
        x=xml.getElementsByTagName("node")[0];
        x.appendChild(newel);
        newel.setAttribute("k",key);
        newel.setAttribute("v", value);
        return

        //debug
        for (var i = 0; i < tous_les_tags.length; i++) {
        console.log(tous_les_tags[i].getAttribute("k") +" : "+ tous_les_tags[i].getAttribute("v"))
        }
        //return

}

function get_tag(xml,key){
      var tous_les_tags = xml.documentElement.getElementsByTagName("tag");
      /*modifier la valeur d'un tag*/
      for (var i = 0; i < tous_les_tags.length; i++) {
        if (tous_les_tags[i].getAttribute("k") === key)
                {
                //console.log(tous_les_tags[i].getAttribute("v"));
                return tous_les_tags[i].getAttribute("v");
                }
        }
      return "non_fourni"
}

function del_tag(xml,key){
      var tous_les_tags = xml.documentElement.getElementsByTagName("tag");
      /*modifier la valeur d'un tag*/
      for (var i = 0; i < tous_les_tags.length; i++) {
        if (tous_les_tags[i].getAttribute("k") === key)
                {
                //supprimer le tag
                tous_les_tags[i].parentNode.removeChild(tous_les_tags[i]);
                }
        }
        return
}

function put_node(xml, changeset_id, id){
        var node = xml.documentElement.getElementsByTagName("node");
        console.log(node[0].getAttribute('changeset'))
        node[0].setAttribute('changeset', changeset_id);

        var tous_les_tags = xml.documentElement.getElementsByTagName("tag");
        for (var i = 0; i < tous_les_tags.length; i++) {
        console.log(tous_les_tags[i].getAttribute("k") +" : "+ tous_les_tags[i].getAttribute("v"))

        }

        var xhr = new XMLHttpRequest();
        xhr.open("PUT", "http://api.openstreetmap.org/api/0.6/node/"+id, false);
        xhr.setRequestHeader("Authorization", basic_auth());
        xhr.send(xml);

        console.log("PUT node/ : " + xhr.status);
        console.log(xhr.responseText);

}

function close_changeset(id){

        var xhr = new XMLHttpRequest();
        xhr.open("PUT", "http://api.openstreetmap.org/api/0.6/changeset/"+id+"/close", false);
        xhr.setRequestHeader("Authorization", basic_auth());
        xhr.send();

        console.log("PUT changeset/close : " + xhr.status);
        console.log(xhr.responseText);
        return xhr.responseText ;

}

function put_changeset(){
        xml = "<osm> <changeset> <tag k='created_by' v='OpenBeerMap javascript editor'/> <tag k='comment' v='OpenBeerMap - Modification de bar'/> </changeset></osm>";
// TODO : passer le nom du bar modifié (ou son id si pas de nom) ?

        var xhr = new XMLHttpRequest();
        xhr.open("PUT", "http://api.openstreetmap.org/api/0.6/changeset/create", false);
        xhr.setRequestHeader("Authorization", basic_auth());
        xhr.send(xml);

        console.log("PUT changeset : " + xhr.status);
        console.log(xhr.responseText);
        return xhr.responseText ;

}

function edit_node(id){
        // récupérer le node initial
        OSMxml = get_node(id)

        //ici, faire les changements nécessaires
        edit_tag(OSMxml,"internet_acces","wlan")

        //ouvrir un changeset
        changeset_id = put_changeset()

        //envoyer le nouveau node
        put_node(OSMxml, changeset_id, id)

        //fermer le changeset
        close_changeset(changeset_id);

}

<|endoftext|>


<commit_before>var fs = require('fs');
var util = require('util');
var path = require('path');

var sh = require('shelljs');

var syspol_fs = require('./fs');
var syspol_util = require('./util');
var isDirRW = syspol_fs.isDirRW;
var Logger = syspol_util.Logger;

// App =============================================================
function App(appName, rootDirPath, extraLogDirs) {
    if(!appName) {
        throw new Error("App appName must be supplied");
    }
    this.appName = appName;

    if (!isDirRW(rootDirPath)) {
        throw new Error(
            util.format("Can't read/write to dir `%s`", rootDirPath));
    }
    this.rootDirPath = rootDirPath;

    this.createDate = new Date();

    // tmp dir
    var tmpDir = path.join(this.rootDirPath, 'tmp');
    if (!isDirRW(tmpDir)) {
        sh.mkdir('-p', tmpDir);
    }
    if (sh.error()) {
        throw new Error('Unable to create tmp directory');
    }

    // Locking
    this.lockFilePath = path.join(this.rootDirPath,
        "var/lock/LCK.." + this.appName);

    // Validate lock.
    try {
        fs.accessSync(lockFilePath, fs.F_OK);
        var msg = util.format(
            "Lock file exists: `%s`\nTerminating application `%s`",
            this.lockFilePath, this.appName);
        console.error(msg);
        process.exit(1);
    }
    catch (e) {
        try {
            var msg = util.format(
                "Lock file doesn't exist, creating lock file `%s`",
                this.lockFilePath);
            sh.mkdir("-p", path.dirname(this.lockFilePath));
            process.pid.toString().toEnd(this.lockFilePath);
            console.log(msg);
        }
        catch (e) {
            throw new Error(
                "Unable to create lock file " + this.lockFilePath);
        }
    }
    process.on('exit', (code) => {
        var logOrConsoleOutput = (msg, severity) => {
            try {
                this.logger.log(msg, severity);
            }
            catch (e) {
                console.error(msg);
                console.error(e);
            }
        };

        sh.rm('-f', this.lockFilePath);
        if (sh.error()) {
            logOrConsoleOutput.error("Unable to remove lock file "
                + this.lockFilePath);
        }
        else {
            var msg = util.format("Removed lock file `%s`", this.lockFilePath)
            logOrConsoleOutput(msg, 'INFO');
        }

        var msg = "||||||||||| End of " + this.appName;
        logOrConsoleOutput(msg, 'INFO');
    });

    // Logging
    var ISODateStr = this.createDate.toISOString();
    var year = ISODateStr.slice(0, 4);
    var month = ISODateStr.slice(5, 7);
    var day = ISODateStr.slice(8, 10);
    var logDirPath = path.join(this.rootDirPath, 'var/log', year, month, day);
    this.logDirPaths = [logDirPath];

    if (extraLogDirs && 'filter' in extraLogDirs) {
        extraLogDirs = extraLogDirs.filter((extraLogDir) => {
            return isDirRW(extraLogDir);
        });
        this.logDirPaths = this.logDirPaths.concat(extraLogDirs);
    }

    this.logFilePaths = this.logDirPaths.map( (logDirPath) => {
        if (!isDirRW(logDirPath)) {
            sh.mkdir('-p', logDirPath);
        }
        if (sh.error()) {
            throw new Error('Unable to create log directory');
        }
        return path.join(logDirPath, ISODateStr.slice(0, 10) + '_log_'
            + this.appName + '.txt');
    });

    this.logger = new Logger(this.appName, this.logFilePaths);
}

Object.defineProperty(App.prototype, "constructor", {
    enumerable: false,
    value: App
});
// End App =========================================================

exports.App = App;
<commit_msg>Application root logging is optional<commit_after>var fs = require('fs');
var util = require('util');
var path = require('path');

var sh = require('shelljs');

var syspol_fs = require('./fs');
var syspol_util = require('./util');
var isDirRW = syspol_fs.isDirRW;
var Logger = syspol_util.Logger;

// App =============================================================
function App(appName, rootDirPath, extraLogDirs, appDirLogging) {
    if(!appName) {
        throw new Error("App appName must be supplied");
    }
    this.appName = appName;

    if (!isDirRW(rootDirPath)) {
        throw new Error(
            util.format("Can't read/write to dir `%s`", rootDirPath));
    }
    this.rootDirPath = rootDirPath;

    this.createDate = new Date();

    // tmp dir
    var tmpDir = path.join(this.rootDirPath, 'tmp');
    if (!isDirRW(tmpDir)) {
        sh.mkdir('-p', tmpDir);
    }
    if (sh.error()) {
        throw new Error('Unable to create tmp directory');
    }

    // Locking
    this.lockFilePath = path.join(this.rootDirPath,
        "var/lock/LCK.." + this.appName);

    // Validate lock.
    try {
        fs.accessSync(lockFilePath, fs.F_OK);
        var msg = util.format(
            "Lock file exists: `%s`\nTerminating application `%s`",
            this.lockFilePath, this.appName);
        console.error(msg);
        process.exit(1);
    }
    catch (e) {
        try {
            var msg = util.format(
                "Lock file doesn't exist, creating lock file `%s`",
                this.lockFilePath);
            sh.mkdir("-p", path.dirname(this.lockFilePath));
            process.pid.toString().toEnd(this.lockFilePath);
            console.log(msg);
        }
        catch (e) {
            throw new Error(
                "Unable to create lock file " + this.lockFilePath);
        }
    }
    process.on('exit', (code) => {
        var logOrConsoleOutput = (msg, severity) => {
            try {
                this.logger.log(msg, severity);
            }
            catch (e) {
                console.error(msg);
                console.error(e);
            }
        };

        sh.rm('-f', this.lockFilePath);
        if (sh.error()) {
            logOrConsoleOutput.error("Unable to remove lock file "
                + this.lockFilePath);
        }
        else {
            var msg = util.format("Removed lock file `%s`", this.lockFilePath)
            logOrConsoleOutput(msg, 'INFO');
        }

        var msg = "||||||||||| End of " + this.appName;
        logOrConsoleOutput(msg, 'INFO');
    });

    // Logging
    var ISODateStr = this.createDate.toISOString();
    var year = ISODateStr.slice(0, 4);
    var month = ISODateStr.slice(5, 7);
    var day = ISODateStr.slice(8, 10);
    var logDirPaths = [];

    // Application root standard log location is optional ($APPROOT/var/log)
    if(appDirLogging) {
        var appRootLogDirPath = path.join(this.rootDirPath, 'var/log', year,
                month, day);
        logDirPaths[logDirPaths.length] = appRootLogDirPath;
    }

    if (extraLogDirs && 'filter' in extraLogDirs) {
        extraLogDirs = extraLogDirs.filter((extraLogDir) => {
            return isDirRW(extraLogDir);
        });
        logDirPaths = logDirPaths.concat(extraLogDirs);
    }

    // Throw error if some logDirPath not readable/writable
    this.logFilePaths = logDirPaths.map( (logDirPath) => {
        if (!isDirRW(logDirPath)) {
            sh.mkdir('-p', logDirPath);
        }
        if (sh.error()) {
            throw new Error('Unable to create log directory');
        }
        return path.join(logDirPath, ISODateStr.slice(0, 10) + '_log_'
            + this.appName + '.txt');
    });

    this.logger = new Logger(this.appName, this.logFilePaths);
}

Object.defineProperty(App.prototype, "constructor", {
    enumerable: false,
    value: App
});
// End App =========================================================

exports.App = App;
<|endoftext|>


<commit_before>"use strict";

const React = require("react");
const PropTypes = require("prop-types");
const AnimatedLogo = require("@sandhose/prettier-animated-logo");
const { MarkdownBlock, Container } = require("../../core/CompLibrary.js");

const siteConfig = require(process.cwd() + "/siteConfig.js");

const ButtonGroup = (props) => (

{props.children}

);

ButtonGroup.propTypes = {
  children: PropTypes.node,
};

class Button extends React.Component {
  render() {
    return (

          {this.props.children}

    );
  }
}

Button.defaultProps = {
  target: "_self",
};

Button.propTypes = {
  href: PropTypes.string,
  target: PropTypes.string,
  children: PropTypes.any,
};

function Tidelift() {
  return (

      PRETTIER FOR ENTERPRISE

  );
}

const HomeSplash = (props) => (

    <Tidelift />

          <AnimatedLogo version="wide" />

                <Button href="/playground/">Try It Online</Button>
                <Button href={"/docs/" + props.language + "/install.html"}>
                  Install Prettier
                </Button>

);

HomeSplash.propTypes = {
  language: PropTypes.string,
};

const TldrSection = ({ language }) => (

    <Container>

What is Prettier?

An opinionated code formatter

Supports many languages

Integrates with most editors

Has few options

Why?

You press save and code is formatted

No need to discuss style in code review

Saves you time and energy

              And more

    </Container>

);

TldrSection.propTypes = {
  language: PropTypes.string,
};

const Language = ({ name, nameLink, showName, image, variants }) => (

      {showName && (

          {nameLink ? {name} : name}

      )}
      {variants.map((variant) => (

          <MarkdownBlock>{variant}</MarkdownBlock>

      ))}

);

Language.propTypes = {
  name: PropTypes.string,
  nameLink: PropTypes.string,
  showName: PropTypes.bool,
  image: PropTypes.string,
  variants: PropTypes.array,
};

const LanguagesSection = () => {
  const languageChunks = siteConfig.supportedLanguages.reduce(
    (acc, language) => {
      const last = acc[acc.length - 1];
      if (
        last &&
        last.length < 2 &&
        last.reduce((sum, lang) => sum + lang.variants.length, 0) +
          language.variants.length <
          9
      ) {
        last.push(language);
      } else {
        acc.push([language]);
      }
      return acc;
    },
    []
  );

  return (

      <Container>

Works with the Tools You Use

          {languageChunks.map((languageChunk, index) => (

              {languageChunk.map((language) => (
                <Language key={language.name} {...language} />
              ))}

          ))}

      </Container>

  );
};

const Editor = ({ content = "", image, name }) => (

{name}

      <MarkdownBlock>{content.replace(/\n/g, "  \n")}</MarkdownBlock>

);

Editor.propTypes = {
  content: PropTypes.string,
  image: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
};

const EditorSupportSection = () => (

    <Container>

Editor Support

        {siteConfig.editors.map((editor) => (
          <Editor key={editor.name} {...editor} />
        ))}

    </Container>

      Got more?
      <a
        href={`${siteConfig.githubUrl}/edit/main/website/data/editors.yml`}
        className="button"
      >
        Send a PR

);

const UsersSection = ({ language }) => {
  const showcase = siteConfig.users
    .filter((user) => user.pinned)
    .map((user, i) => (

    ));

  return (

      <Container>

Used By People You Rely On

          {showcase}

            See Others

Established in the Ecosystem

                Regularly used by more than 70% of respondents
                to State of JS 2020

              <Button href="https://2020.stateofjs.com/en-US/other-tools/utilities">
                Go to Survey Results
              </Button>

                More than{" "}
                3.5 million{" "}
                dependent repositories on GitHub

              <Button href="https://github.com/prettier/prettier/network/dependents">
                Check Them Out
              </Button>

                More than 10k{" "}
                dependent packages on npm

              <Button href="https://www.npmjs.com/browse/depended/prettier">
                See them all
              </Button>

      </Container>

  );
};

UsersSection.propTypes = {
  language: PropTypes.string,
};

class Index extends React.Component {
  render() {
    const language = this.props.language || "en";

    return (


<commit_before>/*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */
/*global module, require*/
module.exports = function (grunt) {
    'use strict';

    // Project configuration.
    grunt.initConfig({
        meta : {
            src   : [
                'src/**/*.js',
                '!src/thirdparty/**',
                '!src/widgets/bootstrap-*.js',
                '!src/extensions/**/unittest-files/**/*.js',
                '!src/extensions/**/thirdparty/**/*.js',
                '!src/extensions/dev/**',
                '!src/extensions/disabled/**',
                '!src/extensions/**/node_modules/**/*.js',
                '!src/**/*-min.js',
                '!src/**/*.min.js'
            ],
            test : [
                'test/**/*.js',
                '!test/perf/*-files/**/*.js',
                '!test/spec/*-files/**/*.js',
                '!test/smokes/**',
                '!test/temp/**',
                '!test/thirdparty/**'
            ],
            /* specs that can run in phantom.js */
            specs : [
                'test/spec/CommandManager-test.js',
                'test/spec/LanguageManager-test.js',
                'test/spec/PreferencesManager-test.js',
                'test/spec/ViewUtils-test.js'
            ]
        },
        watch: {
            test : {
                files: ['Gruntfile.js', '<%= meta.src %>', '<%= meta.test %>'],
                tasks: 'test'
            }
        },
        /* FIXME (jasonsanjose): how to handle extension tests */
        jasmine : {
            src : 'undefined.js', /* trick the default runner to run without importing src files */
            options : {
                junit : {
                    path: 'test/results',
                    consolidate: true
                },
                specs : '<%= meta.specs %>',
                /* Keep in sync with test/SpecRunner.html dependencies */
                vendor : [
                    'src/thirdparty/jquery-1.7.js',
                    'src/thirdparty/CodeMirror2/lib/codemirror.js',
                    'src/thirdparty/CodeMirror2/lib/util/dialog.js',
                    'src/thirdparty/CodeMirror2/lib/util/searchcursor.js',
                    'src/thirdparty/mustache/mustache.js',
                    'src/thirdparty/path-utils/path-utils.min'
                ],
                helpers : [
                    'test/spec/PhantomHelper.js'
                ],
                template : require('grunt-template-jasmine-requirejs'),
                templateOptions: {
                    requireConfig : {
                        baseUrl: 'src',
                        paths: {
                            'test' : '../test',
                            'perf' : '../test/perf',
                            'spec' : '../test/spec',
                            'text' : 'thirdparty/text',
                            'i18n' : 'thirdparty/i18n'
                        }
                    }
                }
            }
        },
        jshint: {
            all: [
                'Gruntfile.js',
                '<%= meta.src %>',
                '<%= meta.test %>'
            ],
            /* use strict options to mimic JSLINT until we migrate to JSHINT in Brackets */
            options: {
                jshintrc: '.jshintrc'
            }
        }
    });

    // load dependencies
    grunt.loadTasks('tasks');
    grunt.loadNpmTasks('grunt-contrib-jasmine');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');

    // task: install
    grunt.registerTask('install', ['write-config']);

    // task: test
    grunt.registerTask('test', ['jshint', 'jasmine']);

    // task: set-sprint
    // Update sprint number in package.json and rewrite src/config.json
    grunt.registerTask('set-sprint', ['update-sprint-number', 'write-config']);

    // Default task.
    grunt.registerTask('default', ['test']);
};
<commit_msg>ignore node_modules everywhere for jshint<commit_after>/*
 * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */
/*global module, require*/
module.exports = function (grunt) {
    'use strict';

    // Project configuration.
    grunt.initConfig({
        meta : {
            src   : [
                'src/**/*.js',
                '!src/thirdparty/**',
                '!src/widgets/bootstrap-*.js',
                '!src/extensions/**/unittest-files/**/*.js',
                '!src/extensions/**/thirdparty/**/*.js',
                '!src/extensions/dev/**',
                '!src/extensions/disabled/**',
                '!**/node_modules/**/*.js',
                '!src/**/*-min.js',
                '!src/**/*.min.js'
            ],
            test : [
                'test/**/*.js',
                '!test/perf/*-files/**/*.js',
                '!test/spec/*-files/**/*.js',
                '!test/smokes/**',
                '!test/temp/**',
                '!test/thirdparty/**'
            ],
            /* specs that can run in phantom.js */
            specs : [
                'test/spec/CommandManager-test.js',
                'test/spec/LanguageManager-test.js',
                'test/spec/PreferencesManager-test.js',
                'test/spec/ViewUtils-test.js'
            ]
        },
        watch: {
            test : {
                files: ['Gruntfile.js', '<%= meta.src %>', '<%= meta.test %>'],
                tasks: 'test'
            }
        },
        /* FIXME (jasonsanjose): how to handle extension tests */
        jasmine : {
            src : 'undefined.js', /* trick the default runner to run without importing src files */
            options : {
                junit : {
                    path: 'test/results',
                    consolidate: true
                },
                specs : '<%= meta.specs %>',
                /* Keep in sync with test/SpecRunner.html dependencies */
                vendor : [
                    'src/thirdparty/jquery-1.7.js',
                    'src/thirdparty/CodeMirror2/lib/codemirror.js',
                    'src/thirdparty/CodeMirror2/lib/util/dialog.js',
                    'src/thirdparty/CodeMirror2/lib/util/searchcursor.js',
                    'src/thirdparty/mustache/mustache.js',
                    'src/thirdparty/path-utils/path-utils.min'
                ],
                helpers : [
                    'test/spec/PhantomHelper.js'
                ],
                template : require('grunt-template-jasmine-requirejs'),
                templateOptions: {
                    requireConfig : {
                        baseUrl: 'src',
                        paths: {
                            'test' : '../test',
                            'perf' : '../test/perf',
                            'spec' : '../test/spec',
                            'text' : 'thirdparty/text',
                            'i18n' : 'thirdparty/i18n'
                        }
                    }
                }
            }
        },
        jshint: {
            all: [
                'Gruntfile.js',
                '<%= meta.src %>',
                '<%= meta.test %>'
            ],
            /* use strict options to mimic JSLINT until we migrate to JSHINT in Brackets */
            options: {
                jshintrc: '.jshintrc'
            }
        }
    });

    // load dependencies
    grunt.loadTasks('tasks');
    grunt.loadNpmTasks('grunt-contrib-jasmine');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');

    // task: install
    grunt.registerTask('install', ['write-config']);

    // task: test
    grunt.registerTask('test', ['jshint', 'jasmine']);

    // task: set-sprint
    // Update sprint number in package.json and rewrite src/config.json
    grunt.registerTask('set-sprint', ['update-sprint-number', 'write-config']);

    // Default task.
    grunt.registerTask('default', ['test']);
};
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var mergeStream = require('merge-stream');

var rimraf = require('rimraf');
var stylish = require('jshint-stylish');
var toCamelCase = require('to-camel-case');

var pkg = require('./package.json');
var bower = require('./bower.json');

var funName = toCamelCase(pkg.name);

var mochaReporter = 'spec';

var banner = [
  '/*!',
  ' * <%= pkg.name %>.js | MIT (c) Shinnosuke Watanabe',
  ' * <%= pkg.homepage %>',
  '*/\n'
].join('\n');

gulp.task('lint', function() {
  gulp.src(['{,src/}*.js'])
    .pipe($.jshint())
    .pipe($.jshint.reporter(stylish))
    .pipe($.jscs('.jscs.json'));
  gulp.src('*.json')
    .pipe($.jsonlint())
    .pipe($.jsonlint.reporter());
});

gulp.task('clean', rimraf.bind(null, 'dist'));

gulp.task('build', ['lint', 'clean'], function() {
  return mergeStream(
    gulp.src(['src/*.js'])
      .pipe($.header(banner + '!function(global) {\n', {pkg: pkg}))
      .pipe($.footer('\nglobal.<%= funName %> = <%= funName %>;\n}(this);\n', {
        funName: funName
      }))
      .pipe($.rename(bower.main))
      .pipe(gulp.dest('')),
    gulp.src(['src/*.js'])
      .pipe($.header(banner, {pkg: pkg}))
      .pipe($.footer('\nmodule.exports = <%= funName %>;\n', {funName: funName}))
      .pipe($.rename(pkg.main))
      .pipe(gulp.dest('')),
    gulp.src(['src/*.js'])
      .pipe($.wrapAmd({exports: funName}))
      .pipe($.header(banner, {pkg: pkg}))
      .pipe($.rename(bower.main))
      .pipe($.rename({suffix: '-amd'}))
      .pipe(gulp.dest(''))
  );
});

gulp.task('test', ['build'], function() {
  gulp.src(['test.js'], {read: false})
    .pipe($.mocha({reporter: 'spec'}));
});

gulp.task('watch', function() {
  mochaReporter = 'dot';
  gulp.watch(['src/*.js'], ['test']);
  gulp.watch(['{,src/}*.js', '*.json', '.jshintrc'], ['lint']);
});

gulp.task('default', ['build', 'watch']);
<commit_msg>improve watch task<commit_after>'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var mergeStream = require('merge-stream');

var rimraf = require('rimraf');
var stylish = require('jshint-stylish');
var toCamelCase = require('to-camel-case');

var pkg = require('./package.json');
var bower = require('./bower.json');

var funName = toCamelCase(pkg.name);

var mochaReporter = 'spec';

var banner = [
  '/*!',
  ' * <%= pkg.name %>.js | MIT (c) Shinnosuke Watanabe',
  ' * <%= pkg.homepage %>',
  '*/\n'
].join('\n');

gulp.task('lint', function() {
  gulp.src(['{,src/}*.js'])
    .pipe($.jshint())
    .pipe($.jshint.reporter(stylish))
    .pipe($.jscs('.jscs.json'));
  gulp.src('*.json')
    .pipe($.jsonlint())
    .pipe($.jsonlint.reporter());
});

gulp.task('clean', rimraf.bind(null, 'dist'));

gulp.task('build', ['lint', 'clean'], function() {
  return mergeStream(
    gulp.src(['src/*.js'])
      .pipe($.header(banner + '!function(global) {\n', {pkg: pkg}))
      .pipe($.footer('\nglobal.<%= funName %> = <%= funName %>;\n}(this);\n', {
        funName: funName
      }))
      .pipe($.rename(bower.main))
      .pipe(gulp.dest('')),
    gulp.src(['src/*.js'])
      .pipe($.header(banner, {pkg: pkg}))
      .pipe($.footer('\nmodule.exports = <%= funName %>;\n', {funName: funName}))
      .pipe($.rename(pkg.main))
      .pipe(gulp.dest('')),
    gulp.src(['src/*.js'])
      .pipe($.wrapAmd({exports: funName}))
      .pipe($.header(banner, {pkg: pkg}))
      .pipe($.rename(bower.main))
      .pipe($.rename({suffix: '-amd'}))
      .pipe(gulp.dest(''))
  );
});

gulp.task('test', ['build'], function() {
  gulp.src(['test.js'], {read: false})
    .pipe($.mocha({reporter: mochaReporter}));
});

gulp.task('watch', function() {
  mochaReporter = 'dot';
  gulp.watch(['{,src/}*.js'], ['test']);
  gulp.watch(['*.json', '.jshintrc'], ['lint']);
});

gulp.task('default', ['test', 'watch']);
<|endoftext|>


<commit_before>/** EVENTS
 ****************************************************************************/

function deleteVideoButtonClicked(li) {
    var playlistElem = $('.playlistElem.selected'),
        playlist = playlistElem.data('model');

    playlist.deleteVideo(li.index());
    playlistManager.save();
    playlistElem.click(); // reload playlist
}

function playlistMouseDown(event) {
	$('#left-menu li').removeClass('selected');
	$(this).addClass('selected');
}

/**
 * Mark the playlistElem in the #left-menu as selected, then
 * fill #playlist with the contained videos.
 */
function playlistClicked(event) {
    $('#playlist').html('');

	$('#results-container ol').hide();
	$('#playlist').show();
	$('#playlist').data('owner', $(this));

    var playlist = $(this).data('model');

    $.each(playlist.videos, function(i, item) {
        var li = createResultsItem(item.title, item.videoId);
        li.data('additionalMenuButtons').push({
            title: 'Delete',
            li: li,
            callback: deleteVideoButtonClicked
        });
        li.addClass('droppable');
        li.addClass('draggable');
        li.addClass('reorderable');
        li.appendTo('#playlist');
    });
}

function shuffleButtonClicked(event) {
    if ($(this).hasClass('shuffle-on')) {
        setShuffle(false, $(this).parent());
        Player.addSiblingsToPlayorder($('#results-container li.playing, #results-container li.paused'), false);
    } else {
        setShuffle(true, $(this).parent());
        Player.addSiblingsToPlayorder($('#results-container li.playing, #results-container li.paused'), true);
    }
    event.stopPropagation();
}

/** MISC
 ****************************************************************************/

function setShuffle(enabled, playlistElem) {
	var playlist = playlistElem.data('model');
	playlist.shuffle = enabled;
	playlistManager.save();
	if (enabled) {
		$(playlistElem).find('.shuffle-off').addClass('shuffle-on');
		$(playlistElem).find('.shuffle-off').removeClass('shuffle-off');
	} else {
		$(playlistElem).find('.shuffle-on').addClass('shuffle-off');
		$(playlistElem).find('.shuffle-on').removeClass('shuffle-on');
	}
}

/** CLASS PLAYLIST
 ****************************************************************************/

function Playlist(title, videos, remoteId, isPrivate, shuffle) {
    this.title = title;
    this.videos = videos;
    this.remoteId = remoteId || null;
    this.isPrivate = isPrivate || false;
    this.shuffle = shuffle;

    this.rename = function(newTitle) {
        var title = $.trim(newTitle);
        if (title.length > 0 && title.length < 50) {
            this.title = newTitle;
        }
    };

    this.unsync = function(callback) {
        console.log("Unsyncing " + this.title);

        $.ajax({
            type: 'DELETE',
            url: '/playlists/' + this.remoteId,
            success: function() {
                if (callback) {
                    callback();
                }
            }
        });

        this.remoteId = null;
    };

    this.sync = function(callback) {
        var self = this,
            params = {
            'json': JSON.stringify(this.toJSON()),
        };

        if (this.remoteId) {
            $.post('/playlists/' + this.remoteId, params, function(data, textStatus) {
                if (textStatus === 'success') {
                    console.log(self.title + ' updated');
                } else {
                    alert('Failed to update playlist ' + self.title);
                }
                if (callback) {
                    callback();
                }
            });
        } else {
            $.post('/playlists', params, function(data, textStatus) {
                if (textStatus === 'success') {
                    console.log(self.title + ' = ' + data);
                    self.remoteId = data;
                } else {
                    alert('Failed to create new playlist ' + self.title);
                }
                if (callback) {
                    callback();
                }
            });
        }
    };

    this.addVideo = function(title, videoId) {
        if (typeof title !== 'string') {
            throw "title param must be string";
        }
        if (typeof videoId !== 'string') {
            throw "videoId param must be string";
        }

        this.videos.push({
            videoId: videoId,
            title: title,
        });
    };

    this.moveVideo = function(sourceIndex, destIndex) {
        var tmp;

        if (destIndex > sourceIndex) {
            destIndex -= 1;
        }

        tmp = this.videos.splice(sourceIndex, 1)[0];
        this.videos.splice(destIndex, 0, tmp);
    };

    this.deleteVideo = function(index) {
        this.videos.splice(index, 1);
    };

    this.toJSON = function() {
        return {
            title: this.title,
            videos: this.videos,
            remoteId: this.remoteId,
            isPrivate: this.isPrivate,
			shuffle: this.shuffle
        };
    };

    this.createListElem = function() {
        var li = $('<li/>')
            .addClass("playlistElem")
            .addClass('droppable')
            .addClass('draggable')
            .addClass('reorderable')
            .data('model', this)
            .text(this.title)
            .bind('contextmenu', showPlaylistContextMenu)
            .mousedown(playlistMouseDown)
            .click(playlistClicked);

        if (this.remoteId) {
            li.addClass('youtube');
        } else {
            li.addClass('local')
        }

        if (this.isPrivate) {
            li.addClass('private');
        }

        var shuffleButton = $('<button/>').click(shuffleButtonClicked);

        if (this.shuffle) {
            shuffleButton.addClass('shuffle-on');
        } else {
            shuffleButton.addClass('shuffle-off');
        }

        shuffleButton.appendTo(li);

        return li;
    };
};
<commit_msg>Lock playlists that are syncing<commit_after>/** EVENTS
 ****************************************************************************/

function deleteVideoButtonClicked(li) {
    var playlistElem = $('.playlistElem.selected'),
        playlist = playlistElem.data('model');

    playlist.deleteVideo(li.index());
    playlistManager.save();
    playlistElem.click(); // reload playlist
}

function playlistMouseDown(event) {
	$('#left-menu li').removeClass('selected');
	$(this).addClass('selected');
}

/**
 * Mark the playlistElem in the #left-menu as selected, then
 * fill #playlist with the contained videos.
 */
function playlistClicked(event) {
    $('#playlist').html('');

	$('#results-container ol').hide();
	$('#playlist').show();
	$('#playlist').data('owner', $(this));

    var playlist = $(this).data('model');

    $.each(playlist.videos, function(i, item) {
        var li = createResultsItem(item.title, item.videoId);
        li.data('additionalMenuButtons').push({
            title: 'Delete',
            li: li,
            callback: deleteVideoButtonClicked
        });
        li.addClass('droppable');
        li.addClass('draggable');
        li.addClass('reorderable');
        li.appendTo('#playlist');
    });
}

function shuffleButtonClicked(event) {
    if ($(this).hasClass('shuffle-on')) {
        setShuffle(false, $(this).parent());
        Player.addSiblingsToPlayorder($('#results-container li.playing, #results-container li.paused'), false);
    } else {
        setShuffle(true, $(this).parent());
        Player.addSiblingsToPlayorder($('#results-container li.playing, #results-container li.paused'), true);
    }
    event.stopPropagation();
}

/** MISC
 ****************************************************************************/

function setShuffle(enabled, playlistElem) {
	var playlist = playlistElem.data('model');
	playlist.shuffle = enabled;
	playlistManager.save();
	if (enabled) {
		$(playlistElem).find('.shuffle-off').addClass('shuffle-on');
		$(playlistElem).find('.shuffle-off').removeClass('shuffle-off');
	} else {
		$(playlistElem).find('.shuffle-on').addClass('shuffle-off');
		$(playlistElem).find('.shuffle-on').removeClass('shuffle-on');
	}
}

/** CLASS PLAYLIST
 ****************************************************************************/

function Playlist(title, videos, remoteId, isPrivate, shuffle) {
    this.title = title;
    this.videos = videos;
    this.remoteId = remoteId || null;
    this.isPrivate = isPrivate || false;
    this.shuffle = shuffle;
    this.synced = true;
    this.syncing = false;

    this.rename = function(newTitle) {
        var title = $.trim(newTitle);
        if (title.length > 0 && title.length < 50) {
            this.title = newTitle;
        }
        this.synced = false;
    };

    this.unsync = function(callback) {
        console.log("Unsyncing " + this.title);

        $.ajax({
            type: 'DELETE',
            url: '/playlists/' + this.remoteId,
            success: function() {
                if (callback) {
                    callback();
                }
            }
        });

        this.remoteId = null;
    };

    this.createNewPlaylistOnRemote = function(callback) {
        var self = this,
            params = {
                'json': JSON.stringify(this.toJSON())
            };

        this.syncing = true;

        $.post('/playlists', params, function(data, textStatus) {
            self.syncing = false;
            if (textStatus === 'success') {
                console.log(self.title + ' = ' + data);
                self.remoteId = data;
                self.synced = true;
            } else {
                alert('Failed to create new playlist ' + self.title);
            }
            if (callback) {
                callback();
            }
        });
    };

    this.updatePlaylistOnRemote = function(callback) {
        var self = this,
            params = {
                'json': JSON.stringify(this.toJSON())
            };

        this.syncing = true;

        $.post('/playlists/' + this.remoteId, params, function(data, textStatus) {
            self.syncing = false;
            if (textStatus === 'success') {
                console.log(self.title + ' updated');
                self.synced = true;
            } else {
                alert('Failed to update playlist ' + self.title);
            }
            if (callback) {
                callback();
            }
        });
    };

    this.sync = function(callback) {
        if (this.remoteId && this.synced) {
            console.log("Skippinig synced playlist " + this.title);
            callback();
            return;
        }

        if (this.remoteId) {
            this.updatePlaylistOnRemote(callback);
        } else {
            this.createNewPlaylistOnRemote(callback);
        }
    };

    this.addVideo = function(title, videoId) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        if (typeof title !== 'string') {
            throw "title param must be string";
        }
        if (typeof videoId !== 'string') {
            throw "videoId param must be string";
        }

        this.videos.push({
            videoId: videoId,
            title: title,
        });

        this.synced = false;
    };

    this.moveVideo = function(sourceIndex, destIndex) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        var tmp;

        if (destIndex > sourceIndex) {
            destIndex -= 1;
        }

        tmp = this.videos.splice(sourceIndex, 1)[0];
        this.videos.splice(destIndex, 0, tmp);

        this.synced = false;
    };

    this.deleteVideo = function(index) {
        if (this.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        this.videos.splice(index, 1);
        this.synced = false;
    };

    this.toJSON = function() {
        return {
            title: this.title,
            videos: this.videos,
            remoteId: this.remoteId,
            isPrivate: this.isPrivate,
			shuffle: this.shuffle
        };
    };

    this.createListElem = function() {
        var li = $('<li/>')
            .addClass("playlistElem")
            .addClass('droppable')
            .addClass('draggable')
            .addClass('reorderable')
            .data('model', this)
            .text(this.title)
            .bind('contextmenu', showPlaylistContextMenu)
            .mousedown(playlistMouseDown)
            .click(playlistClicked);

        if (this.remoteId) {
            li.addClass('youtube');
        } else {
            li.addClass('local')
        }

        if (this.isPrivate) {
            li.addClass('private');
        }

        var shuffleButton = $('<button/>').click(shuffleButtonClicked);

        if (this.shuffle) {
            shuffleButton.addClass('shuffle-on');
        } else {
            shuffleButton.addClass('shuffle-off');
        }

        shuffleButton.appendTo(li);

        return li;
    };
};
<|endoftext|>


<commit_before>//features to add:
//		search-bar
//		custom-Image Cases
//		Ignore row if ...

;(function($) {
	$.fn.gsImport = function( options ) {
		var settings = $.extend({
            cellClass: 'gsCell',
            rowClass: 'gsRow',
            headerClass: 'gsHeader',
            headerRowClass: 'gsHeaderRow',
            bodyClass: 'gsBody',
            tableClass: 'gsTable table table-responsive table-striped',
            image1: '',
            image2: '',
            customImages: '',
            ignore: '',

        }, options );

        return this.append(function gsImporter() {
		var $me = $(this),
			headers = $me.data("headers"),
			key = $me.data('key'),
			index = $me.data('index')

		if (typeof key === 'undefined') {
		    console.error('GSImport: No data-key provided for div: ' + $me.attr('id'))
		    return;
		}

		if (typeof headers === 'undefined') {
		    console.error('GSImport: No data-headers provided for div: ' + $me.attr('id'))
		    return;
		}

		if (typeof index === 'undefined') {
		    console.warn('GSImport: No data-index provided for div: ' + $me.attr('id') + '\nDefaulting to od6')
		    index = "od6"
		}

		var url = "https://spreadsheets.google.com/feeds/list/" + key + "/1/public/values?alt=json";
		var headerList = headers.split(', ');

		function picturize(nStr) {
				switch (nStr)
				{
					case "":
						return '-';
						break;
					case "!":
						return settings.image1;
						break;
					case "X":
						return settings.image2;
						break;
					default:
						return nStr;
						break;
				}
			}

		$.getJSON(url, function(data) {
			var entry = data.feed.entry;
			console.log($me)
			$($me).append('

')

			$(headerList).each(function(){ // Adds headers
				$($me).find(' table thead').append('' + this.toString()+"	")
			})
			$($me).find(' table thead th').wrapAll('

')

			$(entry).each(function(){
				var $curCell = this;
					$(headerList).each(function () {
							$($me).find(' table tbody').append('' + picturize(eval('$curCell.gsx$'+this.toString().toLowerCase()+'.$t')) + '	')
				})
			});

			var i = 0,
			    cells = $($me).find(' table tbody td'),
			    group;

			while ((group = cells.slice(i, i += headerList.length)).length) {
			    group.wrapAll('

');
			}

		});
	});
	}
}(jQuery))
<commit_msg>setup to validate options<commit_after>//features to add:
//		search-bar
//		custom-Image Cases
//		Ignore row if ...

;(function($) {
	$.fn.gsImport = function( options ) {

		var defaults = {
            cellClass: 'gsCell',
            rowClass: 'gsRow',
            headerClass: 'gsHeader',
            headerRowClass: 'gsHeaderRow',
            bodyClass: 'gsBody',
            tableClass: 'gsTable table table-responsive table-striped',
            image1: '',
            image2: '',
            customImages: '',
            ignore: '',
        }

		var settings = $.extend(defaults, options );

        return this.append(function gsImporter() {
		var $me = $(this),
			headers = $me.data("headers"),
			key = $me.data('key'),
			index = $me.data('index')

		if (typeof key === 'undefined') {
		    console.error('GSImport: No data-key provided for div: ' + $me.attr('id'))
		    return;
		}

		if (typeof headers === 'undefined') {
		    console.error('GSImport: No data-headers provided for div: ' + $me.attr('id'))
		    return;
		}

		if (typeof index === 'undefined') {
		    console.warn('GSImport: No data-index provided for div: ' + $me.attr('id') + '\nDefaulting to od6')
		    index = "od6"
		}

		var url = "https://spreadsheets.google.com/feeds/list/" + key + "/1/public/values?alt=json";
		var headerList = headers.split(', ');

		function picturize(nStr) {
				switch (nStr)
				{
					case "":
						return '-';
						break;
					case "!":
						return settings.image1;
						break;
					case "X":
						return settings.image2;
						break;
					default:
						return nStr;
						break;
				}
			}

		$.getJSON(url, function(data) {
			var entry = data.feed.entry;
			console.log($me)
			$($me).append('

')

			$.each(headerList, function(){ // Adds headers
				$($me).find(' table thead').append('' + this.toString()+"	")
			})
			$($me).find(' table thead th').wrapAll('

')

			$(entry).each(function(){
				var $curCell = this;
					$(headerList).each(function () {
							$($me).find(' table tbody').append('' + picturize(eval('$curCell.gsx$'+this.toString().toLowerCase()+'.$t')) + '	')
				})
			});

			var i = 0,
			    cells = $($me).find(' table tbody td'),
			    group;

			while ((group = cells.slice(i, i += headerList.length)).length) {
			    group.wrapAll('

');
			}

		});
	});
	}
}(jQuery))
<|endoftext|>


<commit_before>define('app/controllers/machine_shell', ['app/models/command', 'ember'],
    //
    //  Machine Shell Controller
    //
    //  @returns Class
    //
    function (Command) {

        'use strict';

        return Ember.Object.extend(Ember.Evented, {

            //
            //
            //  Properties
            //
            //

            view: null,
            machine: null,

            //
            //
            //  Methods
            //
            //

            open: function (machine) {
                this._clear();
                this.view.open();
                this.set('machine', machine);

                // Get the first ipv4 public ip to connect to
                var host = '';
                for (var i=0;i<machine.public_ips.length;i++){
                    if (machine.public_ips[i].search(':') == -1){
                        host = machine.public_ips[i];
                    }
                }
                if (host == '')
                    return false;

                // Open shell socket
                Mist.set('shell', Socket({
                    namespace: '/shell',
                    keepAlive: false,
                }));

                var term = new Terminal({
                  cols: 80,
                  rows: 24,
                  screenKeys: true
                });

                term.on('data', function(data) {
                    Mist.shell.emit('shell_data', data);
                });

                term.open(document.getElementById('shell-return'));

                var payload = {'backend_id': machine.backend.id,
                               'machine_id': machine.id,
                               'host': host
                               };
                Mist.shell.emit('shell_open', payload);
                Mist.shell.firstData = true;
                Mist.shell.on('shell_data', function(data){
                    term.write(data);
                    if (Mist.shell.firstData){
                        $('.terminal').focus();
                        Mist.shell.firstData = false;
                    }
                });
                term.write('Connecting to ' + host + '...\r\n');
                Mist.set('term', term);

                Ember.run.next(function(){
                    $(window).trigger('resize');
                });

                if(Terminal._textarea) {
                    // iOS virtual keyboard focus fix
                    $(document).off('focusin');

                    // Tap should trigger resize on Android for virtual keyboard to appear
                    if (Mist.term && Mist.term.isAndroid){
                        $('#shell-return').bind('tap',function(){
                            $(window).trigger('resize');
                        });
                    }
                    $(Terminal._textarea).show();
                }
            },

            close: function () {
                warn('closing shell');
                this.view.close();
                Mist.shell.emit('shell_close');
                Mist.term.destroy();
                Mist.shell.disconnect(); // TODO: Fix me
                $(window).off('resize');
                this._clear();
                if (Terminal._textarea)
                    $(Terminal._textarea).hide();

            },

            //
            //
            //  Pseudo-Private Methods
            //
            //

            _clear: function () {
                Ember.run(this, function () {
                    this.set('machine', null);
                });
            },

            _giveCallback: function (success, action) {
                if (this.callback) this.callback(success, action);
            }
        });
    }
);
<commit_msg>use a foreach for getting host and remove window.off(resize)<commit_after>define('app/controllers/machine_shell', ['app/models/command', 'ember'],
    //
    //  Machine Shell Controller
    //
    //  @returns Class
    //
    function (Command) {

        'use strict';

        return Ember.Object.extend(Ember.Evented, {

            //
            //
            //  Properties
            //
            //

            view: null,
            machine: null,

            //
            //
            //  Methods
            //
            //

            open: function (machine) {
                this._clear();
                this.view.open();
                this.set('machine', machine);

                // Get the first ipv4 public ip to connect to
                var host = '';
                machine.public_ips.forEach(function (ip) {
                    if (ip.search(':') == -1)
                        host = ip;
                });
                if (!host) {
                    this.close();
                    return;
                }

                // Open shell socket
                Mist.set('shell', Socket({
                    namespace: '/shell',
                    keepAlive: false,
                }));

                var term = new Terminal({
                  cols: 80,
                  rows: 24,
                  screenKeys: true
                });

                term.on('data', function(data) {
                    Mist.shell.emit('shell_data', data);
                });

                term.open(document.getElementById('shell-return'));

                var payload = {'backend_id': machine.backend.id,
                               'machine_id': machine.id,
                               'host': host
                               };
                Mist.shell.emit('shell_open', payload);
                Mist.shell.firstData = true;
                Mist.shell.on('shell_data', function(data){
                    term.write(data);
                    if (Mist.shell.firstData){
                        $('.terminal').focus();
                        Mist.shell.firstData = false;
                    }
                });
                term.write('Connecting to ' + host + '...\r\n');
                Mist.set('term', term);

                Ember.run.next(function(){
                    $(window).trigger('resize');
                });

                if(Terminal._textarea) {
                    // iOS virtual keyboard focus fix
                    $(document).off('focusin');

                    // Tap should trigger resize on Android for virtual keyboard to appear
                    if (Mist.term && Mist.term.isAndroid){
                        $('#shell-return').bind('tap',function(){
                            $(window).trigger('resize');
                        });
                    }
                    $(Terminal._textarea).show();
                }
            },

            close: function () {
                warn('closing shell');
                this.view.close();
                Mist.shell.emit('shell_close');
                Mist.term.destroy();
                Mist.shell.disconnect();
                this._clear();
                if (Terminal._textarea)
                    $(Terminal._textarea).hide();
            },

            //
            //
            //  Pseudo-Private Methods
            //
            //

            _clear: function () {
                Ember.run(this, function () {
                    this.set('machine', null);
                });
            },

            _giveCallback: function (success, action) {
                if (this.callback) this.callback(success, action);
            }
        });
    }
);
<|endoftext|>


<commit_before>// This is the example viewer server.
//
// It's purpose is to enable editing the examples
// inside the presentation environment.

var express = require("express");
var bodyParser = require("body-parser");
var fs = require("fs");
var mkdirp = require("mkdirp");
var path = require("path");
var async = require("async");
var updateIndexJSON = require("./updateIndexJSON");
var examplePath = require("../common/examplePath");

var app = express();

app.use(bodyParser.json());
app.use(express.static("."));

app.post("/save", function (req, res){
  const params = req.body.params,
        files = req.body.files,
        fileNames = Object.keys(files);

  async.each(fileNames, function (fileName, callback){
    const directory = examplePath(params),
          filePath = path.join(directory, fileName),
          content = files[fileName];

    mkdirp(directory, function (err) {
      if (err) return res.send(err);
      fs.writeFile(filePath, content, function(err) {
        if (err) return res.send(err);
        callback();
      });
    });
  }, function (){
    res.send("Saved!");
    updateIndexJSON();
  });
});

// Update the index when the server starts,
// in case files have changed outside the editor.
updateIndexJSON();

app.listen(3000, function () {
  console.log("Listening at http://localhost:3000");
});
<commit_msg>Allow dotfiles<commit_after>// This is the example viewer server.
//
// It's purpose is to enable editing the examples
// inside the presentation environment.

var express = require("express");
var bodyParser = require("body-parser");
var fs = require("fs");
var mkdirp = require("mkdirp");
var path = require("path");
var async = require("async");
var updateIndexJSON = require("./updateIndexJSON");
var examplePath = require("../common/examplePath");

var app = express();

app.use(bodyParser.json());
app.use(express.static(".", {
  dotfiles: "allow"
}));

app.post("/save", function (req, res){
  const params = req.body.params,
        files = req.body.files,
        fileNames = Object.keys(files);

  async.each(fileNames, function (fileName, callback){
    const directory = examplePath(params),
          filePath = path.join(directory, fileName),
          content = files[fileName];

    mkdirp(directory, function (err) {
      if (err) return res.send(err);
      fs.writeFile(filePath, content, function(err) {
        if (err) return res.send(err);
        callback();
      });
    });
  }, function (){
    res.send("Saved!");
    updateIndexJSON();
  });
});

// Update the index when the server starts,
// in case files have changed outside the editor.
updateIndexJSON();

app.listen(3000, function () {
  console.log("Listening at http://localhost:3000");
});
<|endoftext|>


<commit_before>/*
 *
 * Footer
 *
 */

import React from 'react'

import { makeDebugger } from '../../utils'
import {
  Container,
  BaseInfo,
  BeianInfo,
  Divider,
  About,
  Beian,
  Powerby,
  PowerbyLink,
  GitSource,
} from './styles'
/* eslint-disable no-unused-vars */
const debug = makeDebugger('c:Footer:index')
/* eslint-enable no-unused-vars */

const Footer = () => {
  return (
    <Container>
      <BaseInfo>
        {/* TODO: use next/link to link to post */}
        <About
          href="http://www.miitbeian.gov.cn"
          rel="noopener noreferrer"
          target="_blank"
        >
          关于 CPS
        </About>
        <Divider>|</Divider>
        <About
          href="http://www.miitbeian.gov.cn"
          rel="noopener noreferrer"
          target="_blank"
        >
          Developer API
        </About>
        <Divider>|</Divider>
        <About
          href="http://www.miitbeian.gov.cn"
          rel="noopener noreferrer"
          target="_blank"
        >
          联系我们
        </About>
        <Divider>|</Divider>
        <Powerby>
          Powered by{' '}
          <PowerbyLink
            href="https://github.com/mastani-stack"
            rel="noopener noreferrer"
            target="_blank"
          >
            Mastani-Stack
          </PowerbyLink>
        </Powerby>
        <Divider>|</Divider>
        <GitSource>
          <iframe
            title="souce_attr"
            src="https://ghbtns.com/github-btn.html?user=mydearxym&repo=mastani_web&type=star&count=true"
            frameBorder="0"
            scrolling="0"
            width="80px"
            height="20px"
          />
        </GitSource>
      </BaseInfo>
      <BeianInfo>
        <Beian
          href="http://www.miitbeian.gov.cn"
          rel="noopener noreferrer"
          target="_blank"
        >
          蜀ICP备17043722号-4
        </Beian>
      </BeianInfo>
    </Container>
  )
}

export default Footer
<commit_msg>add developer API link<commit_after>/*
 *
 * Footer
 *
 */

import React from 'react'

import { makeDebugger } from '../../utils'
import {
  Container,
  BaseInfo,
  BeianInfo,
  Divider,
  About,
  Beian,
  Powerby,
  PowerbyLink,
  GitSource,
} from './styles'
/* eslint-disable no-unused-vars */
const debug = makeDebugger('c:Footer:index')
/* eslint-enable no-unused-vars */

const Footer = () => {
  return (
    <Container>
      <BaseInfo>
        {/* TODO: use next/link to link to post */}
        <About
          href="http://www.miitbeian.gov.cn"
          rel="noopener noreferrer"
          target="_blank"
        >
          关于 CPS
        </About>
        <Divider>|</Divider>
        <About
          href="http://api.coderplanets.com/graphiql"
          rel="noopener noreferrer"
          target="_blank"
        >
          Developer API
        </About>
        <Divider>|</Divider>
        <About
          href="http://www.miitbeian.gov.cn"
          rel="noopener noreferrer"
          target="_blank"
        >
          联系我们
        </About>
        <Divider>|</Divider>
        <Powerby>
          Powered by{' '}
          <PowerbyLink
            href="https://github.com/mastani-stack"
            rel="noopener noreferrer"
            target="_blank"
          >
            Mastani-Stack
          </PowerbyLink>
        </Powerby>
        <Divider>|</Divider>
        <GitSource>
          <iframe
            title="souce_attr"
            src="https://ghbtns.com/github-btn.html?user=mydearxym&repo=mastani_web&type=star&count=true"
            frameBorder="0"
            scrolling="0"
            width="80px"
            height="20px"
          />
        </GitSource>
      </BaseInfo>
      <BeianInfo>
        <Beian
          href="http://www.miitbeian.gov.cn"
          rel="noopener noreferrer"
          target="_blank"
        >
          蜀ICP备17043722号-4
        </Beian>
      </BeianInfo>
    </Container>
  )
}

export default Footer
<|endoftext|>


<commit_before>define([
     "underscore"
    , "jquery"
    , "bacon"
    ]
    , function(_, $, Bacon) {
        //Initialize values and help functions
        var text = $("#title-message")
            , delay = 10000
            , sentenceList = ["Vi er tverrfaglige.","Vi drar på konferanser.","Vi skaper løsninger i team.","Vi har tre fagdager i året."]
            , switchSentence = function(value){
              text.fadeOut(500,function(){
                text.html(value).fadeIn(500);
            });
        }

        var sentence = Bacon.repeatedly(delay,sentenceList)
            .toProperty(sentenceList[sentenceList.length-1])
            .onValue(function(text){
                switchSentence(text);
            });
});<commit_msg>Adds some clean-up and functionalizing text animations<commit_after>define([
     "underscore"
    , "jquery"
    , "bacon"
    ]
    , function(_, $, Bacon) {
        //Initialize values and help functions
        var $text = $("#title-message")
          , delay = 10000
          , sentenceList = [
            "Vi er tverrfaglige.",
            "Vi drar på konferanser.",
            "Vi skaper løsninger i team.",
            "Vi har tre fagdager i året."
          ]
          , switchSentence = function($el){
            return function (value) {
              $el.fadeOut(500,function(){
                $el.html(value).fadeIn(500);
              });
            };
          };

        var sentence = Bacon.repeatedly(delay, sentenceList)
                            .toProperty(_.last(sentenceList))
                            .onValue(switchSentence($text));
});<|endoftext|>