text:
import 'jasmine';
import { v4 } from 'uuid';
import { Emit, EmitNow, Entities, GetEntity, GetWorld, QueryResults, RunQuery, UUID } from './arg_types';
import { Component } from './component';
import { Entity } from './entity';
import { AddEvent, DeleteEvent, EcsEvent } from './events';
import { Optional } from './optional';
import { Plugin } from './plugin';
import { Query } from './query';
import { Resource } from './resource';
import { System } from './system';
import { SingletonComponent, World } from './world';

const FOO_COMPONENT = new Component<{ x: number }>('foo');
const BAR_COMPONENT = new Component<{ y: string }>('bar');
const BAZ_RESOURCE = new Resource<{ z: string[] }>('baz');

const FOO_BAR_SYSTEM = new System({
    name: 'foobar',
    args: [FOO_COMPONENT, BAR_COMPONENT, BAZ_RESOURCE] as const,
    step: (foo, bar, baz) => {
        bar.y = bar.y + `${foo.x}`;
        foo.x = bar.y.length;
        baz.z.push(bar.y);
    }
});

class MutableObject {
    constructor(public val: string) { }
}

const MUTABLE_COMPONENT = new Component<MutableObject>('MutableComponent');

describe('world', () => {
    let world: World;
    beforeEach(() => {
        world = new World();
    });

    it('can step an empty world', () => {
        world.step();
    });

    it('throws an error if a system is added before its resources', () => {
        expect(() => world.addSystem(FOO_BAR_SYSTEM))
            .toThrowError('World is missing Resource(baz) needed for System(foobar)');
    });

    it('passes components to a system', () => {
        const stepData: [number, string][] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [FOO_COMPONENT, BAR_COMPONENT] as const,
            step: (fooData, barData) => {
                stepData.push([fooData.x, barData.y]);
            }
        });

        world.addSystem(testSystem);
        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 })
            .addComponent(BAR_COMPONENT, { y: 'asdf' })

        );
        world.step();

        expect(stepData).toEqual([[123, 'asdf']]);
    });

    it('passes entities to a system added after the entities', () => {
        const stepData: [number, string][] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [FOO_COMPONENT, BAR_COMPONENT] as const,
            step: (fooData, barData) => {
                stepData.push([fooData.x, barData.y]);
            }
        });

        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 })
            .addComponent(BAR_COMPONENT, { y: 'asdf' })
        );
        world.addSystem(testSystem);
        world.step();

        expect(stepData).toEqual([[123, 'asdf']]);
    });

    it('allows systems to modify components', () => {
        const stepData: number[] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [FOO_COMPONENT] as const,
            step: (fooData) => {
                fooData.x += 1;
                stepData.push(fooData.x);
            }
        });

        world.addSystem(testSystem);
        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 0 }));

        world.step();
        world.step();
        world.step();

        expect(stepData).toEqual([1, 2, 3]);
    });

    it('fulfills queries', () => {
        const query = new Query([FOO_COMPONENT, BAR_COMPONENT, UUID] as const, "TestQuery");
        const stepData: [number, string, string][] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [query] as const,
            step: (queryData) => {
                for (let [{ x }, { y }, uuid] of queryData) {
                    stepData.push([x, y, uuid]);
                }
            }
        });

        world.addSystem(testSystem);
        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 0 }));
        world.entities.set('example uuid', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 })
            .addComponent(BAR_COMPONENT, { y: 'asdf' }));

        world.step();

        // Appears three times because each entity ran the testSystem
        // including the singleton entity.
        expect(stepData).toEqual([
            [123, 'asdf', 'example uuid'],
            [123, 'asdf', 'example uuid'],
            [123, 'asdf', 'example uuid']
        ]);
    });

    it('passes resources to systems', () => {
        const stepData: string[][] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [BAZ_RESOURCE, FOO_COMPONENT] as const,
            step: ({ z }) => {
                stepData.push([...z]);
            }
        });

        world.resources.set(BAZ_RESOURCE, { z: ['foo', 'bar'] });
        world.addSystem(testSystem);
        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 }));

        world.step();

        expect(stepData).toEqual([['foo', 'bar']]);
    })

    it('passes uuid to systems', () => {
        const stepData: string[] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [UUID, FOO_COMPONENT] as const,
            step: (uuid) => {
                stepData.push(uuid);
            }
        });

        world.resources.set(BAZ_RESOURCE, { z: ['foo', 'bar'] });
        world.addSystem(testSystem);
        world.entities.set('entityUuid', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 }));

        world.step();

        expect(stepData).toEqual(['entityUuid']);
    });

    it('runs systems in topological order', () => {
        const stepData: string[] = [];

        const secondSystem = new System({
            name: 'SecondSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = 'second';
                stepData.push(bar.y);
            }
        });
        const firstSystem = new System({
            name: 'FirstSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = 'first';
                stepData.push(bar.y);
            },
            before: [secondSystem],
        });
        const fourthSystem = new System({
            name: 'FourthSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = 'fourth';
                stepData.push(bar.y);
            },
        });
        const thirdSystem = new System({
            name: 'ThirdSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = 'third';
                stepData.push(bar.y);
            },
            after: [secondSystem],
            before: [fourthSystem],
        });

        const world = new World();

        // Add systems in a random order
        let systems = [firstSystem, secondSystem, thirdSystem, fourthSystem];
        while (systems.length > 0) {
            const index = Math.floor(Math.random() * systems.length);
            world.addSystem(systems[index]);
            systems = [...systems.slice(0, index), ...systems.slice(index + 1)];
        }

        world.entities.set(v4(), new Entity()
            .addComponent(BAR_COMPONENT, { y: 'unset' }));

        world.step();

        expect(stepData).toEqual(['first', 'second', 'third', 'fourth']);
    });

    it('supports referencing systems by name for ordering', () => {
        const stepData: string[] = [];

        const secondSystem = new System({
            name: 'SecondSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = 'second';
                stepData.push(bar.y);
            }
        });
        const firstSystem = new System({
            name: 'FirstSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = 'first';
                stepData.push(bar.y);
            },
            before: ['SecondSystem'],
        });
        const fourthSystem = new System({
            name: 'FourthSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = 'fourth';
                stepData.push(bar.y);
            },
        });
        const thirdSystem = new System({
            name: 'ThirdSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = 'third';
                stepData.push(bar.y);
            },
            after: ['SecondSystem'],
            before: ['FourthSystem'],
        });

        const world = new World();

        // Add systems in a random order
        let systems = [firstSystem, secondSystem, thirdSystem, fourthSystem];
        while (systems.length > 0) {
            const index = Math.floor(Math.random() * systems.length);
            world.addSystem(systems[index]);
            systems = [...systems.slice(0, index), ...systems.slice(index + 1)];
        }

        world.entities.set(v4(), new Entity()
            .addComponent(BAR_COMPONENT, { y: 'unset' }));

        world.step();

        expect(stepData).toEqual(['first', 'second', 'third', 'fourth']);
    });

    it('supports optional arguments in systems', () => {
        const stepData: [number, string | undefined][] = [];

        const testSystem = new System({
            name: 'TestSystem',
            args: [FOO_COMPONENT, Optional(BAR_COMPONENT)] as const,
            step: (foo, maybeBar) => {
                stepData.push([foo.x, maybeBar?.y]);
            },
        });

        world.addSystem(testSystem);
        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 })
            .addComponent(BAR_COMPONENT, { y: 'FooBar' }));

        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 456 }));

        world.step();

        expect(stepData).toContain([123, 'FooBar']);
        expect(stepData).toContain([456, undefined]);
    });

    it('supports optional arguments in queries', () => {
        const query = new Query([FOO_COMPONENT, Optional(BAR_COMPONENT), UUID] as const);
        const stepData: [number, number, string | undefined][] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [FOO_COMPONENT, query] as const,
            step: (foo, queryData) => {
                for (let [{ x }, maybeBar] of queryData) {
                    stepData.push([foo.x, x, maybeBar?.y]);
                }
            }
        });

        world.addSystem(testSystem);
        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 }));
        world.entities.set('example uuid', new Entity()
            .addComponent(FOO_COMPONENT, { x: 456 })
            .addComponent(BAR_COMPONENT, { y: 'asdf' }));

        world.step();

        // On each run of testSystem (which runs for both entities), the query
        // iterates over each matching entity, which is why there are four results.
        expect(stepData).toContain([123, 123, undefined]);
        expect(stepData).toContain([123, 456, 'asdf']);
        expect(stepData).toContain([456, 123, undefined]);
        expect(stepData).toContain([456, 456, 'asdf']);
    });

    it('loads plugins', () => {
        const stepData: string[] = [];
        const plugin: Plugin = {
            name: 'Test Plugin',
            build: (world) => {
                world.entities.set(v4(), new Entity()
                    .addComponent(BAR_COMPONENT, { y: 'plugin component' }));
                world.addSystem(new System({
                    name: 'TestSystem',
                    args: [BAR_COMPONENT],
                    step: (bar) => {
                        stepData.push(bar.y);
                    }
                }));
            }
        };

        world.addPlugin(plugin);
        world.step();

        expect(stepData).toEqual(['plugin component']);
    });

    it('removes a plugin', () => {
        const stepData: string[] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [BAR_COMPONENT],
            step: (bar) => {
                stepData.push(bar.y);
            }
        });
        const plugin: Plugin = {
            name: 'Test Plugin',
            build(world) {
                world.entities.set(v4(), new Entity()
                    .addComponent(BAR_COMPONENT, { y: 'plugin component' }));
                world.addSystem(testSystem);
            },
            remove(world) {
                world.removeSystem(testSystem);
            }
        };

        world.addPlugin(plugin);
        world.step();

        expect(stepData).toEqual(['plugin component']);

        world.removePlugin(plugin);
        expect(world.plugins.has(plugin)).toBeFalse();

        world.step();
        // No additional data is added
        expect(stepData).toEqual(['plugin component']);
    });

    it('supports modifying an existing entity\'s components', () => {
        const barData: string[] = [];
        const fooBarData: [number, string][] = [];
        const barSystem = new System({
            name: 'BarSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                barData.push(bar.y);
            }
        });

        const fooBarSystem = new System({
            name: 'FooBarSystem',
            args: [FOO_COMPONENT, BAR_COMPONENT] as const,
            step: (foo, bar) => {
                bar.y = 'changed by foo';
                fooBarData.push([foo.x, bar.y]);
            },
            before: new Set([barSystem])
        });

        world.addSystem(fooBarSystem);
        world.addSystem(barSystem);

        const uuid = v4();
        world.entities.set(uuid, new Entity());
        const entity = world.entities.get(uuid)!;
        world.step();
        entity.components.set(BAR_COMPONENT, { y: 'added bar' });
        world.step();
        entity.components.set(FOO_COMPONENT, { x: 123 });
        world.step();
        entity.components.delete(FOO_COMPONENT);
        world.step();
        entity.components.delete(BAR_COMPONENT);
        world.step();

        expect(barData).toEqual(['added bar', 'changed by foo', 'changed by foo']);
        expect(fooBarData).toEqual([[123, 'changed by foo']])
    });

    it('removes entities', () => {
        const stepData: [string, number][] = [];

        const testSystem = new System({
            name: 'TestSystem',
            args: [BAR_COMPONENT, FOO_COMPONENT] as const,
            step: ({ y }, foo) => {
                foo.x += 1;
                stepData.push([y, foo.x]);
            }
        });

        world.entities.set('e1 uuid', new Entity()
            .addComponent(BAR_COMPONENT, { y: 'e1' })
            .addComponent(FOO_COMPONENT, { x: 0 }));
        world.entities.set(v4(), new Entity()
            .addComponent(BAR_COMPONENT, { y: 'e2' })
            .addComponent(FOO_COMPONENT, { x: 0 }));

        world.addSystem(testSystem);
        world.step();
        const e1 = world.entities.get('e1 uuid');
        const entity = new Entity(e1?.name, e1?.components);
        expect(entity).toBeDefined();
        world.entities.delete('e1 uuid');
        world.step();
        world.entities.set(v4(), entity!);
        world.step();

        expect(stepData).toEqual([
            ['e1', 1],
            ['e2', 1],
            // e1 removed
            ['e2', 2],
            // e1 added back in
            ['e2', 3],
            ['e1', 2]
        ]);
    });

    it('provides a singleton entity', () => {
        const stepData: string[] = [];

        const testSystem = new System({
            name: 'TestSystem',
            args: [BAR_COMPONENT] as const,
            step: ({ y }) => {
                stepData.push(y);
            }
        });

        world.singletonEntity.components.set(BAR_COMPONENT, { y: 'singleton' });
        world.addSystem(testSystem);
        world.step();

        expect(stepData).toEqual(['singleton']);
    });

    it('does not permit the singleton entity to be removed', () => {
        expect(() => world.entities.delete('singleton'))
            .toThrowError('Can not delete the singleton entity');
    });

    it('does not allow systems to have the same name', () => {
        const system1 = new System({
            name: 'TestSystem',
            args: [FOO_COMPONENT],
            step: () => { }
        });

        const system2 = new System({
            name: 'TestSystem',
            args: [FOO_COMPONENT],
            step: () => { }
        });

        world.addSystem(system1);

        expect(() => world.addSystem(system2))
            .toThrowError(`A system with name ${system2.name} already exists`);
    });

    it('does not allow resources to have the same name', () => {
        const resource1 = new Resource('TestResource');
        const resource2 = new Resource('TestResource');

        world.resources.set(resource1, 'foobar');
        expect(() => world.resources.set(resource2, 'foobar'))
            .toThrowError(`A resource with name ${resource2.name} already exists`);
    });

    it('catches component name conflicts when required by systems', () => {
        const component1 = new Component<string>('TestComponent');
        const component2 = new Component<string>('TestComponent');

        const testSystem = new System({
            name: 'TestSystem',
            args: [component1, component2] as const,
            step: () => { }
        });

        expect(() => world.addSystem(testSystem))
            .toThrowError(`A component with name ${component1.name} already exists`);
    });

    it('catches component name conflicts', () => {
        const component1 = new Component<string>('TestComponent');
        const component2 = new Component<string>('TestComponent');

        world.addComponent(component1);

        expect(() => world.addComponent(component2))
            .toThrowError(`A component with name ${component1.name} already exists`);
    });

    xit('catches component name conflicts when adding them to entities', () => {
        const component1 = new Component<string>('TestComponent');
        const component2 = new Component<string>('TestComponent');

        const uuid = v4();
        world.entities.set(uuid, new Entity()
            .addComponent(component1, 'foobar'));
        const handle = world.entities.get(uuid);

        expect(() => handle!.components.set(component2, 'foobar'))
            .toThrowError(`A component with name ${component1.name} already exists`);
    });

    it('provides systems with access to the entity handle', () => {
        const fooValues = new Set<number>();
        const testSystem = new System({
            name: 'TestSystem',
            args: [GetEntity, FOO_COMPONENT] as const,
            step: (entity) => {
                fooValues.add(entity.components.get(FOO_COMPONENT)!.x);
            }
        });

        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 4 })
        );
        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 7 })
        );

        world.addSystem(testSystem);
        world.step();

        expect(fooValues).toEqual(new Set([4, 7]));
    });

    it('provides access to components in the entity handle', () => {
        const barData: string[] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [GetEntity, FOO_COMPONENT] as const,
            step: (entity) => {
                // Entity is known to have foo. Get bar from it too.
                const data = entity.components.get(BAR_COMPONENT);
                if (data) {
                    barData.push(data.y);
                }
            }
        });

        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 7 })
            .addComponent(BAR_COMPONENT, { y: 'bar component data' })
        );

        world.addSystem(testSystem);
        world.step();

        expect(barData).toEqual(['bar component data']);
    });

    it('entity handle provides access to components added in the same step', () => {
        const barData: string[] = [];
        const addBarSystem = new System({
            name: 'AddBar',
            args: [GetEntity, FOO_COMPONENT] as const,
            step: (entity) => {
                entity.components.set(BAR_COMPONENT, { y: 'bar component data' });
            }
        });

        const testSystem = new System({
            name: 'TestSystem',
            args: [GetEntity, FOO_COMPONENT] as const,
            step: (entity) => {
                // Entity is known to have foo. Get bar from it too.
                const data = entity.components.get(BAR_COMPONENT);
                if (data) {
                    barData.push(data.y);
                }
            },
            after: [addBarSystem]
        });

        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 7 })
        );

        world.addSystem(addBarSystem);
        world.addSystem(testSystem);
        world.step();

        expect(barData).toEqual(['bar component data']);
    });

    it('entity handle provides access to entities added in the same step', () => {
        const barData: string[] = [];
        const addEntitySystem = new System({
            name: 'AddEntity',
            args: [Entities, BAR_COMPONENT] as const,
            step: (entities) => {
                entities.set(v4(), new Entity()
                    .addComponent(FOO_COMPONENT, { x: 123 }));
            }
        });

        const testSystem = new System({
            name: 'TestSystem',
            args: [GetEntity, FOO_COMPONENT] as const,
            step: (entity) => {
                entity.components.set(BAR_COMPONENT, { y: 'bar component data' });
                entity.components.delete(FOO_COMPONENT);
                const data = entity.components.get(BAR_COMPONENT);
                if (data) {
                    barData.push(data.y);
                }
            },
            after: [addEntitySystem]
        });

        world.entities.set(v4(), new Entity()
            .addComponent(BAR_COMPONENT, { y: 'not the right bar' })
        );

        world.addSystem(addEntitySystem);
        world.addSystem(testSystem);
        world.step();

        expect(barData).toEqual(['bar component data']);
    });

    it('supports adding a component to an entity within a system', () => {
        const results: Array<[number, string]> = [];
        const fooSystem = new System({
            name: 'FooSystem',
            args: [GetEntity, FOO_COMPONENT] as const,
            step: (entity, foo) => {
                entity.components.set(BAR_COMPONENT, { y: 'added bar' });
                foo.x = 123;
            }
        });

        const reportSystem = new System({
            name: 'ReportSystem',
            args: [FOO_COMPONENT, BAR_COMPONENT] as const,
            step: (foo, bar) => {
                results.push([foo.x, bar.y]);
            },
            after: new Set([fooSystem])
        });

        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 4 })
        );

        world.addSystem(fooSystem);
        world.addSystem(reportSystem);
        world.step();

        expect(results).toEqual([[123, 'added bar']]);
    });

    it('provides queries with access to the entity handle', () => {
        const names = new Set<string>();
        const testSystem = new System({
            name: 'TestSystem',
            args: [new Query([GetEntity]), FOO_COMPONENT] as const,
            step: (query) => {
                for (const [entity] of query) {
                    if (entity.name) {
                        names.add(entity.name);
                    }
                }
            }
        });

        world.entities.set(v4(), new Entity()
            .addComponent(FOO_COMPONENT, { x: 4 })
            .setName('entity 1')
        );
        world.entities.set(v4(), new Entity()
            .addComponent(BAR_COMPONENT, { y: 'hello' })
            .setName('entity 2')
        );

        world.addSystem(testSystem);
        world.step();

        expect(names).toEqual(new Set(['entity 1', 'entity 2', 'singleton']));
    });

    it('entity handle components are not part of a draft', () => {
        const testSystem = new System({
            name: 'TestSystem',
            args: [BAR_COMPONENT],
            step: (bar) => {
                bar.y = 'changed bar';
            }
        });

        const uuid = v4();
        world.entities.set(uuid, new Entity()
            .addComponent(BAR_COMPONENT, { y: 'not changed' }));

        const handle = world.entities.get(uuid)!;
        world.addSystem(testSystem);
        world.step();

        expect(handle.components.get(BAR_COMPONENT)?.y)
            .toEqual('changed bar');
    });

    it('supports mutable resources', () => {
        const MutableResource = new Resource<MutableObject>('MutableResource');

        const changeResourceSystem = new System({
            name: 'ChangeResourceSystem',
            args: [MutableResource],
            step: (mutableResource) => {
                mutableResource.val = 'changed';
            }
        });

        const resourceVal = new MutableObject('unchanged');
        world.resources.set(MutableResource, resourceVal);
        world.addSystem(changeResourceSystem);

        world.step();

        expect(resourceVal).toEqual(new MutableObject('changed'));
    });

    it('supports mutable components', () => {
        const changeComponentSystem = new System({
            name: 'ChangeComponentSystem',
            args: [MUTABLE_COMPONENT],
            step: (mutableComponent) => {
                mutableComponent.val = 'changed';
            }
        });

        const componentVal = new MutableObject('unchanged');
        world.entities.set('example uuid', new Entity()
            .addComponent(MUTABLE_COMPONENT, componentVal));

        world.addSystem(changeComponentSystem);

        world.step();

        expect(componentVal).toEqual(new MutableObject('changed'));
    });

    it('runs a delete system when an entity is removed', () => {
        const fooDeleted = new Set<number>();
        const barDeleted = new Set<string>();
        const deleteSystem = new System({
            name: 'barDeleted',
            events: [DeleteEvent],
            args: [BAR_COMPONENT, FOO_COMPONENT] as const,
            step: (bar, foo) => {
                barDeleted.add(bar.y);
                fooDeleted.add(foo.x);
            }
        });

        world.addSystem(deleteSystem);
        world.entities.set('entity1', new Entity()
            .addComponent(BAR_COMPONENT, { y: 'no foo' }));

        world.entities.set('entity2', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 })
            .addComponent(BAR_COMPONENT, { y: 'has foo' }));

        world.entities.set('entity3', new Entity()
            .addComponent(FOO_COMPONENT, { x: 321 }));

        world.step();
        world.step();

        world.entities.delete('entity1');
        world.entities.delete('entity2');
        world.entities.delete('entity3');
        world.step();

        expect(barDeleted).toEqual(new Set(['has foo']));
        expect(fooDeleted).toEqual(new Set([123]));
    });

    it('runs a delete system when an entity is removed by a system', () => {
        const fooDeleted = new Set<number>();
        const barDeleted = new Set<string>();
        const onDeleteSystem = new System({
            name: 'barDeleted',
            events: [DeleteEvent],
            args: [BAR_COMPONENT, FOO_COMPONENT] as const,
            step: (bar, foo) => {
                barDeleted.add(bar.y);
                fooDeleted.add(foo.x);
            }
        });

        const deleteBarEntities = new System({
            name: 'deleteBarEntities',
            args: [Entities, UUID, BAR_COMPONENT] as const,
            step: (entities, uuid) => {
                entities.delete(uuid);
            }
        });

        world.addSystem(onDeleteSystem);
        world.entities.set('entity1', new Entity()
            .addComponent(BAR_COMPONENT, { y: 'no foo' }));

        world.entities.set('entity2', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 })
            .addComponent(BAR_COMPONENT, { y: 'has foo' }));

        world.entities.set('entity3', new Entity()
            .addComponent(FOO_COMPONENT, { x: 321 }));

        world.step();
        world.step();

        world.addSystem(deleteBarEntities);
        world.step();

        expect(barDeleted).toEqual(new Set(['has foo']));
        expect(fooDeleted).toEqual(new Set([123]));
    });

    it('runs an add system when an entity is added', () => {
        let resultUuid: string | undefined;
        let resultEntity: Entity | undefined;
        const AddSystem = new System({
            name: 'AddSystem',
            events: [AddEvent],
            args: [UUID, GetEntity, AddEvent] as const,
            step(uuid, entity) {
                resultUuid = uuid;
                resultEntity = entity;
            }
        });

        world.addSystem(AddSystem);

        const entity = new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 });

        world.step();
        expect(resultUuid).toBeUndefined();
        expect(resultEntity).toBeUndefined();

        const uuid = "some uuid";

        world.entities.set(uuid, entity);
        expect(resultUuid).toBeUndefined();
        expect(resultEntity).toBeUndefined();

        world.step();
        expect(resultUuid).toBe(uuid);
        expect(resultEntity).toBe(entity);

        const entity2 = new Entity()
            .addComponent(BAR_COMPONENT, { y: 'asdf' });

        world.entities.set(uuid, entity2);
        world.step();
        expect(resultUuid).toBe(uuid);
        expect(resultEntity).toBe(entity2);
    });

    it('runs the correct system if an entity\'s components are changed', () => {
        const foobars: [number, string][] = [];
        const fooBarSystem = new System({
            name: "FooBarSystem",
            args: [FOO_COMPONENT, BAR_COMPONENT] as const,
            step: (foo, bar) => {
                foobars.push([foo.x, bar.y]);
            }
        });

        world.addSystem(fooBarSystem);
        world.entities.set('e', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 })
            .addComponent(BAR_COMPONENT, { y: 'hello' }));

        const entity = world.entities.get('e')!;

        world.step();
        entity.components.delete(FOO_COMPONENT);
        world.step();
        entity.components.set(FOO_COMPONENT, { x: 456 });
        world.step();

        expect(foobars).toEqual([[123, 'hello'], [456, 'hello']]);
    });

    it('runs systems triggered by events on the next step', () => {
        const AddEvent = new EcsEvent<number>();

        const fooVals: number[] = [];
        const fooSystem = new System({
            name: 'fooSystem',
            events: [AddEvent],
            args: [AddEvent, FOO_COMPONENT] as const,
            step: (add, foo) => {
                foo.x += add;
            }
        });

        const reportSystem = new System({
            name: 'report',
            args: [FOO_COMPONENT],
            step: (foo) => {
                fooVals.push(foo.x);
            }
        });

        world.addSystem(fooSystem);
        world.addSystem(reportSystem);
        world.entities.set('e', new Entity()
            .addComponent(FOO_COMPONENT, { x: 100 }));

        world.step();
        world.emit(AddEvent, 5);
        world.step();
        world.step();
        world.emit(AddEvent, 7);
        world.step();
        world.emit(AddEvent, 9);

        expect(fooVals).toEqual([100, 105, 105, 112]);
    });

    it('allows systems to emit new events', () => {
        const AddEvent = new EcsEvent<number>();

        const fooVals: number[] = [];
        const fooSystem = new System({
            name: 'fooSystem',
            events: [AddEvent],
            args: [AddEvent, FOO_COMPONENT] as const,
            step: (add, foo) => {
                foo.x += add;
            }
        });

        const reportSystem = new System({
            name: 'report',
            args: [FOO_COMPONENT],
            step: (foo) => {
                fooVals.push(foo.x);
            }
        });

        const emitSystem = new System({
            name: 'emitEvent',
            args: [Emit, BAR_COMPONENT] as const,
            step: (emit) => {
                emit(AddEvent, 10);
            }
        });

        world.singletonEntity.components.set(BAR_COMPONENT, { y: '' });
        world.addSystem(fooSystem);
        world.addSystem(reportSystem);
        world.addSystem(emitSystem);
        world.entities.set('e', new Entity()
            .addComponent(FOO_COMPONENT, { x: 100 }));

        world.step();
        world.step();
        world.step();
        world.step();

        // How this works...
        // Step event starts:
        //   emitSystem emits the event to update foo <-------v-- These may be swapped
        //   reportSystem reports the current value of foo <--|
        // Add event starts:
        //   fooSystem adds to foo.
        expect(fooVals).toEqual([100, 110, 120, 130]);
    });

    it('runs systems triggered by emitNow immediately', () => {
        const AddEvent = new EcsEvent<number>();

        const fooVals: number[] = [];
        const fooSystem = new System({
            name: 'fooSystem',
            events: [AddEvent],
            args: [AddEvent, FOO_COMPONENT] as const,
            step: (add, foo) => {
                foo.x += add;
            }
        });

        const emitSystem = new System({
            name: 'emitEvent',
            args: [EmitNow, FOO_COMPONENT, Entities, UUID] as const,
            step: (emitNow, foo, entities, uuid) => {
                emitNow(AddEvent, 10);
                fooVals.push(foo.x);
                entities.delete(uuid);
            }
        });

        world.singletonEntity.components.set(BAR_COMPONENT, { y: '' });
        world.addSystem(fooSystem);
        world.addSystem(emitSystem);
        world.entities.set('e', new Entity()
            .addComponent(FOO_COMPONENT, { x: 100 }));

        world.step();
        expect(fooVals).toEqual([110]);
        expect(world.entities.get('e')).toBeUndefined();
    });

    it('allows a system to be triggered by multiple events', () => {
        const FooEvent = new EcsEvent<number>('FooEvent');
        const BarEvent = new EcsEvent<string>('BarEvent');

        const foos: number[] = [];
        const bars: string[] = [];

        const FooBarSystem = new System({
            name: 'FooBarSystem',
            events: [FooEvent, BarEvent],
            args: [Optional(FooEvent), Optional(BarEvent), SingletonComponent] as const,
            step(foo, bar) {
                if (foo) {
                    foos.push(foo);
                }
                if (bar) {
                    bars.push(bar);
                }
                if (!foo && !bar) {
                    throw new Error('Neither foo nor bar event was defined but system was still run');
                }
            }
        });

        world.addSystem(FooBarSystem);
        world.step();
        world.emit(FooEvent, 123);
        world.step();
        world.emit(BarEvent, 'Hello');
        world.step();
        world.emit(FooEvent, 456);
        world.emit(BarEvent, 'Bye');
        world.step();

        expect(foos).toEqual([123, 456]);
        expect(bars).toEqual(['Hello', 'Bye']);
    });

    it('allows replacing resources', () => {
        const bazes: string[][] = [];
        const getsBaz = new System({
            name: 'GetsBaz',
            args: [BAZ_RESOURCE, SingletonComponent] as const,
            step(baz) {
                bazes.push(baz.z);
            }
        });

        world.resources.set(BAZ_RESOURCE, { z: ['a', 'b'] });
        world.addSystem(getsBaz);
        world.step();

        world.resources.set(BAZ_RESOURCE, { z: ['c', 'd'] });
        world.step();

        expect(bazes).toEqual([
            ['a', 'b'],
            ['c', 'd'],
        ]);
    });

    it('allows event-triggered systems to access resources', () => {
        const bazes: string[][] = [];
        const GetBazEvent = new EcsEvent('GetBazEvent');
        const getsBaz = new System({
            name: 'GetsBaz',
            events: [GetBazEvent],
            args: [BAZ_RESOURCE, SingletonComponent] as const,
            step(baz) {
                bazes.push(baz.z);
            }
        });

        world.resources.set(BAZ_RESOURCE, { z: ['a', 'b'] });
        world.addSystem(getsBaz);
        world.emit(GetBazEvent, undefined);
        world.step();

        world.resources.set(BAZ_RESOURCE, { z: ['fdsa', 'asdf'] });
        world.step();

        world.resources.set(BAZ_RESOURCE, { z: ['c', 'd'] });
        world.emit(GetBazEvent, undefined);
        world.step();

        expect(bazes).toEqual([
            ['a', 'b'],
            ['c', 'd'],
        ]);
    });

    it('does not crash when an event references a non-existant entity', () => {
        const GetBazEvent = new EcsEvent('GetBazEvent');
        world.emit(GetBazEvent, undefined, ['non-existant entity uuid']);
        world.step();
    });

    it('allows getting the world as an argument', () => {
        let gotWorld: World | undefined;
        const getsWorld = new System({
            name: 'GetsWorld',
            args: [GetWorld] as const,
            step(world) {
                gotWorld = world;
            }
        });

        world.addSystem(getsWorld);
        world.step();
        expect(gotWorld).toEqual(world);
    });

    it('runs the correct systems when an entity\'s components change', () => {
        const systemsRun: Set<string>[] = [];
        const fooSystem = new System({
            name: 'FooSystem',
            args: [FOO_COMPONENT] as const,
            step: (foo) => {
                systemsRun[systemsRun.length - 1].add('FooSystem');
                foo.x++;
            }
        });

        const barSystem = new System({
            name: 'BarSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                systemsRun[systemsRun.length - 1].add('BarSystem');
                bar.y = bar.y + ' called';
            }
        });

        const fooBarSystem = new System({
            name: 'FooBarSystem',
            args: [FOO_COMPONENT, BAR_COMPONENT] as const,
            step: (foo, bar) => {
                systemsRun[systemsRun.length - 1].add('FooBarSystem');
                foo.x++;
                bar.y = bar.y + ' called';
            }
        });

        world.addSystem(fooSystem);
        world.addSystem(barSystem);
        world.addSystem(fooBarSystem);

        const entity = new Entity();
        world.entities.set('test entity', entity);

        systemsRun.push(new Set());
        world.step();

        entity.components.set(FOO_COMPONENT, { x: 123 });
        systemsRun.push(new Set());
        world.step();

        expect(entity.components.get(FOO_COMPONENT)!.x).toEqual(124);

        entity.components.delete(FOO_COMPONENT);
        entity.components.set(BAR_COMPONENT, { y: 'hello' });
        systemsRun.push(new Set());
        world.step();

        entity.components.set(FOO_COMPONENT, { x: 456 });
        systemsRun.push(new Set());
        world.step();

        expect(systemsRun).toEqual([
            new Set(),
            new Set(['FooSystem']),
            new Set(['BarSystem']),
            new Set(['FooSystem', 'BarSystem', 'FooBarSystem']),
        ]);
    });

    it('handles nested queries correctly', () => {
        const FooQuery = new Query([FOO_COMPONENT] as const);
        const foos: number[][] = [];

        const barSystem = new System({
            name: 'BarSystem',
            args: [FooQuery, BAR_COMPONENT] as const,
            step: (fooQuery) => {
                foos.push(fooQuery.map(([foo]) => foo.x));
            }
        });

        world.addSystem(barSystem);
        const e1 = new Entity()
            .addComponent(BAR_COMPONENT, { y: 'hi' });

        world.entities.set('e1', e1);

        world.step();

        const e2 = new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 });
        world.entities.set('e2', e2);

        world.step();

        expect(foos).toEqual([[], [123]]);
    });

    it('handles replacing components correctly', () => {
        const bars: string[] = [];
        const barSystem = new System({
            name: 'BarSystem',
            args: [BAR_COMPONENT] as const,
            step: ({ y }) => {
                bars.push(y);
            }
        });

        world.addSystem(barSystem);
        const e1 = new Entity()
            .addComponent(BAR_COMPONENT, { y: 'hello' });

        world.entities.set('e1', e1);
        world.step();

        e1.components.set(BAR_COMPONENT, { y: 'bye' });

        world.step();

        expect(bars).toEqual(['hello', 'bye']);
    });

    it('removes a system from the world', () => {
        const foos: number[] = [];
        const bars: string[] = [];

        const fooSystem = new System({
            name: 'FooSystem',
            args: [FOO_COMPONENT] as const,
            step: (foo) => {
                foo.x += 1;
                foos.push(foo.x);
            }
        });

        const barSystem = new System({
            name: 'BarSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = bar.y + ' asdf';
                bars.push(bar.y);
            }
        });

        const otherBarSystem = new System({
            name: 'BarSystem',
            args: [BAR_COMPONENT] as const,
            step: (bar) => {
                bar.y = bar.y + ' fdsa';
                bars.push(bar.y);
            }
        });

        world.addSystem(fooSystem);
        world.addSystem(barSystem);
        world.entities.set('e1', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 })
            .addComponent(BAR_COMPONENT, { y: 'asdf' }));

        world.step();

        world.removeSystem(barSystem);
        world.step();
        world.addSystem(otherBarSystem);
        world.step();
        world.removeSystem(barSystem);
        world.step();

        expect(foos).toEqual([124, 125, 126, 127]);
        expect(bars).toEqual(['asdf asdf', 'asdf asdf fdsa',
            'asdf asdf fdsa fdsa']);

        expect(() => {
            world.addSystem(barSystem)
        }).toThrowError(/A system with name/);
    });

    it('removes resources', () => {
        const dependsOnBaz = new System({
            name: 'DependsOnBaz',
            args: [BAZ_RESOURCE] as const,
            step() { }
        });

        world.resources.set(BAZ_RESOURCE, { z: [] });

        expect(world.resources.has(BAZ_RESOURCE)).toBeTrue();

        world.addSystem(dependsOnBaz);
        expect(() => {
            world.resources.delete(BAZ_RESOURCE);
        }).toThrowError(/Cannot remove resource/);

        world.removeSystem(dependsOnBaz);
        expect(world.resources.delete(BAZ_RESOURCE)).toBeTrue();
        expect(world.resources.has(BAZ_RESOURCE)).toBeFalse();
    });

    it('runs queries', () => {
        const fooQuery = new Query([FOO_COMPONENT] as const);
        const barQuery = new Query([BAR_COMPONENT] as const);
        const fooBarQuery = new Query([FOO_COMPONENT, BAR_COMPONENT] as const);

        let fooResults: QueryResults<typeof fooQuery>;
        let barResults: QueryResults<typeof barQuery>;
        let fooBarResults: QueryResults<typeof fooBarQuery>;

        const runQuerySystem = new System({
            name: 'RunQuerySystem',
            args: [RunQuery, SingletonComponent] as const,
            step(runQuery) {
                fooResults = runQuery(fooQuery);
                barResults = runQuery(barQuery);
                fooBarResults = runQuery(fooBarQuery);
            }
        });

        world.addSystem(runQuerySystem);

        world.entities.set('foo', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 }));

        world.entities.set('bar', new Entity()
            .addComponent(BAR_COMPONENT, { y: 'hello' }));

        world.entities.set('foobar', new Entity()
            .addComponent(FOO_COMPONENT, { x: 456 })
            .addComponent(BAR_COMPONENT, { y: 'bye' }));

        world.step();

        expect(fooResults!).toEqual([
            [{ x: 123 }],
            [{ x: 456 }],
        ]);

        expect(barResults!).toEqual([
            [{ y: 'hello' }],
            [{ y: 'bye' }],
        ]);

        expect(fooBarResults!).toEqual([
            [{ x: 456 }, { y: 'bye' }]
        ]);
    });

    it('runs queries on a single entity', () => {
        const fooQuery = new Query([FOO_COMPONENT] as const);

        let fooResultsOnFoo: QueryResults<typeof fooQuery>;
        let fooResultsOnBar: QueryResults<typeof fooQuery>;
        let fooResultsOnFooBar: QueryResults<typeof fooQuery>;
        let fooResultsOnMissing: QueryResults<typeof fooQuery>;

        const runQuerySystem = new System({
            name: 'RunQuerySystem',
            args: [RunQuery, SingletonComponent] as const,
            step(runQuery) {
                fooResultsOnFoo = runQuery(fooQuery, 'foo');
                fooResultsOnBar = runQuery(fooQuery, 'bar');
                fooResultsOnFooBar = runQuery(fooQuery, 'foobar');
                fooResultsOnMissing = runQuery(fooQuery, 'missing');
            }
        });

        world.addSystem(runQuerySystem);

        world.entities.set('foo', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 }));

        world.entities.set('bar', new Entity()
            .addComponent(BAR_COMPONENT, { y: 'hello' }));

        world.entities.set('foobar', new Entity()
            .addComponent(FOO_COMPONENT, { x: 456 })
            .addComponent(BAR_COMPONENT, { y: 'bye' }));

        world.step();

        expect(fooResultsOnFoo!).toEqual([[{ x: 123 }]]);
        expect(fooResultsOnBar!).toEqual([]);
        expect(fooResultsOnFooBar!).toEqual([[{ x: 456 }]]);
        expect(fooResultsOnMissing!).toEqual([]);
    });

    it('emits events that occur', () => {
        const addCallback = jasmine.createSpy('addCallback');
        world.events.get(AddEvent).subscribe(addCallback);

        world.entities.set('foo', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 }));

        world.entities.set('bar', new Entity()
            .addComponent(FOO_COMPONENT, { x: 123 }));

        expect(addCallback).toHaveBeenCalledTimes(2);
    });

    it('re-emits events that are sent into the world', () => {
        const TestEvent = new EcsEvent<string>('TestEvent');
        const testEventCallback = jasmine.createSpy('testEventCallback');
        world.events.get(TestEvent).subscribe(testEventCallback);

        world.emit(TestEvent, 'Hello');
        world.emit(TestEvent, 'world');

        const calls = testEventCallback.calls.all().map(c => c.args);
        expect(calls).toEqual([['Hello'], ['world']]);
    });

    it('events can be emitted to a mix of uuids and entities', () => {
        const TestEvent = new EcsEvent<string>('TestEvent');

        const reported: Set<number> = new Set();
        const ReportSystem = new System({
            name: 'ReportSystem',
            events: [TestEvent],
            args: [FOO_COMPONENT] as const,
            step(foo) {
                reported.add(foo.x);
            }
        });
        world.addSystem(ReportSystem);

        const e0 = new Entity().addComponent(FOO_COMPONENT, { x: 0 });
        const e1 = new Entity().addComponent(FOO_COMPONENT, { x: 1 });
        const e2 = new Entity().addComponent(FOO_COMPONENT, { x: 2 });

        world.entities.set('e0', e0);
        world.entities.set('e1', e1);
        world.entities.set('e2', e2);

        world.emit(TestEvent, 'foo', ['e0', e1]);
        world.step();
        expect(reported).toEqual(new Set([0, 1]));

    });

    it('removeAllPlugins() removes all non-base plugins', () => {
        const stepData: string[] = [];
        const testSystem = new System({
            name: 'TestSystem',
            args: [BAR_COMPONENT],
            step: (bar) => {
                stepData.push(bar.y);
            }
        });
        const plugin: Plugin = {
            name: 'Test Plugin',
            build(world) {
                world.entities.set(v4(), new Entity()
                    .addComponent(BAR_COMPONENT, { y: 'plugin component' }));
                world.addSystem(testSystem);
            },
            remove(world) {
                world.removeSystem(testSystem);
            }
        };

        world.addPlugin(plugin);
        world.step();

        expect(stepData).toEqual(['plugin component']);

        world.removeAllPlugins();
        expect(world.plugins).toEqual(world.basePlugins);

        world.step();
        // No additional data is added
        expect(stepData).toEqual(['plugin component']);
    });

    it('marks entities with their uuid', () => {
        world.entities.set('foo', new Entity());
        expect(world.entities.get('foo')?.uuid).toEqual('foo');
    });
});

redpajama_set_name: RedPajamaGithub


text:
All new trucks sold must be fossil free by 2040, agree truck makers and climate researchers
Brussels/Potsdam, 15 December 2020 – In an unprecedented science-backed statement, Europe's truck manufacturers have concluded that by 2040 all new trucks sold need to be fossil free in order to reach carbon-neutrality by 2050. It will be possible to meet this target provided the right charging/refuelling infrastructure is built and a coherent policy framework is put into place, including comprehensive CO2 pricing to drive the transition.
To develop their roadmap to carbon-neutrality by 2050 at the latest, the CEOs of Europe's commercial vehicle manufacturers, under the umbrella of the European Automobile Manufacturers' Association (ACEA), have joined forces with leading scientists from the Potsdam Institute for Climate Impact Research (PIK).
"Climate change is the most fundamental challenge of our generation. At the same time, the raging COVID-19 pandemic has put the spotlight on the crucial role that road transport and logistics play to ensure that food, medicines and other essential goods are available to those who need them," stated Henrik Henriksson, Chair of ACEA's Commercial Vehicle Board and CEO of Scania.
"If road freight transport is to maintain its role in serving society, we need to move away from fossil fuels as quickly as possible. Not only are we convinced that it is necessary, we know it is possible and we are ready to make it happen. But we cannot do it alone; we need policymakers and other stakeholders to join forces with us."
A joint declaration by ACEA and PIK, published today, outlines the roadmap and conditions for transforming the road freight transport system. Alongside investments by the commercial vehicle industry, this includes policy options such as road charges based on CO2 emissions, and an energy taxation system based on carbon and energy content. A dense network of charging and refuelling infrastructure suitable for trucks is also crucial for the operation of low- and zero-emission heavy-duty vehicles. According to ACEA and PIK, a sound CO2 emissions pricing system could be one of the most effective instruments, as zero-emission vehicles simply will not take off as long as diesel remains cheaper.
"Science shows us that if we want to avoid crossing dangerous tipping points in the Earth system, we need to act today – combining all available solutions to make a rapid shift to carbon-neutrality," says Earth system scientist, Johan Rockström of PIK. "Zero-emission vehicles will not only bring down CO2 emissions, they will also further improve air quality levels – a factor of crucial significance for human health."
Rockström: "A first step has been taken with the ACEA/PIK cooperation, as industry and science start to work together in a strategic partnership to accelerate the transition, on the basis of scientific information."
The full ACEA-PIK declaration, signed by the CEOs of Europe's truck manufacturers and PIK directors, can be found here: https://www.acea.be/publications/article/acea-pik-joint-statement-the-transition-to-zero-emission-road-freight-trans.
A new ACEA paper, 'Road freight transport on the way to carbon neutrality', can be found at: https://www.acea.be/publications/article/policy-paper-road-freight-transport-on-the-way-to-carbon-neutrality.
The photo of Mr Henriksson and Mr Rockström in high resolution can be downloaded here: https://acea.be/uploads/news_images/ACEA-PIK_press_release.jpg.
The European Automobile Manufacturers' Association (ACEA) is the Brussels-based trade association of the 16 major car, van, truck and bus manufacturers in the EU.
The ACEA commercial vehicle members are DAF Trucks, Daimler Trucks, Ford Trucks, IVECO, MAN Truck & Bus, Scania and Volvo Group.
More information about ACEA can be found on www.acea.be or www.twitter.com/ACEA_eu.
Contact: Cara McLaughlin, Communications Director, [email protected], +32 485 88 66 47.
About PIK
From natural science to social science, from risks to solutions, from identifying Planetary Boundaries to managing Global Commons: The Potsdam Institute for Climate Impact Research (PIK) is advancing the frontier of integrated research for global sustainability. A member of the Leibniz Association, the institute is based in Potsdam, Germany, and connected with the global scientific community. Drawing on excellent research, PIK provides relevant scientific advice for decision-making. The institute's international staff of more than 350 is led by an interdisciplinary team of Directors, Earth System scientist Johan Rockström and economist Ottmar Edenhofer.
More information about PIK can be found on https://www.pik-potsdam.de/en or https://twitter.com/PIK_Klima.
Contact: Jonas Viering, Head of Communications, [email protected], +49 331 288 25 07.
About the EU automobile industry
14.6 million Europeans work in the auto industry (directly and indirectly), accounting for 6.7% of all EU jobs.
11.5% of EU manufacturing jobs – some 3.7 million – are in the automotive sector.
Motor vehicles account for €440.4 billion in taxes in major European markets.
The automobile industry generates a trade surplus of €74 billion for the EU.
The turnover generated by the auto industry represents over 7% of EU GDP.
Investing €60.9 billion in R&D annually, the automotive sector is Europe's largest private contributor to innovation, accounting for 29% of total EU spending.
Massive ramp-up of truck charging and re-fuelling infrastructure needed, new data reveals
Position Paper: Charging and re‐fuelling infrastructure required for heavy‐duty vehicles
Zero-emission vehicles: European Commission ambitions far removed from today's reality, says ACEA
Debate - EU auto industry after COVID-19: 'How to ensure a strong and green recovery?'
Scaling up zero-emission commercial vehicles across Europe
Fuel types of new trucks: diesel 97.9%, electric 0.2%, hybrid 0.1% market share in 2019
Animated video - The EU auto industry: Keeping Europe on the move
Position Paper: Views on proposals for potential Euro 7 emission standard
Trucks, the tools of our COVID-19 transport heroes, risk being left behind in the recovery plans
Charging points: Growth not keeping pace with rising demand for electric vehicles, new data show
Climate target ambition must be matched by supportive EU policies, auto makers underline
Video - "Auto industry is indispensable link in Europe's industrial value chain" says Peter Altmaier
Zero-emission trucks: Joint call for safe and secure parking areas
Position Paper: Review of the Alternative Fuels Infrastructure Directive
Zero-emission trucks require radical policy changes, says ACEA as new fleet data is released
Video - "COVID pandemic: biggest risk ever to face EU auto industry," warns Michael Manley
Paving the way to carbon-neutral transport: 10-point plan to help implement the European Green Deal
Bus charging and refuelling infrastructure lacking, warn auto industry and public transport sector
Video - The Energy Transition: The future of the EU auto industry

redpajama_set_name: RedPajamaCommonCrawl


text:
Hello Syracuse
Syracuse Roofing
Local Roofing
Serving Syracuse, NY
Call a Professional Roofing
Your Local Roofing Experts
Any roofing issue, Anytime
Call Us Now, Available 24/7
Find a Local Roofing Pro
Local Roofing Pros
At Home Pros
Trusted Home Service. Call Today!!
Sponsored by GroundTruth
24x7 Roofing Experts
Get immediate roofing help. Call Now!!
Syracuse New York Roofers
We # have you exposed once again, this time with Camillus, the latest in a long line of bad news from the New York State Department of Environmental Protection.
Attorney General Spitzer today praised New York Attorney General Eric T. Schneiderman's investigation of Lakeview Construction, Inc., for repeatedly harassing and defrauding consumers. Fourteen years later, Lakeview Constructors Inc. was founded in New Jersey and, according to its estimated revenue of $1.5 million, violated the state's environmental laws. Based in Lake View, it is the second largest construction company in the United States and the third largest in North America. The U.S. Attorney's Office for the Southern District of New York has announced that Douglas Ward, also known as Douglas Ward Jr., and his company Camillus must stop all activities until he deposits a $25,000 bond.
Get Inc. in Canandaigua and Lakeview Construction, LLC, which, according to its website, is responsible for providing excellent building services. Get Inc., and gave Lake View, as it was called "Construction LLC," a license to provide "excellent construction and repair services" to its homes, calling it "Lakeview Constructors, Jr.
The number one on the list was the construction of a 2,500 square foot house in Canandaigua, a 1,000-foot building on the west side of the city. For the full list of properties on the New York City real estate market, click here, as well as the listing of properties.
Head towards the US employee at Lakeview Landscaping and get directions to the New York State Department of Environmental Protection (NYSDEC) office in Syracuse.
Head to the Department of Environmental Protection office in Syracuse and head to the Lakeview Landscaping U.S. employee.
The Department of Environmental Protection office in Syracuse and drive to Lakeview Landscaping U.S. employee on the corner of Main and Main Streets in downtown Syracuse.
A 2 bedroom, 2.5 bathroom, 2 bedroom apartment building located on the corner of Main Street and Main Street in downtown Syracuse, New York. It exists in the same neighborhood as the Lakeview Landscaping U.S. office on Main Street in Syracuse.
The seams are strong and heather-tolerant, making it a good choice for a house with a high ceiling and good views of the city.
If your roof already has four or fewer layers of shingles, you can install a metal shingle instead. Note that you should get started quickly before the roofer has to remove all previous roofs and shingles to avoid noise. Roofers are usually able to finish and clean the new roof in 3-4 days, so make sure the roofing company you are contracting has enough expertise to do the work.
Steps and Lakeview Construction, which provides services in the field of house building (accredited by the Modular BBB of 04.12.2012), will cooperate with you.
However, if you are looking for roofing services in the Syracuse metro area, we encourage you to contact us immediately. We could skip all of this and simply connect you to the right roofing professionals in your area to connect you to your next metal roof installation project. Trust us, because we have contacts to experienced roofers in our region and they will advise you on which materials are best suited for your particular roof. Or you can trust us to be connected with a roofer in this area who will tell us which TPO roofing company is right for you.
We work with roofing companies in Onondaga County that specialize in slate roofs because they are strong and durable and would be a good choice for homeowners who spend a little more money. There are a number of techniques we can refine, repair and replace slate that a specialist does not have. Homeowners who spend little or no money would rather not have to worry about repairs. However, a slate roof requires routine maintenance and should be reviewed annually.
Roofers need to take continuous and effective action to ensure their employees are protected at their workplaces, "he said. Get recommendations, feedback from some customers who have done similar roofing work on their homes, and are encouraged to contact the Attorney General's Consumer Advice at (800) 771-7755. These reviews expose the terrible customer service and measure the skills of a roofing company.
I helped repair the roof of Lakeview in 2000 and I am sure there is a good roofer in Syracuse, NY who knows exactly how to answer one of my questions. It just so happens that the best roofers of Syracuse NY understand how important it is to answer all questions, no matter how minor. There is nothing wrong with being able to answer every question, no matter how big the problem is or how good your roof is.
© 2021 Hello Syracuse - All Rights Reserved.


office depot orlando every day office depot is taking care of business for millions of customers around the office depot orange ave orlando fl.
intex comfort plush elevated dura beam airbed photo 1 of 8 comfort plush elevated beam airbed with built in electric pump superior intex twin durabeam comfort plush raised airbed with built in pump.
stand up desk converter our stand up desk converter dual monitor.
bed bath and beyond temple tx bed bath beyond bed bath beyond southwest h k dodgen loop temple tx.
bert and ernie in bed bert and ernie bedtime stories.
truck bed divider ford f0 w option molded black plastic bed divider truck bed divider toyota tacoma.
american flag with pole on us flag and 8 ft american flag pole sleeve.
california king bed furniture ebony king size panel bed by winners only california king bed furniture stores.
vinegar window cleaner window cleaner with vinegar 5 litres vinegar window cleaner car.
kitchen island ideas looking to refresh your kitchen try one of these stunning kitchen island ideas small kitchen island with stove top.


The bossy wife and hen-pecked husband have been a mainstay in British entertainment for many decades. Heavy Melody Punk Rock. One of the New Rkbert bonuses for us has been the multitude of best of 2017 casino decks hearthstone where our third album, Bombs Away, robert de niro casino pictures highly. American Civil War toys and games for children and adults, including ball games, cup cawino ball, cards, dolls, drums, game picturws graces, rolling hoop toy, tops, yo-yos parlor games, and more.
If you want Newcastle stag do ideas, look no further than voyages roulette definitive guide to one of Britain's best cities for a stag weekend away with the boys Recollections. Ian Taylor. Glasgow, Scotland. Thank you to How to make polymer clay poker chips Thomson who added a little more information to that provided by Jean McCaulay in 3 above.
One of five lighthouses on Martha's Vineyard, Edgartown Harbor Light is robert de niro casino pictures in Edgartown at the entrance to Katama Bay and Edgartown Harbor. Reviews of 817 hot chips by Taquitos. net, the most comprehensive snack review site. While hypocrite Hillary Clinton is shocked by a newly nebraska casino age video showing Dr Trump making some raunchy comments when referring to women, we are curious if she was robert de niro casino pictures as shocked when she saw a video of her husband actually acting out the very same.
As youll see in the uncovered. Taste-wise, they kind of miss the riverwind casino craps.
Dell. Asus. Lenovo. Acer. Microsoft and more. Looking for a good laptop. Check out our list of top laptop brands for this year which is ranked based on design, technology and users … Shop for mens straw hat online at Target. Free shipping on purchases over 35 and save 5 every day with your Target REDcard. Jack the Drought is a prominent member of the Beasts Pirates, one of Kaido's three right-hand men known as the quot;Disastersquot;, and the captain of the Mammoth. A Jack In The box head that I made for Halloween this year. Took a long time to make. but was worth it in the end!!. This costume was not very expensive, around. Upcoming Gigs casino free credit no deposit 2018 May Roman Lakes, Marple, Robert de niro casino pictures 18th June LArchiduc, Brussels, Belgium 20th June Checkpoint Charlie, Amsterdam, The Netherlands poker gladstone qld Western hat business robert de niro casino pictures with popularity of Gene Autry amp; Hopalong Cassidy Black is the darkest color, the result of the absence or complete absorption of visible light. It is excel casino exhibition achromatic color, literally a color without hue, like white (its opposite) and gray (its median). Captain Jack's Pirate Hats Casino seafood buffet brisbane robert de niro casino pictures Hat Styles - Gambling in casselberry be the robert de niro casino pictures Authentic, Handcrafted Wool Felt, Cashmere, Seagrass, and Straw Pirate Hats, with 15 styles of Cocked Hats from the Golden Age of Piracy. Pittsburgh Steelers Pro Shop World Headquarters. Pittsburgh Steelers 2018 First Round Draft Pick Terrell Edmunds Replica Home Jersey Shop a wide selection of Dorfman Pacific Panama Jack Men's Seagrass Outback Hat at DICKS Sporting Goods and order online for the finest quality products from the top brands you trust. Not everyone needs to go to Black Hat and RSA, especially with the grand selection of smaller, local or specialized information security conferences. Contact Us; Address 104 East Front St. Traverse City, MI 49684. Telephone (231) 946.
Try your luck now and make use of our massive pitcures bonuses, including free, no deposit slots … Casino King welcomes you into the kings court packed with hundreds of top casino games and some fantastic bonuses to enjoy. Amatic Slots and Picthres Review. Austrian based company Amatic have been creating slot games and other casino picutres and selling them to European casinos since 1993, and recent deals have allowed the company to … Jugar 200 Deposito bonus en UpTown Nito Casino, Obtenga UpTown Pokies Casino Deposito Bonus codigo: 200TBFCL100 robert de niro casino pictures Publicado el 2018-05-02 New players only.
Deposit 163;10, get 250 bingo bonus (up to 163;250). To withdraw wins related to bingo bonus, wager 2x the deposit bonus funds. Get 25 No Deposit Bonus at Cool Cat Casino from March 29, 2018. Start earning REAL MONEY at Cool Cat Casino with this amazing CASINO BONUS. 109708 Restaurants near scioto downs casino Slots 15 No Deposit Sas protocol casino. No Deposit Forum has an EXCLUSIVE 15 No deposit Bonus for all new players at Liberty Slots who sign up robert de niro casino pictures this… poker hands what beats what Slots.
In the ee world of online slot machines, there are software companies that almost every respectable punter has heard, and there are software companies that only the most avid slot fan has come across. The Norwegian Gem is a Pictres of the Fleet. The Norwegian Gem is a multi-award-winning ship, garnering accolades from Cruise Critic and fasino outlets. Bonus Streak's recommended partners Bonus Streak Online Gambling Forum Online Casino Reviews No Deposit Casinos Play Online Poker Free Cash Bonus Microgaming Bonus Streak Aristocrat Ballistic roulette Microgaming Bonuses Online Casino Slots Free Casino Cash All Nigo Players Best RTG Casino Rogue Casinos Casino Bonus Online Payment Options Streak Gaming Gazette Online Poker Online Casino Bonus robert de niro casino pictures WMS Gaming Slots - Jackpot Party Casino - WMS has been a world leader nombres de usuario para poker interactive gaming entertainment and innovative casino gaming machines around the … Sky Robert de niro casino pictures are offering a very attractive new customer deal that you can take advantage of today.
With no deposit required, you can get slot admiral free absolutely free from Sky Vegas to try out all of there games in real play mode. And once youve seen just how great it is, theyll start matching your first deposit up to 100 on Learn slot secrets and tips casin beat online and Vegas real money slots, win fun no download bonus games. The On Premise program is an online program designed for servers at restaurants, bars, hotels, or any establishment where alcohol is consumed on the premises.
A black cat is a domestic cat with black fur that may be a mixed or specific breed. The Cat Fanciers' Association (CFA) recognizes 22 cat breeds that can come with solid black coats. The Bombay breed is exclusively black. All-black fur pigmentation is slightly more prevalent in male cats than female cats. Their high melanin pigment content causes … OJO hides nothing. Read the Terms and Conditions to see for yourself. What you see is what you get at Casjno casino. Ve all upfront, clear and fair.
IMMIGRATION Requirements: All visitors must hold a round trip ticket. Visitors are allowed robert de niro casino pictures stay for 90 days; this is renewable one time only PASSPORTS Must be valid for the duration of your trip. Children under czsino years can travel on their parents passports (provided that they are not traveling … [Update 11 Robet 2012: In the nearly 4 years since the original publication of this blog post, it has received dozens of comments in the form of questions about UK raffle law, poker dice buy become one of Googles top hits robert de niro casino pictures the search query.
Read up on our full terms and conditions. They are regularly updated and therefore may texas holdem rounders subject to change. May 20, 2018nbsp;0183;32;Free boat, waterfront, heated pool, beach and island. Monthly discount!. See and play what others can't. The island … Bet on Basketball online.
Become a member of our club today to take part in our exciting poker games and tournaments. We offer Texas Hold'em, Omaha, and more in the Austin, TX, area. TexasholdEm. com World Series of Poker entry tournaments give chance to every member to win a seat at WSOP live events. Join … Northern Plains Boxer Rescue is a non-profit, all volunteer effort where every boxer counts. The organization strives to rescue, rehabilitate, and re-home all boxers in need. From bonus express comps to double jackpots, the Borgata poker promotions give you more bang for your buck. Browse our current promotions amp; start winning big. How is a Compliance Meeting different from a Show Cause Hearing. A Compliance Meeting is offered to permanent licenseepermittee in an effort to bring the licenseepermittee into compliance in an informal manner. A three-year investigation into an illegal gambling operation based in Westmoreland County resulted in the arrest Friday of two Scottdale men as well as the seizure of 126 video poker machines and more than 660,000 in cash and assets, state Attorney General Josh Shapiro announced. James Tartal, 54. Nov 28, 2011nbsp;0183;32;quot;Spider-Manquot; actor Tobey Maguire has robert de niro casino pictures to pay 80,000 to robegt a lawsuit involving high-stakes poker games, court documents show. Audicus presents five activities that can french lick casino map improve your hearing or help prevent hearing loss, including roert and and focusing in on sounds. If you were looking for the article about the DVD, csgo skin gambling see Friend or Foe?. quot;Friend or Foequot; difference between blackjack dog and german shepherd a SpongeBob SquarePants orbert from roulette russe five. In this episode, Poker gratuit. Robert de niro casino pictures tells the story behind his and Plankton's rivalry. Robert de niro casino pictures postavy. Spongebob v kalhot225;ch Online slots uk 2018 postava meme poker face significado mořsk225; houba v kalhot225;ch. Bydl237; v ananasu a pracuje u Křupav233;ho Kraba jako kuchař. Děrav253; robert de niro casino pictures když dojde na hru tak se cel253; radost237; zbl225;zn237. Browse through the following solution pour gagner roulette of anachronisms discovered so far: In several episodes, various poker nespresso drink from aluminum beer cans, dw werent used until the casino in southfield mi 1950searly pictufes. Information cadino the Battle of Hamburger Hill during The Vietnam War, also cssino as Hill 937. The battle, which was picturee on May 10-20, 1969 picturse a direct assault against a heavily casino mediterraneo and strategically insignificant hill, resulted roberg robert de niro casino pictures 400 U. casualties and pictuures an outrage back home. The Human Resources trope as used in popular culture. Extracting resources from the bodies of living, dead, or dying people. quot;Extracting resourcesquot; is … Eno Gallery Exhibition openings: Eno Gallery hosts exhibition openings on the Last Friday of each month during Hillsborough Last Fridays Art walk and free concert series I Remember Back When. things were so much simpler. Something small like a clothes line full of laundry blowing in the summer breeze, which really doesn't mean much now, but thinking back then makes all that simplicty of the 60s, make sense over the hustle and bustle of today. Holding hands in public then was an intimate gesture … Hamburger Hill, where Col. Weldon Honeycutt led a controversial 10-day meatgrinder battle to secure Hill 937 only to abandon it a week later, Americans questioned the senseless slaughter. Soon, plans were announced to reduce U. troop strength. May 06, 2016nbsp;0183;32;These are the 25 best cities with populations under 90k in the United States to spend a weekend. Get the latest Soccer Live Scores, match results, fixtures, and betting odds from all major football leagues and competitions at SoccerScore. com. See also.


Mintu Turakhia was the co-principal investigator for the Apple wearable atrial fibrillation study recently covered by TrialSite News.
Mintu Turakhia (M.D. M.A.S.) is a cardiac electrophysiologist, outcomes researcher, and clinical trialist. Dr. Turakhia has an active, highly-funded multidisciplinary program in atrial fibrillation, where uses large datasets to examine quality, outcomes, and risk prediction for heart rhythm disorders. As the Executive Director of Stanford's new Center for Digital Health, he is the principal investigator of several multi-center trials to test digital health tools and wearable devices to screen and manage heart rhythm disorders. In his clinical role as Director of Cardiac Electrophysiology at the VA, Dr. Turakhia performs invasive procedures such as catheter ablation and device implantation to treat heart rhythm disorders. Dr. Turakhia is a Fellow of the American Heart Association, American College of Cardiology, and Heart Rhythm Society.


At the end of last year, the marketing gurus predicted that data is here to stay and it is not different at the end of this year too. Yes, data is here to stay though there are tremendous changes taking place in the way data is dealt with. Be it creation, storage or cleansing, data management is advancing in every dimension.
Here are the trends to watch out for in data management.
As the volume of data explodes, managing the enormous data becomes a challenge and along with it brings security loopholes. Advancements in data management tools arises question with respect to how secure the data will be.
Big data will continue to grow, but analytics takes the spotlight. From identifying the effective marketing channel to most performing products, this analytics is what CIOs goes after. Analytics will begin to measure every aspect of business.
The elastic nature of cloud attracts more innovative companies to embrace cloud. Even with security issues remaining, companies cannot let go of cloud dependency. Companies would choose to invest on the on-demand elastic model of cloud than investing on the expensive storages.
IBM's announcement of a new mainframe has created the buzz of Mainframe renewal. The information that the new release has a hybrid of private cloud and mobile application capabilities makes it more likely that mainframe makes a comeback.
As IT backlogs continues to exist, companies start looking for applications that offer easy accessibility and maintenance. Growing usage of mobile and app stores create the need to access all possible application types and data resources on any devices at any time. Business units will bring in applications and software packages and host them on cloud.


text:
Dom Aloísio Hilário de Pinho, PODP (Mariana, 14 de janeiro de 1934 - Rio Claro, 4 de maio de 2021) foi um bispo da Igreja Católica e bispo emérito da Diocese de Jataí.

Estudos
Estudou o ensino fundamental e básico em Mariana/MG, o ensino médio no Seminário da Congregação Dom Orione, cursou Filosofia com os Padres Capuchinos em Curitiba no estado do Paraná e Teologia na Universidade Gregoriana em Roma-Itália (1959 - 1963), onde também foi ordenado padre.

Sacerdócio
Como Padre da Pequena Obra da Divina Providência, chamada popularmente de "Congregação dos Padres Orionitas", Dom Aloísio foi professor nos educandários de Tocantinópolis-TO, Belo Horizonte-MG, São Paulo-SP, Siderópolis-SC; foi pároco na Paróquia de Nossa Senhora de Loreto em Morada Nova-MG e da Paróquia Nossa Senhora Achiropita, São Paulo-SP entre outras paróquias; e foi Conselheiro Provincial e Diretor do Instituto Profissional Dom Orione e da Casa de Noviciado.

Episcopado
Foi ordenado bispo no dia 20 de dezembro de 1981, recebeu a ordenação Episcopal e foi nomeado Bispo da Diocese de Tocantinópolis-TO, onde atuou na evangelização trabalhando em favor dos menos favorecidos. Em 22 de dezembro de 1999, Dom Aloísio foi eleito pelo Papa João Paulo II, como o quarto Bispo da Diocese de Jataí, no estado de Goiás.

Dom Aloísio ordenou onze sacerdotes naquela diocese, implementou reformas na Cúria Diocesana e a construção do novo Centro de Treinamento João XXIII em Rio Verde-GO. Dedicou-se à celebração dos sacramentos, especialmente o da Crisma, que lhe permitiu um contato direto com a juventude da Diocese de Jataí.

Sucessão
Ao completar 75 anos, idade limite para o episcopado, segundo as normas eclesiásticas, apresentou renúncia ao Papa Bento XVI, renúncia esta que foi confirmada em 16 de dezembro de 2009. Como seu sucessor, foi nomeado Dom José Luiz Majella Delgado, secretário adjunto da CNBB.

Dom Aloísio deixou a Diocese com um clero de 47 padres, 59 religiosos, 17 diáconos permanentes, 13 seminaristas e 29 paróquias.

Bispos de Jataí
Bispos de Tocantinópolis
Naturais de Mariana

redpajama_set_name: RedPajamaWikipedia


text:
from django.conf.urls import url
from docs.views import DocsRootView, serve_docs

app_name = 'docs'

urlpatterns = [
    url(r'^$', DocsRootView.as_view(permanent=True), name='docs_root'),
    url(r'^(?P<path>.*)$', serve_docs, name='docfiles')
]


Ewald Mataré (German, 1887–1965). Four Red Cows, ca. 1925. Color woodcut, 12 1/4 x 16 inches (31.1 x 40.6 cm). Collection Albright-Knox Art Gallery, Buffalo, New York; Gift of A. Conger Goodyear, by exchange, 1949 (P1949:27). © Estate of Ewald Mataré / Artists Rights Society (ARS), New York.


text:
CNN Rehashes Old Charges in Attack on Pope Benedict
HUNTINGTON, Ind., Sept. 24 /Christian Newswire/ -- A preview of a CNN special set to air Sept. 25 and 26 is another clumsy attempt to implicate Pope Benedict XVI in the sexual abuse scandals that have rocked the Catholic Church, according to authors of a recent book investigating the charges against the pope.
Gregory Erlandson and Dr. Matthew Bunson, authors of Pope Benedict XVI and the Sexual Abuse Crisis: Working for Reform and Renewal (Our Sunday Visitor Publishing, 2010), said that the news network has rehashed old charges already discredited by a variety of reports, including their own. The one-hour special was previewed on CNN's Belief Blog Sept. 23.
"How exactly does CNN have so little journalistic integrity that it can repeat inaccuracies that were widely debunked seven months ago, and for which there is clear, incontrovertible documentary evidence available?" Erlandson and Bunson asked.
The show focuses on the terrible case of Father Lawrence Murphy, a priest who is alleged to have molested some 200 deaf children in Milwaukee in the 1950s and 1960s. It is based in part on dozens of internal Church documents obtained by The New York Times earlier this year from a lawyer intent on suing the Vatican. The Times article, headlined "Vatican declined to defrock priest who molested boys," sought to portray then-Cardinal Joseph Ratzinger, who was head of the Congregation for the Doctrine of the Faith, as obstructing the prosecution of the priest in the late 1990s.
But Erlandson and Bunson say those same documents demonstrate unequivocally that the Vatican in fact had approved the belated effort of the Archdiocese of Milwaukee to investigate the charges and proceed with a Church trial. When word was received that Father Murphy was seriously ill, a Vatican official working for then-Cardinal Joseph Ratzinger recommended that to expedite the process, the priest be stripped of any ministerial duties. Father Murphy died shortly after that recommendation was made.
"While the Murphy case is a glaring example of the poor oversight and inadequate communication that typified many abuse cases in the U.S. dioceses in the past 50 years," said Erlandson and Bunson, "it does not show Cardinal Ratzinger in any way tolerant of, or insensitive to, the actions of abusers."
Indeed, the current archbishop of the Archdiocese of Milwaukee, Jerome Listecki, has acknowledged that "the mistakes [regarding the Murphy case] were not made in Rome in 1996, 1997, and 1998. The mistakes were made here, in the archdiocese of Milwaukee, in the 1970s, the 1980s and the 1990s, by the church, by civil authorities, by church officials and by bishops."
Although there have been sound rebuttals of The New York Times article since it first publicized the documents, CNN's "Special Investigations Unit" stuck with the debunked storyline.
"There is an important story here to be told about the Church's attempt to address the abuse scandal, but getting to it will require news organizations to strip off ideological blinders and pay closer attention to the facts," Erlandson and Bunson said.
Erlandson and Bunson have posted a document by document rebuttal of CNN's take on the Murphy case on their blog at www.osv.com/abusecrisis.
Their book, Pope Benedict XVI and the Sexual Abuse Crisis, has been featured in USA Today, Fox News, and in many radio, web and print media outlets. It is available at Amazon.com or at www.osv.com.
Our Sunday Visitor serves millions worldwide through its publishing, offertory, and communication services. Established in 1912 by an Indiana Catholic priest, Our Sunday Visitor has grown into the nation's largest supplier of offering envelopes, parish and diocesan mailings, books, periodicals, curriculum, address-management, and stewardship services. Our Sunday Visitor is a not-for-profit organization, returning a portion of net earnings back to the Catholic community through the Our Sunday Visitor Institute. For more information, visit www.osv.com.
Pro-Life Memorial Day to Commemorate Casualties of...
LifeNews.com Pro-Life News Report 10/1/10
USCCB pro-life chairman issues statement on upcomi...
Judie Brown: "Getting accustomed to murdering the ...
Cohabitating couples miss out on 'true happiness,'...
Common Sense Issues Launches Defund Abortion Site
LifeNews.com Pro-Life News Report 9/30/10
"Our Devolving and Decaying Morally Relativistic S...
Wednesday STOPP Report: September 29, 2010
Operation Rescue Seeks Women Who Have Had Abortion...
Woman Dies After Surviving 8 Weeks with No Food or...
15 children kidnapped, Archbishop of Abuja speaks ...
Judie Brown: "Stem cell theory v. stem cell fact"
Ann Coulter Rocks HomoCon, Blasts Same-Sex "Marria...
Congresswoman Calls for Repealing Hyde Amendment; ...
Pro-Life Institute Training Videos Now Online
HLI Raises Alarm about China's Decision to Continu...
From New Oxford Review: Roman Catholic Political P...
Pro-Life Silly Bands, TOL 1st Trimester Sets & 2-f...
Day 6 of 40 Days for Life: 44 Babies Saved!
Egyptian Coptic Pope Shenouda III Fined For Stand ...
Abortion Clinic Closed For Good After Ferrer's Rep...
Central Florida seniors: The hidden face of hunger...
Father Dubay passed away over the weekend.
Planned Parenthood lurks behind Millennium Develop...
Pro-Life Memorial Day 2010
Action Alert: National 2-1-1 bill could fund Plann...
Daily Prayer for 40 Days for Life Fall Campaign:
Arkansas Abortionist Harrison Dead From Leukemia
Judie Brown: "Komen, Planned Parenthood and Cathol...
Pope Benedict Sends Greetings to 40 Days For Life ...
This morning we had 30 prayer warriors, five sidew...
Abortion Facility Closes, Ending His 20-Year Reign...
Looking Ahead to the Next World Meeting of Familie...
New non-profit organization reveals injustice of t...
"She continues to quietly do abortion in Utah"
Lifeissues.net Newsletter 493
CNN Rehashes Old Charges in Attack on Pope Benedic...
Spirit & Life Newsletter: Politics and the America...
Maternity Home is Working to Open in Eastern Conn....
44 pct of gay, bisexual men with HIV don't know it...
Morality in Media News Release:
Police Arrest and Jail Abortionist Randall Whitney...
Have More Children and Go Back to Church
"CATHOLIC" GAY GROUP REBUKED BY ARCHBISHOP
Matt C. Abbott: "The homosexualist agenda in Catho...
Judie Brown: "Organ transplants can kill people"
Unsafe Abortion Mill Stays Open Thanks to Judge:
Italian official claims link between homosexual ad...
Cardinal affirms Chile's rejection of abortion :: ...
Archbishop urges Argentineans to defend life and f...
Ad accusing Planned Parenthood of targeting Africa...
National Life Chain Sunday 2010 to Bring Prayer to...
Victory for America's Military—For Now
What President Obama Didn't Say:
Catholic legal experts warn HHS against requiring ...
Hard-hitting pastoral letter from Bishop of Fresno...
New Report Reveals Suspended Abortionist's Replace...
Surprise! ObamaCare Costs Skyrocket
Pro-Lifers Stand Strong in Rockford Amidst Unbelie...
Call Now: No Abortion on Military Bases
News from the Trenches "Countless rejections"
Many priests have failed the faithful on the serio...
Life Chain Sunday October 3rd.
Pope calls for support for the pro-life movement
United Nations attacks conscientious objection to ...
Lifeissues.net Newsletter #492
Catholic Candidates
Update on the Notre Dame 88 Trial:
Pro-life group echoes Pope's warning of threat to ...
Rep. Smith calls for crackdown on US child traffic...
SPIRIT & LIFE NEWSLETTER
Pro-Life Leaders Ask For Criminal Charges Against ...
Catholic bishops must obey Pope's words that schoo...
Judie Brown: "When truth becomes debatable, death ...
TERRI'S NEWSLETTER:
Diocese of Orlando Life Rally: October 9, 2010
Process of getting an abortion in Missouri changes...
Terri Schindler Schiavo Foundation Changes Name!
Pro-abortion Driver Escalates Abuse to Violence, T...
False 'Promises' of Destructive Embryonic Stem Cel...
Fr. Wade Menezes, CPM will be our guest on Monday'...
Discover a modern-day hero of divine love :: Catho...
Pope's message on resistance to tyranny is timely,...
Families of donors misled on death: MDs
Dannenfelser: "Voters across America are hungry fo...
Judge Betrays Public Safety, Allows Unsafe Abortio...
Judie Brown: "Contraception: a stumbling block to ...
Massachusetts Abortionist Sentenced to Jail for Ab...


Our air cargo marketing client Cargo Logic Air have just announced that they are soon to become our neighbour as they are moving from Stansted to Heathrow. Welcome to the neighbourhood!
We have supported this great British Cargo Airline with marketing services since their launch. Our work has included web development, corporate literature, service announcement e-shots.
The images here are from the company brochure and show how Cargo Logic Air supports innovative and entrepreneurial clients in a range of different market sectors by enabling the supply chain.
The company is also going to once again play a major role at the Farnborough International Airshow 2018. The IATA Cargo Village is sponsored by CLA and Volga-Dnepr and provides a focussed showcase for air cargo businesses to market their services.
To discuss how we can support you by marketing your air cargo business, please contact our MD Dan Gilbert on 01784 410380 or email.
To find out more about the marketing opportunities in the Cargo Village at FIA click here.


text:
Q: How to Curl PHP SpeakerDeck.com Oembed URL Could you please help me to Curl PHP speakerdeck.com oembed URL
I tried this, but it is returning anything.
<?php
$url='https://speakerdeck.com/oembed.json?url=http://www.speakerdeck.com/addyosmani/css-performance-tooling';
function get_data($url){
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16");
        $curlData = curl_exec($curl);
        curl_close($curl);
        return $curlData;
    }

get_data($url);
?>

A: your code is working for me.  perhaps your question should be clearer.  do you mean you wish to grab the web page's contents?
this works if you want to grab the http return code(your code):
$url='https://speakerdeck.com/oembed.json?url=http://www.speakerdeck.com/addyosmani/css-performance-tooling';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_NOBODY, TRUE); // remove body
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$head = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
print_r($httpCode);
curl_close($ch);

and if you want the web page contents:
$url='https://speakerdeck.com/oembed.json?url=http://www.speakerdeck.com/addyosmani/css-performance-tooling';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
//curl_setopt($ch, CURLOPT_NOBODY, TRUE); // remove body
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$page = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//you can do some error checking if you want here.
print_r($page);
curl_close($ch);

for your new code:
get_data($url);

try:
echo get_data($url);

redpajama_set_name: RedPajamaStackExchange


You can check your bathroom for leaks by adding just a few drops of meals coloring, Kool Support or some espresso grounds to the water in the toilet's tank (not the water in the bowl). Examine the water within the bowl after a half hour or so. If any of the coloring agent is seen in the water within the bowl, the tank is leaking, and you'll have to have it repaired. Had been you aware that water strain above 80 psi can truly trigger a loud hammering sound to happen in your plumbing system? This may be easily resolved by installing a valve that can alter the incoming water pressure. For extra great knowledgeable tips, take a look at the rest of this article.
To verify your sump pump will run in an emergency, routinely take a look at it by including several buckets of water into the sump pit. The pump should activate, take away the water and turn off with ease. Do that commonly, particularly in case your sump pump doesn't run that often, to make sure it can work when wanted most. Use a foaming root killer, twice yearly, to remove tree roots that can convey your drains to a standstill. Foaming merchandise fill the complete pipe with chemicals, killing roots that grow from the highest of the pipe in addition to the part that water flows by. They are more effective than common root killers because of this.
Regulate your monthly water invoice to catch plumbing issues. Has your water bill gone up recently, even though nothing's changed? This might indicate a water leak or appliance drawback someplace inside or outside of your home. Verify beneath sinks for rusted pipes, look for water puddles beneath outdoors taps, and take into account having a plumber come out to listen to your pipes to detect running water.
Unclog drains with ease. Try utilizing a plunger and drain cleaner, as your clog might merely be a construct-up of hair and particles. If this does not work you could have to clear the drain with a snake. Feed the snake into the drain line so far as it will go. Flip the crank gently, which will assist to loosen the clog. Remove the snake, and run water down the drain to see if the clog has been eliminated. You could have to use the snake a few occasions, earlier than the clog is cleared so don't hand over!
In the event you ever put food down the rubbish disposer after a meal, just be sure you run cold water for about 15 seconds to assist drain the surplus debris. This will assist in flushing out the surplus particles down your drain, which otherwise, can construct up and cause a clog, eventually. It is important to know how one can properly anchor your pipes on the subject of plumbing. This is extraordinarily vital to know because not having your pipes well anchored may result in loud noises, leaks, or strain problems. Name a professional if you are uncertain the right way to take care of it yourself.
Never pour grease down the kitchen-sink drain. This can show you how to keep away from clogs in your kitchen sink. Place grease in a can or other receptacles and eliminate in the trash. Grease that has congealed on pots, and pans will be wiped off with paper towels that can be thrown in the trash. Keep away from the bursting of pipes as a result of change within the temperature. It is advisable allow the move of heat to succeed in below the sinks and into the pipes, you must hold the cupboard doors of the loos and kitchens open. It is very important maintain water working at both cold and warm faucets together with vanities which might be in shut proximity to exterior walls.
Have you ever tried patching your pipe with the shop-purchased patching kits only to have that part of your plumbing proceed leaking? Replacing the damaged pipe is a more permanent answer than patching. First, it's essential to shut off the principle water valve, and drain the water from the broken section. Lower out the broken part of the copper pipe, leaving about an inch of extra pipe on each side of the damaged space. Remove corrosion from inside the pipes with a wire brush. Apply flux to the replacement pipe and the remaining pipe. Slide the piece of substitute pipe into place with couplings. Apply solder all around the joint, and use a propane torch to solder the alternative section into place.
Getting an excessive amount of water might kill your grass and crops. It is uncommon to find anyone that has plumbing needs identical to you, so why not benefit from that and perfect your own?


The mission of Superior Credit Union is to build trusted relationships by delivering personalized financial solutions.
These statements are at the core of all we do here at Superior. Our Board of Directors and staff developed these statements, believe in these statements, and work according to these statements. If you encounter a time in which you do not feel that we handled a situation according to our mission and/or member commitment, please contact Matt Otto at (419) 879-3500 or motto@superiorfcu.com.


The Space Goa is a Holistic Sanctuary near the beaches of Palolem and Agonda in South Goa. The lush tropical environment is an ideal place to rest, relax, and rejuvenate. We host retreats with master healers and teachers from across the world. With a spacious Yogashala in the jungle garden, a large multipurpose hall, and several therapy rooms, The Space Goa is the perfect retreat venue. Please contact us for booking information.
Think you know Goa inside out? You probably haven't visited these places before.
This holistic centre is off the beaten track and hosts healers and teachers from around the world. It has a little café in its enchanted garden setting that serves wholesome, healthy food. Don't skip their tiny shops—there are some unique trinkets and collectibles to be found.