<commit_before>/*global define:true, describe:true , it:true , expect:true,
beforeEach:true, sinon:true, spyOn:true , expect:true */
/* jshint strict: false */
define(['gsocket'], function(GSocket) {
    window.GSocket = GSocket;

    var noop = function() {};

    var MockWebSocket = function(url, protocols) {
        this.created = true;
        this.url = url;
        this.protocols = protocols;
        MockWebSocket.METHODS = ['send', 'close'];
        MockWebSocket.HANDLERS = ['onopen', 'onclose', 'onmessage', 'onerror'];

        var spies = [].concat(MockWebSocket.METHODS, MockWebSocket.HANDLERS);

        spies.forEach(function(method) {
            this[method] = sinon.spy();
        }.bind(this));
    };

    // MockWebSocket.prototype.send = function() {};
    // MockWebSocket.prototype.close = function() {};

    // MockWebSocket.prototype.onopen = function() {};
    // MockWebSocket.prototype.onclose = function() {};
    // MockWebSocket.prototype.onmessage = function() {};
    // MockWebSocket.prototype.onerror = function() {};

    describe('GSocket', function() {
        var gsocket;

        beforeEach(function() {
            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        return new MockWebSocket(url);
                    }
                },
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets'
            });
        });

        it('should be loaded', function() {
            expect(GSocket).toBeTruthy();
            expect(gsocket).toBeTruthy();
        });

        it('should have a DEFAULTS class property', function() {
            expect(GSocket.DEFAULTS).toBeTruthy();
        });

        it('should have a VERSION class property', function() {
            expect(GSocket.VERSION).toBeTruthy();
        });

        it('should initialize an instance with all DEFAULTS props', function() {
            var props = Object.keys(GSocket.DEFAULTS);
            expect(gsocket).toHaveProperties(props);
        });

        it('should have a name property on prototype and constructor', function() {
            expect(GSocket.name).toEqual('GSocket');
            expect(GSocket.prototype.name).toEqual('GSocket');
        });

        xit('once initialized it should not execute the init method more than once', function() {
            var spy = sinon.spy(GSocket, 'extend');
            gsocket = new GSocket({
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets'
            });
            gsocket.init();
            expect(gsocket.initialized).toBeTruthy();
            expect(spy).toHaveBeenCalledTwice();
            GSocket.extend.restore();
        });
    });

    describe('GSocket', function() {
        var gsocket;

        beforeEach(function() {
            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        return new MockWebSocket(url);
                    }
                },
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets'
            })
        });

        it('should connect to service', function() {
            gsocket.connect();
            expect(gsocket.service).toBeInstanceOf(MockWebSocket)
        });

        it('after connecting it should be on CONNECTING state', function() {
            gsocket.connect();
            expect(gsocket.state).toEqual(GSocket.CONNECTING);
        });

        it('connect generates a timeoutId', function() {
            gsocket.connect();
            expect(gsocket.timeoutId).toBeTruthy();
        });

        xit('connect should attach listeners for Service events', function() {

            var events = {
                    onerror: 'onError',
                    onopen: 'onConnected',
                    onclose: 'onClosed',
                    onmessage: 'onMessage'
                },
                spies = {};

            var method;

            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        throw new Error('FAKE ERROR');
                    }
                },
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets',
                autoconnect: false

            })
            Object.keys(events).forEach(function(type) {
                method = events[type];
                spies[method] = sinon.spy(gsocket, method);
            });

            gsocket.connect();
            console.warn('================')
            Object.keys(events).forEach(function(type) {
                method = events[type];
                gsocket.service[type].call(gsocket, {});
                console.log('method', method, 'type', type, 'spy', spies[method].getCall(0));
                expect(spies[method]).toHaveBeenCalled();
            });
            console.warn('================')
        });

        it('should try catch errors on connect from Service', function() {
            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        throw new Error('FAKE ERROR');
                    }
                },
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets'
            });
            // gsocket.connect();
            expect(gsocket.state).toEqual(GSocket.ERRORED);
            expect(gsocket.errors).toHaveLength(1);
        });

        it('clearIds should reset timeouts', function() {

            GSocket.timeoutIds.forEach(function(id) {
                gsocket[id] = setTimeout(function() {}, 100);
            });

            gsocket.clearIds();

            GSocket.timeoutIds.forEach(function(id) {
                expect(gsocket[id]).toBeFalsy();
            });
        });

        it('connect without an endpoint should throw error', function() {
            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        return new MockWebSocket(url);
                    }
                },
                emit: noop,
                autoconnect: false
            });

            gsocket.connect();

            expect(gsocket.state).toEqual(GSocket.ERRORED);
            expect(gsocket.errors).toHaveLength(1);
        });
    });
});<commit_msg>SPEC: WIP...<commit_after>/*global define:true, describe:true , it:true , expect:true,
beforeEach:true, sinon:true, spyOn:true , expect:true */
/* jshint strict: false */
define(['gsocket'], function(GSocket) {
    window.GSocket = GSocket;

    var noop = function() {};

    var MockWebSocket = function(url, protocols) {
        this.created = true;
        this.url = url;
        this.protocols = protocols;
        MockWebSocket.METHODS = ['send', 'close'];
        MockWebSocket.HANDLERS = ['onopen', 'onclose', 'onmessage', 'onerror'];

        var spies = [].concat(MockWebSocket.METHODS, MockWebSocket.HANDLERS);

        spies.forEach(function(method) {
            this[method] = sinon.spy();
        }.bind(this));
    };

    // MockWebSocket.prototype.send = function() {};
    // MockWebSocket.prototype.close = function() {};

    // MockWebSocket.prototype.onopen = function() {};
    // MockWebSocket.prototype.onclose = function() {};
    // MockWebSocket.prototype.onmessage = function() {};
    // MockWebSocket.prototype.onerror = function() {};

    describe('GSocket', function() {
        var gsocket;

        beforeEach(function() {
            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        return new MockWebSocket(url);
                    }
                },
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets'
            });
        });

        it('should be loaded', function() {
            expect(GSocket).toBeTruthy();
            expect(gsocket).toBeTruthy();
        });

        it('should have a DEFAULTS class property', function() {
            expect(GSocket.DEFAULTS).toBeTruthy();
        });

        it('should have a VERSION class property', function() {
            expect(GSocket.VERSION).toBeTruthy();
        });

        it('should initialize an instance with all DEFAULTS props', function() {
            var props = Object.keys(GSocket.DEFAULTS);
            expect(gsocket).toHaveProperties(props);
        });

        it('should have a name property on prototype and constructor', function() {
            expect(GSocket.name).toEqual('GSocket');
            expect(GSocket.prototype.name).toEqual('GSocket');
        });

        xit('once initialized it should not execute the init method more than once', function() {
            var spy = sinon.spy(GSocket, 'extend');
            gsocket = new GSocket({
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets'
            });
            gsocket.init();
            expect(gsocket.initialized).toBeTruthy();
            expect(spy).toHaveBeenCalledTwice();
            GSocket.extend.restore();
        });
    });

    describe('GSocket', function() {
        var gsocket;

        beforeEach(function() {
            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        return new MockWebSocket(url);
                    }
                },
                emit: noop,
                reconnectAfterTimeout: false,
                endpoint: 'ws://localhost:9000/API/websockets'
            })
        });

        it('isValidEndpoint should validate endpoint URL', function() {
            gsocket.endpoint = 'http://localhost:9000/API/websockets';
            expect(gsocket.isValidEndpoint()).toBeFalsy();

            gsocket.endpoint = 'ws://localhost:9000/API/websockets';
            expect(gsocket.isValidEndpoint()).toBeTruthy();

            gsocket.endpoint = 'wss://localhost:9000/API/websockets';
            expect(gsocket.isValidEndpoint()).toBeTruthy();
        });

        it('should have a default platform event processor', function() {
            expect(gsocket).toHaveMethods(['processPlatformEvent']);
        });

        it('processPlatformEvent should parse event string data into object', function() {
            var data = {
                name: 'Peperone',
                age: 23,
                email: 'peperone@gmail.com'
            };
            var event = {
                event: 'scene_change',
                type: 'command'
            };
            event.data = JSON.stringify(data);

            var out = gsocket.processPlatformEvent(event);

            expect(out).toMatchObject(data);

        });

        it('should connect to service', function() {
            gsocket.connect();
            expect(gsocket.service).toBeInstanceOf(MockWebSocket)
        });

        it('after connecting it should be on CONNECTING state', function() {
            gsocket.connect();
            expect(gsocket.state).toEqual(GSocket.CONNECTING);
        });

        it('connect generates a timeoutId', function() {
            gsocket.connect();
            expect(gsocket.timeoutId).toBeTruthy();
        });

        xit('connect should attach listeners for Service events', function() {

            var events = {
                    onerror: 'onError',
                    onopen: 'onConnected',
                    onclose: 'onClosed',
                    onmessage: 'onMessage'
                },
                spies = {};

            var method;

            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        throw new Error('FAKE ERROR');
                    }
                },
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets',
                autoconnect: false

            })
            Object.keys(events).forEach(function(type) {
                method = events[type];
                spies[method] = sinon.spy(gsocket, method);
            });

            gsocket.connect();
            console.warn('================')
            Object.keys(events).forEach(function(type) {
                method = events[type];
                gsocket.service[type].call(gsocket, {});
                console.log('method', method, 'type', type, 'spy', spies[method].getCall(0));
                expect(spies[method]).toHaveBeenCalled();
            });
            console.warn('================')
        });

        it('should try catch errors on connect from Service', function() {
            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        throw new Error('FAKE ERROR');
                    }
                },
                emit: noop,
                endpoint: 'ws://localhost:9000/API/websockets'
            });
            // gsocket.connect();
            expect(gsocket.state).toEqual(GSocket.ERRORED);
            expect(gsocket.errors).toHaveLength(1);
        });

        it('clearIds should reset timeouts', function() {

            GSocket.timeoutIds.forEach(function(id) {
                gsocket[id] = setTimeout(function() {}, 100);
            });

            gsocket.clearIds();

            GSocket.timeoutIds.forEach(function(id) {
                expect(gsocket[id]).toBeFalsy();
            });
        });

        it('connect without an endpoint should throw error', function() {
            gsocket = new GSocket({
                config: {
                    provider: function(url) {
                        return new MockWebSocket(url);
                    }
                },
                emit: noop,
                autoconnect: false
            });

            gsocket.connect();

            expect(gsocket.state).toEqual(GSocket.ERRORED);
            expect(gsocket.errors).toHaveLength(1);
        });
    });
});<|endoftext|>


<commit_before>Ext.namespace('ui','ui.cmp');

ui.cmp.Chat = Ext.extend(Ext.Window,
{
    id        : 'win-chat',
    iconCls   : 'iconChat',
    layout    : 'fit',
    width     : 800,
    height    : 600,
    modal     : true,
    plain     : true,
    bodyStyle : 'color:#000',
    closeAction:'hide',

    initComponent : function()
    {
        var chatLogin = PhDOE.user.login;

        if( PhDOE.user.isAnonymous ) {
            chatLogin = 'anonymous_%3F%3F%3F';
        }

        Ext.apply(this,
        {
            title : _('Chat with us on IRC !'),
            items : [new Ext.ux.IFrameComponent({
                id: 'frame-win-chat',
                url: 'http://widget.mibbit.com/?settings=8eec4034df2eb666b0600bdfe151529a&server=irc.umich.edu&channel=%23php.doc&nick=phdoe_'+ chatLogin
            })]
        });
        ui.cmp.Chat.superclass.initComponent.call(this);
    }
});<commit_msg>Shorten default handle length, the limit appears to be 9. Example: poe_an424<commit_after>Ext.namespace('ui','ui.cmp');

ui.cmp.Chat = Ext.extend(Ext.Window,
{
    id        : 'win-chat',
    iconCls   : 'iconChat',
    layout    : 'fit',
    width     : 800,
    height    : 600,
    modal     : true,
    plain     : true,
    bodyStyle : 'color:#000',
    closeAction:'hide',

    initComponent : function()
    {
        var chatLogin = PhDOE.user.login;

        if( PhDOE.user.isAnonymous ) {
            chatLogin = 'an%3F%3F%3F';
        }

        Ext.apply(this,
        {
            title : _('Chat with us on IRC !'),
            items : [new Ext.ux.IFrameComponent({
                id: 'frame-win-chat',
                url: 'http://widget.mibbit.com/?settings=8eec4034df2eb666b0600bdfe151529a&server=irc.umich.edu&channel=%23php.doc&nick=poe_'+ chatLogin
            })]
        });
        ui.cmp.Chat.superclass.initComponent.call(this);
    }
});<|endoftext|>


<commit_before>$(function (){

  $('.add_to_collection').on('click', function(event){
    event.preventDefault();
    event.stopPropagation();
    var route = $('input.add_to_collection').parent().attr("action");
    var serial = $('input.add_to_collection').parent().serialize();
    var user = serial.user_id
    console.log(user)

    // $.ajax({
    //   method: 'POST',
    //   url: route,
    //   data:
    // })
  });

  $('.remove_from_collection').on('click', function(event){
    event.preventDefault();
    event.stopPropagation();
    var route = $('input.remove_from_collection').parent().attr("action");

    console.log(this)

  });

});
<commit_msg>clean up ajax branch misplacement<commit_after><|endoftext|>


<commit_before>import test from 'ava' ;
import { decrement } from '../../../src' ;

function macro ( t , r , x , e ) {

	const _x = [ 'x' , ...x.slice() , 'x' ] ;

	decrement(r, _x, 1, _x.length - 1) ;

	t.deepEqual( e , _x.slice(1, _x.length - 1) ) ;

}

macro.title = ( title , r , x , e ) => `${title} ${JSON.stringify(x)}_${r} - 1 = ${JSON.stringify(e)}`.trim() ;

test( macro , 10 , [ ] , [ ] ) ;
test( macro , 10 , [ 0 ] , [ 9 ]) ;
test( macro , 10 , [ 0 , 0 , 0 ] , [ 9 , 9 , 9 ] ) ;
test( macro , 10 , [ 7 , 0 , 0 ] , [ 6 , 9 , 9 ] ) ;
test( macro , 11 , [ 7 , 0 , 0 ] , [ 6 , 10 , 10 ] ) ;
test( macro , 11 , [ 1 , 2 , 3 ] , [ 1 , 2 , 2 ] ) ;
test( macro , 2 , [ 0 , 0 , 0 ] , [ 1 , 1 , 1 ] ) ;
<commit_msg>:mag: test: Check bounds in decrement.<commit_after>import test from 'ava' ;
import { decrement } from '../../../src' ;

function macro ( t , r , x , e ) {

	const _x = [ 'x' , ...x.slice() , 'x' ] ;
	const _e = [ 'x' , ...e.slice() , 'x' ] ;

	decrement(r, _x, 1, _x.length - 1) ;

	t.deepEqual( _e , _x ) ;

}

macro.title = ( title , r , x , e ) => `${title} ${JSON.stringify(x)}_${r} - 1 = ${JSON.stringify(e)}`.trim() ;

test( macro , 10 , [ ] , [ ] ) ;
test( macro , 10 , [ 0 ] , [ 9 ]) ;
test( macro , 10 , [ 0 , 0 , 0 ] , [ 9 , 9 , 9 ] ) ;
test( macro , 10 , [ 7 , 0 , 0 ] , [ 6 , 9 , 9 ] ) ;
test( macro , 11 , [ 7 , 0 , 0 ] , [ 6 , 10 , 10 ] ) ;
test( macro , 11 , [ 1 , 2 , 3 ] , [ 1 , 2 , 2 ] ) ;
test( macro , 2 , [ 0 , 0 , 0 ] , [ 1 , 1 , 1 ] ) ;
<|endoftext|>


<commit_before>var gc2i18n;
gc2i18n = {
    dict: {
        /* Start of viewer and widget */
        "Legend": "Leyenda",
        "Property": "Propiedad",
        "Value": "Valor",
        "Pop up": "Ventana emergente",
        "Layers": "Capas",
        "Baselayers": "Capa base",
        "Share": "Compartir",
        "Info": "Info",
        "Close": "Cerrar",
        "Back": "Atrás",
        "Share the map": "Compartir el mapa",
        "URL to this map": "URL para este mapa",
        "Search": "Buscar",
        "Iframe with this map to embed on web page": "Iframe con este mapa para incrustarlo en una página web",
        "URL to a static PNG image of this map": "URL a una imagen PNG estática de este mapa",
        "JavaScript for an application": "Incrustar este mapa como JavaScript",
        /* Start of Admin */
        "Map": "Mapa",
        "Advanced": "Avanzado",
        "Services": "Servicios",
        "Clear tile cache": "Limpiar el cache",
        "New layer": "Nueva capa",
        "Move layers": "Mover capas",
        "Delete layers": "Borrar capas",
        "Draw": "Dibujar",

        "Save": "Guardar",
        "Reset": "Reiniciar",
        "Delete": "Borrar",
        "Stop editing": "Detener la edición",
        "Quick draw": "Dibujo rápido",
        "Reload tree": "Recargar el árbol",
        "Save extent": "Guardar la extensión",
        "Attributes": "Atributos",
        "You don't have privileges to do this. Please contact the database owner, who can grant you privileges.": "No tiene privilegios para hacer esto. Por favor, contacte al propietario de la base de datos, quien puede darle los privilegios necesarios.",
        "Privileges": "Privileges",
        "Confirm": "Confirmar",
        "You are about to delete the tile cache for the whole schema. Are you sure?": "Está a punto de borar el tile caché para el esquema entero. ¿Quiere continuar?",
        "Schema": "Esquema",
        "Rename schema": "Renombrar esquema",
        "Delete schema": "Borrar esquema",
        "Add new schema": "Agregar nuevo esquema",
        "New schema created": "Nuevo esquema creado",
        "You've to select a layer": "Debe seleccionar una caoa",
        "Are you sure you want to delete": "Está seguro que quiere borrar",
        "table(s)": "tabla(s)",
        "layers deleted": "capas borradas",
        "Add vector": "Agregar vector",
        "Add raster": "Agregar raster",
        "Add imagery": "Agregar imágenes",
        "Blank layer": "Capa en blanco",
        "Move": "Mover",
        "selected to another schema": "seleccionar otro esquema",
        "New name": "Nuevo nombre",
        "Rename": "Renombrar",
        "Failure": "Error",
        "Are you sure you want to do that? All layers in the schema will be deleted!": "¿En verdad desea hacer esto? ¡Todas las capas en el esquema se borrarán!",
        "CartoMobile settings for the layer": "Configuración de CartoMobile para las capas",
        "A SQL must return a primary key and a geometry. Naming and srid must match this": "Un SQL debe devolver una clave primaria y una geometría. La denominación y el SRID deben corresponder",
        "Advanced settings on": "Configuración avanzada encencida",
        "Meta data URL": "URL de los metadatos",
        "WMS source": "Fuente WMS",
        "SQL where clause": "cláusula SQL where",
        "Update": "Actualizar",
        "Settings updated": "Configuración actualizada",
        "HTTP Basic auth password and API key are set for the specific (sub) user.": "La contraseña de autor HTTP básica y la clave API se han configurado para al (sub) usuario específico.",
        "Sorry, but something went wrong. The whole transaction is rolled back. Try to correct the problem and hit save again. You can look at the error below, maybe it will give you a hint about what's wrong": "Lo sentimos, pero algo falló. La transacción total fue deshecha. Intente corregir el problema y oprima guardar de nuevo. Usted puede observar el error más abajo, tal vez esto le dará una pista sobre lo que salió mal",
        "Grant privileges to sub-users on": "Garantizar privilegios a los sub-usuarios encendido",
        "Sub-user": "Sub-usuario",
        "None": "Ninguno",
        "Only read": "Solo lectura",
        "Read and write": "Lectura y escritura",
        "All": "Todo",
        "The layer doesn't exist for the sub-user.": "La capa no existe para el subusuario.",
        "The sub-user can see and query the layer.": "El sub-usuario puede ver y consultar la capa.",
        "The sub-user can edit the layer.": "El sub-usuario puede editar la capa.",
        "The sub-user change properties like style and alter table structure.": "El sub-usuario cambia propiedades como estilo y alterar la estructura de la tabla.",
        "The privileges are granted for both Admin and external services like WMS and WFS.": "Los privilegios se han garantizado tanto para Admin como para servicios externos como WMS y WFS.",
        "Database": "Base de datos",
        "Created": "Creada",
        "Geom field": "Campo Geom",
        "Last modified": "Último modificado",
        "Classes": "Clases",
        "Style is updated": "El estilo se ha actualizado",
        "Settings": "Configuracióni",
        "Log": "Log",
        "Name": "Nombre",
        "Type": "Tipo",
        "Title": "Título",
        "Description": "Descripción",
        "Group": "Crupo",
        "Sort id": "Ordenar id",
        "Authentication": "Autenticación",
        "Tile cache": "Tile cache",
        "You are about to delete the tile cache for layer": "Está a punto de borrar el caché de tiles para la capa",
        "Are you sure?": "¿Seguro?",
        "Editable": "Editable",
        "Clear": "Limpio",
        "No files you uploaded seems to be recognized as a valid image format.": "Ningún archivo cargado parece reconocerse como un formato válido de imagen.",
        "Raster formats": "Formatos ráster",
        "Image formats": "Formátos de imagen",
        "Vector formats": "Formatos vector",
        "At the moment you can upload": "Al momento usted puede cargar",
        "You need Flash or a modern browser, which supports HTML5": "Necesita Flash o un navegador moderno que soporte HTML5",
        "Create layer from scratch": "Generar una capa desde cero",
        "EPSG number": "cópdigo EPSG",
        "Auto": "Auto",
        "Point": "Punto",
        "Line": "Línea",
        "Polygon": "Polígono",
        "Encoding": "Codificación",
        "Are you sure you want to do that?": "¿En verdad quiere hacer esto?",
        "Sorry! Some thing failed.": "¡Lo sentimos! Algo ha fallado.",
        "Sorry! Connection problems": "¡Lo sentimos! hay problemas de conexión",
        "New API key": "Nuava clave API",
        "Load": "Cargar",
        "Load features": "Cargar rasgos",
        "Update table": "Actualizar tabla",
        "Column": "Columna",
        "Native field type": "Tipo de campo nativo",
        "Available": "Disponible",
        "Cartomobile field type": "Tipo de campo Cartomobile",
        "Properties": "Propiedades",
        "Single": "Único",
        "Unique values": "Valores únicos",
        "Field": "Campo",
        "Intervals": "Intervalos",
        "Numeric field": "Campo numérico",
        "# of colors": "# de colores",
        "Start color": "Color de inicio",
        "End color": "Color final",
        "Create": "Crear",
        "Additional settings": "Configuraciones adicionales",
        "These setting are applied to all created classes. Set them before hitting a create button above.": "Estas configuraciones se aplican a todas las clases creadas. Por favor, configúrelas antes de oprimir el botón Crear.",
        "Label text": "Texto de etiquetado",
        "Label color": "Color de etiquetado",
        "Label size": "Tamaño de etiquetado",
        "Symbol": "Símbolo",
        "Symbol angle": "Ángulo del símbolo",
        "Symbol size": "Tamaño del símbolo",
        "Outline color": "Solor del subrayado",
        "Outline width": "Ancho del subrayado",
        "Opacity": "Opacidad",
        "Alias": "Alias",
        "Queryable": "Consultable",
        "Link": "Enlace",
        "Link prefix": "Prefijo del enlace",
        "New column name": "Nuevo nombre de columna",
        "New column type": "Nuevo tipo de columna",
        "Add new column": "Agregar nueva columna",
        "Delete column": "Borrar columna",
        "Start track changes": "Comenzar a rastrear cambios",
        "Stop track changes": "Parar de rastrear cambios",
        "This will track changes on the table. For each edit a new version of the feature is made. Four new system columns will be added to the table. Do you want to proceed?": "Esto rastreará los cambios en la tabla. Por cada edición se genera una nueva versión del rasgo. Se agregarán a la tabla cuatro nuevas columnas de sistema. ¿Desea continuar?",
        "This will remove 'track changes' from the table. The versions will not be deleted, but all tracking information will be deleted. Do you want to proceed?": "Esto removerá el 'rastreo de cambios' de la tabla. Las versiones no se borrarán, pero toda la información de rastreamiento se borrará. ¿Desea continuar?",
        "Show legend": "Mostrar leyenda",
        "Open map in pop up window": "Abrir mapa en una ventana emergente",
        "Change the baselayer": "Cambiar la capa base",
        "Locate me on the map": "Localizarme en el mapa",
        "Close this window to disable measure tool": "Cerrar esta ventana para deshabilitar las herramientas de medición",
        "Measure": "Medición",
        "Distance": "Distancia",
        "Area": "Área",
        "Class wizards": "Class wizards",
        "Rename layer": "Rename layer",
        "Either select 'latest, 'all' or write a date/time in the form yyyy-mm-dd hh:mm:ss

If you are tracking changes on your table, you can either load the latest (current) versions or you can 'slice' at a given point in time. You can also load all versions.

Earlier features will be shown with a red dashed line.": "Seleccione 'el más reciente, 'todo' o escribir una fecha/hora en el formato yyyy-mm-dd hh:mm:ss

Si está rastreando cambios en su tabla, puede cargar la(s) versión(es) más reciente(s) (actual) o puede 'desplazarse' a un punto dato en el tiempo. También puede cargar todas las versiones.

Los rasgos más antiguos se mostrarán con una línea roja discontínua.",
        "The width or height of map extent exceed the limit. Create a table instead for better performance.": "El ancho o la altura de la extensión del mapa excede el límite. En vez de ello cree una tabla para un mejor desempeño.",
        "The width or height of map extent exceed 200km, which are the limit for the map extent.": "El ancho o la altura de la extensión del mapa excede 200 Km, que es el límite para la extensión del mapa."
    }
};
<commit_msg>Update es_ES.js<commit_after>var gc2i18n;
gc2i18n = {
    dict: {
        /* Start of viewer and widget */
        "Legend": "Leyenda",
        "Property": "Propiedad",
        "Value": "Valor",
        "Pop up": "Ventana emergente",
        "Layers": "Capas",
        "Baselayers": "Capa base",
        "Share": "Compartir",
        "Info": "Info",
        "Close": "Cerrar",
        "Back": "Atrás",
        "Share the map": "Compartir el mapa",
        "URL to this map": "URL para este mapa",
        "Search": "Buscar",
        "Iframe with this map to embed on web page": "Iframe con este mapa para incrustarlo en una página web",
        "URL to a static PNG image of this map": "URL a una imagen PNG estática de este mapa",
        "JavaScript for an application": "Incrustar este mapa como JavaScript",
        /* Start of Admin */
        "Map": "Mapa",
        "Advanced": "Avanzado",
        "Services": "Servicios",
        "Clear tile cache": "Limpiar el cache",
        "New layer": "Nueva capa",
        "Move layers": "Mover capas",
        "Delete layers": "Borrar capas",
        "Draw": "Dibujar",

        "Save": "Guardar",
        "Reset": "Reiniciar",
        "Delete": "Borrar",
        "Stop editing": "Detener la edición",
        "Quick draw": "Dibujo rápido",
        "Reload tree": "Recargar el árbol",
        "Save extent": "Guardar la extensión",
        "Attributes": "Atributos",
        "You don't have privileges to do this. Please contact the database owner, who can grant you privileges.": "No tiene privilegios para hacer esto. Por favor, contacte al propietario de la base de datos, quien puede darle los privilegios necesarios.",
        "Privileges": "Privilegios",
        "Confirm": "Confirmar",
        "You are about to delete the tile cache for the whole schema. Are you sure?": "Está a punto de borrar el tile caché para el esquema entero. ¿Quiere continuar?",
        "Schema": "Esquema",
        "Rename schema": "Renombrar esquema",
        "Delete schema": "Borrar esquema",
        "Add new schema": "Agregar nuevo esquema",
        "New schema created": "Nuevo esquema creado",
        "You've to select a layer": "Debe seleccionar una capa",
        "Are you sure you want to delete": "Está seguro que quiere borrar",
        "table(s)": "tabla(s)",
        "layers deleted": "capas borradas",
        "Add vector": "Agregar vector",
        "Add raster": "Agregar ráster",
        "Add imagery": "Agregar imágenes",
        "Blank layer": "Capa en blanco",
        "Move": "Mover",
        "selected to another schema": "seleccionar otro esquema",
        "New name": "Nuevo nombre",
        "Rename": "Renombrar",
        "Failure": "Error",
        "Are you sure you want to do that? All layers in the schema will be deleted!": "¿En verdad desea hacer esto? ¡Todas las capas en el esquema se borrarán!",
        "CartoMobile settings for the layer": "Configuración de CartoMobile para las capas",
        "A SQL must return a primary key and a geometry. Naming and srid must match this": "Un SQL debe devolver una clave primaria y una geometría. La denominación y el SRID deben corresponder",
        "Advanced settings on": "Configuración avanzada encendida",
        "Meta data URL": "URL de los metadatos",
        "WMS source": "Fuente WMS",
        "SQL where clause": "cláusula where de SQL ",
        "Update": "Actualizar",
        "Settings updated": "Configuración actualizada",
        "HTTP Basic auth password and API key are set for the specific (sub) user.": "La contraseña de autor HTTP básica y la clave API se han configurado para al (sub)usuario específico.",
        "Sorry, but something went wrong. The whole transaction is rolled back. Try to correct the problem and hit save again. You can look at the error below, maybe it will give you a hint about what's wrong": "Lo sentimos, pero algo falló. La transacción total fue deshecha. Intente corregir el problema y oprima guardar de nuevo. Usted puede observar el error más abajo; tal vez esto le dará una pista sobre lo que salió mal",
        "Grant privileges to sub-users on": "Otorgar privilegios a los sub-usuarios encendido",
        "Sub-user": "Sub-usuario",
        "None": "Ninguno",
        "Only read": "Solo lectura",
        "Read and write": "Lectura y escritura",
        "All": "Todo",
        "The layer doesn't exist for the sub-user.": "La capa no existe para el sub-usuario.",
        "The sub-user can see and query the layer.": "El sub-usuario puede ver y consultar la capa.",
        "The sub-user can edit the layer.": "El sub-usuario puede editar la capa.",
        "The sub-user change properties like style and alter table structure.": "El sub-usuario cambia propiedades como estilo y altera la estructura de la tabla.",
        "The privileges are granted for both Admin and external services like WMS and WFS.": "Los privilegios se han otorgado tanto para Admin como para servicios externos, como WMS y WFS.",
        "Database": "Base de datos",
        "Created": "Creada",
        "Geom field": "Campo Geom",
        "Last modified": "Último modificado",
        "Classes": "Clases",
        "Style is updated": "El estilo se ha actualizado",
        "Settings": "Configuracióni",
        "Log": "Log",
        "Name": "Nombre",
        "Type": "Tipo",
        "Title": "Título",
        "Description": "Descripción",
        "Group": "Grupo",
        "Sort id": "Ordenar id",
        "Authentication": "Autenticación",
        "Tile cache": "Tile cache",
        "You are about to delete the tile cache for layer": "Está a punto de borrar el caché de tiles para la capa",
        "Are you sure?": "¿Seguro?",
        "Editable": "Editable",
        "Clear": "Limpio",
        "No files you uploaded seems to be recognized as a valid image format.": "Ningún archivo cargado parece reconocerse como un formato válido de imagen.",
        "Raster formats": "Formatos ráster",
        "Image formats": "Formátos de imagen",
        "Vector formats": "Formatos vector",
        "At the moment you can upload": "Al momento usted puede cargar",
        "You need Flash or a modern browser, which supports HTML5": "Necesita Flash o un navegador moderno que soporte HTML5",
        "Create layer from scratch": "Generar una capa desde cero",
        "EPSG number": "cópdigo EPSG",
        "Auto": "Auto",
        "Point": "Punto",
        "Line": "Línea",
        "Polygon": "Polígono",
        "Encoding": "Codificación",
        "Are you sure you want to do that?": "¿En verdad quiere hacer esto?",
        "Sorry! Some thing failed.": "¡Lo sentimos! Algo ha fallado.",
        "Sorry! Connection problems": "¡Lo sentimos! hay problemas de conexión",
        "New API key": "Nuava clave API",
        "Load": "Cargar",
        "Load features": "Cargar rasgos",
        "Update table": "Actualizar tabla",
        "Column": "Columna",
        "Native field type": "Tipo de campo nativo",
        "Available": "Disponible",
        "Cartomobile field type": "Tipo de campo Cartomobile",
        "Properties": "Propiedades",
        "Single": "Único",
        "Unique values": "Valores únicos",
        "Field": "Campo",
        "Intervals": "Intervalos",
        "Numeric field": "Campo numérico",
        "# of colors": "# de colores",
        "Start color": "Color de inicio",
        "End color": "Color final",
        "Create": "Crear",
        "Additional settings": "Configuraciones adicionales",
        "These setting are applied to all created classes. Set them before hitting a create button above.": "Estas configuraciones se aplican a todas las clases creadas. Por favor, configúrelas antes de oprimir el botón Crear.",
        "Label text": "Texto de etiquetado",
        "Label color": "Color de etiquetado",
        "Label size": "Tamaño de etiquetado",
        "Symbol": "Símbolo",
        "Symbol angle": "Ángulo del símbolo",
        "Symbol size": "Tamaño del símbolo",
        "Outline color": "Color del subrayado",
        "Outline width": "Ancho del subrayado",
        "Opacity": "Opacidad",
        "Alias": "Alias",
        "Queryable": "Consultable",
        "Link": "Enlace",
        "Link prefix": "Prefijo del enlace",
        "New column name": "Nuevo nombre de columna",
        "New column type": "Nuevo tipo de columna",
        "Add new column": "Agregar nueva columna",
        "Delete column": "Borrar columna",
        "Start track changes": "Comenzar a rastrear cambios",
        "Stop track changes": "Dejar de rastrear cambios",
        "This will track changes on the table. For each edit a new version of the feature is made. Four new system columns will be added to the table. Do you want to proceed?": "Esto rastreará los cambios en la tabla. Por cada edición se genera una nueva versión del rasgo. Se agregarán a la tabla cuatro nuevas columnas de sistema. ¿Desea continuar?",
        "This will remove 'track changes' from the table. The versions will not be deleted, but all tracking information will be deleted. Do you want to proceed?": "Esto removerá el 'rastreo de cambios' de la tabla. Las versiones no se borrarán, pero toda la información de rastreamiento sí. ¿Desea continuar?",
        "Show legend": "Mostrar leyenda",
        "Open map in pop up window": "Abrir mapa en una ventana emergente",
        "Change the baselayer": "Cambiar la capa base",
        "Locate me on the map": "Localizarme en el mapa",
        "Close this window to disable measure tool": "Cerrar esta ventana para deshabilitar las herramientas de medición",
        "Measure": "Medición",
        "Distance": "Distancia",
        "Area": "Área",
        "Class wizards": "Asistente de clases",
        "Rename layer": "Renombrar capa",
        "Either select 'latest, 'all' or write a date/time in the form yyyy-mm-dd hh:mm:ss

If you are tracking changes on your table, you can either load the latest (current) versions or you can 'slice' at a given point in time. You can also load all versions.

Earlier features will be shown with a red dashed line.": "Seleccione 'el más reciente, 'todo' o escriba una fecha/hora en el formato yyyy-mm-dd hh:mm:ss

Si está rastreando cambios en su tabla, puede cargar la(s) versión(es) más reciente(s) (actual) o puede 'desplazarse' a un punto dado en el tiempo. También puede cargar todas las versiones.

Los rasgos más antiguos se mostrarán con una línea roja discontínua.",
        "The width or height of map extent exceed the limit. Create a table instead for better performance.": "El ancho o la altura de la extensión del mapa excede el límite. En vez de ello cree una tabla para un mejor desempeño.",
        "The width or height of map extent exceed 200km, which are the limit for the map extent.": "El ancho o la altura de la extensión del mapa excede 200 Km, que es el límite para la extensión del mapa."
    }
};
<|endoftext|>


<commit_before>/**
 * output json map for the runtime
 * eg:
 * {
 *    "tpl": {
 *      "demo:page/index.tpl": {
 *           "src": "/template/demo/page/index.tpl",
 *           "type": "tpl"
 *       },
 *       ...
 *    },
 *    "res": {
 *      "d41d8cd": {
 *           "src": "/static/demo/page/index.css",
 *           "type": "css",
 *           "defines": [
 *               "demo:page/index.css"
 *           ]
 *       },
 *       ...
 *    },
 *    "pkg": {
 *       "6a5a5bb": {
 *           "src": "/static/demo/pkg/aio.css",
 *           "type": "css",
 *           "defines": [
 *               "demo:widget/hehe/hehe.css",
 *               "demo:resource/css/common.css"
 *           ],
 *           "requires": [],
 *           "requireAsyncs": []
 *       },
 *       ...
 *    }
 * }
 */
'use strict';

var gutil = require('gulp-util');
var File = require('vinyl');

module.exports = function (ret, opt) {

  if (!ret)
    return;

  opt = opt || {};
  var useHash = her.config.get('useHash');
  var useDomain = her.config.get('useDomain');

  her.util.map(ret.ids, function (id, file) {
    //if file already packed, do nothing
    if (file.packed)
      return;
    if (file.release && file.useMap) {
      if (file.isJsLike || file.isCssLike) {
        var content = String(file.contents);
        var hashId = file.getHash();
        if (file.isCssLike) {
          content += "\n" + ".css_" + hashId + "{height:88px}";
          file.contents = new Buffer(content);
        }
        var res = ret.map.res[hashId] = {
          src: file.getUrl(useHash, useDomain),
          type: file.rExt.replace(/^\./, '')
        };

        res.defines = [file.id];
        if (file.requires && file.requires.length) {
          res.requires = file.requires;
        }
        if (file.extras && file.extras.async) {
          res.requireAsyncs = file.extras.async;
        }
      } else if (file.isHtmlLike) {
        file.addSameNameRequire('.css');
        var res = ret.map.tpl[file.id] = {
          src: file.getUrl(),
          type: file.rExt.replace(/^\./, '')
        };
        if(file.requires && file.requires.length){
          res.deps = file.requires;
        }
      }
    }
  });

  var cwd = process.cwd() || opt.cwd;
  var ns = her.config.get('namespace');
  var name = (ns ? ns + '-' : '') + 'map.json';
  var optimize = her.config.get('optimize');
  var mapvinyl = new File({
    cwd: cwd,
    path: cwd + '/config/' + name,
    contents: new Buffer(JSON.stringify(ret.map, null, optimize ? null : 4)),
  });
  mapvinyl.release = '/';
  var mapFile = her.file(mapvinyl);
  ret.pkg[mapFile.id] = mapFile;

};
<commit_msg>修改map表的输出方式<commit_after>/**
 * output json map for the runtime
 * eg:
 * {
 *    "tpl": {
 *      "demo:page/index.tpl": {
 *           "src": "/template/demo/page/index.tpl",
 *           "type": "tpl"
 *       },
 *       ...
 *    },
 *    "res": {
 *      "d41d8cd": {
 *           "src": "/static/demo/page/index.css",
 *           "type": "css",
 *           "defines": [
 *               "demo:page/index.css"
 *           ]
 *       },
 *       ...
 *    },
 *    "pkg": {
 *       "6a5a5bb": {
 *           "src": "/static/demo/pkg/aio.css",
 *           "type": "css",
 *           "defines": [
 *               "demo:widget/hehe/hehe.css",
 *               "demo:resource/css/common.css"
 *           ],
 *           "requires": [],
 *           "requireAsyncs": []
 *       },
 *       ...
 *    }
 * }
 */
'use strict';

var gutil = require('gulp-util');
var File = require('vinyl');

module.exports = function (ret, opt) {

  if (!ret)
    return;

  opt = opt || {};
  var useHash = her.config.get('useHash');
  var useDomain = her.config.get('useDomain');

  her.util.map(ret.ids, function (id, file) {
    //if file already packed, do nothing
    if (file.packed)
      return;
    if (file.release && file.useMap) {
      if (file.isJsLike || file.isCssLike) {
        var content = String(file.contents);
        var hashId = file.getHash();
        if (file.isCssLike) {
          content += "\n" + ".css_" + hashId + "{height:88px}";
          file.contents = new Buffer(content);
        }
        var res = ret.map.her[hashId] = {
          src: file.getUrl(useHash, useDomain),
          type: file.rExt.replace(/^\./, '')
        };

        res.defines = [file.id];
        if (file.requires && file.requires.length) {
          res.requires = file.requires;
        }
        if (file.extras && file.extras.async) {
          res.requireAsyncs = file.extras.async;
        }
      } else if (file.isHtmlLike) {
        file.addSameNameRequire('.css');
        var res = ret.map.res[file.id] = {
          uri: file.getUrl(),
          type: file.rExt.replace(/^\./, '')
        };
        if(file.requires && file.requires.length){
          res.deps = file.requires;
        }
      }
    }
  });

  var cwd = process.cwd() || opt.cwd;
  var ns = her.config.get('namespace');
  var name = (ns ? ns + '-' : '') + 'map.json';
  var optimize = her.config.get('optimize');
  var mapvinyl = new File({
    cwd: cwd,
    path: cwd + '/config/' + name,
    contents: new Buffer(JSON.stringify(ret.map, null, optimize ? null : 4)),
  });
  mapvinyl.release = '/';
  var mapFile = her.file(mapvinyl);
  ret.pkg[mapFile.id] = mapFile;

};
<|endoftext|>


<commit_before>/**
 * Created by meathill on 14/11/14.
 */
'use strict';
(function (ns, $, _, Backbone, Handlebars, tp) {
  /**
   * @class
   */
  ns.Loader = Backbone.View.extend({
    $context: null,
    fresh: false,
    tagName: 'div',
    events: {
      'click .edit': 'edit_clickHandler',
      'click .refresh-button': 'refreshButton_clickHandler'
    },
    initialize: function (options) {
      if (this.model instanceof Backbone.Model && !options.hasData) {
        this.model.once('sync', this.model_syncHandler, this);
        this.model.on('error', this.model_errorHandler, this);
        this.model.fetch(_.omit(options, 'loader', 'model'));
      } else {
        this.isModelReady = true;
      }

      $.ajax({
        url: options.template + '?v=' + tp.VERSION,
        success: _.bind(this.template_getHandler, this),
        error: _.bind(this.template_errorHandler, this),
        contentType: 'html'
      });
      this.options = options;

      if ('refresh' in options) {
        this.refresh = options.refresh;
      }
    },
    remove: function () {
      tp.component.Manager.clear(this.$el);
      Backbone.View.prototype.remove.call(this);
    },
    render: function () {
      if (this.model) {
        this.model.off();
      }
      this.$el.html(this.template(this.model instanceof Backbone.Model ? this.model.toJSON() : this.model));
      if (this.refresh) {
        this.refresh = false;
        this.model.on('change', this.model_changeHandler, this);
      }
      var self = this
        , $el = this.$el
        , model = this.model;
      setTimeout(function () {
        tp.component.Manager.check($el, model);
        self.trigger('complete');
      }, 0);
      this.options = null;
    },
    edit_clickHandler: function (event) {
      var target = $(event.currentTarget)
        , options = target.data()
        , prop = event.currentTarget.hash.substr(1);
      options.label = options.label || target.closest('td').prev('th').text();
      this.$context.trigger('edit-model', this.model, prop, options);
      event.preventDefault();
    },
    model_changeHandler: function () {
      // 记录当前活动元素的位置
      var id = this.$('.active').filter('.tab-pane').attr('id');
      tp.component.Manager.clear(this.$el);
      this.render();
      if (id) {
        this.$('[href="#' + id + '"][data-toggle]').click();
      }
    },
    model_errorHandler: function (model, response) {
      this.$el.html(tp.component.Manager.createErrorMsg(response));
      this.trigger('complete');
    },
    model_syncHandler: function () {
      if (this.template) {
        return this.render();
      }
      this.isModelReady = true;
      this.model.off('error', null, this);
    },
    refreshButton_clickHandler: function (event) {
      if (this.noTemplate) {
        return Backbone.history.loadUrl(Backbone.history.fragment);
      }
      this.model.fetch(this.options);
      $(event.currentTarget).spinner();
    },
    template_errorHandler: function () {
      this.noTemplate = true;
      this.$el.html(tp.component.Manager.createErrorMsg({
        msg: '加载模板失败，请稍后重试。'
      }));
      this.trigger('complete');
    },
    template_getHandler: function (data) {
      this.template = Handlebars.compile(data);
      if (this.isModelReady) {
        this.render();
      }
    }
  });
}(Nervenet.createNameSpace('tp.view'), jQuery, _, Backbone, Handlebars, tp));<commit_msg>hot fix<commit_after>/**
 * Created by meathill on 14/11/14.
 */
'use strict';
(function (ns, $, _, Backbone, Handlebars, tp) {
  /**
   * @class
   */
  ns.Loader = Backbone.View.extend({
    $context: null,
    fresh: false,
    tagName: 'div',
    events: {
      'click .edit': 'edit_clickHandler',
      'click .refresh-button': 'refreshButton_clickHandler'
    },
    initialize: function (options) {
      if (this.model instanceof Backbone.Model && !options.hasData) {
        this.model.once('sync', this.model_syncHandler, this);
        this.model.on('error', this.model_errorHandler, this);
        this.model.fetch(_.omit(options, 'loader', 'model'));
      } else {
        this.isModelReady = true;
      }

      $.ajax({
        url: options.template + '?v=' + tp.VERSION,
        success: _.bind(this.template_getHandler, this),
        error: _.bind(this.template_errorHandler, this),
        contentType: 'html'
      });
      this.options = options;

      if ('refresh' in options) {
        this.refresh = options.refresh;
      }
    },
    remove: function () {
      tp.component.Manager.clear(this.$el);
      Backbone.View.prototype.remove.call(this);
    },
    render: function () {
      if (this.model instanceof Backbone.Model) {
        this.model.off();
      }
      this.$el.html(this.template(this.model instanceof Backbone.Model ? this.model.toJSON() : this.model));
      if (this.refresh) {
        this.refresh = false;
        this.model.on('change', this.model_changeHandler, this);
      }
      var self = this
        , $el = this.$el
        , model = this.model;
      setTimeout(function () {
        tp.component.Manager.check($el, model);
        self.trigger('complete');
      }, 0);
      this.options = null;
    },
    edit_clickHandler: function (event) {
      var target = $(event.currentTarget)
        , options = target.data()
        , prop = event.currentTarget.hash.substr(1);
      options.label = options.label || target.closest('td').prev('th').text();
      this.$context.trigger('edit-model', this.model, prop, options);
      event.preventDefault();
    },
    model_changeHandler: function () {
      // 记录当前活动元素的位置
      var id = this.$('.active').filter('.tab-pane').attr('id');
      tp.component.Manager.clear(this.$el);
      this.render();
      if (id) {
        this.$('[href="#' + id + '"][data-toggle]').click();
      }
    },
    model_errorHandler: function (model, response) {
      this.$el.html(tp.component.Manager.createErrorMsg(response));
      this.trigger('complete');
    },
    model_syncHandler: function () {
      if (this.template) {
        return this.render();
      }
      this.isModelReady = true;
      this.model.off('error', null, this);
    },
    refreshButton_clickHandler: function (event) {
      if (this.noTemplate) {
        return Backbone.history.loadUrl(Backbone.history.fragment);
      }
      this.model.fetch(this.options);
      $(event.currentTarget).spinner();
    },
    template_errorHandler: function () {
      this.noTemplate = true;
      this.$el.html(tp.component.Manager.createErrorMsg({
        msg: '加载模板失败，请稍后重试。'
      }));
      this.trigger('complete');
    },
    template_getHandler: function (data) {
      this.template = Handlebars.compile(data);
      if (this.isModelReady) {
        this.render();
      }
    }
  });
}(Nervenet.createNameSpace('tp.view'), jQuery, _, Backbone, Handlebars, tp));<|endoftext|>


<commit_before>/*global jQuery,cyberDojo*/
'use strict';
var cyberDojo = (function(cd, $) {

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Filenames
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  let theCurrentFilename = '';
  let theLastNonOutputFilename = '';
  let theLastOutputFilename = '';

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Load a named file
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.loadFile = (filename) => {
    fileDiv(cd.currentFilename()).hide();
    fileDiv(filename).show();

    selectFileInFileList(filename);
    cd.focusSyntaxHighlightEditor(filename);

    theCurrentFilename = filename;
    if (cd.isOutput(filename)) {
      theLastOutputFilename = filename;
    } else {
      theLastNonOutputFilename = filename;
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.loadTestOutputFile = () => {
    if (fileContent('stderr') != '') {
      cd.loadFile('stderr');
    } else {
      cd.loadFile('stdout');
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.currentFilename = () => {
    return theCurrentFilename;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.eachFilename = (f) => {
    cd.filenames().forEach(f);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.filenames = () => {
    // Gets the kata/edit page filenames. The review/show
    // page/dialog collects filenames in its own way.
    const filenames = [];
    const prefix = 'file_content_for_';
    $('textarea[id^=' + prefix + ']').each(function(_) {
      const id = $(this).attr('id');
      const filename = id.substr(prefix.length, id.length - prefix.length);
      filenames.push(filename);
    });
    return filenames;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.isOutput = (filename) => {
    if (filename == 'stdout') return true;
    if (filename == 'stderr') return true;
    if (filename == 'status') return true;
    return false;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.sortedFilenames = (filenames) => {
    // Controls the order of files in the filename-list
    // Used in two places
    // 1. kata/edit page to help show filename-list
    // 2. review/show page/dialog to help show filename-list
    const output = ['stdout','stderr','status'];
    return [].concat(hiFilenames(filenames), output, loFilenames(filenames));
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Filename hot-key navigation
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // See app/assets/javascripts/cyber-dojo_codemirror.js
  // See app/views/shared/_hotkeys.html.erb
  // Alt-J ==> loadNextFile()
  // Alt-K ==> loadPreviousFile()
  // Alt-O ==> toggleOutputFile()

  cd.loadNextFile = () => {
    const hi = hiFilenames(cd.filenames());
    const index = $.inArray(cd.currentFilename(), hi);
    if (index == -1) {
      const next = 0;
      cd.loadFile(hi[next]);
    } else {
      const next = (index + 1) % hi.length;
      cd.loadFile(hi[next]);
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.loadPreviousFile = () => {
    const hi = hiFilenames(cd.filenames());
    const index = $.inArray(cd.currentFilename(), hi);
    if (index === 0 || index === -1) {
      const previous = hi.length - 1;
      cd.loadFile(hi[previous]);
    } else {
      const previous = index - 1;
      cd.loadFile(hi[previous]);
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.toggleOutputFile = () => {
    if (cd.isOutput(cd.currentFilename())) { //} !== 'stdout') {
      cd.loadFile(theLastNonOutputFilename);
    } else {
      cd.loadFile(theLastOutputFilename);
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // new-file, rename-file, delete-file
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // See app/views/kata/_file_new_rename_delete.html.erb
  // See app/views/kata/_files.html.erb
  // See app/views/kata/_run_tests.js.erb

  cd.changeFile = (filename, content) => {
    cd.deleteFile(filename);
    cd.newFile(filename, content);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.newFile = (filename, content) => {
    const newFile = makeNewFile(filename, content);
    $('#visible-files-container').append(newFile);
    rebuildFilenameList();
    cd.switchEditorToCodeMirror(filename);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.deleteFile = (filename) => {
    fileDiv(filename).remove();
    rebuildFilenameList();
    theLastNonOutputFilename = testFilename();
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.renameFile = (oldFilename, newFilename) => {
    // This should restore the caret/cursor/selection
    // but it currently does not. See
    // https://github.com/cyber-dojo/web/issues/51
    const content = fileContent(oldFilename);
    cd.deleteFile(oldFilename);
    cd.newFile(newFilename, content);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Helpers
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.editorRefocus = () => {
    cd.loadFile(cd.currentFilename());
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.loadTestFile = () => {
    cd.loadFile(testFilename());
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.radioEntrySwitch = (previous, current) => {
    // Used in test-page, setup-pages, and history/diff-dialog
    // See app/assets/stylesheets/wide-list-item.scss
    if (previous != undefined) {
      previous.removeClass('selected');
    }
    current.addClass('selected');
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.hashOfFile = (filename) => {
    const content = fileContent(filename);
    let hash = 0;
    for (let i = 0; i < content.length; ++i) {
      hash = (hash << 5) - hash + content.charCodeAt(i);
      hash &= hash;
    }
    return hash;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const testFilename = () => {
    // When starting and in filename-list navigation
    // when the current file is deleted, try to
    // select a test file.
    const filenames = cd.filenames();
    for (let i = 0; i < filenames.length; i++) {
      // split into dir names and filename
      const parts = filenames[i].toLowerCase().split('/');
      // careful to return the whole dirs+filename
      // and with the original case
      const filename = parts[parts.length - 1];
      if (filename.search('test') !== -1) {
        return filenames[i];
      }
      if (filename.search('spec') !== -1) {
        return filenames[i];
      }
    }
    return filenames[0];
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const fileContent = (filename) => {
    cd.saveCodeFromIndividualSyntaxHighlightEditor(filename);
    return jqElement('file_content_for_' + filename).val();
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const jqElement = (name) => {
    return $('[id="' + name + '"]');
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const fileDiv = (filename) => {
    return jqElement(filename + '_div');
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const makeNewFile = (filename, content) => {
    const div = $('<div>', {
      'class': 'filename_div',
      id: filename + '_div'
    });
    const text = $('<textarea>', {
      'class': 'file_content',
      'spellcheck': 'false',
      'data-filename': filename,
      name: 'file_content[' + filename + ']',
      id: 'file_content_for_' + filename
      //wrap: 'off'
    });
    // For some reason, setting wrap cannot be done as per the
    // commented out line above... when you create a new file in
    // FireFox 17.0.1 it still wraps at the textarea width.
    // So instead I do it like this, which works in FireFox?!
    text.attr('wrap', 'off');

    text.val(content);
    div.append(text);

    return div;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const setRenameAndDeleteButtons = (filename) => {
    const fileOps = $('#file-operations');
    const renameFile = fileOps.find('#rename');
    const deleteFile = fileOps.find('#delete');
    const disable = (node) => { node.prop('disabled', true ); };
    const enable  = (node) => { node.prop('disabled', false); };

    if (cantBeRenamedOrDeleted(filename)) {
      disable(renameFile);
      disable(deleteFile);
    } else {
      enable(renameFile);
      enable(deleteFile);
    }
  };

  const cantBeRenamedOrDeleted = (filename) => {
    return cd.isOutput(filename) || filename == 'cyber-dojo.sh';
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const rebuildFilenameList = () => {
    const filenameList = $('#filename-list');
    filenameList.empty();
    $.each(cd.sortedFilenames(cd.filenames()), (_, filename) => {
      filenameList.append(makeFileListEntry(filename));
    });
  };

  const makeFileListEntry = (filename) => {
    const div = $('<div>', {
      'class': 'filename',
           id: 'radio_' + filename,
         text: filename
    });
    if (cd.inArray(filename, cd.highlightFilenames())) {
      div.addClass('highlight');
    }
    div.click(() => { cd.loadFile(filename); });
    return div;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const selectFileInFileList = (filename) => {
    // Can't do $('radio_' + filename) because filename
    // could contain characters that aren't strictly legal
    // characters in a dom node id so I do this instead...
    const node = $('[id="radio_' + filename + '"]');
    const previousFilename = cd.currentFilename();
    const previous = $('[id="radio_' + previousFilename + '"]');
    cd.radioEntrySwitch(previous, node);
    setRenameAndDeleteButtons(filename);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const hiFilenames = (filenames) => {
    // Controls which filenames appear at the
    // top of the filename-list, above 'output'
    // Used in three places.
    // 1. kata/edit page to help show filename list
    // 2. kata/edit page in alt-j alt-k hotkeys
    // 3. review/show page/dialog to help show filename list
    let hi = [];
    $.each(filenames, (_, filename) => {
      if (isSourceFile(filename) || filename == 'instructions' || filename == 'readme.txt') {
        hi.push(filename);
      }
    });
    hi.sort();
    hi = hi.filter(item => item !== 'stdout');
    hi = hi.filter(item => item !== 'stderr');
    hi = hi.filter(item => item !== 'status');
    hi = hi.filter(item => item !== 'cyber-dojo.sh');
    return hi;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const loFilenames = (filenames) => {
    // Controls which filenames appear at the
    // bottom of the filename list, below 'output'
    // Used in three places.
    // 1. kata/edit page to help show filename-list
    // 2. kata/edit page in Alt-j Alt-k hotkeys
    // 3. review/show page/dialog to help show filename-list
    let lo = [];
    $.each(filenames, (_, filename) => {
      if (!isSourceFile(filename) && filename != 'instructions' && filename != 'readme.txt') {
        lo.push(filename);
      }
    });
    lo.sort();
    lo = lo.filter(item => item !== 'stdout');
    lo = lo.filter(item => item !== 'stderr');
    lo = lo.filter(item => item !== 'status');
    return lo;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const isSourceFile = (filename) => {
    let match = false;
    $.each(cd.extensionFilenames(), (_, extension) => {
      // Shell test frameworks (eg shunit2) use .sh as their
      // filename extension but we don't want cyber-dojo.sh
      // in the hiFilenames() above output in the filename-list.
      if (filename.endsWith(extension) && filename != 'cyber-dojo.sh') {
        match = true;
      }
    });
    return match;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  return cd;

})(cyberDojo || {}, jQuery);
<commit_msg>make sure Alt-O works when there are no test events yet<commit_after>/*global jQuery,cyberDojo*/
'use strict';
var cyberDojo = (function(cd, $) {

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Filenames
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  let theCurrentFilename = '';
  let theLastNonOutputFilename = '';
  let theLastOutputFilename = 'stdout';

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Load a named file
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.loadFile = (filename) => {
    fileDiv(cd.currentFilename()).hide();
    fileDiv(filename).show();

    selectFileInFileList(filename);
    cd.focusSyntaxHighlightEditor(filename);

    theCurrentFilename = filename;
    if (cd.isOutput(filename)) {
      theLastOutputFilename = filename;
    } else {
      theLastNonOutputFilename = filename;
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.loadTestOutputFile = () => {
    if (fileContent('stderr') != '') {
      cd.loadFile('stderr');
    } else {
      cd.loadFile('stdout');
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.currentFilename = () => {
    return theCurrentFilename;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.eachFilename = (f) => {
    cd.filenames().forEach(f);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.filenames = () => {
    // Gets the kata/edit page filenames. The review/show
    // page/dialog collects filenames in its own way.
    const filenames = [];
    const prefix = 'file_content_for_';
    $('textarea[id^=' + prefix + ']').each(function(_) {
      const id = $(this).attr('id');
      const filename = id.substr(prefix.length, id.length - prefix.length);
      filenames.push(filename);
    });
    return filenames;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.isOutput = (filename) => {
    if (filename == 'stdout') return true;
    if (filename == 'stderr') return true;
    if (filename == 'status') return true;
    return false;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.sortedFilenames = (filenames) => {
    // Controls the order of files in the filename-list
    // Used in two places
    // 1. kata/edit page to help show filename-list
    // 2. review/show page/dialog to help show filename-list
    const output = ['stdout','stderr','status'];
    return [].concat(hiFilenames(filenames), output, loFilenames(filenames));
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Filename hot-key navigation
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // See app/assets/javascripts/cyber-dojo_codemirror.js
  // See app/views/shared/_hotkeys.html.erb
  // Alt-J ==> loadNextFile()
  // Alt-K ==> loadPreviousFile()
  // Alt-O ==> toggleOutputFile()

  cd.loadNextFile = () => {
    const hi = hiFilenames(cd.filenames());
    const index = $.inArray(cd.currentFilename(), hi);
    if (index == -1) {
      const next = 0;
      cd.loadFile(hi[next]);
    } else {
      const next = (index + 1) % hi.length;
      cd.loadFile(hi[next]);
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.loadPreviousFile = () => {
    const hi = hiFilenames(cd.filenames());
    const index = $.inArray(cd.currentFilename(), hi);
    if (index === 0 || index === -1) {
      const previous = hi.length - 1;
      cd.loadFile(hi[previous]);
    } else {
      const previous = index - 1;
      cd.loadFile(hi[previous]);
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.toggleOutputFile = () => {
    if (cd.isOutput(cd.currentFilename())) { //} !== 'stdout') {
      cd.loadFile(theLastNonOutputFilename);
    } else {
      cd.loadFile(theLastOutputFilename);
    }
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // new-file, rename-file, delete-file
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // See app/views/kata/_file_new_rename_delete.html.erb
  // See app/views/kata/_files.html.erb
  // See app/views/kata/_run_tests.js.erb

  cd.changeFile = (filename, content) => {
    cd.deleteFile(filename);
    cd.newFile(filename, content);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.newFile = (filename, content) => {
    const newFile = makeNewFile(filename, content);
    $('#visible-files-container').append(newFile);
    rebuildFilenameList();
    cd.switchEditorToCodeMirror(filename);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.deleteFile = (filename) => {
    fileDiv(filename).remove();
    rebuildFilenameList();
    theLastNonOutputFilename = testFilename();
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.renameFile = (oldFilename, newFilename) => {
    // This should restore the caret/cursor/selection
    // but it currently does not. See
    // https://github.com/cyber-dojo/web/issues/51
    const content = fileContent(oldFilename);
    cd.deleteFile(oldFilename);
    cd.newFile(newFilename, content);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  // Helpers
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.editorRefocus = () => {
    cd.loadFile(cd.currentFilename());
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.loadTestFile = () => {
    cd.loadFile(testFilename());
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.radioEntrySwitch = (previous, current) => {
    // Used in test-page, setup-pages, and history/diff-dialog
    // See app/assets/stylesheets/wide-list-item.scss
    if (previous != undefined) {
      previous.removeClass('selected');
    }
    current.addClass('selected');
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd.hashOfFile = (filename) => {
    const content = fileContent(filename);
    let hash = 0;
    for (let i = 0; i < content.length; ++i) {
      hash = (hash << 5) - hash + content.charCodeAt(i);
      hash &= hash;
    }
    return hash;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const testFilename = () => {
    // When starting and in filename-list navigation
    // when the current file is deleted, try to
    // select a test file.
    const filenames = cd.filenames();
    for (let i = 0; i < filenames.length; i++) {
      // split into dir names and filename
      const parts = filenames[i].toLowerCase().split('/');
      // careful to return the whole dirs+filename
      // and with the original case
      const filename = parts[parts.length - 1];
      if (filename.search('test') !== -1) {
        return filenames[i];
      }
      if (filename.search('spec') !== -1) {
        return filenames[i];
      }
    }
    return filenames[0];
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const fileContent = (filename) => {
    cd.saveCodeFromIndividualSyntaxHighlightEditor(filename);
    return jqElement('file_content_for_' + filename).val();
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const jqElement = (name) => {
    return $('[id="' + name + '"]');
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const fileDiv = (filename) => {
    return jqElement(filename + '_div');
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const makeNewFile = (filename, content) => {
    const div = $('<div>', {
      'class': 'filename_div',
      id: filename + '_div'
    });
    const text = $('<textarea>', {
      'class': 'file_content',
      'spellcheck': 'false',
      'data-filename': filename,
      name: 'file_content[' + filename + ']',
      id: 'file_content_for_' + filename
      //wrap: 'off'
    });
    // For some reason, setting wrap cannot be done as per the
    // commented out line above... when you create a new file in
    // FireFox 17.0.1 it still wraps at the textarea width.
    // So instead I do it like this, which works in FireFox?!
    text.attr('wrap', 'off');

    text.val(content);
    div.append(text);

    return div;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const setRenameAndDeleteButtons = (filename) => {
    const fileOps = $('#file-operations');
    const renameFile = fileOps.find('#rename');
    const deleteFile = fileOps.find('#delete');
    const disable = (node) => { node.prop('disabled', true ); };
    const enable  = (node) => { node.prop('disabled', false); };

    if (cantBeRenamedOrDeleted(filename)) {
      disable(renameFile);
      disable(deleteFile);
    } else {
      enable(renameFile);
      enable(deleteFile);
    }
  };

  const cantBeRenamedOrDeleted = (filename) => {
    return cd.isOutput(filename) || filename == 'cyber-dojo.sh';
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const rebuildFilenameList = () => {
    const filenameList = $('#filename-list');
    filenameList.empty();
    $.each(cd.sortedFilenames(cd.filenames()), (_, filename) => {
      filenameList.append(makeFileListEntry(filename));
    });
  };

  const makeFileListEntry = (filename) => {
    const div = $('<div>', {
      'class': 'filename',
           id: 'radio_' + filename,
         text: filename
    });
    if (cd.inArray(filename, cd.highlightFilenames())) {
      div.addClass('highlight');
    }
    div.click(() => { cd.loadFile(filename); });
    return div;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const selectFileInFileList = (filename) => {
    // Can't do $('radio_' + filename) because filename
    // could contain characters that aren't strictly legal
    // characters in a dom node id so I do this instead...
    const node = $('[id="radio_' + filename + '"]');
    const previousFilename = cd.currentFilename();
    const previous = $('[id="radio_' + previousFilename + '"]');
    cd.radioEntrySwitch(previous, node);
    setRenameAndDeleteButtons(filename);
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const hiFilenames = (filenames) => {
    // Controls which filenames appear at the
    // top of the filename-list, above 'output'
    // Used in three places.
    // 1. kata/edit page to help show filename list
    // 2. kata/edit page in alt-j alt-k hotkeys
    // 3. review/show page/dialog to help show filename list
    let hi = [];
    $.each(filenames, (_, filename) => {
      if (isSourceFile(filename) || filename == 'instructions' || filename == 'readme.txt') {
        hi.push(filename);
      }
    });
    hi.sort();
    hi = hi.filter(item => item !== 'stdout');
    hi = hi.filter(item => item !== 'stderr');
    hi = hi.filter(item => item !== 'status');
    hi = hi.filter(item => item !== 'cyber-dojo.sh');
    return hi;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const loFilenames = (filenames) => {
    // Controls which filenames appear at the
    // bottom of the filename list, below 'output'
    // Used in three places.
    // 1. kata/edit page to help show filename-list
    // 2. kata/edit page in Alt-j Alt-k hotkeys
    // 3. review/show page/dialog to help show filename-list
    let lo = [];
    $.each(filenames, (_, filename) => {
      if (!isSourceFile(filename) && filename != 'instructions' && filename != 'readme.txt') {
        lo.push(filename);
      }
    });
    lo.sort();
    lo = lo.filter(item => item !== 'stdout');
    lo = lo.filter(item => item !== 'stderr');
    lo = lo.filter(item => item !== 'status');
    return lo;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  const isSourceFile = (filename) => {
    let match = false;
    $.each(cd.extensionFilenames(), (_, extension) => {
      // Shell test frameworks (eg shunit2) use .sh as their
      // filename extension but we don't want cyber-dojo.sh
      // in the hiFilenames() above output in the filename-list.
      if (filename.endsWith(extension) && filename != 'cyber-dojo.sh') {
        match = true;
      }
    });
    return match;
  };

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  return cd;

})(cyberDojo || {}, jQuery);
<|endoftext|>


<commit_before>'use strict';

var _            = require('underscore');
var elixir       = require('laravel-elixir');
var notification = require('laravel-elixir/Notification');
var gulp         = require('gulp');
var gutil        = require('gulp-util');
var plugins      = require('gulp-load-plugins')();
var config       = elixir.config;
var name         = 'postcss';

elixir.extend('postcss', function(src, options) {

  options = _.extend({
    output: 'public/css',
    plugins: [],
    srcDir: 'resources/assets/postcss/'
  }, options);

  new elixir.Task(name, function() {

    var err = function(e) {
      // line break
      console.log('');
      console.log(gutil.colors.bgRed('PostCSS - Error'));
      console.log('   - ' + e.message);
    };

    return gulp.src(options.srcDir + src)
      .pipe(plugins.if(config.sourcemaps, plugins.sourcemaps.init()))
      .pipe(plugins.postcss(options.plugins).on('error', err))
      .pipe(plugins.if(config.production, plugins.minifyCss()))
      .pipe(plugins.if(config.sourcemaps, plugins.sourcemaps.write('.')))
      .pipe(gulp.dest(options.output))
      .pipe(new notification().message(name + ' Compiled!'));

  })
  .watch([options.srcDir + '/**/*.css']);

});
<commit_msg>move name variable into function<commit_after>'use strict';

var _            = require('underscore');
var elixir       = require('laravel-elixir');
var notification = require('laravel-elixir/Notification');
var gulp         = require('gulp');
var gutil        = require('gulp-util');
var plugins      = require('gulp-load-plugins')();
var config       = elixir.config;

elixir.extend('postcss', function(src, options) {

  var name = 'postcss';

  options = _.extend({
    output: 'public/css',
    plugins: [],
    srcDir: 'resources/assets/postcss/'
  }, options);

  new elixir.Task(name, function() {

    var err = function(e) {
      // line break
      console.log('');
      console.log(gutil.colors.bgRed('PostCSS - Error'));
      console.log('   - ' + e.message);
    };

    return gulp.src(options.srcDir + src)
      .pipe(plugins.if(config.sourcemaps, plugins.sourcemaps.init()))
      .pipe(plugins.postcss(options.plugins).on('error', err))
      .pipe(plugins.if(config.production, plugins.minifyCss()))
      .pipe(plugins.if(config.sourcemaps, plugins.sourcemaps.write('.')))
      .pipe(gulp.dest(options.output))
      .pipe(new notification().message(name + ' Compiled!'));

  })
  .watch([options.srcDir + '/**/*.css']);

});
<|endoftext|>


<commit_before>
const domParser = new DOMParser();
const parseXml = (xml) => domParser.parseFromString(xml, 'application/xml');

export default (rssFeedUrl) => {
  return fetch(rssFeedUrl)
  .then(res => res.text())
  .then((rss) => {
    const xml = parseXml(rss);
    const json = xmlToJson(xml);
    return json.rss.channel;
  });
}

function xmlToJson(xml) {
  // based on: https://davidwalsh.name/convert-xml-json
  // Create the return object
	var obj = {};
	if (xml.nodeType == 1) { // element
		// do attributes
		if (xml.attributes.length > 0) {
		obj["@attributes"] = {};
			for (var j = 0; j < xml.attributes.length; j++) {
				var attribute = xml.attributes.item(j);
				obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
			}
		}
  }

	var nrOfChildren = xml.children.length;
	if (!nrOfChildren && xml.textContent.length) {
	    return xml.textContent;
	} else { // do children
		for(var i = 0; i < nrOfChildren; i++) {
			var item = xml.children.item(i);
      var nodeName = item.nodeName;
      if(/:/i.test(nodeName)){ // skip namespaced elements
        continue;
      }
			if (typeof(obj[nodeName]) == "undefined") {
				obj[nodeName] = xmlToJson(item);
			} else {
				if (typeof(obj[nodeName].push) == "undefined") {
					var old = obj[nodeName];
					obj[nodeName] = [];
          obj[nodeName].push(old);
				}
				obj[nodeName].push(xmlToJson(item));
			}
		}
	}
	return obj;
};
<commit_msg>fix rssFetcher so that the feedUrl is set to show id<commit_after>
const domParser = new DOMParser();
const parseXml = (xml) => domParser.parseFromString(xml, 'application/xml');

export default (rssFeed) => {
  const feedProxyUrl = `/rss/${encodeURIComponent(rssFeed)}`;
  return fetch(feedProxyUrl)
  .then(res => res.text())
  .then((rss) => {
    const xml = parseXml(rss);
    const json = xmlToJson(xml);
    const show = json.rss.channel;
    // assign feed url as id and return
    show.id = rssFeed;
    return show;
  });
}

function xmlToJson(xml) {
  // based on: https://davidwalsh.name/convert-xml-json
  // Create the return object
	var obj = {};
	if (xml.nodeType == 1) { // element
		// do attributes
		if (xml.attributes.length > 0) {
		obj["@attributes"] = {};
			for (var j = 0; j < xml.attributes.length; j++) {
				var attribute = xml.attributes.item(j);
				obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
			}
		}
  }

	var nrOfChildren = xml.children.length;
	if (!nrOfChildren && xml.textContent.length) {
	    return xml.textContent;
	} else { // do children
		for(var i = 0; i < nrOfChildren; i++) {
			var item = xml.children.item(i);
      var nodeName = item.nodeName;
      if(/:/i.test(nodeName)){ // skip namespaced elements
        continue;
      }
			if (typeof(obj[nodeName]) == "undefined") {
				obj[nodeName] = xmlToJson(item);
			} else {
				if (typeof(obj[nodeName].push) == "undefined") {
					var old = obj[nodeName];
					obj[nodeName] = [];
          obj[nodeName].push(old);
				}
				obj[nodeName].push(xmlToJson(item));
			}
		}
	}
	return obj;
};
<|endoftext|>