text:
// http://www.apache.org/licenses/LICENSE-2.0
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
#include "voxelworld/api.h"
#include "network/api.h"
#include "client_file/api.h"
#include "replicate/api.h"
#include "main_context/api.h"
#include "core/log.h"
#include "interface/module.h"
#include "interface/server.h"
#include "interface/event.h"
#include "interface/mesh.h"
#include "interface/voxel.h"
#include "interface/block.h"
#include "interface/voxel_volume.h"
#include "interface/polyvox_numeric.h"
#include "interface/polyvox_cereal.h"
#include "interface/polyvox_std.h"
#include "interface/os.h"
#include <PolyVoxCore/RawVolume.h>
#include <cereal/archives/portable_binary.hpp>
#include <cereal/types/string.hpp>
#include <Node.h>
#include <Scene.h>
#include <Model.h>
#include <RigidBody.h>
#include <CollisionShape.h>
#include <Context.h>
#include <ResourceCache.h>
#include <Light.h>
#include <Geometry.h>
#include <Zone.h>
#include <deque>
#include <algorithm>
#define MODULE "voxelworld"

using interface::Event;
namespace magic = Urho3D;
namespace pv = PolyVox;
using namespace Urho3D;
using interface::VoxelInstance;
using interface::container_coord;
using interface::container_coord16;

namespace voxelworld {

struct ChunkBuffer
{
	pv::Vector3DInt32 chunk_p; // For logging
	up_<pv::RawVolume<VoxelInstance>> volume;
	bool dirty = false; // If false, buffer has only been read from so far
	int64_t last_accessed_us = 0;

	ChunkBuffer(){}
	void timer_reset(const pv::Vector3DInt32 &chunk_p_){
		chunk_p = chunk_p_;
		last_accessed_us = interface::os::time_us();
	}
	bool unload_if_old(int64_t timeout_us){ // True if not loaded
		if(!volume)
			return true;
		if(interface::os::time_us() < last_accessed_us + timeout_us)
			return false;
		log_t(MODULE, "Unloading chunk " PV3I_FORMAT, PV3I_PARAMS(chunk_p));
		volume.reset();
		dirty = false;
		return true;
	}
};

struct Section
{
	SceneReference m_scene_ref;
	pv::Vector3DInt16 section_p; // Position in sections
	pv::Vector3DInt16 chunk_size;
	pv::Region contained_chunks; // Position and size in chunks
	// Static voxel nodes (each contains one chunk); Initialized to 0.
	sp_<pv::RawVolume<uint32_t>> node_ids;
	size_t num_chunks = 0;
	// Cache these for speed
	int w_chunks = 0;
	int h_chunks = 0;
	int d_chunks = 0;

	// Chunk buffers (index using get_chunk_i())
	sv_<ChunkBuffer> chunk_buffers;

	// TODO: Specify what exactly do these mean and how they are used
	bool loaded = false;
	bool save_enabled = false;
	bool generated = false;

	Section(): // Needed for containers
		chunk_size(0, 0, 0) // This is used to detect uninitialized instance
	{}
	Section(SceneReference scene_ref,
			pv::Vector3DInt16 section_p,
			pv::Vector3DInt16 chunk_size,
			pv::Region contained_chunks):
		m_scene_ref(scene_ref),
		section_p(section_p),
		chunk_size(chunk_size),
		contained_chunks(contained_chunks),
		node_ids(new pv::RawVolume<uint32_t>(contained_chunks)),
		num_chunks(contained_chunks.getWidthInVoxels() *
				contained_chunks.getHeightInVoxels() *
				contained_chunks.getDepthInVoxels())
	{
		chunk_buffers.resize(num_chunks);
		// Cache these for speed
		w_chunks = contained_chunks.getWidthInVoxels();
		h_chunks = contained_chunks.getHeightInVoxels();
		d_chunks = contained_chunks.getDepthInVoxels();
	}

	size_t get_chunk_i(const pv::Vector3DInt32 &chunk_p); // global chunk_p
	pv::Vector3DInt32 get_chunk_p(size_t chunk_p);

	ChunkBuffer& get_buffer(const pv::Vector3DInt32 &chunk_p,
			interface::Server *server, size_t *total_buffers_loaded);
};

size_t Section::get_chunk_i(const pv::Vector3DInt32 &chunk_p) // global chunk_p
{
	auto &lc = contained_chunks.getLowerCorner();
	// NOTE: pv::Vector3DInt32 operators and getters are too slow
	int local_x = chunk_p.getX() - lc.getX();
	int local_y = chunk_p.getY() - lc.getY();
	int local_z = chunk_p.getZ() - lc.getZ();
	const int &w = w_chunks;
	const int &h = h_chunks;
	size_t i = local_z * h * w + local_y * w + local_x;
	if(i >= num_chunks) // NOTE: This is not accurate but it is safe and fast
		throw Exception(ss_()+"get_chunk_i: Section "+cs(section_p)+
				" does not contain chunk"+cs(chunk_p));
	return i;
}

pv::Vector3DInt32 Section::get_chunk_p(size_t chunk_i)
{
	const int &w = w_chunks;
	const int &h = h_chunks;
	pv::Vector3DInt32 p;
	p.setZ(chunk_i / h / w);
	p.setY(chunk_i / w - p.getZ() * h);
	p.setX(chunk_i - p.getZ() * h * w - p.getY() * w);
	return contained_chunks.getLowerCorner() + p;
}

ChunkBuffer& Section::get_buffer(const pv::Vector3DInt32 &chunk_p,
		interface::Server *server, size_t *total_buffers_loaded)
{
	size_t chunk_i = get_chunk_i(chunk_p);
	ChunkBuffer &buf = chunk_buffers[chunk_i];
	buf.timer_reset(chunk_p);
	// If loaded, return right away
	if(buf.volume)
		return buf;
	// Not loaded.
	// Get the static voxel node from the scene and read the volume from it
	int32_t node_id = node_ids->getVoxelAt(chunk_p);
	if(node_id == 0){
		log_w(MODULE, "Section::get_buffer(): No node found for chunk "
				PV3I_FORMAT " in section " PV3I_FORMAT,
				PV3I_PARAMS(chunk_p), PV3I_PARAMS(section_p));
		return buf;
	}
	log_t(MODULE, "Loading chunk " PV3I_FORMAT " (node %i)",
			PV3I_PARAMS(chunk_p), node_id);

	main_context::access(server, [&](main_context::Interface *imc)
	{
		Scene *scene = imc->check_scene(m_scene_ref);
		Node *n = scene->GetNode(node_id);
		if(!n){
			log_w(MODULE,
					"Section::get_buffer(): Node %i not found in scene "
					"for chunk " PV3I_FORMAT " in section " PV3I_FORMAT,
					node_id, PV3I_PARAMS(chunk_p), PV3I_PARAMS(section_p));
			return;
		}
		const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
		const PODVector<unsigned char> &rawbuf = var.GetBuffer();
		ss_ data((const char*)&rawbuf[0], rawbuf.Size());
		buf.volume = interface::deserialize_volume(data);
		if(!buf.volume){
			log_w(MODULE,
					"Section::get_buffer(): Voxel volume could not be "
					"loaded from node %i for chunk "
					PV3I_FORMAT " in section " PV3I_FORMAT,
					node_id, PV3I_PARAMS(chunk_p), PV3I_PARAMS(section_p));
			return;
		}
	});
	(*total_buffers_loaded)++;
	return buf;
}

struct QueuedNodePhysicsUpdate
{
	uint node_id = 0;
	// TODO bool is_static_chunk = false;
	// TODO pv::Vector3DInt32 chunk_p; // Only set if is_static_chunk == true

	QueuedNodePhysicsUpdate(const uint &node_id):
		node_id(node_id){}
	bool operator>(const QueuedNodePhysicsUpdate &other) const {
		return node_id > other.node_id;
	}
};

struct CInstance: public voxelworld::Instance
{
	interface::Server *m_server;

	SceneReference m_scene_ref;

	// Clients that are ready to receive things (by peer id)
	set_<int> m_clients_initialized;

	// Accessing any of these outside of Server::access_scene is disallowed
	sp_<interface::AtlasRegistry> m_atlas_reg;
	sp_<interface::VoxelRegistry> m_voxel_reg;
	sp_<interface::BlockRegistry> m_block_reg;

	sv_<up_<CommitHook>> m_commit_hooks;

	// One node holds one chunk of voxels (eg. 24x24x24)
	pv::Vector3DInt16 m_chunk_size_voxels = pv::Vector3DInt16(32, 32, 32);
	//pv::Vector3DInt16 m_chunk_size_voxels = pv::Vector3DInt16(24, 24, 24);
	//pv::Vector3DInt16 m_chunk_size_voxels = pv::Vector3DInt16(16, 16, 16);
	//pv::Vector3DInt16 m_chunk_size_voxels = pv::Vector3DInt16(8, 8, 8);

	// The world is loaded and unloaded by sections (eg. 2x2x2)
	pv::Vector3DInt16 m_section_size_chunks = pv::Vector3DInt16(2, 2, 2);

	int64_t m_buffer_unload_timeout = 5000000;
	size_t m_max_buffers_loaded = 50;

	// Sections (this(y,z)=sector, sector(x)=section)
	sm_<pv::Vector<2, int16_t>, sm_<int16_t, Section>> m_sections;
	// Cache of last used sections (add to end, remove from beginning)
	std::deque<Section*> m_last_used_sections;

	// Set of sections that have buffers allocated
	// (as a sorted array in descending order)
	std::vector<Section*> m_sections_with_loaded_buffers;
	size_t m_total_buffers_loaded = 0;
	size_t m_total_buffers_dirty = 0;

	// Set of nodes by node_id that need set_voxel_physics_boxes()
	// (as a sorted array in descending node_id order)
	std::vector<QueuedNodePhysicsUpdate> m_nodes_needing_physics_update;

	CInstance(interface::Server *server, SceneReference scene_ref,
			const pv::Region &region):
		m_server(server),
		m_scene_ref(scene_ref)
	{
		m_voxel_reg.reset(interface::createVoxelRegistry());
		m_block_reg.reset(interface::createBlockRegistry(m_voxel_reg.get()));

		main_context::access(m_server, [&](main_context::Interface *imc){
			Context *context = imc->get_context();

			m_atlas_reg.reset(interface::createAtlasRegistry(context));
		});

		// TODO: Load from disk or something

		auto lc = region.getLowerCorner();
		auto uc = region.getUpperCorner();
		for(int z = lc.getZ(); z <= uc.getZ(); z++){
			for(int y = lc.getY(); y <= uc.getY(); y++){
				for(int x = lc.getX(); x <= uc.getX(); x++){
					load_or_generate_section(pv::Vector3DInt16(x, y, z));
				}
			}
		}

		// Find peers that already are on the scene and iniitalize them
		sv_<replicate::PeerId> peers;
		replicate::access(m_server, [&](replicate::Interface *ireplicate){
			peers = ireplicate->find_peers_on_scene(m_scene_ref);
		});
		ss_ peers_s = dump(peers);
		log_v(MODULE, "Existing peers on scene: %s", cs(peers_s));
		for(auto &peer : peers){
			initialize_peer(peer);
		}
	}

	~CInstance()
	{
	}

	void event(const Event::Type &type, const Event::Private *p)
	{
		EVENT_TYPEN("core:tick", on_tick, interface::TickEvent)
		EVENT_TYPEN("replicate:peer_joined_scene", on_peer_joined_scene,
				replicate::PeerJoinedScene);
		EVENT_TYPEN("replicate:peer_left_scene", on_peer_left_scene,
				replicate::PeerLeftScene);
		EVENT_TYPEN("client_file:files_transmitted", on_files_transmitted,
				client_file::FilesTransmitted)
		/*EVENT_TYPEN("network:packet_received/voxelworld:get_section",
				on_get_section, network::Packet)*/
	}

	void on_tick(const interface::TickEvent &event)
	{
		main_context::access(m_server, [&](main_context::Interface *imc){
			Scene *scene = imc->find_scene(m_scene_ref);
			if(!scene){
				// Scene was deleted; hope that Module deletes us at some point
				return;
			}

			Context *context = imc->get_context();

			// Update node collision boxes
			if(!m_nodes_needing_physics_update.empty()){
				log_v(MODULE, "Updating physics of %zu nodes",
						m_nodes_needing_physics_update.size());
			}
			for(QueuedNodePhysicsUpdate &update: m_nodes_needing_physics_update){
				uint node_id = update.node_id;
				Node *n = scene->GetNode(node_id);
				if(!n){
					log_w(MODULE, "on_tick(): Node physics update: "
							"Node %i not found", node_id);
					return;
				}
				// Get volume
				const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
				const PODVector<unsigned char> &rawbuf = var.GetBuffer();
				ss_ data((const char*)&rawbuf[0], rawbuf.Size());
				up_<pv::RawVolume<VoxelInstance>> volume =
						interface::deserialize_volume(data);
				// Update collision shape
				interface::mesh::set_voxel_physics_boxes(n, context, *volume,
						m_voxel_reg.get());
			}
			m_nodes_needing_physics_update.clear();
		});

		// Unload stuff if needed
		maintain_maximum_buffer_limit();

		// Send updated voxel registry if needed
		send_voxel_registry_if_dirty();
	}

	void on_peer_joined_scene(const replicate::PeerJoinedScene &event)
	{
		initialize_peer(event.peer);
	}

	void on_peer_left_scene(const replicate::PeerLeftScene &event)
	{
		m_clients_initialized.erase(event.peer);
	}

	void on_files_transmitted(const client_file::FilesTransmitted &event)
	{
	}

	// TODO: How should nodes be filtered for replication?
	// TODO: Generally the client wants roughly one section, but isn't
	//       positioned at the middle of a section
	/*void on_get_section(const network::Packet &packet)
	{
		pv::Vector3DInt16 section_p;
		{
			std::istringstream is(packet.data, std::ios::binary);
			cereal::PortableBinaryInputArchive ar(is);
			ar(section_p);
		}
		log_v(MODULE, "C%i: on_get_section(): " PV3I_FORMAT,
				packet.sender, PV3I_PARAMS(section_p));
	}*/

	void initialize_peer(replicate::PeerId peer)
	{
		log_v(MODULE, "Initializing peer %i", peer);
		// Load the client-side module (can be called multiple times)
		network::access(m_server, [&](network::Interface *inetwork){
			inetwork->send(peer, "core:run_script",
					"require(\"buildat/module/voxelworld\")");
		});
		// Send initialization data and tell the client that it is now ready
		std::ostringstream os(std::ios::binary);
		{
			cereal::PortableBinaryOutputArchive ar(os);
			ar(m_chunk_size_voxels);
			ar(m_section_size_chunks);
		}
		network::access(m_server, [&](network::Interface *inetwork){
			inetwork->send(peer, "voxelworld:init", os.str());
			inetwork->send(peer, "voxelworld:voxel_registry",
					m_voxel_reg->serialize());
			inetwork->send(peer, "voxelworld:ready", "");
		});
		m_clients_initialized.insert(peer);
	}

	void unload_node(Scene *scene, uint node_id)
	{
		log_d(MODULE, "Unloading node %i", node_id);
		Node *n = scene->GetNode(node_id);
		if(!n){
			log_w(MODULE, "Cannot unload node %i: Not found in scene", node_id);
			return;
		}
		// Remove RigidBody first to speed up removal of CollisionShapes
		RigidBody *body = n->GetComponent<RigidBody>();
		if(body)
			n->RemoveComponent(body);
		// Remove everything else
		n->RemoveAllComponents();
		n->Remove();
	}

	void send_voxel_registry_if_dirty()
	{
		// Send updated voxel registry if needed
		// NOTE: This probably really only supports additions
		if(m_voxel_reg->is_dirty()){
			m_voxel_reg->clear_dirty();
			log_v(MODULE, "Sending updated voxel registry to peers");

			ss_ voxel_reg_data = m_voxel_reg->serialize();

			network::access(m_server, [&](network::Interface *inetwork){
				for(auto &peer: m_clients_initialized){
					inetwork->send(peer, "voxelworld:voxel_registry",
							voxel_reg_data);
				}
			});
		}
	}

	// Get section if exists
	Section* get_section(const pv::Vector3DInt16 &section_p)
	{
		// Check cache
		for(Section *section : m_last_used_sections){
			if(section->section_p == section_p)
				return section;
		}
		// Not in cache
		pv::Vector<2, int16_t> p_yz(section_p.getY(), section_p.getZ());
		auto sector_it = m_sections.find(p_yz);
		if(sector_it == m_sections.end())
			return nullptr;
		sm_<int16_t, Section> &sector = sector_it->second;
		auto section_it = sector.find(section_p.getX());
		if(section_it == sector.end())
			return nullptr;
		Section &section = section_it->second;
		// Add to cache and return
		m_last_used_sections.push_back(&section);
		if(m_last_used_sections.size() > 2) // 2 is maybe optimal-ish
			m_last_used_sections.pop_front();
		return &section;
	}

	// Get a section; allocate it if it doesn't exist yet
	Section& force_get_section(const pv::Vector3DInt16 &section_p)
	{
		pv::Vector<2, int16_t> p_yz(section_p.getY(), section_p.getZ());
		sm_<int16_t, Section> &sector = m_sections[p_yz];
		Section &section = sector[section_p.getX()];
		if(section.chunk_size.getX() == 0){
			// Initialize newly created section properly
			pv::Region contained_chunks(
					section_p.getX() * m_section_size_chunks.getX(),
					section_p.getY() * m_section_size_chunks.getY(),
					section_p.getZ() * m_section_size_chunks.getZ(),
					(section_p.getX()+1) * m_section_size_chunks.getX() - 1,
					(section_p.getY()+1) * m_section_size_chunks.getY() - 1,
					(section_p.getZ()+1) * m_section_size_chunks.getZ() - 1
			);
			section = Section(m_scene_ref, section_p, m_chunk_size_voxels,
					contained_chunks);
		}
		return section;
	}

	void create_chunk_node(Scene *scene, Section &section, int x, int y, int z)
	{
		Context *context = scene->GetContext();

		pv::Vector3DInt16 section_p = section.section_p;
		pv::Vector3DInt32 chunk_p(
				section_p.getX() * m_section_size_chunks.getX() + x,
				section_p.getY() * m_section_size_chunks.getY() + y,
				section_p.getZ() * m_section_size_chunks.getZ() + z
		);

		Vector3 node_p(
				chunk_p.getX() * m_chunk_size_voxels.getX() +
				m_chunk_size_voxels.getX() / 2.0f - 0.5f,
				chunk_p.getY() * m_chunk_size_voxels.getY() +
				m_chunk_size_voxels.getY() / 2.0f - 0.5f,
				chunk_p.getZ() * m_chunk_size_voxels.getZ() +
				m_chunk_size_voxels.getZ() / 2.0f - 0.5f
		);

		ss_ name = "static_"+dump(chunk_p);

		log_t(MODULE, "create_chunk_node(): node_p=(%f, %f, %f), name=\"%s\"",
				node_p.x_, node_p.y_, node_p.z_, cs(name));

		Node *n = scene->CreateChild(name.c_str());
		if(n->GetID() == 0)
			throw Exception("Can't handle static node id=0");
		section.node_ids->setVoxelAt(chunk_p, n->GetID());

		// Distinguish static voxel nodes from others
		n->SetVar(StringHash("buildat_static"), Variant(true));

		int w = m_chunk_size_voxels.getX();
		int h = m_chunk_size_voxels.getY();
		int d = m_chunk_size_voxels.getZ();

		// This makes sure the node will be found when searched from the octree,
		// both on the server and the client
		Zone *node_zone = n->CreateComponent<Zone>();
		node_zone->SetPriority(-1000);
		node_zone->SetBoundingBox(BoundingBox(
				Vector3(-w/2, -h/2, -d/2), Vector3(w/2, h/2, d/2)));

		n->SetScale(Vector3(1.0f, 1.0f, 1.0f));
		n->SetPosition(node_p);

		// NOTE: These volumes have one extra voxel at each edge in order to
		//       make proper meshes without gaps
		// TODO: Is this needed anymore?
		pv::Region region(-1, -1, -1, w, h, d);
		sp_<pv::RawVolume<VoxelInstance>> volume(
				new pv::RawVolume<VoxelInstance>(region));

		auto lc = region.getLowerCorner();
		auto uc = region.getUpperCorner();
		for(int z = lc.getZ(); z <= uc.getZ(); z++){
			for(int y = lc.getY(); y <= uc.getY(); y++){
				for(int x = lc.getX(); x <= uc.getX(); x++){
					volume->setVoxelAt(x, y, z, VoxelInstance(0));
				}
			}
		}

		run_commit_hooks_in_thread(chunk_p, *volume);

		ss_ data = interface::serialize_volume_compressed(*volume);
		n->SetVar(StringHash("buildat_voxel_data"), Variant(
				PODVector<uint8_t>((const uint8_t*)data.c_str(), data.size())));

		run_commit_hooks_in_scene(chunk_p, n);

		m_server->emit_event("voxelworld:node_volume_updated",
				new NodeVolumeUpdated(m_scene_ref, n->GetID(), true, chunk_p));

		// There are no collision shapes initially, but add the rigid body now
		RigidBody *body = n->CreateComponent<RigidBody>(LOCAL);
		body->SetFriction(0.75f);
	}

	void create_section(Section &section)
	{
		main_context::access(m_server, [&](main_context::Interface *imc){
			Scene *scene = imc->check_scene(m_scene_ref);
			auto lc = section.contained_chunks.getLowerCorner();
			auto uc = section.contained_chunks.getUpperCorner();
			for(int z = 0; z <= uc.getZ() - lc.getZ(); z++){
				for(int y = 0; y <= uc.getY() - lc.getY(); y++){
					for(int x = 0; x <= uc.getX() - lc.getX(); x++){
						create_chunk_node(scene, section, x, y, z);
					}
				}
			}
		});
	}

	// Somehow get the section's static nodes and possible other nodes, either
	// by loading from disk or by creating new ones
	void load_section(Section &section)
	{
		if(section.loaded)
			return;
		section.loaded = true;
		pv::Vector3DInt16 section_p = section.section_p;
		log_d(MODULE, "Loading section " PV3I_FORMAT, PV3I_PARAMS(section_p));

		// TODO: If found on disk, load nodes from there
		// TODO: If not found on disk, create new static nodes
		// Always create new nodes for now
		create_section(section);
	}

	// Generate the section; requires static nodes to already exist
	void generate_section(Section &section)
	{
		if(section.generated)
			return;
		section.generated = true;
		pv::Vector3DInt16 section_p = section.section_p;
		log_v(MODULE, "Section will be generated: " PV3I_FORMAT,
				PV3I_PARAMS(section_p));
		m_server->emit_event("voxelworld:generation_request",
				new GenerationRequest(m_scene_ref, section_p));
	}

	void mark_node_for_physics_update(uint node_id)
	{
		QueuedNodePhysicsUpdate update(node_id);
		auto it = std::lower_bound(m_nodes_needing_physics_update.begin(),
				m_nodes_needing_physics_update.end(), update,
				std::greater<QueuedNodePhysicsUpdate>());
		if(it == m_nodes_needing_physics_update.end()){
			m_nodes_needing_physics_update.insert(it, update);
		} else if(it->node_id != node_id){
			m_nodes_needing_physics_update.insert(it, update);
		} else {
			*it = update;
		}
	}

	// Should be called before the volume is serialized so that the hook can
	// modify the volume
	void run_commit_hooks_in_thread(
			const pv::Vector3DInt32 &chunk_p,
			pv::RawVolume<VoxelInstance> &volume)
	{
		for(up_<CommitHook> &hook : m_commit_hooks)
			hook->in_thread(this, chunk_p, volume);
	}

	void run_commit_hooks_in_scene(
			const pv::Vector3DInt32 &chunk_p, Node *n)
	{
		for(up_<CommitHook> &hook : m_commit_hooks)
			hook->in_scene(this, chunk_p, n);
	}

	void unload_old_buffers(int64_t unload_timeout, size_t max_buffers)
	{
		// Swap out the current set
		std::vector<Section*> sections_with_loaded_buffers;
		sections_with_loaded_buffers.swap(m_sections_with_loaded_buffers);
		// Allocate a new set to put back stuff that is still loaded
		m_sections_with_loaded_buffers.reserve(
				sections_with_loaded_buffers.size());
		// Go through the swapped set, putting back sections that are still loaded
		m_total_buffers_loaded = 0;
		m_total_buffers_dirty = 0;
		for(Section *section : sections_with_loaded_buffers){
			size_t num_loaded = 0;
			for(size_t i = 0; i < section->chunk_buffers.size(); i++){
				ChunkBuffer &chunk_buffer = section->chunk_buffers[i];
				bool unloaded = chunk_buffer.unload_if_old(unload_timeout);
				if(!unloaded){
					num_loaded++;
					m_total_buffers_loaded++;
					if(chunk_buffer.dirty)
						m_total_buffers_dirty++;
				}
			}
			if(num_loaded > 0)
				m_sections_with_loaded_buffers.push_back(section);
		}
		// Call recursively if too many buffers are still loaded
		if(unload_timeout > 1000 && m_total_buffers_loaded > max_buffers)
			unload_old_buffers(unload_timeout / 4, max_buffers);
	}

	void maintain_maximum_buffer_limit()
	{
		if(m_total_buffers_loaded > m_max_buffers_loaded)
			unload_old_buffers(m_buffer_unload_timeout, m_max_buffers_loaded);
	}

	// Interface

	interface::VoxelRegistry* get_voxel_reg()
	{
		return m_voxel_reg.get();
	}

	void add_commit_hook(up_<CommitHook> hook)
	{
		m_commit_hooks.push_back(std::move(hook));
	}

	pv::Vector3DInt16 get_section_size_voxels()
	{
		return pv::Vector3DInt16(
				m_section_size_chunks.getX() * m_chunk_size_voxels.getX(),
				m_section_size_chunks.getY() * m_chunk_size_voxels.getY(),
				m_section_size_chunks.getZ() * m_chunk_size_voxels.getZ()
		);
	}

	pv::Region get_section_region_voxels(const pv::Vector3DInt16 &section_p)
	{
		pv::Vector3DInt32 p0 = pv::Vector3DInt32(
				section_p.getX() * m_section_size_chunks.getX() *
				m_chunk_size_voxels.getX(),
				section_p.getY() * m_section_size_chunks.getY() *
				m_chunk_size_voxels.getY(),
				section_p.getZ() * m_section_size_chunks.getZ() *
				m_chunk_size_voxels.getZ()
		);
		pv::Vector3DInt32 p1 = p0 + pv::Vector3DInt32(
				m_section_size_chunks.getX() * m_chunk_size_voxels.getX() - 1,
				m_section_size_chunks.getY() * m_chunk_size_voxels.getY() - 1,
				m_section_size_chunks.getZ() * m_chunk_size_voxels.getZ() - 1
		);
		return pv::Region(p0, p1);
	}

	const pv::Vector3DInt16& get_chunk_size_voxels()
	{
		return m_chunk_size_voxels;
	}

	pv::Region get_chunk_region_voxels(const pv::Vector3DInt32 &chunk_p)
	{
		pv::Vector3DInt32 p0 = pv::Vector3DInt32(
				chunk_p.getX() * m_chunk_size_voxels.getX(),
				chunk_p.getY() * m_chunk_size_voxels.getY(),
				chunk_p.getZ() * m_chunk_size_voxels.getZ()
		);
		pv::Vector3DInt32 p1 = p0 + pv::Vector3DInt32(
				m_chunk_size_voxels.getX() - 1,
				m_chunk_size_voxels.getY() - 1,
				m_chunk_size_voxels.getZ() - 1
		);
		return pv::Region(p0, p1);
	}

	void load_or_generate_section(const pv::Vector3DInt16 &section_p)
	{
		Section &section = force_get_section(section_p);
		if(!section.loaded)
			load_section(section);
		if(!section.generated)
			generate_section(section);
	}

	void set_voxel_direct(const pv::Vector3DInt32 &p,
			const interface::VoxelInstance &v)
	{
		log_t(MODULE, "set_voxel_direct() p=" PV3I_FORMAT ", v=%i",
				PV3I_PARAMS(p), v.data);
		pv::Vector3DInt32 chunk_p = container_coord(p, m_chunk_size_voxels);
		pv::Vector3DInt16 section_p =
				container_coord16(chunk_p, m_section_size_chunks);
		Section *section = get_section(section_p);
		if(section == nullptr){
			log_w(MODULE, "set_voxel_direct() p=" PV3I_FORMAT ", v=%i: No section "
					" " PV3I_FORMAT " for chunk " PV3I_FORMAT,
					PV3I_PARAMS(p), v.data, PV3I_PARAMS(section_p),
					PV3I_PARAMS(chunk_p));
			return;
		}
		int32_t node_id = section->node_ids->getVoxelAt(chunk_p);
		if(node_id == 0){
			log_w(MODULE, "set_voxel_direct() p=" PV3I_FORMAT ", v=%i: No node for "
					"chunk " PV3I_FORMAT " in section " PV3I_FORMAT,
					PV3I_PARAMS(p), v.data, PV3I_PARAMS(chunk_p),
					PV3I_PARAMS(section_p));
			return;
		}

		// Have to commit first so that this modification doesn't get
		// overwritten by some older one
		// TODO: Commit only the current chunk
		commit();

		main_context::access(m_server, [&](main_context::Interface *imc){
			Scene *scene = imc->check_scene(m_scene_ref);
			Node *n = scene->GetNode(node_id);
			const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
			const PODVector<unsigned char> &buf = var.GetBuffer();
			ss_ data((const char*)&buf[0], buf.Size());
			up_<pv::RawVolume<VoxelInstance>> volume =
					interface::deserialize_volume(data);

			pv::Vector3DInt32 voxel_p(
					p.getX() - chunk_p.getX() * m_chunk_size_voxels.getX(),
					p.getY() - chunk_p.getY() * m_chunk_size_voxels.getY(),
					p.getZ() - chunk_p.getZ() * m_chunk_size_voxels.getZ()
			);
			log_t(MODULE, "set_voxel_direct() p=" PV3I_FORMAT ", v=%i: "
					"Chunk " PV3I_FORMAT " in section " PV3I_FORMAT
					"; internal position " PV3I_FORMAT,
					PV3I_PARAMS(p), v.data, PV3I_PARAMS(chunk_p),
					PV3I_PARAMS(section_p), PV3I_PARAMS(voxel_p));
			volume->setVoxelAt(voxel_p, v);

			run_commit_hooks_in_thread(chunk_p, *volume);

			ss_ new_data = interface::serialize_volume_compressed(*volume);

			n->SetVar(StringHash("buildat_voxel_data"), Variant(
					PODVector<uint8_t>((const uint8_t*)new_data.c_str(),
					new_data.size())));

			run_commit_hooks_in_scene(chunk_p, n);
		});

		// Mark node for collision box update
		mark_node_for_physics_update(node_id);

		m_server->emit_event("voxelworld:node_volume_updated",
				new NodeVolumeUpdated(m_scene_ref, node_id, true, chunk_p));
	}

	void set_voxel(const pv::Vector3DInt32 &p, const interface::VoxelInstance &v,
			bool disable_warnings)
	{
		// Don't log here; this is a too busy place for even ignored log calls
		/*log_t(MODULE, "set_voxel() p=" PV3I_FORMAT ", v=%i",
				PV3I_PARAMS(p), v.data);*/
		pv::Vector3DInt32 chunk_p = container_coord(p, m_chunk_size_voxels);
		pv::Vector3DInt16 section_p =
				container_coord16(chunk_p, m_section_size_chunks);
		Section *section = get_section(section_p);
		if(section == nullptr){
			log_(disable_warnings ? CORE_DEBUG : CORE_WARNING,
					MODULE, "set_voxel() p=" PV3I_FORMAT ", v=%i: No section "
					PV3I_FORMAT " for chunk " PV3I_FORMAT,
					PV3I_PARAMS(p), v.data, PV3I_PARAMS(section_p),
					PV3I_PARAMS(chunk_p));
			return;
		}

		// Unload stuff if needed
		maintain_maximum_buffer_limit();

		// Set in buffer
		ChunkBuffer &buf = section->get_buffer(chunk_p, m_server,
				&m_total_buffers_loaded);
		if(!buf.volume){
			log_(disable_warnings ? CORE_DEBUG : CORE_WARNING,
					MODULE, "set_voxel() p=" PV3I_FORMAT ", v=%i: Couldn't get "
					"buffer volume for chunk " PV3I_FORMAT " in section "
					PV3I_FORMAT, PV3I_PARAMS(p), v.data, PV3I_PARAMS(chunk_p),
					PV3I_PARAMS(section_p));
			return;
		}
		pv::Vector3DInt32 voxel_p(
				p.getX() - chunk_p.getX() * m_chunk_size_voxels.getX(),
				p.getY() - chunk_p.getY() * m_chunk_size_voxels.getY(),
				p.getZ() - chunk_p.getZ() * m_chunk_size_voxels.getZ()
		);
		buf.volume->setVoxelAt(voxel_p, v);

		// Set buffer dirty
		if(!buf.dirty){
			buf.dirty = true;
			m_total_buffers_dirty++;
		}

		// Set section buffer loaded flag
		auto it = std::lower_bound(m_sections_with_loaded_buffers.begin(),
				m_sections_with_loaded_buffers.end(), section,
				std::greater<Section*>()); // position in descending order
		if(it == m_sections_with_loaded_buffers.end() || *it != section)
			m_sections_with_loaded_buffers.insert(it, section);
	}

	// Commit and unload chunk buffer
	void commit_chunk_buffer(Section *section, size_t chunk_i)
	{
		ChunkBuffer &chunk_buffer = section->chunk_buffers[chunk_i];
		if(!chunk_buffer.dirty){
			// No changes
			return;
		}

		pv::Vector3DInt32 chunk_p = section->get_chunk_p(chunk_i);
		uint node_id = section->node_ids->getVoxelAt(chunk_p);

		log_d(MODULE, "Committing chunk " PV3I_FORMAT " (node %i)",
				PV3I_PARAMS(chunk_p), node_id);

		if(node_id == 0){
			log_w(MODULE, "commit_chunk_buffer() chunk_i=%zu: "
					"No node found for chunk " PV3I_FORMAT
					" in section " PV3I_FORMAT,
					chunk_i, PV3I_PARAMS(chunk_p),
					PV3I_PARAMS(section->section_p));
			return;
		}

		run_commit_hooks_in_thread(chunk_p, *chunk_buffer.volume);

		ss_ new_data = interface::serialize_volume_compressed(
				*chunk_buffer.volume);

		main_context::access(m_server, [&](main_context::Interface *imc){
			Scene *scene = imc->check_scene(m_scene_ref);
			Context *context = scene->GetContext();

			Node *n = scene->GetNode(node_id);
			if(!n){
				log_w(MODULE, "commit_chunk_buffer(): Node %i not found",
						node_id);
				return;
			}
			const Variant &var = n->GetVar(StringHash("buildat_voxel_data"));
			if(var.GetType() != VAR_BUFFER){
				log_w(MODULE, "commit_chunk_buffer(): Node %i does not contain "
						"an existing buffer; assuming some kind of error",
						node_id);
				return;
			}

			n->SetVar(StringHash("buildat_voxel_data"), Variant(
					PODVector<uint8_t>((const uint8_t*)new_data.c_str(),
					new_data.size())));

			run_commit_hooks_in_scene(chunk_p, n);
		});

		// First send updated voxel registry to clients so that they are ready
		// to generate stuff from the voxels
		send_voxel_registry_if_dirty();

		// Then synchronize node and notify clients about it
		sv_<replicate::PeerId> peers;
		replicate::access(m_server, [&](replicate::Interface *ireplicate){
			ireplicate->sync_node_immediate(m_scene_ref, node_id);
			peers = ireplicate->find_peers_that_know_node(m_scene_ref, node_id);
		});
		std::ostringstream os(std::ios::binary);
		{
			cereal::PortableBinaryOutputArchive ar(os);
			ar((int32_t)node_id);
		}
		network::access(m_server, [&](network::Interface *inetwork){
			for(auto &peer_id: peers){
				if(!m_clients_initialized.count(peer_id))
					continue;
				inetwork->send(peer_id, "voxelworld:node_volume_updated",
						os.str());
			}
		});

		// Mark node for collision box update
		mark_node_for_physics_update(node_id);

		// Reset dirty flag
		chunk_buffer.dirty = false;
		m_total_buffers_dirty--;

		m_server->emit_event("voxelworld:node_volume_updated",
				new NodeVolumeUpdated(m_scene_ref, node_id, true, chunk_p));
	}

	size_t num_buffers_loaded()
	{
		return m_total_buffers_loaded;
	}

	void commit()
	{
		if(m_sections_with_loaded_buffers.empty())
			return;
		log_d(MODULE, "Committing %zu dirty buffers in %zu sections",
				m_total_buffers_dirty,
				m_sections_with_loaded_buffers.size());
		for(Section *section : m_sections_with_loaded_buffers){
			for(size_t i = 0; i < section->chunk_buffers.size(); i++){
				commit_chunk_buffer(section, i);
			}
		}
	}

	VoxelInstance get_voxel(const pv::Vector3DInt32 &p, bool disable_warnings)
	{
		pv::Vector3DInt32 chunk_p = container_coord(p, m_chunk_size_voxels);
		pv::Vector3DInt16 section_p =
				container_coord16(chunk_p, m_section_size_chunks);
		Section *section = get_section(section_p);
		if(section == nullptr){
			log_(disable_warnings ? CORE_DEBUG : CORE_WARNING,
					MODULE, "get_voxel() p=" PV3I_FORMAT ": No section "
					PV3I_FORMAT " for chunk " PV3I_FORMAT,
					PV3I_PARAMS(p), PV3I_PARAMS(section_p),
					PV3I_PARAMS(chunk_p));
			return VoxelInstance(interface::VOXELTYPEID_UNDEFINED);
		}

		// Unload stuff if needed
		maintain_maximum_buffer_limit();

		// Get from buffer
		ChunkBuffer &buf = section->get_buffer(chunk_p, m_server,
				&m_total_buffers_loaded);
		if(!buf.volume){
			log_(disable_warnings ? CORE_DEBUG : CORE_WARNING,
					MODULE, "get_voxel() p=" PV3I_FORMAT ": Couldn't get "
					"buffer volume for chunk " PV3I_FORMAT " in section "
					PV3I_FORMAT, PV3I_PARAMS(p), PV3I_PARAMS(chunk_p),
					PV3I_PARAMS(section_p));
			return VoxelInstance(interface::VOXELTYPEID_UNDEFINED);
		}
		pv::Vector3DInt32 voxel_p(
				p.getX() - chunk_p.getX() * m_chunk_size_voxels.getX(),
				p.getY() - chunk_p.getY() * m_chunk_size_voxels.getY(),
				p.getZ() - chunk_p.getZ() * m_chunk_size_voxels.getZ()
		);
		VoxelInstance v = buf.volume->getVoxelAt(voxel_p);

		// Set section buffer loaded flag
		auto it = std::lower_bound(m_sections_with_loaded_buffers.begin(),
				m_sections_with_loaded_buffers.end(), section,
				std::greater<Section*>()); // position in descending order
		if(it == m_sections_with_loaded_buffers.end() || *it != section)
			m_sections_with_loaded_buffers.insert(it, section);

		return v;
	}
};

struct Module: public interface::Module, public voxelworld::Interface
{
	interface::Server *m_server;

	sm_<SceneReference, up_<CInstance>> m_instances;

	Module(interface::Server *server):
		interface::Module(MODULE),
		m_server(server)
	{
		log_t(MODULE, "voxelworld construct");
	}

	~Module()
	{
		log_t(MODULE, "voxelworld destruct");
	}

	void init()
	{
		// NOTE: These also apply to CInstances
		m_server->sub_event(this, Event::t("core:start"));
		m_server->sub_event(this, Event::t("core:unload"));
		m_server->sub_event(this, Event::t("core:continue"));
		m_server->sub_event(this, Event::t("core:tick"));
		m_server->sub_event(this, Event::t("replicate:peer_joined_scene"));
		m_server->sub_event(this, Event::t("replicate:peer_left_scene"));
		m_server->sub_event(this, Event::t("client_file:files_transmitted"));
		m_server->sub_event(this, Event::t("main_context:scene_deleted"));
		/*m_server->sub_event(this, Event::t(
					"network:packet_received/voxelworld:get_section"));*/
	}

	void event(const Event::Type &type, const Event::Private *p)
	{
		EVENT_VOIDN("core:start", on_start)
		EVENT_VOIDN("core:unload", on_unload)
		EVENT_VOIDN("core:continue", on_continue)
		EVENT_TYPEN("core:tick", on_tick, interface::TickEvent)
		EVENT_TYPEN("replicate:peer_joined_scene", on_peer_joined_scene,
				replicate::PeerJoinedScene);
		EVENT_TYPEN("replicate:peer_left_scene", on_peer_left_scene,
				replicate::PeerLeftScene);
		EVENT_TYPEN("client_file:files_transmitted", on_files_transmitted,
				client_file::FilesTransmitted)
		EVENT_TYPEN("main_context:scene_deleted", on_scene_deleted,
				main_context::SceneDeleted);

		for(auto &pair : m_instances){
			up_<CInstance> &instance = pair.second;
			instance->event(type, p);
		}
	}

	void on_start()
	{
	}

	void unload_node(Scene *scene, uint node_id)
	{
		log_d(MODULE, "Unloading node %i", node_id);
		Node *n = scene->GetNode(node_id);
		if(!n){
			log_w(MODULE, "Cannot unload node %i: Not found in scene", node_id);
			return;
		}
		// Remove RigidBody first to speed up removal of CollisionShapes
		RigidBody *body = n->GetComponent<RigidBody>();
		if(body)
			n->RemoveComponent(body);
		// Remove everything else
		n->RemoveAllComponents();
		n->Remove();
	}

	void on_unload()
	{
		log_v(MODULE, "on_unload()");

		// TODO

		/*commit();

		// Remove everything managed by us from the scene
		main_context::access(m_server, [&](main_context::Interface *imc){
			Scene *scene = imc->check_scene();
			size_t progress = 0;
			for(auto &sector_pair: m_sections){
				log_v(MODULE, "Unloading nodes... %i%%",
						100 * progress / m_sections.size());
				progress++;
				for(auto &section_pair: sector_pair.second){
					Section &section = section_pair.second;

					auto region = section.node_ids->getEnclosingRegion();
					auto lc = region.getLowerCorner();
					auto uc = region.getUpperCorner();
					for(int z = lc.getZ(); z <= uc.getZ(); z++){
						for(int y = lc.getY(); y <= uc.getY(); y++){
							for(int x = lc.getX(); x <= uc.getX(); x++){
								uint id = section.node_ids->getVoxelAt(x, y, z);
								section.node_ids->setVoxelAt(x, y, z, 0);
								unload_node(scene, id);
							}
						}
					}
				}
			}
			log_v(MODULE, "Unloading nodes... 100%%");
		});

		// Store voxel registry and stuff
		std::ostringstream os(std::ios::binary);
		{
			cereal::PortableBinaryOutputArchive ar(os);
			ar(m_voxel_reg->serialize());
		}
		m_server->tmp_store_data("voxelworld:restore_info", os.str());*/
	}

	void on_continue()
	{
		// TODO

		/*// Restore voxel registry and stuff
				ss_ data = m_server->tmp_restore_data("voxelworld:restore_info");
		ss_ voxel_reg_data;
		{
			std::istringstream is(data, std::ios::binary);
			cereal::PortableBinaryInputArchive ar(is);
			ar(voxel_reg_data);
		}
		m_voxel_reg->deserialize(voxel_reg_data);*/

		// Start up normally
		on_start();
	}

	void on_tick(const interface::TickEvent &event)
	{
	}

	void on_peer_joined_scene(const replicate::PeerJoinedScene &event)
	{
	}

	void on_peer_left_scene(const replicate::PeerLeftScene &event)
	{
	}

	void on_files_transmitted(const client_file::FilesTransmitted &event)
	{
	}

	void on_scene_deleted(const main_context::SceneDeleted &event)
	{
		// Drop instance of the deleted scene (there should be only one, but
		// loop through all of them just for robustness)
		for(auto it = m_instances.begin(); it != m_instances.end();){
			auto current_it = it++;
			up_<CInstance> &instance = current_it->second;
			if(instance->m_scene_ref == event.scene){
				m_instances.erase(current_it);
			}
		}
	}

	/*// TODO: How should nodes be filtered for replication?
	// TODO: Generally the client wants roughly one section, but isn't
	//       positioned at the middle of a section
			void on_get_section(const network::Packet &packet)
	{
		pv::Vector3DInt16 section_p;
		{
			std::istringstream is(packet.data, std::ios::binary);
			cereal::PortableBinaryInputArchive ar(is);
			ar(section_p);
		}
		log_v(MODULE, "C%i: on_get_section(): " PV3I_FORMAT,
				packet.sender, PV3I_PARAMS(section_p));
		}*/

	// Interface

	void create_instance(SceneReference scene_ref, const pv::Region &region)
	{
		auto it = m_instances.find(scene_ref);
		// TODO: Is an exception the best way to handle this?
		if(it != m_instances.end())
			throw Exception("create_instance(): Scene already has a voxel"
					" world instance");

		up_<CInstance> instance(new CInstance(m_server, scene_ref, region));
		m_instances[scene_ref] = std::move(instance);
	}

	void delete_instance(SceneReference scene_ref)
	{
		auto it = m_instances.find(scene_ref);
		if(it == m_instances.end())
			throw Exception("delete_instance(): Scene does not have a voxel"
					" world instance");
		m_instances.erase(it);
	}

	Instance* get_instance(SceneReference scene_ref)
	{
		auto it = m_instances.find(scene_ref);
		if(it == m_instances.end())
			return nullptr;
		return it->second.get();
	}

	void commit()
	{
		for(auto &pair : m_instances){
			up_<CInstance> &instance = pair.second;
			instance->commit();
		}
	}

	void* get_interface()
	{
		return dynamic_cast<Interface*>(this);
	}
};

extern "C" {
	BUILDAT_EXPORT void* createModule_voxelworld(interface::Server *server){
		return (void*)(new Module(server));
	}
}
}

// vim: set noet ts=4 sw=4:

redpajama_set_name: RedPajamaGithub


text:
Obereopsis paravariipes är en skalbaggsart som beskrevs av Stefan von Breuning 1977. Obereopsis paravariipes ingår i släktet Obereopsis och familjen långhorningar. Inga underarter finns listade i Catalogue of Life.

Källor

Långhorningar
paravariipes

redpajama_set_name: RedPajamaWikipedia


It is an excellent price, has performance ratio, more than acceptable image quality and clean Doppler signal.
I would like to see an option for uninterrupted power supply, slightly smaller dimensions and screen a little deeper.
Since when do you use the Logiq F6?I have been using this device since 2015. In what condition was the Logiq F6?It was purchased as a new device. For what application did you use the Logiq F6?It is used for vascular surgery, angiology and phlebology. By whom the briefing was carried out and do you feel satisfied?Manufacturer carried out the briefing. Is the user manual of the device useful?Typical GE operation, therefore user manual rarely used. Would you get the Logiq F6 again, why?Since I have always worked with GE devices and I did not want to change in the software and workflows, it was very clear that it has to be a GE machine again. This premium brand had only premium prices before. With the Logiq F6, there is a new and very good alternative for surgery application into the market.


text:
Franco Harris Makes The "Immaculate Reception"
The Immaculate Reception is the nickname given to one of the most famous plays in the history of American football.
It occurred in the AFC divisional playoff game between the Pittsburgh Steelers and the Oakland Raiders at Three Rivers Stadium in Pittsburgh, Pennsylvania, on December 23, 1972. Late in the game, after Frenchy Fuqua, a Pittsburgh half back, collided with Raiders Safety Jack Tatum as he tried to make a catch, Pittsburgh running back Franco Harris caught the deflected football just before it hit the ground, and ran in for a touchdown that won the game for the Steelers.
NFL Films has chosen it as the greatest play of all time, as well as the most controversial. The play was a turning point for the Steelers, who reversed four decades of futility with their first playoff win ever, and went on to win four Super Bowls by the end of the decade. The play's name is a neologism derived from the Immaculate Conception, a dogma in the Roman Catholic Church that Mary, mother of Jesus, when conceived by her parents, bore no stain of original sin. The phrase was first used on air by Myron Cope, a Pittsburgh sportscaster who was reporting on the Steelers' victory. A Pittsburgh woman, Sharon Levosky, called Cope the night of the game and suggested the name, which was coined by her friend Michael Ord. Cope used the term on television and the phrase stuck. The term was apparently meant to imply that the play was miraculous or divine in nature (see Hail Mary pass for a similar term), though "immaculate" means "clean" or "pure."
Source: Wikipedia Added by: Jabril Faraj
Great Sports Moments
View other events that happened on December 23

redpajama_set_name: RedPajamaCommonCrawl


text:
Did Trump Win A Medal From The NAACP?
Lauren Briggs
Donald Trump's longtime attorney said that the GOP presidential nominee received an NAACP award with Rosa Parks and Muhammad Ali in 1989. But that is not exactly true.
Trump's lawyer, Michael Cohen, posted the following photo to Twitter on Oct. 18, saying that Trump received the NAACP award for "helping America's inner cities" and is "a man for ALL people!"
But the NAACP told The Huffington Post that they have never awarded any medals to Trump for such a cause, and Trump's biographers confirmed that no other civil rights groups have, either.
In reality, Trump, who was embroiled in a housing discrimination lawsuit at the time, received the medal along with 79 others, most of whom were white, after a well-connected businessman, William Fugazi, who was Trump's real estate broker at the time, protested against 12 immigrants receiving "medals of liberty" from President Ronald Reagan for the Statue of Liberty's 100th anniversary.
Fugazi, along with the Coalition of Italo-American Associations, a group led by him, campaigned against the awards on the grounds that they were not honoring native-born citizens and that they explicitly excluded ethnicities like Irish, Italian and Polish.
"We think it's an insult to ― on the one hand ― ask for donations to restore the foremost international symbol of freedom for immigrants and ― on the other hand ― to exclude most of them from the Medal of Liberty list," the coalition's executive director, Joseph Martorana, told the Miami Herald at the time, notes the Post. Martorana said that those ethnic groups left out "account for 76 percent of the nation's population."
Many others backed up Fugazi, including Democratic Mayor Ed Koch of New York, who called the selections "idiotic," and New York City Council majority leader Peter Vallone, who told the Miami Herald that the awards were like "denying some of the building blocks of the nation."
"It's an historical betrayal," Vallone added.
Fugazi then created a new organization, the National Ethnic Coalition of Organizations, or NECO, and awarded Trump, Ali, Parks and 77 others -- two of whom were black -- with the new Ellis Island Medal of Honor, which awards those who "uphold the ideals and spirit of America" while "maintaining the traditions of their ethnic heritage."
Democratic presidential nominee Hillary Clinton, Frank Sinatra, Lee Iacocca, Quincy Jones, Nobel laureate Elie Wiesel, Louis Zamperini and six U.S. presidents have also received the award, notes NECO's official website.
Sources: The Huffington Post, Michael Cohen/Twitter, NECO / Photo credit: Michael Cohen/Twitter
Trump inner cityTrump NAACP awardTrump Muhammad Alipoliticstrump


text:
Mormon Tabernacle Choir lyrics
Many of the popular songs we know and love have a special story behind them. That being said, "God Be With You Till We Meet Again", which was written by Jeremiah Rankin, was simply composed so his church choir could have something to sing when they parted each week. Rankin was the minister for the First Congregational Church in Washington, D.C. and said this about the hymn, "Written…as a Christian goodbye, it was called forth by no person or occasion, but was deliberately composed as a Christian hymn on basis of the etymology of "goodbye, " which is "God be with you." He got the idea for the first stanza of the song when he saw the dictionary definition of "good-bye" was short for "God be with you." The song was written in 1882 when Rankin was 54 years old.
While Rankin was responsible for writing the lyrics, William Tomer, who was the music director at Grace Methodist Episcopal Church, composed the music.
The hymn became the official closing song for the Christian Endeavor Convention. Dr. Rankin said: "It has had no sweeter recognition than that given it by its adoption by the Young People's Society of Christian Endeavor. Long, long, may they sing it!"
During the war, many postcards were printed with hymn lyrics to help soldiers in battle feel at ease. One such postcard was a colorful picture of soldiers going to battle with the following verse: "God be with you till we meet again; keep love's banner floating o'er you, smite death's threatening wave before you; God be with you till we meet again."
While the original hymn had eight verses, it is verses 1, 2, 4, and 7 that are generally heard in congregations. In the hymnbook of The Church of Jesus Christ of Latter-day Saints, there are three verses included. As a close to many of the Mormon Tabernacle Choir broadcasts, "God Be With You Till We Meet Again" is the final goodbye number and acts as a benediction to many of the General Conferences of the church. For more information regarding the history of this sacred hymn, listen to Episode 26 of the History of hymns series on The Mormon Channel.
Here are the lyrics as sung by the Choir in the video above:
God be with you till we meet again By his counsels guide, uphold you
With his sheep securely fold you God be with you till we meet again
Till we meet, till we meet, God be with you till we meet again
Homeward Bound - Mormon Tabernacle Choir
Joy to the World - Mormon Tabernacle Choir
You Raise Me Up Lyrics - Mormon Tabernacle Choir
Mormon Tabernacle Choir History
For more than eight decades, nearly the lifetime of radio, the Mormon Tabernacle Choir has presented a weekly program — Music…
Christmas Mormon Tabernacle Choir
Christmas with the Mormon Tabernacle Choir Featuring Santino Fontana & the Sesame Street Muppets Holiday Specials…
Choir VST plugin
Mormon Tabernacle Choir YouTube channel
Methodist Church Choir
Celebration Choir songs
John Burroughs High School show Choir
Mormon Tabernacle Choir music Video
Gospel songs for Children Choir


Mountain High - Ski/Snowboard Rest Of This Season And All Of Next For As Little As $299!
Ski/Snowboard Rest Of This Season And All Of Next For As Little As $299!
Mountain High, Southern California's closest winter resort, just released its spring season pass offer which is sure to have you dancing in your boots. Beginning Thursday, March 1st, skiers and snowboarders can get an adult Anytime Season Pass good for the remainder of this season and all of next for just $349. That's a savings of 50% over a traditional single-year pass. In addition, anyone who has held a season pass within the last three years saves an extra $50, bringing the price down to an amazing $299. This $299 offer is also available to 2011/2012 season pass holders from ANY other California Winter Resort. Current season pass must be shown when purchasing.
Mountain High's Anytime Season Pass is good any day or night the resort is open with no restrictions. Benefits include FREE skiing at Stevens Pass, WA, FREE tubing at the North Pole Tubing Park, $20 Off Midweek Zipline Tours at the Wrightwood NAVITAT Center, $10 Off Adult Ski/Snowboard Lessons, 10% Off non-sale retail apparel, and the ability to TRACK your days ridden, runs per day, and vertical feet on Mountain High's new App for iPhone and Android.
Children's Passes for ages 7 to 12 are available as well for just $129 with the purchase of an adult season pass and $179 without. (Regularly $229) Children six and under ski FREE when accompanied by a paying adult.
Big snow years tend to follow light ones, so if recent reports hold true, Mountain High is in for a whopper next winter.
Mountain High's Spring Season Pass offer is available March 1st to April 15th, 2012. At $349 or less it is the best deal of any major resort in Southern California. Shop around and compare for yourself. Guests are encouraged to purchase their passes online at mthigh.com; however, passes can also be purchased at the resort and by phone at 888 754 7878. Please note there is a $10 processing for all new passes purchased.
Mountain High is Southern California's closest winter resort located just an hour and a half from Los Angeles and Orange County. The area consists of three separate mountains (Mountain High East, West, and North), and offers a wide variety of lifts and trails, a world-class terrain park, an outstanding Winter Sports School, and the region's largest tubing area. Night skiing & snowboarding is available most evenings until 10pm and snowmaking covers more than 80% of the slopes. Mountain High has been the first resort to open in Southern California for the past 14 years and traditionally operates from mid November to mid April. Get more at mthigh.com.


So yesterday's mani was difficult when it should have been easy. Today's mani went off without a hitch! I just love the color green. It is my favorite color....it goes with purple, pink, brown, coppers, black, yellow...you get the picture. I also love it because it is the color of Ireland, the country of my ancestors. ( A little fact: My maiden name is Kelly Michelle Finn. Doesn't get much more Irish than that. Well, unless you added O'Connell) Green is the color of trees and grass and nature. It is a beautifully natural color. I have A LOT of green nail polish, so it was hard to choose this time. I decided to go with one I recently purchased by Ultra Pro called Mossy Britches. Don't you just love that name? It really is a great mossy color. I also used another of my D & R Apothecary indie polishes called High Tech. It is a clear base with black glitter and green, yellow, and black hexagon glitters. Of course, I also did an accent nail because I can't stop myself.
I would like to know your opinion on using the accent nail. This is one of my favorite things to do, but what do you think? Should I do more with all nails the same? or do you like the accent nail?
Thanks for stopping by and having a look! I appreciate all of your comments.
Love this, from the glitter to the accent nail!
I'm a fan of the accent nail too!
Wow! Thanks so much! Can't wait to get started...I have a bunch of newbie bloggers that I know deserve this too!
Love, love, love your accent nail!


Posted June 12, 2014 by Joel Goldman & filed under Creating characters, Crime Fiction, Crime Novels, How to write, Reading fiction, Story Telling, Writing Crime Fiction, Writing Crime Thrillers.
Are There Any New Stories?
Posted December 31, 2012 by Joel Goldman & filed under Story Telling.


The letter by Chris K. Gober of the Gober Group calls for a cease and desist of running the advertisement regarding Matt Rosendale.
"It has come to our attention that Montanans for Tester is airing a blatantly false and misleading advertisement on your station regarding Mr. Rosendale," the letter states.
Rosendale is running against incumbent Democratic Sen. Jon Tester in the Nov. 6 election. At the beginning of the ad Tester says he approves of its content. The ad is paid for by Montanans for Tester.
"In general the station will contact their own attorney and determine if they will run it or not," he said.
He also said that by law, a radio or TV station cannot change the content of a candidate's ad. But they can pull third-party ads.
"Like our neighbors, we were excited to raise our family there. We were promised a lot, but Matt Rosendale didn't deliver," Raile says, adding that the homes were built with weak foundations.
Gober said the ad gives the false impression Rosendale was responsible for the design and home construction. He also said courts have found Rosendale and his company were not involved and ruled in favor of Rosendale in its summary judgment.
He also notes that the plaintiffs' attorney, Stephanie Oblander of Great Falls, has called the advertisement unfair.
"Given that the courts of Montana and the plaintiffs' attorney, who litigated the claims against Mr. Rosendale have refused the truth of the advertisement, it is clear that Montanans for Tester is airing a blatantly false and misleading advertisement that defames Mr. Rosendale," Gober states.
Raile said Wednesday he stands by his comments and believes Rosendale let the residents down.
He said it is a matter of public record that multiple families sued Rosendale's company for negligence after experiencing problems with their homes in the development.
"Rosendale was warned before the homes were built about potential problems and he chose to ignore those warnings," Meagher said.
This letter surfaces the same time that a woman who lives in the Eagle Crossing subdivision said her home was featured in the ad without her consent and has asked Tester's staff to remove it from the commercial.
Anna Hewitt told the Tribune she has not had any structural problems with her home.
Hewitt, a Democrat who turned Republican during the 2016 presidential campaign of Donald Trump, said people are now calling her and asking if her house has a weak foundation. She said other neighbors without home issues are angry as well.
"I want it removed or else we will go after them," she said.
She first saw the ad while watching a recording of "Dr. Phil" on TV.
She then told her daughter "do not delete that" and her phone starting ringing with friends asking what was wrong with her house.
"I understand what (Tester campaign) is trying to say and what to do, but I don't understand him using my property to get that message across," she said.
Mark Doll, who said he is Hewitt's neighbor, agrees.
Doll would not say what party he supports.


text:
NOTICE: This is an archived press release. Information contained on this page may be outdated. Please refer to our latest press releases for up-to-date information.
Post date: May 23 2016
A.G. Schneiderman Announces Settlements With Three Real Estate Companies For Unlawful Housing Discrimination
Attorney General's Investigation Identified Evidence Of Systemic Discrimination Against Tenants Seeking To Use Section 8 Vouchers By Three Companies, Including Douglas Elliman, Fourth Largest Real Estate Company In The Country
NEW YORK – Attorney General Eric T. Schneiderman announced today that his office has secured settlement agreements with three real estate brokerage firms operating in New York City, Nassau County, and Westchester County, following investigations that revealed unlawful housing discrimination against potential applicants with Section 8 housing vouchers. Local regulations prohibit discrimination in housing on the basis of lawful source of income, a category that includes government vouchers as well any legitimate occupation.
"Turning away individuals from an apartment based on a lawful source of income is a blatant form of discrimination," Attorney General Schneiderman said. "Everyone deserves a fair shot at renting an apartment in New York—especially during a time when many are struggling to find affordable housing. We will not let unscrupulous companies create unlawful barriers to renters, and my office is committed to ensuring that everyone is treated equally under the law, regardless of race, ethnicity, or income."
"New York is in the midst of an affordable housing crisis, and programs like Section 8 are critical tools to keep hardworking families living in our City," said Scott M. Stringer, New York City Comptroller. "These companiesessentially told New Yorkers 'no Section 8 residents need apply,' mirroring decades of discrimination against our City's most vulnerable residents. The settlements announced today by Attorney General Schneiderman send a clear message that these unlawful actions have no place in New York."
"New Yorkers face so many hurdles finding affordable housing, and discrimination against source of income should not, and will not, be one of them," said New York City Public Advocate Letitia James. "I applaud Attorney General Schneiderman for his investigation to hold these firms accountable for keeping tenants from homes they are entitled to. We will never stop fighting to ensure that every New Yorker has a safe and decent home."
In 2014, the Attorney General reached agreements with three NYC real estate brokers and two Buffalo landlords for discrimination against prospective tenants who received government assistance.
In 2015, the office received a complaint that Empire State Equities, which manages properties throughout Manhattan and the Bronx, rejected a prospective tenant with a Section 8 voucher. The individual was initially told that Empire would not accept "programs," but when told that such a denial was unlawful discrimination, Empire claimed that it would accept Section 8, but said that there was a months-long waitlist for the apartment. The Attorney General's office then conducted undercover phone tests, asking if Section 8 vouchers would be accepted by Empire. Each time, the testers were told they would be put on a waiting list that ranged from three to four months. Meanwhile, testers who called about the same properties but did not mention Section 8 were told that the units were immediately available. The Attorney General's office then took testimony from the manager of Empire, who explained that a waitlist was essentially used to reject unwanted prospective tenants.
The Office of the Attorney General (OAG) also conducted compliance testing to determine if Douglas Elliman and Crifasi Real Estate engaged in unlawful housing discrimination. Douglas Elliman has over 70 offices in the country, including several that list properties in Nassau County, while Crifasi lists properties in both Westchester and New York City. The OAG found that representatives from both companies twice told undercover testers that Section 8 and other government assistance programs would not be accepted at certain properties. The OAG also discovered that Crifasi had no written policy for employees regarding compliance with fair housing rules. Douglas Elliman had a written policy that prohibited source of income discrimination and related training for its employees, yet several listings in Nassau County nonetheless indicated that "current employment" was required for tenants.
All companies have agreed to certain reforms, including:
Forwarding the OAG any complaints and documentation about housing discrimination
Developing new non-discriminatory policies
Maintaining rental information about certain properties to provide to OAG for review to ensure compliance with the law
Douglas Elliman and Crifarsi have also agreed to have their employees attend a Fair Housing training program.
Crifasi will pay a $40,000 fine to New York State, Douglas Elliman will pay $35,000, and Empire will pay a $13,000 penalty.
The Civil Rights Bureau of the Attorney General's Office is committed to promoting fair housing policies and combating discrimination faced by all New Yorkers. To file a civil rights complaint, contact the Attorney General's Office at (212) 416-8250, civil.rights@ag.ny.govor visit www.ag.ny.gov.


text:
The Walking Dead Review: "The Storm"
By Jim Vorel | March 31, 2019 | 10:41pm
Photos via AMC TV Reviews The Walking Dead
Surely, there's never been an episode of The Walking Dead, through the course of nine seasons, that is more perfectly and stupidly high-concept than "The Storm." And yea, verily, it shall always be remembered as the fruit of that time when one writer turned to another and said something along the lines of "Well, what about … winter?"
I mean, really. How can you do anything but laugh at The Walking Dead suddenly choosing to explore a concept so basic as "cold weather" after they've desperately avoided doing exactly that for the last NINE YEARS? It's such an obvious hurdle to the plausibility of communities such as Alexandria, The Hilltop and The Kingdom that it's the kind of thing The Walking Dead has avoided touching with a 10-foot pole in the past, but we're so clearly beyond the edge of "who gives a damn" at this point that not even the showrunners care about plausibility anymore. Suddenly, winter can be this impossible, horrific burden that can claim entire communities, such as The Kingdom, whose inhabitants are all setting out for The Hilltop en masse. Never mind the fact that in the setting of The Walking Dead, we're now some 10-11 years into the zombie apocalypse. Never mind the fact that these communities have somehow dealt with TEN WINTERS before, and emerged unscathed. A writer said the word "winter" to another, and now it's the subject of an episode. Enjoy!
"The Storm" is bookended by narration, like so many Walking Dead episodes, with Ezekiel talking over the radio with another character, who is revealed to be Judith in Alexandria. The big hook at the end of the episode is meant to be the crackle of static and "is anyone out there?" we briefly hear in the closing moments, but come on—we already know full well that there's another community out there that is somehow continuing to operate helicopters. We know that Rick is out there, after AMC pulled the old bait and switch with Andrew Lincoln's departure. We know this is all leading in the direction of the TV movies that will star Lincoln and Danai Gurira as Michonne. Every one of us knows this information, but it's still treated as a bombshell, somehow.
The meat of the episode is the pilgrimage of the population of The Kingdom, which variably switches between "20 people" and "hundreds of people" from shot to shot, as they head out at the worst possible time for The Hilltop, having waited for the dead of winter to make what would otherwise be a short and pleasant walk. It's unclear how much time has passed since The Whisperers stuck a bunch of secondary characters' heads on pikes, but it's been at least a few months, making this the third time skip in the course of a single Walking Dead season. It's generally unclear where everyone is, but Maggie receives a brief mention—they are apparently "sending letters" to wherever she is, the writers having not yet decided what the hell that means. Personally, I like to imagine that they're sending letters through time and space to the set of ABC's Whiskey Cavalier, asking Lauren Cohan to return.
Meanwhile, Lydia is suicidal, Carol is losing her mind yet again and slipping back into hermit-Carol mode, and Judith is running off into a blinding snowstorm in search of a dog who is literally named Dog. Oh, and Negan is a heroic character now. Sure, he was indirectly responsible for the death of Rick's son, but now he's saved the life of Rick's daughter. There's poetic justice in it, we will admit.
But why talk about things like characters and boring old plot (what little there is) when we can be going into depth discussing how completely, painfully stupid the mere concept of "Walking Dead Winter" truly is? In fact, let's break out the bullet points.
— Ezekiel is afraid of The Whisperers, saying "we don't know how to fight them yet!" How hard have you been trying to learn, man? They're human beings, with masks, who carry knives. They don't have guns. YOU DO. I suggest you use your guns to shoot them. This isn't rocket science. Just because you lost your war with The Kingdom's boilers, and somehow allowed The Whisperers to abduct a bunch of people out of your walled community during a festival, that doesn't mean you can't rectify things with judicious use of THE GUNS YOU BUILT A BULLET FACTORY TO SUPPLY.
— Michonne, Ezekiel, Carol and co. debate the danger of venturing out into Whisperer territory, but decide they need to do it because the horrible snowstorm will kill them otherwise. Bear in mind, the people making this discussion are bundled from head to toe in winter coats, hats, gloves and multiple layers. The Whisperers BARELY WEAR FREAKING CLOTHING. Michonne, you're concerned that The Whisperers are out there, watching you? In the storm that will apparently kill any of your people in minutes? How would people wearing rags and zombie masks, lurching around as slowly as possible, have any chance of immediately not dying in the same storm?
— Oh, never mind. When we visit The Whisperer encampment, there isn't even the barest suggestion of snow on the ground. I guess everything is fine!
Look, I don't even know what more to say, here. "The Storm" is arguably as bad and as nonsensical as The Walking Dead has ever been. We're headed into one more season of Whisperer conflicts, which will be the final one for Danai Gurira before she flies off to the same magical TV movie land as Rick Grimes. But I have no doubt that The Walking Dead will continue to limp on, having left behind any of the characters that anyone gave a damn about.
In the meantime, I'm looking forward to Game of Thrones, another diminished series where at least they spent the majority of seven seasons bemoaning and preparing for the coming of winter before it finally descended on them. On The Walking Dead, on the other hand, you know … winter just happens once every 10 years, in between episodes. And man, is it a pain when that happens.
Jim Vorel is a Paste staff writer and resident horror guru. You can follow him on Twitter for more film and TV writing.
Also from The Walking Dead
The Walking Dead Just Delivered Its Most Confusing Death Ever By Jim Vorel November 17, 2019 | 11:04pm
The Walking Dead Season 10 Premiere Draws Series-Low Ratings By Scott Russell October 8, 2019 | 12:34pm
The Walking Dead: "Lines We Cross" By Jim Vorel October 6, 2019 | 10:56pm
The Walking Dead Straight Bourbon Whiskey By Jim Vorel October 6, 2019 | 1:30pm
The Jimmy Carter Museum's Georgia Film Exhibit Is a Treasure Trove for Fans By Allison Keene September 11, 2019 | 1:10pm
The Walking Dead's Andrew Lincoln Joins Penguin Bloom, His First Feature Film in Nearly a Decade By Molly Schramm July 25, 2019 | 5:15pm
More from The Walking Dead
HBO Hopes Slow and Steady Wins the Space Race in Armando Iannucci's Avenue 5 By LaToya Ferguson January 16, 2020 | 10:30am
The Magicians Season 5 Works Through Grief with Grace By Rae Nudson January 13, 2020 | 10:00am
With Giri / Haji, Netflix Delivers a Masterful, Emotionally Engrossing International Thriller By Allison Keene January 9, 2020 | 10:45am
The Outsider's Doppelganger Crime Tale Keeps Stephen King Fans at Arm's Length By Jacob Oller January 9, 2020 | 9:50am
Freeform's Immigrant-Focused Party of Five Reboot Is Compelling, Not Preachy By Amy Amatangelo January 8, 2020 | 11:49am
The Remarkable Final Season of Schitt's Creek Is Filled with More Love Than Ever By Allison Shoemaker January 7, 2020 | 5:32pm
Indigo Girls 2013-02-24T00:00:00-07:00
Kool Keith 2010-12-09T00:00:00-07:00
The Polyphonic Spree 2016-06-02T00:00:00-07:00


PHP :: Request #58891 :: Passing of parameters by reference should be changed.
Passing of parameters by reference should be changed.
This extension uses pass-by-reference which is deprecated and produces a warning in PHP >= 5.3.0.
It should be modified to accept parameters by value instead.
That's not the PECL uuid extension.


text:
Oxfam international lobby team: respond now to West Africa food crisis
by Oxfam | April 13, 2012
Since the first warnings of drought and poor harvests in Africa's Sahel region in late 2011, communities in many areas have been threatened by a looming food crisis.
That crisis is now real. More than 15 million people are vulnerable to hunger in seven countries: Niger, Mauritania, Mali, Chad, The Gambia, Senegal, and Burkina Faso.
An Oxfam team from the region was in Ottawa, Canada, Thursday, April 12th, to call for an urgent, early response to protect lives and livelihoods, averting a large-scale humanitarian disaster like one in the Horn of Africa last summer.
"We can still avoid the worst by delivering a timely adequate response," Eric Hazard says in this Oxfam Canada video. Mr. Hazard is the Senegal-based Oxfam International GROW campaign coordinator for the Sahel region.
The twin message by teams on the Oxfam lobby tour in Ottawa, Washington, London, Spain and France, is that long-term solutions are possible and necessary to break the cycle of hunger in West Africa, a region with huge potential.
Mamadou Goïta of Mali, executive secretary of ROPPA, the West African Peasants' and Farmers' Network, speaks in this Oxfam Canada video about the importance of investment in small-scale farming and processing as "a key starting point to break the cycle of the food crisis in the region."
They were joined at a news conference on Parliament Hill by Mahamadou Issoufou, executive secretary of the Federation of Peasant Group Unions of Niger, Robert Fox, executive director of Oxfam Canada, and Lina Holguin, Oxfam Quebec policy director. Read the Press Release.
Less than half of the $724.5 million the United Nations said in January was needed in the region had been committed in early April. The need is likely to increase towards $1bn in coming weeks.
-Juliet O'Neill, Media Officer, Oxfam Canada


Hit the waves and stay connected: KENWOOD outdoor and marine products provide the best sounding outdoor experience available. Packed with built-in features and advanced connectivity that turns a smartphone into the hottest entertainment device. This unit is engineered to withstand harsh outdoor environments, look great and sound even better.


Playful clutch by night, sweet handbag by day. Also comes with a detachable cross-body strap giving you three ways to carry this bag. Features spacious zipped pocket on rear.
• Magnetic closure main compartment.
• New Republic special geomatric print-lined interior, 15cm zip pocket.


ORUÃ is a child of downtown, was born at night and attends the balls at dawn. The latest music project by Lê Almeida, one of the most important Indie rock artists from South America to be discovered, this time accompanied by João Luiz and Phill Fernandes.
The ensemble emerged at the end of 2016, during improvisation sessions at Escritório* in Rio de Janeiro, where everything was taped, trimmed, reassembled and pasted, giving birth to their first record Sem Bênção / Sem Crença, released in Brazil by Transfusão Noise Records* and just released in the United States as a double LP via IFB Records.
With nuances of krautrock and free jazz, the lyrics, always in Portuguese, bring encoded messages and guided symbols, turning music into a potential weapon. Live, ORUÃ is a stage for fraternity, occasionally counting on a second drummer, percussion and some extra vocals.
Between one trip and another, they released some singles and are recording their second album, Romã, which will be released in Brazil and in the US in early 2019 on vinyl, another partnership between Transfusão Noise Records and IFB Records.
*Transfusão Noise Records (TNR) is an independent record label founded by Lê Almeida in 2004. Hailing from Rio de Janeiro, Brazil, the label has released 99 records over the years, including Lê's bands Oruã, Treli Feli Repi, Tape Rec, Babe Florida, as well as his solo work.
It was born out of the idea of creating a label to represent all of the good noise being made between friends in the suburbs of Rio de Janeiro, Baixada Fluminense.
More recently, the label's founder, Lê Almeida, one of the label's partners, João Casaes, and further João Luiz, who also plays in Oruã, toured as the new members of Built to Spill, playing shows in Brazil and Chile.
*Created in 2013, Escritório "Office", the label's headquarters, has assembled bands in a DIY community. There, the bands meet to rehearse, record, hold events, workshops and do social studies. Over these 5 years, Escritório has received bands from all over Brazil and the world, carrying the honor of being the samba's capital main punk underground house.


Dodgers manager Dave Roberts on Friday announced relievers Yimi Garcia, Dylan Floro and Caleb Ferguson have made the club's opening day roster, nearly rounding out the bullpen a day before the team departs for California. One vacancy remains.
The initial plan was for Julio Urias to begin the season as a reliever. The thinking was the Dodgers could closely monitor his workload two years after major shoulder surgery and ensure he would be available in the playoffs -- possibly as a starter. But Rich Hill's strained medial collateral ligament has complicated matters. The Dodgers need to replace the veteran lefty in the rotation and they will go with their young one.
Urias' next outing is scheduled for Tuesday in the Freeway Series at Dodger Stadium. He is then slated to start against either the Arizona Diamondbacks the following Sunday or the San Francisco Giants in the fifth game of the season.
As a result, the Dodgers will choose someone to complete their eight-man bullpen. Right-handers Kevin Quackenbush and Stetson Allie are the only relievers still in major league camp who aren't projected to make the opening day roster. But neither is on the 40-man roster. Other options with relief experience on the 40-man roster include right-handers JT Chargois, Jaime Schultz and Josh Sborz, and left-handers Donnie Hart and Adam McCreery.
Chargois, 28, was the last of the group sent to minor league camp. He was optioned Wednesday after allowing four runs in 6⅔ innings this spring. He posted a 3.34 earned-run average in 39 games for the Dodgers last season.
Joc Pederson was not in the Dodgers' lineup Friday after exiting Thursday's game with back spasms. Roberts, however, insisted the decision was precautionary.
"He could've played [Friday] and finished the game, and could've played today but there's not a whole lot of upside," Roberts said.
Roberts added he expects the outfielder to play in all three games in the Freeway Series.


With more power than ever to drive demanding applications, creative efforts, and the most serious workstation tasks, deliver second generation AMD Ryzen™ Threadripper™ processors to your customers, and hand them the keys to unleashed creativity and possibility.
The Quick Reference Guide highlights 2nd Generation AMD Ryzen™ Threadripper™ Processors' features, specifications, and more!
The packaging info sheet includes the 2nd Generation AMD Ryzen™ Threadripper™ Processor details such as box dimensions and weight.
The 2nd Generation AMD Ryzen™ Threadripper™ Processor toolkit is filled with assets to help you promote AMD's fastest processor.
Watch the replay of the webinar as Don Woligroski, AMD's Product Marketing Manager, introduces the world's first 32-core desktop processor.¹ With up to 64-threads of processing power your creativity is limited only by your imagination.
One of the pillars of AMD Radeon Software is to ensure a reliable stable experience for both gamers and professional users. In a head-to-head test by QA Consultants comparing six AMD and NVIDIA graphics cards, the QA report concluded that "AMD has the most stable graphics driver in the industry.
We are very excited to announce the expansion of the AMD Partner Hub, previously focused solely on the Channel, to support our Consumer and Commercial partners.
Now all AMD Partners can download relevant and timely sales and marketing materials to efficiently support AMD sales and help customers make the best buying decisions.
Make sure that you have the latest Channel Partner resources! Bookmark amd.com/partner and visit often for the newest AMD product trainings, webinars, marketing materials, sales tools, and other resources.


Shalom! We arrived yesterday evening with all family members in tact and only missing one piece of luggage - the baby's car seat (he rode commando from the airport), which arrived to my in-laws this morning via London. When we got to passport control and the woman in the next line over cut in front of us when our window became available, I knew we'd arrived in the right country. The older kids went to sleep last night around 11pm and woke up at noon. Not bad. The baby was up pretty much from midnight until 4am. Not great.
Mr. Rosen and I ducked out at 10 this morning to start our administrative journey. We dragged the baby along in an effort to reset his internal clock. First stop, the Ministry of the Interior where we had to change our National ID cards to reflect our marriage and three kids. As we got out of the car I started to put the baby's little fleece slippers on and Mr. Rosen said, I don't think he needs those today (it's about 65 out). I knew that if we didn't put them on I would get reamed by at least eleven older women for exposing my child to the elements. We stopped for a latte at the mall under the ministry and a fifty year old man mentioned to us that it was windy outside and that our baby should have a sweater. Didn't see that one coming. While we were sitting there we also saw a young woman come in with her friends to get coffee wearing the clothes she was trying on from the store next door still with tags and a security device attached. Maybe she got thirsty all of a sudden? Only in Israel.
We headed upstairs to get passport pictures taken and we saw a a religious woman (head covering and modest flowy garb) and her teenage son (side curls and giant knit kippah) in line, both wearing Vibram five-finger frog feet "shoes". I guess the quest for good arch support is universal.
With our photos and baby in hand we headed upstairs to the Ministry. The Bedouin man ahead of us was there to register his newest child too. I overheard the clerk doing triage handing out the numbers at the front desk say to him, first wife or second? Nice. The Bedouin are still keeping it real I guess.
After waiting for about forty minutes, which was not a long wait considering the last time I was here fifteen years ago I actually learned how to knit and completed a six foot long scarf in the time it took before I spoke to anyone official, it's our turn. We are both in the system as citizens but it apparently takes the same system 72 hours from the time we go through passport control to recognize we are in country. We have to come back on Sunday. Minor setback. Fortunately Mr. Rosen can come by himself and complete the task for both of us.
Next up, finalizing the bank account that my in-laws already opened for us. On Thursdays the banks are closed from 12-4 and reopen from 4-7. Until then, the kids are at the park and the baby is asleep and mama needs to take a shower. In queue after the bank, shopping for a refrigerator, Ministry of Absorption, elementary school registration and dealing with our iPhones that don't work here. Good times. So far I have not yelled at anyone or cried or used any vulgar hand gestures.


text:
Ball Don't Lie
BDL 25: Is the new-look Indiana Pacers core worth fearing?
Kelly Dwyer
Myles Turner, in the sun. (Getty Images)
The NBA offseason has brought many changes to rosters, coaching staffs, and the list of championship contenders. As we draw closer to opening night, it's time to move our focus from the potential impact of each offseason event and onto the broader issues that figure to define this season. The BDL 25 takes stock of, uh, 25 key storylines to get you up to speed on where the most fascinating teams, players, and people stand on the brink of 2016-17.
Lost in the ha-ha feigned outrage behind Courtney Lee's decision to amplify his New York Knicks into "contender" status was the similar sentiment shared by Indiana Pacers big (or, at least, "tall") man Myles Turner.
[Follow Dunks Don't Lie on Tumblr: The best slams from all of basketball]
Even after an up and down rookie year as a pro, following a disappointing stint in the NCAAs, Turner is looked upon as the Pacers' next great cornerstone. A do-it-all center/forward perfectly set to act as the combative force helping to push Indiana's move into the future.
And, as Turner sees it, a move back into the upper echelon of the East, following a two-season absence:
"As a team, we want to finish top three in the East and I feel like we're very capable of doing so. On paper, we're very talented, but it's about how we put stuff together. I do feel like the East will be a lot stronger next year with some of the moves that have been made in our conference, but I feel like we can go out there and get the job done and finish in the top three.
"That's the goal, and then we want to go make a deep playoff run. And obviously, we're all chasing rings; that's a big goal of mine. I don't see why we can't do it next year. I know that 'sounds good' and anybody can just say that, but I'm a very confident player and with that confidence comes ambition."
As the too-sweaty plains sees its summer run droll on, it isn't too tough a task to get behind Turner's sense of zeal.
His "disappointment stint in the NCAAs" likely had more to do with the untenable situation he was presented with during his lone year at the University of Texas at Austin. And his "up and down rookie year" was unavoidable after an early-season hand injury coupled with former coach Frank Vogel's (at-times understandable) decision to present him with an inconsistent rotation role.
Turner started in half of his 60 games, notching averages of 10.3 points, 5.5 rebounds and 1.4 blocks in just under 23 minutes a contest. By the time the playoffs hit the sometimes-starter (four out of seven games) led the postseason in blocks per game (3.3, despite playing just 28 minutes a contest) and block percentage in Indiana's first round dismissal at the hands of the Toronto Raptors.
If Turner and his Pacers want to hit top-three status, they'll have to provide that just-about-even postseason showing with the Raptors over the course of an 82-game season. Cleveland is a given for the top three, even if injuries and malaise hit following quite long 2014-15 and 2015-16 campaigns. Boston is looking to edge its way into that theatre, and any number of Eastern surprises could take flight.
Four teams tied for third place last year, with these Pacers and the similarly champing Pistons just a few games behind that mess. Meanwhile, hopefuls in Chicago and Washington are pining to return to fjords form, with younger squads in Milwaukee and Orlando setting sights on an unforeseen one-year jump. The East hardly any prettier, as we gear for 2016-17, and nobody is scaring Cleveland, but that hardly means the thirst for that top three placement isn't real.
Would a crashing Myles Turner and too-good Paul George be enough to lift the Pacers into that 50-win realm?
To begin, Myles don't crash.
For someone with his length, athletic gifts, and sometimes-there offensive game, it would seem like Turner would have bounded into this league as a typically raw offensive rebound-first, figure everything else out-later sort of youngster. Instead, for whatever reasons, he stayed away from caroms on that end of the floor for both the regular and postseason. Any hopes for him to consistently turn into a lights-out splash maven from the perimeter may have to wait – his stroke fundamentals are sound and his long two-point percentage is impressive, but Turner missed 13 of 16 three-pointers in his age 19 season.
This is where Paul George and to a lesser extent Jeff Teague – two locked-in scorers from behind the arc when a hand isn't inching too close to the schnoz – come in.
George took seven three-pointers a game last year, which is a lot even in the glorious modern era that we find ourselves in, making 37 percent of his looks. Teague hit a robust 40 percent from out there, even as the line of thinking in defending his pick and roll game started to recognize his iffy finishing touch on contested drives to the hoop. Together the fully-healthy stalwart and new addition (working with one year left on his contract, in his hometown) will be charged with providing the veteran heft needed to turn the Pacers into something consistently formidable.
That is the core. You can be fearful of Monta Ellis' odd Sleepy Floyd impersonations or respectful of what Al Jefferson might bring to this group off the bench (or as a starter) down low, but George, Teague and Turner will act as the core.
Will that be enough?
In the East, potentially.
George hardly dipped his toe into things during his first full year back from a broken leg, establishing career highs in points and free throw attempts per game. At age 26, and with Teague around to take more chances with the ball than George Hill ever did (but not too many chances with it), he should thrive.
Jeff Teague meets the brass. (Getty Images)
As should Teague. The longtime Atlanta Hawk only seemed to have but one comfortable year in Georgia, not co-incidentally his 2014-15 All-Star turn, either staving off nagging injury or role (too young, youngster behind him, contract year, etc.) limitations while stuck trying to find offensive balance.
The sense of give and take between Teague's handling of Nate McMillan's offense is better left for a season preview or, more appropriately, a year-end summation, but for now the 28-year old would seem to be in the catbird seat. The "McMillan doesn't really run fast offenses" revelations just about hit by the time Nate was even done with his introductory press conference alongside Larry Bird, and as a result of that outcry (to say nothing of the obvious adaptation to the talent given him) McMillan likely will not ask Teague to act as a pinpoint, get-out-of-the-way type to remind of Luke Ridnour or Steve Blake.
Which would be a warming start, because the Pacers will need an all-out Jeff Teague attack to help the team turn the corner in the wake of the respected-yet-boxy stylings of George Hill. He'll have the screenin' friends in the frontcourt to aid him in his turns – Thaddeus Young will be a boon on both sides of the court, and Jefferson can still crash for rebounds defensively – and few excuses in a contract year.
The Pacers will play the bulk of their contests against Eastern Conference counterparts and it's possible that spots No. 2 through No. 13 (or 14, we see you Bojan) could be considered a coin-flip matchup. The Pacers have to take a healthy chunk of the pairings placed on their side of the Mississippi while working against counterparts that have seen Teague before, opponents that know what Paul George just did in Rio, and coaches that have been waiting for Myles Turner to bust out.
"Top three" isn't just ambitious, it's a real possibility. That core, however, will have to play to the brink of its capabilities for the Indiana Pacers to join the East's sub-elite. Good-to-great is still a hell of a jump.
Previously, on BDL 25:
Chris Bosh's increasingly hazy career prospects
Kevin Durant sets about winning back our love
Stephen Curry's search for an encore, and for invincibility lost
The NBA, social activism and a change we need to see in 2016-17
The Trail Blazers, and the promise and peril of 'pretty good'
Will the Pistons ever get into gear?
Introducing the (maybe) thoroughly modern Grizzlies
Kelly Dwyer is an editor for Ball Don't Lie on Yahoo Sports. Have a tip? Email him at KDonhoops@yahoo.com or follow him on Twitter!
Follow @KDonhoops
NFL playoffs bracket: AFC and NFC championship game matchups, kickoff times, TV information
There will be two fantastic matchups for conference championship weekend.


text:
Q: string generated from c# into view of MVC I am using a custom validator at class level in my MVC appications's model.
So inside the custom validator I am generating the error message based on the conditions and tryint to return to the MVC and assign it to summary list as below.
Model name is "Insured" here
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
            string errorMessage = "";
           //StringBuilder errorMessage1 = new StringBuilder();

            var model = value as Insured;
            if (model == null)
            {
                return new ValidationResult("No valid Session exists.");
            }
            else
            {
                if (model.Age > 19)
                  errorMessage += " <li> Age cannot be greater than 19. </li> " + Environment.NewLine;

            }
      return new ValidationResult(errorMessage);
    }

And so on adding all the text to errormessage string.But when i display it on the page it is displaying everything in one line instead of displaying each one in next line sunce I am using Environment.NewLine.
I tried with <br/> \n\r and so on but everything is displayed as a text instead of html.
I tried to use string builder also.
Displaying: <li> Age cannot be greater than 19. </li><li> Another error. </li>
instead of

* Age cannot be greater than 19.
* Another error.
EDIT:
When i go into HTML by editing from firebug and just give a space inside generated error message everything getting aligned perfectly alright. This is so wierd, dont understand the issue.

A: Try HtmlString instead of string
new System.Web.HtmlString(" <li> Age cannot be greater than 19. </li> ");

redpajama_set_name: RedPajamaStackExchange


Hyundai's premium sedan battles it out with Infiniti's top-shelf Q70 GT for luxo-barge supremacy.
Analogue clock underscores a classy cabin, yet it's modern enough to feature slick ambient lighting, though 'leather appointed' trim is not all actual leather. Masses of rear legroom and there's an armrest with controls for front seat position, audio and the rear window shade. Boot opens hands-free when it detects the key; hauls 493 litres.
Hyundai's 3.8-litre V6 is powerful but not especially sonorous; musters 397Nm at a steep 5000rpm and 232kW at 6000rpm. Eight-speed auto keeps it spinning for 0-100km/h in 6.5sec, while combined-cycle consumption is only okay for a two-tonne limo, at 11.2L/100km. Thankfully, the Genesis is happy with a (77L) tankful of 91 RON.
Encouraging initial ride and refinement impressions from the back seat, and similarly positive from behind the wheel. Isolates tyre, wind and suspension noise superbly, with no unwanted road and drivetrain vibes, and rides beautifully. Conservative combination of 245/45 Hankooks on 18-inch wheels with locally tuned suspension do the job.
Initial dynamic assessment from a quick track session suggests the Genesis is quite good fun, but away from its natural habitat, it's no Ultimate Driving Machine. Yet it's well balanced, with accurate steering and decent drive out of corners. However, the rack-mounted motor-assisted steering is low on feel and ESC can be over-zealous.
Shared equipment includes a reversing camera, auto wipers, dual-zone climate control, powered and heated front seats, electric steering column, smart key, sat-nav, bluetooth connectivity and tyre-pressure monitoring. But the Q70's lane-departure and blind-spot systems provide corrective input, and it has ventilated front seats and a sunroof.
Infiniti features semi-aniline leather and terrific build quality. Design is a bit fussy but the overall vibe is modern Jap-luxe. Foot parking brake is old-fashioned, though driver's memory function adds exterior mirror position and climate control setting to the usual seat and steering wheel position. Rear compartment is generous; likewise its 500-litre boot.
Smaller 3.7-litre V6 makes less torque (360Nm) but spins to 7000rpm to produce 235kW and has a purposeful, if coarse, note. It's a bit quicker (and sportier) than the Hyundai, sprinting to 100km/h in 6.2sec. Relatively light 1719kg kerb weight helps Q70 deliver 10.2L/100km economy. And seven-speed auto's downshift rev-match function is cool.
GT level is the Q70 sweet spot if ride comfort is a priority. With sports suspension – and pretensions – dropped, along with the Sport Premium's 20s (in favour of modest 18s with 245/50 tyres), the Infiniti takes on a more relaxed touring persona. All versions are quiet inside but the GT is even better on narrower rubber with fatter sidewalls.
On smooth roads the Q70 is entertaining and reasonably well balanced, its variable-assist, speed-sensitive rack-and-pinion steering moderate in its responses. However, the common bumpy Aussie road removes much of the Infiniti's poise and ultimately betrays a lack of chassis cohesion and dynamic polish.
Infiniti money, though they're close in terms of spec and equipment. The Hyundai is a bit roomier, with a more appealing cabin design, but both do non-Euro prestige respectably well. On the flipside, the Q70 gets the nod in the drivetrain department, being sportier, quicker and thriftier. Yet, as we summarise in Showroom, the 'Hyundai Genesis is a better luxury sedan'.