text:
package org.nlpcn.es4sql;

import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Range;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.InternalMultiBucketAggregation;
import org.elasticsearch.search.aggregations.bucket.filter.InternalFilter;
import org.elasticsearch.search.aggregations.bucket.filter.InternalFilters;
import org.elasticsearch.search.aggregations.bucket.geogrid.InternalGeoHashGrid;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.InternalHistogram;
import org.elasticsearch.search.aggregations.bucket.nested.InternalNested;
import org.elasticsearch.search.aggregations.bucket.nested.InternalReverseNested;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.Avg;
import org.elasticsearch.search.aggregations.metrics.ExtendedStats;
import org.elasticsearch.search.aggregations.metrics.InternalGeoBounds;
import org.elasticsearch.search.aggregations.metrics.InternalSum;
import org.elasticsearch.search.aggregations.metrics.InternalTopHits;
import org.elasticsearch.search.aggregations.metrics.Max;
import org.elasticsearch.search.aggregations.metrics.Min;
import org.elasticsearch.search.aggregations.metrics.Percentiles;
import org.elasticsearch.search.aggregations.metrics.Stats;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.aggregations.metrics.ValueCount;
import org.junit.Assert;
import org.junit.Test;
import org.nlpcn.es4sql.exception.SqlParseException;
import org.nlpcn.es4sql.query.SqlElasticSearchRequestBuilder;

import java.io.IOException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.elasticsearch.search.aggregations.bucket.range.Range.Bucket;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasKey;
import static org.nlpcn.es4sql.TestsConstants.TEST_INDEX_ACCOUNT;
import static org.nlpcn.es4sql.TestsConstants.TEST_INDEX_DOG;
import static org.nlpcn.es4sql.TestsConstants.TEST_INDEX_GAME_OF_THRONES;
import static org.nlpcn.es4sql.TestsConstants.TEST_INDEX_LOCATION;
import static org.nlpcn.es4sql.TestsConstants.TEST_INDEX_NESTED_TYPE;

public class AggregationTest {

	@Test
	public void countTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account", TEST_INDEX_ACCOUNT));
		ValueCount count = result.get("COUNT(*)");
		Assert.assertEquals(1000, count.getValue());
	}

	@Test
	public void sumTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT SUM(balance) FROM %s/account", TEST_INDEX_ACCOUNT));
		Sum sum = result.get("SUM(balance)");
		assertThat(sum.getValue(), equalTo(25714837.0));
	}

    // script on metric aggregation tests. uncomment if your elastic has scripts enable (disabled by default)
    //todo: find a way to check if scripts are enabled
//    @Test
//    public void sumWithScriptTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
//        Aggregations result = query(String.format("SELECT SUM(script('','doc[\\'balance\\'].value + doc[\\'balance\\'].value')) as doubleSum FROM %s/account", TEST_INDEX));
//        Sum sum = result.get("doubleSum");
//        assertThat(sum.getValue(), equalTo(25714837.0*2));
//    }
//
//    @Test
//    public void sumWithImplicitScriptTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
//        Aggregations result = query(String.format("SELECT SUM(balance + balance) as doubleSum FROM %s/account", TEST_INDEX));
//        Sum sum = result.get("doubleSum");
//        assertThat(sum.getValue(), equalTo(25714837.0*2));
//    }
//
//    @Test
//    public void sumWithScriptTestNoAlias() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
//        Aggregations result = query(String.format("SELECT SUM(balance + balance) FROM %s/account", TEST_INDEX));
//        Sum sum = result.get("SUM(script=script(balance + balance,doc('balance').value + doc('balance').value))");
//        assertThat(sum.getValue(), equalTo(25714837.0*2));
//    }
//
//    @Test
//    public void scriptedMetricAggregation() throws SQLFeatureNotSupportedException, SqlParseException {
//        Aggregations result = query ("select scripted_metric('map_script'='if(doc[\\'balance\\'].value > 49670){ if(!_agg.containsKey(\\'ages\\')) { _agg.put(\\'ages\\',doc[\\'age\\'].value); } " +
//                "else { _agg.put(\\'ages\\',_agg.get(\\'ages\\')+doc[\\'age\\'].value); }}'," +
//                "'reduce_script'='sumThem = 0; for (a in _aggs) { if(a.containsKey(\\'ages\\')){ sumThem += a.get(\\'ages\\');} }; return sumThem;') as wierdSum from " + TEST_INDEX + "/account");
//        ScriptedMetric metric = result.get("wierdSum");
//        Assert.assertEquals(136L,metric.aggregation());
//    }
//
//    @Test
//    public void scriptedMetricConcatWithStringParamAndReduceParamAggregation() throws SQLFeatureNotSupportedException, SqlParseException {
//        String query = "select scripted_metric(\n" +
//                "  'init_script' = '_agg[\"concat\"]=[] ',\n" +
//                "  'map_script'='_agg.concat.add(doc[field].value)' ,\n" +
//                "  'combine_script'='return _agg.concat.join(delim);',\t\t\t\t\n" +
//                "  'reduce_script'='_aggs.removeAll(\"\"); return _aggs.join(delim)'," +
//                "'@field' = 'name.firstname' , '@delim'=';',@reduce_delim =';' ) as all_characters \n" +
//                "from "+TEST_INDEX+"/gotCharacters";
//        Aggregations result = query (query);
//        ScriptedMetric metric = result.get("all_characters");
//        List<String> names = Arrays.asList(metric.aggregation().toString().split(";"));
//
//
//        Assert.assertEquals(4,names.size());
//        String[] expectedNames = new String[]{"brandon","daenerys","eddard","jaime"};
//        for(String name : expectedNames){
//            Assert.assertTrue("not contains:" + name,names.contains(name));
//        }
//    }
//
//    @Test
//    public void scriptedMetricAggregationWithNumberParams() throws SQLFeatureNotSupportedException, SqlParseException {
//        Aggregations result = query ("select scripted_metric('map_script'='if(doc[\\'balance\\'].value > 49670){ if(!_agg.containsKey(\\'ages\\')) { _agg.put(\\'ages\\',doc[\\'age\\'].value+x); } " +
//                "else { _agg.put(\\'ages\\',_agg.get(\\'ages\\')+doc[\\'age\\'].value+x); }}'," +
//                "'reduce_script'='sumThem = 0; for (a in _aggs) { if(a.containsKey(\\'ages\\')){ sumThem += a.get(\\'ages\\');} }; return sumThem;'" +
//                ",'@x'=3) as wierdSum from " + TEST_INDEX + "/account");
//        ScriptedMetric metric = result.get("wierdSum");
//        Assert.assertEquals(148L,metric.aggregation());
//    }
//

    @Test
	public void minTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT MIN(age) FROM %s/account", TEST_INDEX_ACCOUNT));
		Min min = result.get("MIN(age)");
		assertThat(min.getValue(), equalTo(20.0));
	}

	@Test
	public void maxTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT MAX(age) FROM %s/account", TEST_INDEX_ACCOUNT));
		Max max = result.get("MAX(age)");
		assertThat(max.getValue(), equalTo(40.0));
	}

	@Test
	public void avgTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT AVG(age) FROM %s/account", TEST_INDEX_ACCOUNT));
		Avg avg = result.get("AVG(age)");
		assertThat(avg.getValue(), equalTo(30.171));
	}

	@Test
	public void statsTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT STATS(age) FROM %s/account", TEST_INDEX_ACCOUNT));
		Stats stats = result.get("STATS(age)");
		Assert.assertEquals(1000, stats.getCount());
		assertThat(stats.getSum(), equalTo(30171.0));
		assertThat(stats.getMin(), equalTo(20.0));
		assertThat(stats.getMax(), equalTo(40.0));
		assertThat(stats.getAvg(), equalTo(30.171));
	}

    @Test
    public void extendedStatsTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        Aggregations result = query(String.format("SELECT EXTENDED_STATS(age) FROM %s/account", TEST_INDEX_ACCOUNT));
        ExtendedStats stats = result.get("EXTENDED_STATS(age)");
        Assert.assertEquals(1000, stats.getCount());
        assertThat(stats.getMin(),equalTo(20.0));
        assertThat(stats.getMax(),equalTo(40.0));
        assertThat(stats.getAvg(),equalTo(30.171));
        assertThat(stats.getSum(),equalTo(30171.0));
        assertThat(stats.getSumOfSquares(),equalTo(946393.0));
        Assert.assertTrue(Math.abs(stats.getStdDeviation()- 6.008640362012022) < 0.0001);
        Assert.assertTrue(Math.abs(stats.getVariance()- 36.10375899999996) < 0.0001);
    }

    @Test
    public void percentileTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        Aggregations result = query(String.format("SELECT PERCENTILES(age) FROM %s/account", TEST_INDEX_ACCOUNT));
        Percentiles percentiles = result.get("PERCENTILES(age)");
        Assert.assertTrue(Math.abs(percentiles.percentile(1.0) - 20.0) < 0.001 );
        Assert.assertTrue(Math.abs(percentiles.percentile(5.0) - 21.0) < 0.001 );
        Assert.assertTrue(Math.abs(percentiles.percentile(25.0) - 25.0) < 0.001 );
        Assert.assertTrue(Math.abs(percentiles.percentile(75.0) - 35.0) < 0.001 );
        Assert.assertTrue(Math.abs(percentiles.percentile(95.0) - 39.0) < 0.001 );
        Assert.assertTrue(Math.abs(percentiles.percentile(99.0) - 40.0) < 0.001 );
    }

    @Test
    public void percentileTestSpecific() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        Aggregations result = query(String.format("SELECT PERCENTILES(age,25.0,75.0) x FROM %s/account", TEST_INDEX_ACCOUNT));
        Percentiles percentiles = result.get("x");
        Assert.assertTrue(Math.abs(percentiles.percentile(25.0) - 25.0) < 0.001 );
        Assert.assertTrue(Math.abs(percentiles.percentile(75.0) - 35.0) < 0.001 );
    }

    @Test
	public void aliasTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT COUNT(*) AS mycount FROM %s/account", TEST_INDEX_ACCOUNT));
		assertThat(result.asMap(), hasKey("mycount"));
	}

	@Test
	public void groupByTest() throws Exception {
		Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY gender", TEST_INDEX_ACCOUNT));
		Terms gender = result.get("gender");
		for(Terms.Bucket bucket : gender.getBuckets()) {
			String key = bucket.getKey().toString();
			long count = ((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue();
			if(key.equalsIgnoreCase("m")) {
				Assert.assertEquals(507, count);
			}
			else if(key.equalsIgnoreCase("f")) {
				Assert.assertEquals(493, count);
			}
			else {
				throw new Exception(String.format("Unexpected key. expected: m OR f. found: %s", key));
			}
		}
	}

    @Test
    public void postFilterTest() throws Exception {
        SqlElasticSearchRequestBuilder select = getSearchRequestBuilder(String.format("SELECT /*! POST_FILTER({\"term\":{\"gender\":\"m\"}}) */ COUNT(*) FROM %s/account GROUP BY gender", TEST_INDEX_ACCOUNT));
        SearchResponse res = (SearchResponse) select.get();
        Assert.assertEquals(507, res.getHits().getTotalHits().value);

        Aggregations result = res.getAggregations();
        Terms gender = result.get("gender");
        for (Terms.Bucket bucket : gender.getBuckets()) {
            String key = bucket.getKey().toString();
            long count = ((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue();
            if (key.equalsIgnoreCase("m")) {
                Assert.assertEquals(507, count);
            } else if (key.equalsIgnoreCase("f")) {
                Assert.assertEquals(493, count);
            } else {
                throw new Exception(String.format("Unexpected key. expected: m OR f. found: %s", key));
            }
        }
    }

	@Test
	public void multipleGroupByTest() throws Exception {
		Set expectedAges = new HashSet<Integer>(ContiguousSet.create(Range.closed(20, 40), DiscreteDomain.integers()));

		Map<String, Set<Integer>> buckets = new HashMap<>();

		Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY gender,  terms('field'='age','size'=200,'alias'='age')", TEST_INDEX_ACCOUNT));
		Terms gender = result.get("gender");
		for(Terms.Bucket genderBucket : gender.getBuckets()) {
			String genderKey = genderBucket.getKey().toString();
			buckets.put(genderKey, new HashSet<Integer>());
			Terms ageBuckets = (Terms) genderBucket.getAggregations().get("age");
			for(Terms.Bucket ageBucket : ageBuckets.getBuckets()) {
				buckets.get(genderKey).add(Integer.parseInt(ageBucket.getKey().toString()));
			}
		}

		Assert.assertEquals(2, buckets.keySet().size());
		Assert.assertEquals(expectedAges, buckets.get("m"));
		Assert.assertEquals(expectedAges, buckets.get("f"));
	}

    @Test
    public void multipleGroupBysWithSize() throws Exception {
        Set expectedAges = new HashSet<Integer>(ContiguousSet.create(Range.closed(20, 40), DiscreteDomain.integers()));

        Map<String, Set<Integer>> buckets = new HashMap<>();

        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY gender, terms('alias'='ageAgg','field'='age','size'=3)", TEST_INDEX_ACCOUNT));
        Terms gender = result.get("gender");
        Assert.assertEquals(2,gender.getBuckets().size());
        for(Terms.Bucket genderBucket : gender.getBuckets()) {

            String genderKey = genderBucket.getKey().toString();
            buckets.put(genderKey, new HashSet<Integer>());
            Terms ageBuckets = genderBucket.getAggregations().get("ageAgg");
            Assert.assertEquals(3,ageBuckets.getBuckets().size());

        }

    }

    @Test
    public void termsWithSize() throws Exception {

        Map<String, Set<Integer>> buckets = new HashMap<>();

        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY terms('alias'='ageAgg','field'='age','size'=3)", TEST_INDEX_ACCOUNT));
        Terms gender = result.get("ageAgg");
        Assert.assertEquals(3,gender.getBuckets().size());

    }

    @Test
    public void termsWithMissing() throws Exception {
        Aggregations result = query(String.format("SELECT count(*) FROM %s/gotCharacters GROUP BY terms('alias'='nick','field'='nickname','missing'='no_nickname')", TEST_INDEX_GAME_OF_THRONES));
        Terms name = result.get("nick");
        Assert.assertNotNull(name.getBucketByKey("no_nickname"));
        Assert.assertEquals(6, name.getBucketByKey("no_nickname").getDocCount());
    }

    @Test
    public void termsWithOrder() throws Exception {
        Aggregations result = query(String.format("SELECT count(*) FROM %s/dog GROUP BY terms('field'='dog_name', 'alias'='dog_name', order='desc')", TEST_INDEX_DOG));
        Terms name = result.get("dog_name");
        Assert.assertEquals("snoopy",name.getBuckets().get(0).getKeyAsString());
        Assert.assertEquals("rex",name.getBuckets().get(1).getKeyAsString());

        result = query(String.format("SELECT count(*) FROM %s/dog GROUP BY terms('field'='dog_name', 'alias'='dog_name', order='asc')", TEST_INDEX_DOG));
        name = result.get("dog_name");
        Assert.assertEquals("rex",name.getBuckets().get(0).getKeyAsString());
        Assert.assertEquals("snoopy",name.getBuckets().get(1).getKeyAsString());
    }

    @Test
	public void orderByAscTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		ArrayList<Long> agesCount = new ArrayList<>();

		Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY age ORDER BY COUNT(*)", TEST_INDEX_ACCOUNT));
		Terms age = result.get("age");

		for(Terms.Bucket bucket : age.getBuckets()) {
			agesCount.add(((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue());
		}

		ArrayList<Long> sortedAgesCount = (ArrayList<Long>)agesCount.clone();
		Collections.sort(sortedAgesCount);
		Assert.assertTrue("The list is not ordered ascending", agesCount.equals(agesCount));
	}

	@Test
	public void orderByDescTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		ArrayList<Long> agesCount = new ArrayList<>();

		Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY age ORDER BY COUNT(*) DESC", TEST_INDEX_ACCOUNT));
		Terms age = result.get("age");

		for(Terms.Bucket bucket : age.getBuckets()) {
			agesCount.add(((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue());
		}

		ArrayList<Long> sortedAgesCount = (ArrayList<Long>)agesCount.clone();
		Collections.sort(sortedAgesCount, Collections.reverseOrder());
		Assert.assertTrue("The list is not ordered descending", agesCount.equals(agesCount));
	}

	@Test
	public void limitTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY age ORDER BY COUNT(*) LIMIT 5", TEST_INDEX_ACCOUNT));
		Terms age = result.get("age");

		assertThat(age.getBuckets().size(), equalTo(5));
	}

	@Test
	public void countGroupByRange() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
		Aggregations result = query(String.format("SELECT COUNT(age) FROM %s/account GROUP BY range(age, 20,25,30,35,40) ", TEST_INDEX_ACCOUNT));
		org.elasticsearch.search.aggregations.bucket.range.Range  ageRanges = result.get("range(age,20,25,30,35,40)");
		assertThat(ageRanges.getBuckets().size(), equalTo(4));

		long[] expectedResults = new long[] {225L, 226L, 259L, 245L};
		int index = 0;
		for(Bucket bucket : ageRanges.getBuckets()) {
			assertThat(((ValueCount) bucket.getAggregations().get("COUNT(age)")).getValue(), equalTo(expectedResults[index]));
			index++;
		}
	}

	/**
	 * 时间 聚合 , 每天按照天聚合 参数说明:
	 *
	 * http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html
	 *
	 * @throws IOException
	 * @throws SqlParseException
	 */
	@Test
	public void countGroupByDateTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        String result = MainTestSuite.getSearchDao().explain("select insert_time from online  group by date_histogram(field='insert_time','interval'='1.5h','format'='yyyy-MM','min_doc_count'=5,'offset'='+8h') ").explain().toString();
        Assert.assertTrue(result.replaceAll("\\s+", "").contains("{\"date_histogram\":{\"field\":\"insert_time\",\"format\":\"yyyy-MM\",\"interval\":\"1.5h\",\"offset\":28800000,\"order\":{\"_key\":\"asc\"},\"keyed\":false,\"min_doc_count\":5}"));
	}

    @Test
    public void countGroupByDateTestWithAlias() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        SqlElasticSearchRequestBuilder result = (SqlElasticSearchRequestBuilder) MainTestSuite.getSearchDao().explain("select insert_time from online  group by date_histogram(field='insert_time','interval'='1.5h','format'='yyyy-MM','alias'='myAlias') ").explain();
        boolean containAlias = result.toString().replaceAll("\\s+","").contains("myAlias\":{\"date_histogram\":{\"field\":\"insert_time\",\"format\":\"yyyy-MM\",\"interval\":\"1.5h\"");
        Assert.assertTrue(containAlias);
    }

	/**
	 * 时间范围聚合
	 *
	 * http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-bucket-daterange-aggregation.html
	 *
	 * @throws IOException
	 * @throws SqlParseException
	 */
	@Test
	public void countDateRangeTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        SqlElasticSearchRequestBuilder result = (SqlElasticSearchRequestBuilder) MainTestSuite.getSearchDao().explain("select online from online  group by date_range(field='insert_time','format'='yyyy-MM-dd' ,'2014-08-18','2014-08-17','now-8d','now-7d','now-6d','now') ").explain();
		System.out.println(result);
	}

	/**
	 * tophits 查询
	 *
	 * http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-aggregations-metrics-top-hits-aggregation.html
	 *
	 * @throws IOException
	 * @throws SqlParseException
	 */
	@Test
	public void topHitTest() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        Aggregations result = query(String.format("select topHits('size'=3,age='desc') from %s group by gender ", TEST_INDEX_ACCOUNT));
		System.out.println(result);
	}

    @Test
    public void topHitTest_WithInclude() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        Aggregations result = query(String.format("select topHits('size'=3,age='desc',include=age) from %s/account group by gender ", TEST_INDEX_ACCOUNT));
        List<? extends Terms.Bucket> buckets = ((Terms) (result.asList().get(0))).getBuckets();
        for (Terms.Bucket bucket : buckets){
            SearchHits hits = ((InternalTopHits) bucket.getAggregations().asList().get(0)).getHits();
            for(SearchHit hit: hits ){
                Set<String> fields = hit.getSourceAsMap().keySet();
                Assert.assertEquals(1,fields.size());
                Assert.assertEquals("age",fields.toArray()[0]);
            }
        }
    }

    @Test
    public void topHitTest_WithIncludeTwoFields() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        Aggregations result = query(String.format("select topHits('size'=3,'include'='age,firstname',age='desc') from %s/account group by gender ", TEST_INDEX_ACCOUNT));
        List<? extends Terms.Bucket> buckets = ((Terms) (result.asList().get(0))).getBuckets();
        for (Terms.Bucket bucket : buckets){
            SearchHits hits = ((InternalTopHits) bucket.getAggregations().asList().get(0)).getHits();
            for(SearchHit hit: hits ){
                Set<String> fields = hit.getSourceAsMap().keySet();
                Assert.assertEquals(2,fields.size());
                Assert.assertTrue(fields.contains("age"));
                Assert.assertTrue(fields.contains("firstname"));
            }
        }
    }

    @Test
    public void topHitTest_WithExclude() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        Aggregations result = query(String.format("select topHits('size'=3,'exclude'='lastname',age='desc') from %s/account group by gender ", TEST_INDEX_ACCOUNT));
        List<? extends Terms.Bucket> buckets = ((Terms) (result.asList().get(0))).getBuckets();
        for (Terms.Bucket bucket : buckets){
            SearchHits hits = ((InternalTopHits) bucket.getAggregations().asList().get(0)).getHits();
            for(SearchHit hit: hits ){
                Set<String> fields = hit.getSourceAsMap().keySet();
                Assert.assertTrue(!fields.contains("lastname"));
            }
        }
    }

    @Test
    public void topHitTest_WithIncludeAndExclude() throws IOException, SqlParseException, SQLFeatureNotSupportedException {
        Aggregations result = query(String.format("select topHits('size'=3,'exclude'='lastname','include'='firstname,lastname',age='desc') from %s/account group by gender ", TEST_INDEX_ACCOUNT));
        List<? extends Terms.Bucket> buckets = ((Terms) (result.asList().get(0))).getBuckets();
        for (Terms.Bucket bucket : buckets) {
            SearchHits hits = ((InternalTopHits) bucket.getAggregations().asList().get(0)).getHits();
            for (SearchHit hit : hits) {
                Set<String> fields = hit.getSourceAsMap().keySet();
                Assert.assertEquals(1, fields.size());
                Assert.assertTrue(fields.contains("firstname"));
            }
        }
    }

	private Aggregations query(String query) throws SqlParseException, SQLFeatureNotSupportedException {
        SqlElasticSearchRequestBuilder select = getSearchRequestBuilder(query);
		return ((SearchResponse)select.get()).getAggregations();
	}

    private SqlElasticSearchRequestBuilder getSearchRequestBuilder(String query) throws SqlParseException, SQLFeatureNotSupportedException {
        SearchDao searchDao = MainTestSuite.getSearchDao();
        return (SqlElasticSearchRequestBuilder) searchDao.explain(query).explain();
    }

    @Test
    public void testFromSizeWithAggregations() throws Exception {
        final String query1 = String.format("SELECT /*! DOCS_WITH_AGGREGATION(0,1) */" +
                " account_number FROM %s/account GROUP BY gender", TEST_INDEX_ACCOUNT);
        SearchResponse response1 = (SearchResponse) getSearchRequestBuilder(query1).get();

        Assert.assertEquals(1, response1.getHits().getHits().length);
        Terms gender1 = response1.getAggregations().get("gender");
        Assert.assertEquals(2, gender1.getBuckets().size());
        Object account1 = response1.getHits().getHits()[0].getSourceAsMap().get("account_number");

        final String query2 = String.format("SELECT /*! DOCS_WITH_AGGREGATION(1,1) */" +
                " account_number FROM %s/account GROUP BY gender", TEST_INDEX_ACCOUNT);
        SearchResponse response2 = (SearchResponse) getSearchRequestBuilder(query2).get();

        Assert.assertEquals(1, response2.getHits().getHits().length);
        Terms gender2 = response2.getAggregations().get("gender");
        Assert.assertEquals(2, gender2.getBuckets().size());
        Object account2 = response2.getHits().getHits()[0].getSourceAsMap().get("account_number");

        Assert.assertEquals(response1.getHits().getTotalHits(), response2.getHits().getTotalHits());
        Assert.assertNotEquals(account1, account2);
    }

    @Test
	public void testSubAggregations() throws  Exception {
		Set expectedAges = new HashSet<>(ContiguousSet.create(Range.closed(20, 40), DiscreteDomain.integers()));
		final String query = String.format("SELECT /*! DOCS_WITH_AGGREGATION(10) */" +
                " * FROM %s/account GROUP BY (gender, terms('field'='age','size'=200,'alias'='age')), (state) LIMIT 200,200", TEST_INDEX_ACCOUNT);

		Map<String, Set<Integer>> buckets = new HashMap<>();

        SqlElasticSearchRequestBuilder select = getSearchRequestBuilder(query);
		SearchResponse response = (SearchResponse) select.get();
		Aggregations result = response.getAggregations();

		Terms gender = result.get("gender");
		for(Terms.Bucket genderBucket : gender.getBuckets()) {
			String genderKey = genderBucket.getKey().toString();
			buckets.put(genderKey, new HashSet<Integer>());
			Terms ageBuckets = (Terms) genderBucket.getAggregations().get("age");
			for(Terms.Bucket ageBucket : ageBuckets.getBuckets()) {
				buckets.get(genderKey).add(Integer.parseInt(ageBucket.getKey().toString()));
			}
		}

		Assert.assertEquals(2, buckets.keySet().size());
		Assert.assertEquals(expectedAges, buckets.get("m"));
		Assert.assertEquals(expectedAges, buckets.get("f"));

		Terms state = result.get("state");
		for(Terms.Bucket stateBucket : state.getBuckets()) {
			if(stateBucket.getKey().toString().equalsIgnoreCase("ak")) {
				Assert.assertTrue("There are 22 entries for state ak", stateBucket.getDocCount() == 22);
			}
		}

		Assert.assertEquals(response.getHits().getTotalHits().value, 1000);
		Assert.assertEquals(response.getHits().getHits().length, 10);
	}

	@Test
	public void testSimpleSubAggregations() throws  Exception {
		final String query = String.format("SELECT /*! DOCS_WITH_AGGREGATION(10) */ * FROM %s/account GROUP BY (gender), (state) ", TEST_INDEX_ACCOUNT);

        SqlElasticSearchRequestBuilder select = getSearchRequestBuilder(query);
		SearchResponse response = (SearchResponse) select.get();
		Aggregations result = response.getAggregations();

		Terms gender = result.get("gender");
		for(Terms.Bucket genderBucket : gender.getBuckets()) {
			String genderKey = genderBucket.getKey().toString();
			Assert.assertTrue("Gender should be m or f", genderKey.equals("m") || genderKey.equals("f"));
		}

		Assert.assertEquals(2, gender.getBuckets().size());

		Terms state = result.get("state");
		for(Terms.Bucket stateBucket : state.getBuckets()) {
			if(stateBucket.getKey().toString().equalsIgnoreCase("ak")) {
				Assert.assertTrue("There are 22 entries for state ak", stateBucket.getDocCount() == 22);
			}
		}

		Assert.assertEquals(response.getHits().getTotalHits().value, 1000);
		Assert.assertEquals(response.getHits().getHits().length, 10);
	}

    @Test
    public void geoHashGrid() throws SQLFeatureNotSupportedException, SqlParseException {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/location GROUP BY geohash_grid(field='center',precision=5) ", TEST_INDEX_LOCATION));
        InternalGeoHashGrid grid = result.get("geohash_grid(field=center,precision=5)");
        Collection<? extends InternalMultiBucketAggregation.InternalBucket> buckets = grid.getBuckets();
        for (InternalMultiBucketAggregation.InternalBucket bucket : buckets) {
            Assert.assertTrue(bucket.getKeyAsString().equals("w2fsm") || bucket.getKeyAsString().equals("w0p6y") );
            Assert.assertEquals(1,bucket.getDocCount());
        }
    }

    @Test
    public void geoBounds() throws SQLFeatureNotSupportedException, SqlParseException {
        Aggregations result = query(String.format("SELECT * FROM %s/location GROUP BY geo_bounds(field='center',alias='bounds') ", TEST_INDEX_LOCATION));
        InternalGeoBounds bounds = result.get("bounds");
        Assert.assertEquals(0.5,bounds.bottomRight().getLat(),0.001);
        Assert.assertEquals(105.0,bounds.bottomRight().getLon(),0.001);
        Assert.assertEquals(5.0,bounds.topLeft().getLat(),0.001);
        Assert.assertEquals(100.5,bounds.topLeft().getLon(),0.001);
    }

    @Test
    public void groupByOnNestedFieldTest() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/nestedType GROUP BY nested(message.info)", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        Terms infos = nested.getAggregations().get("message.info");
        Assert.assertEquals(3,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            String key = bucket.getKey().toString();
            long count = ((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue();
            if(key.equalsIgnoreCase("a")) {
                Assert.assertEquals(2, count);
            }
            else if(key.equalsIgnoreCase("c")) {
                Assert.assertEquals(2, count);
            }
            else if(key.equalsIgnoreCase("b")) {
                Assert.assertEquals(1, count);
            }
            else {
                throw new Exception(String.format("Unexpected key. expected: a OR b OR c . found: %s", key));
            }
        }
    }

    @Test
    public void groupByTestWithFilter() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY filter(gender='m'),gender", TEST_INDEX_ACCOUNT));
        InternalFilter filter = result.get("filter(gender = 'm')@FILTER");
        Terms gender = filter.getAggregations().get("gender");

        for(Terms.Bucket bucket : gender.getBuckets()) {
            String key = bucket.getKey().toString();
            long count = ((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue();
            if(key.equalsIgnoreCase("m")) {
                Assert.assertEquals(507, count);
            }
            else {
                throw new Exception(String.format("Unexpected key. expected: only m. found: %s", key));
            }
        }
    }

    @Test
    public void groupByOnNestedFieldWithFilterTest() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/nestedType GROUP BY  nested(message.info),filter('myFilter',message.info = 'a')", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        InternalFilter filter = nested.getAggregations().get("myFilter@FILTER");
        Terms infos = filter.getAggregations().get("message.info");
        Assert.assertEquals(1,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            String key = bucket.getKey().toString();
            long count = ((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue();
            if(key.equalsIgnoreCase("a")) {
                Assert.assertEquals(2, count);
            }

            else {
                throw new Exception(String.format("Unexpected key. expected: only a . found: %s", key));
            }
        }
    }

    @Test
    public void minOnNestedField() throws Exception {
        Aggregations result = query(String.format("SELECT min(nested(message.dayOfWeek)) as minDays FROM %s/nestedType", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.dayOfWeek@NESTED");
        Min mins = nested.getAggregations().get("minDays");
        Assert.assertEquals(1.0,mins.getValue(),0.0001);

    }

    @Test
    public void sumOnNestedField() throws Exception {
        Aggregations result = query(String.format("SELECT sum(nested(message.dayOfWeek)) as sumDays FROM %s/nestedType", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.dayOfWeek@NESTED");
        Sum sum = nested.getAggregations().get("sumDays");
        Assert.assertEquals(13.0,sum.getValue(),0.0001);

    }

    @Test
    public void histogramOnNestedField() throws Exception {
        Aggregations result = query(String.format("select count(*) from %s/nestedType group by histogram('field'='message.dayOfWeek','nested'='message','interval'='2' , 'alias' = 'someAlias' )", TEST_INDEX_NESTED_TYPE));
        InternalNested nested  = result.get("message@NESTED");
        Histogram histogram = nested.getAggregations().get("someAlias");
        for(Histogram.Bucket bucket : histogram.getBuckets()){
            long count = ((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue();
            String key = ((Double)bucket.getKey()).intValue()+"";
            if(key.equals("0") || key.equals("4")){
                Assert.assertEquals(2,count);
            }
            else if (key.equals("2")){
                Assert.assertEquals(1,count);
            }
            else{
                Assert.assertTrue("only 0 2 4 keys are allowed got:" + key,false);
            }
        }

    }

    @Test
    public void reverseToRootGroupByOnNestedFieldWithFilterTestWithReverseNestedAndEmptyPath() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/nestedType GROUP BY  nested(message.info),filter('myFilter',message.info = 'a'),reverse_nested(someField,'')", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        InternalFilter filter = nested.getAggregations().get("myFilter@FILTER");
        Terms infos = filter.getAggregations().get("message.info");
        Assert.assertEquals(1,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            InternalReverseNested reverseNested = bucket.getAggregations().get("someField@NESTED");
            Terms terms = reverseNested.getAggregations().get("someField");
            Terms.Bucket internalBucket = terms.getBuckets().get(0);

            long count = ((ValueCount) internalBucket.getAggregations().get("COUNT(*)")).getValue();
            String key = internalBucket.getKey().toString();
            if(key.equalsIgnoreCase("b")) {
                Assert.assertEquals(2, count);
            }
            else {
                throw new Exception(String.format("Unexpected key. expected: only a . found: %s", key));
            }
        }
    }
    @Test
    public void reverseToRootGroupByOnNestedFieldWithFilterTestWithReverseNestedNoPath() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/nestedType GROUP BY  nested(message.info),filter('myFilter',message.info = 'a'),reverse_nested(someField)", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        InternalFilter filter = nested.getAggregations().get("myFilter@FILTER");
        Terms infos = filter.getAggregations().get("message.info");
        Assert.assertEquals(1,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            InternalReverseNested reverseNested = bucket.getAggregations().get("someField@NESTED");
            Terms terms = reverseNested.getAggregations().get("someField");
            Terms.Bucket internalBucket = terms.getBuckets().get(0);

            long count = ((ValueCount) internalBucket.getAggregations().get("COUNT(*)")).getValue();
            String key = internalBucket.getKey().toString();
            if(key.equalsIgnoreCase("b")) {
                Assert.assertEquals(2, count);
            }
            else {
                throw new Exception(String.format("Unexpected key. expected: only a . found: %s", key));
            }
        }
    }

    @Test
    public void reverseToRootGroupByOnNestedFieldWithFilterTestWithReverseNestedOnHistogram() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/nestedType GROUP BY  nested(message.info),filter('myFilter',message.info = 'a'),histogram('field'='myNum','reverse_nested'='','interval'='2' , 'alias' = 'someAlias' )", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        InternalFilter filter = nested.getAggregations().get("myFilter@FILTER");
        Terms infos = filter.getAggregations().get("message.info");
        Assert.assertEquals(1,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            InternalReverseNested reverseNested = bucket.getAggregations().get("someAlias@NESTED");
            InternalHistogram histogram = reverseNested.getAggregations().get("someAlias");
            Assert.assertEquals(3, histogram.getBuckets().size());

        }
    }

    @Test
    public void reverseToRootGroupByOnNestedFieldWithFilterAndSumOnReverseNestedField() throws Exception {
        Aggregations result = query(String.format("SELECT sum(reverse_nested(myNum)) bla FROM %s/nestedType GROUP BY  nested(message.info),filter('myFilter',message.info = 'a')", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        InternalFilter filter = nested.getAggregations().get("myFilter@FILTER");
        Terms infos = filter.getAggregations().get("message.info");
        Assert.assertEquals(1,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            InternalReverseNested reverseNested = bucket.getAggregations().get("myNum@NESTED");
            InternalSum sum = reverseNested.getAggregations().get("bla");
            Assert.assertEquals(5.0,sum.getValue(),0.000001);

        }
    }

    @Test
    public void reverseAnotherNestedGroupByOnNestedFieldWithFilterTestWithReverseNestedNoPath() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/nestedType GROUP BY  nested(message.info),filter('myFilter',message.info = 'a'),reverse_nested(comment.data,'~comment')", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        InternalFilter filter = nested.getAggregations().get("myFilter@FILTER");
        Terms infos = filter.getAggregations().get("message.info");
        Assert.assertEquals(1,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            InternalReverseNested reverseNested = bucket.getAggregations().get("comment.data@NESTED_REVERSED");
            InternalNested innerNested = reverseNested.getAggregations().get("comment.data@NESTED");
            Terms terms = innerNested.getAggregations().get("comment.data");
            Terms.Bucket internalBucket = terms.getBuckets().get(0);

            long count = ((ValueCount) internalBucket.getAggregations().get("COUNT(*)")).getValue();
            String key = internalBucket.getKey().toString();
            if(key.equalsIgnoreCase("ab")) {
                Assert.assertEquals(2, count);
            }
            else {
                throw new Exception(String.format("Unexpected key. expected: only a . found: %s", key));
            }
        }
    }

    @Test
    public void reverseAnotherNestedGroupByOnNestedFieldWithFilterTestWithReverseNestedOnHistogram() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/nestedType GROUP BY  nested(message.info),filter('myFilter',message.info = 'a'),histogram('field'='comment.likes','reverse_nested'='~comment','interval'='2' , 'alias' = 'someAlias' )", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        InternalFilter filter = nested.getAggregations().get("myFilter@FILTER");
        Terms infos = filter.getAggregations().get("message.info");
        Assert.assertEquals(1,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            InternalReverseNested reverseNested = bucket.getAggregations().get("~comment@NESTED_REVERSED");
            InternalNested innerNested = reverseNested.getAggregations().get("~comment@NESTED");
            InternalHistogram histogram = innerNested.getAggregations().get("someAlias");
            Assert.assertEquals(2, histogram.getBuckets().size());

        }
    }

    @Test
    public void reverseAnotherNestedGroupByOnNestedFieldWithFilterAndSumOnReverseNestedField() throws Exception {
        Aggregations result = query(String.format("SELECT sum(reverse_nested(comment.likes,'~comment')) bla FROM %s/nestedType GROUP BY  nested(message.info),filter('myFilter',message.info = 'a')", TEST_INDEX_NESTED_TYPE));
        InternalNested nested = result.get("message.info@NESTED");
        InternalFilter filter = nested.getAggregations().get("myFilter@FILTER");
        Terms infos = filter.getAggregations().get("message.info");
        Assert.assertEquals(1,infos.getBuckets().size());
        for(Terms.Bucket bucket : infos.getBuckets()) {
            InternalReverseNested reverseNested = bucket.getAggregations().get("comment.likes@NESTED_REVERSED");
            InternalNested innerNested = reverseNested.getAggregations().get("comment.likes@NESTED");
            InternalSum sum = innerNested.getAggregations().get("bla");
            Assert.assertEquals(4.0,sum.getValue(),0.000001);

        }
    }

    @Test
    public void docsReturnedTestWithoutDocsHint() throws Exception {
        String query = String.format("SELECT count(*) from %s/account", TEST_INDEX_ACCOUNT);
        SqlElasticSearchRequestBuilder searchRequestBuilder = getSearchRequestBuilder(query);
        SearchResponse response = (SearchResponse) searchRequestBuilder.get();
        Assert.assertEquals(0,response.getHits().getHits().length);
    }

    @Test
    public void docsReturnedTestWithDocsHint() throws Exception {
        String query = String.format("SELECT /*! DOCS_WITH_AGGREGATION(10) */ count(*) from %s/account",TEST_INDEX_ACCOUNT);
        SqlElasticSearchRequestBuilder searchRequestBuilder = getSearchRequestBuilder(query);
        SearchResponse response = (SearchResponse) searchRequestBuilder.get();
        Assert.assertEquals(10,response.getHits().getHits().length);
    }

    @Test
    public void termsWithScript() throws Exception {
        String query = "select count(*), avg(number) from source group by terms('alias'='asdf', substring(field, 0, 1)), date_histogram('alias'='time', 'field'='timestamp', 'interval'='20d ', 'format'='yyyy-MM-dd') limit 1000";
        String result = MainTestSuite.getSearchDao().explain(query).explain().toString();
        Assert.assertTrue(result.contains("\"script\":{\"source\""));
        Assert.assertTrue(result.contains("substring(0,1)"));
    }

    @Test
    public void groupByScriptedDateHistogram() throws Exception {
        String query = "select count(*), avg(number) from source group by date_histogram('alias'='time', ceil(timestamp), 'interval'='20d ', 'format'='yyyy-MM-dd') limit 1000";
        String result = MainTestSuite.getSearchDao().explain(query).explain().toString();
        Assert.assertTrue(result.contains("Math.ceil(doc['timestamp'].value);"));
        Assert.assertTrue(result.contains("\"script\":{\"source\""));
    }

    @Test
    public void groupByScriptedHistogram() throws Exception {
	    String query = "select count(*) from source group by histogram('alias'='field', pow(field,1))";
	    String result = MainTestSuite.getSearchDao().explain(query).explain().toString();
	    System.out.println(result);
	    Assert.assertTrue(result.contains("Math.pow(doc['field'].value, 1)"));
        Assert.assertTrue(result.contains("\"script\":{\"source\""));
    }

    @Test
    public void groupByTestWithFilters() throws Exception {
        Aggregations result = query(String.format("SELECT COUNT(*) FROM %s/account GROUP BY filters(gender,other,filter(male,gender='m'),filter(female,gender='f'))", TEST_INDEX_ACCOUNT));
        InternalFilters filters = result.get("gender@FILTERS");
        for (InternalFilters.InternalBucket bucket : filters.getBuckets()) {
            String key = bucket.getKey();
            long count = ((ValueCount) bucket.getAggregations().get("COUNT(*)")).getValue();
            if (key.equalsIgnoreCase("male@FILTER")) {
                Assert.assertEquals(507, count);
            } else if (key.equalsIgnoreCase("female@FILTER")) {
                Assert.assertEquals(493, count);
            } else {
                throw new Exception(String.format("Unexpected key: %s", key));
            }
        }
    }
}

redpajama_set_name: RedPajamaGithub


I am so excited about todays post and giveaway! Today I have teamed up with Piace Boutique to style two of their newest arrivals. First, this dress!! By now you all know I love a little neon! The back of this dress is so fun and really makes the dress so unique! And this chevron skirt! I am also sure you all know that I love chevron and mint, so this is one of my faves!! Scroll down to enter the Piace Voutique giveaway!
For todays giveaway one of my favorites, Piace Boutique has offered to give ONE lucky Spoonful of Style reader a $50 gift card to there online boutique! If you haven't already stopped by their store you must! You won't be disappointed! They have so many fun pieces, I especially love their dresses! Happy shopping and good luck! See how to enter below!!
You look so cute!! I love both of these looks on you.
I love the black dress with the neon on the back! Both outfits look great on you.
Love your chambray shirt with the printed skirt Jade!
The detailing on that LBD? Gorgeous!
I love the neon green piping paired with your bright pink lip! Looks great!
I know you hear it all the time, but you are so stunning! You look incredible in those KWs!
These are both such fun looks!! I love your necklace with the chambray and the back of that dress is stunning!


This workshop focuses on creating various paper elements to be added to the community installation. Using repetitive paper cutting techniques, volunteers will create a visual representation of the hidden stories of Homer. Paper instruction and design includes: paper pleating, pop-up sculpture and simple kirigami techniques.


Priest in l'Arche. Co-animator for ESDAC retreats and formations. Spiritual accompaniment.
Engineer, trained in psychotherapy and organization psychology, trainer and consultant, retired.
Religious of the Sacred Heart.
She has accompanied many groups and communities. She is still animating group and individual retreats.
Sister of the Religious Congregation "Annunciaten van Heverlee". Coordinator of the lay forum of the Flemish Chatholic Church.
Jesuit Father, Provincial of the South Belgium Province and Luxemburg.
Has studied economy. Member of l'Arche communities since 1977. Lived 20 years in Latin America (Honduras y Republica Dominicana) and is today part of L'Arche in Brussels.
Jesuit. Director Platform Ignatian Spirituality.


Engage in epic 6-on-6 multiplayer combat and destroy the enemy. There are overall 24 robots with varying strengths customizable with 20 weapon types to create the perfect machine. Use tactics in conjunction with your awesome gear to lead your clan to victory. Join epic PvP battles now and become the Best Pilot in the War Robots Premium hack world!
New Robots: Weyland and Mender! Now you can Repair and Support your teammates!
New Feature: Boosters! Get extended burst of power on the battlefield!
New Map: Rome! Ancient battle arena in WR world!
Weapon Chimera: It's like Spiral, but BIGGER. Lock on!
Weapon Avenger: machine gun for your heavy slot? - no problemo!
New WR Event coming soon! Are you ready for Star Invasion, Pilots? Stay tuned for more info!
Extract obb into the path Sdcard/Android/obb, Install Apk and play.
Note: Game is updated on this same page, so cheats may change with each version!


Auditors role contain analyzing and analyzing accounts. The incumbent additionally has to carry out different kinds of financial dealing with jobs. He also has to organize monetary studies for its clients. For this job profile, individuals with bachelor's diploma in commerce or economics are most popular. But if candidate posses greater degree of relevant disciplines, probabilities of getting recruited increases.
It has been reported that the success of the Royal Financial institution of Scotland (RBS) is especially attributed to a various provide chain. That is what the pinnacle of procurement with RBS, Jonathan Sutherland feels. Participation of SMEs is crucial for RBS' long run success, Mr Sutherland famous and explained that the move is a "strategic imperative" and good enterprise for the firm because the bank has the most prospects in SMEs serving roughly 32 per cent of the sector. This suggests that the fortunes of RBS are carefully related with the success of these SMEs. He described these firms as "progress makers".
Free Resume Builder services present resume samples online where you've a chance to easily fill template with your individual academic and skilled experience details. If you're on the lookout for resume companies, it will be good if you happen to take into account few issues. Research on how strong their foundation is whether or not you're taking help on-line or offline. If they aren't being able to assist themselves they both can't enable you to.
3) Journals and magazines: Each business has their very own periodicals, journals or journals. Plenty of recruiters go to these publications for employing specialists. Some is perhaps bought in magazine stands and others come by subscription. If you are wishing to ascertain your profession primarily based on your finished space of investigation, you can subscribe to an knowledgeable journal and increase your local task prospects.
Once you are done with the license process, you have to present all important license particulars within the related phase of your resume. It's important to point out the title of the state from the place you bought the license, date from which the license got here into impact. It is fairly a risk that your employer would naturally ask you for a copy of the license, when you get the provide from the corporate; there is no such thing as a want to mention the license number in your resume.


To install Clash Of Clans MOD (unlimited gems) apk, you android device Not need root. The min android os for this apk is Android 、 Unlimited Gems Clash of Clans for Android + APK Download. Version: (1) for APK File SHA1: 78badf22d4dfe1e23e0b21a2c. 21 Feb Clash of Clans [coc] Mod Apk is available to download with unlimited Clash of Clans mod apk was prevalently known as COC is the best Android MOD ( unlimited gems) COC APK's Permission Required From APK File.
19 Apr Clash of Clans Mod Apk gives you unlimited gems and Step 1: Download the Apk file, copy it anywhere on your Android device. 5 Aug This is working for both rooted and unrooted Android in Clash of Clans Mod – Unlimited Gems, Elixir and Gold You just need to download menuiserie-pvc-fermeture-18.com file to install the mod according to the steps written below. With unlimited resources including Clash of Clans Free Gems, Unlimited Your iOS or android device, connected to a good network source. Now go to the location where the Clash of Clans Hack apk file is saved and click on it to install. 4.
Tips cheat for Clash of Clans Guide cheats for Clash of Clans free unlimited coins and keys on a coin Tips cheats for Clash of Clans free unlimited coins and. 16 May Download Last version Android Clash of Clans Apk Android + apk MOD (hacked) + ClashBot VIP (all version) From RevDl. if you want to hack clash royale gems and coins use this apk for hacking unlimited resources for free download hack clash of clans v clash of clans hack apk data file host clash of clans hack apk get unlimited gems android/ios. Clash of Clans (Mod Unlimited Money) v games for Android clan war The newest version of the game Clash of Clans Mod Unlimited gems+gold Android. Game Clash of Clans tribal conflict in the post Apkhouse to introduce the latest version of its website, we can be one of the best Source code file: www. 3 Sep - 4 min - Uploaded by Adria Clash of Clans Hack APK - Clash of Clans Working Apk Hack *No clash of clans hack.


There are many sugar alternatives out there. Find out which ones are the best right now for overall health and for rapid weight loss while eating sweets.
There are also many different flours out there. Find out which ones are the best to burn fat, keep you full, and help you change your diet into a permanent lifestyle change simply and easily.
Visit the show notes on http://www.shortsimplehealth.com and search for the episode title for the show notes and my free and amazing peanut butter pie recipe.


text:
Quentin Clémence & Alice Weil | Research Trip
Madagascar | Multi-Disciplinary
December 2022 — Multi-Disciplinary
Studio ICAI
Studio ICAI (Interdisciplinary and Caring Architecture – For the Inhabitants) was founded by Quentin Clémence and Alice Weil in 2022 with the main objective of linking practice and research in the framework of interdisciplinary projects. The two architects will undertake a research trip in Madagascar from 15 December 2022 to 1 January 2023 in preparation for a collaborative exhibition they are developing titled «From 'house-being' to 'having a house'» that focuses on Zafimaniry art and architecture.
The research trip will allow the architects to undertake an investigation into the contemporary material and constructive culture of the Zafimaniry, a society in the south-east Highlands of Madagascar, in order to understand and account for the relationships that the rural Malagasy population have with the house in a context of globalization. They will be assisted by Malagasy anthropologist Irchade Zavaraly in the role of expert and interpreter. Studio ICAI share an excerpt from their project statement:
"In Zafimaniry country, the house, traditionally built entirely of wood, is a particular entity occupying a central place in the social organization; it embodies the marriage relationship and does not exist outside of it. Thus, the beginning of the construction of a house marks the social birth of each individual and continues to be both a support and an influential element in all the major phases of its inhabitants life, until it continues after their death thanks to the maintenance and carvings provided by the descendants of the original couple. The specificities of the practices associated with the house make it a remarkable technical and artistic object, which earned the Zafimaniry woodwork its inclusion in UNESCO's intangible cultural heritage in 2008. This patrimonialization as well as other transfers and exchanges linked to ancient and recent globalization are constantly changing the characteristics of the Zafimaniry house. Phenomena such as the deforestation of their environment, the import of materials or land grabbing have direct influences on the architecture and its place in society. In addition, Zafimaniry artistic productions, which are materialized by woodcuts, initially made on elements of houses — whether old or contemporary — occupy a central place in the imagination of the local population and define in part the modality of their relationship to the material world."
The research that this trip builds on was refined and supported in the framework of a master's degree and then a PhD (in progress) in social anthropology by Alice Weil, under the direction of Laurent Berger, an anthropologist specialised in globalization and Madagascar. The trip will allow Studio ICAI to refine the orientation of the project, which is planned to include photographs, soundscapes, audio and video testimonies and Zafimaniry art pieces. While in Madagascar, Quentin and Alice will develop photographic and sound recording documentations that will feed into the multimedia exhibition. In parallel to this, the team are working on publications that will complete and contextualise the exhibition.
Inside a minibus taxi
Architectural diversity in a Zafimaniry village
Children playing in the main square in a village
Construction of a house in raw earth
All journeys are made on foot
Interior of a traditional Zafimaniry wooden house
Market day in the main Zafimaniry village
Woman preparing beans in her wooden house
Woven Zafimaniry pizza plate
Rice has become the staple of the Zafimaniry diet in recent decades. Handmade mats and cushions are present in almost every Zafimaniry house
Zafimaniry man in his wooden house
View from a house
Quentin Clémence is a French-Swiss architect. He worked at Graber Pulver in Zürich (2015-2017) and as a project manager at Bruther in Paris (2018-2021). He is currently pursuing a specialisation to become a heritage architect at the École Nationale Supérieure d'Architecture de Paris-Belleville
Alice Weil is an architect by training, she was notably a research and teaching assistant at the two Swiss polytechnics, EPFL and ETHZ for the Bruther studio (2017-2021) and is preparing a PhD in social anthropology, under contract with the School for Advanced Studies in the Social Sciences.
[All images by Studio ICAI]

redpajama_set_name: RedPajamaCommonCrawl


text:
Notable Alumni: Terry Crawford
Ms. Crawford coached Women's Track & Field at the University of Tennessee from 1974-84, winning the first national title for any Lady Vol athletic team in 1981. At the University of Texas from 1984-1992, she led the Lady Longhorns to five national championships. In 1988, she was the Olympic women's head track & field coach, and was a 1996 inductee into the U.S. Track & Field and Cross Country Coaches Association Hall of Fame. In 2008, that organization established the Terry Crawford Program of the Year Award, awarded annually to the most outstanding NCAA Division I women's cross country and track & field program. She has served as President of the Women's Collegiate Cross Country Association and as President of the U.S. Track Coaches Association (1999-2001) and is a former member of USATF's board of directors, as chair of the USATF Coaches Advisory Committee. In 2009, she was named USA Track & Field's first Director of Coaching.
athleticsNotable Alumni


New tax rules have taxpayers confused about what deductions to claim on 2017 returns. Plenty of myths exists on how to speed up your refund, too.
The timing of tax refunds plus the confusion about tax reform are generating a long list of myths this filing season.
The false notions raise questions such as: Will all refunds be delayed? Isn't there a secret way to uncover your refund date? Why do I even need to worry about digging up receipts to claim charitable deductions on my 2017 return? Aren't all deductions eliminated with tax reform?
Too many consumers are befuddled about taxes every year. But things got even more mixed up after Washington lawmakers passed the Tax Cuts and Jobs Act, a sweeping tax reform package, in late December.
Since then, tax professionals and the IRS have been getting phone calls indicating that many taxpayers think the new rules will change the game for their 2017 returns. The reality: Not much has changed for the 2017 return.
Consider the mistake some tax filers are making with home equity interest.
George W. Smith IV, a Southfield-based accountant, said he's had some clients forget to bring him paperwork for their home equity loan interest because they were under the impression that home equity loan interest is no longer deductible. The rules don't change for 2017 returns.
"We've conditioned ourselves to ask (about those forms) when we see big drops in mortgage interest deductions on the return," Smith said.
The rules will change for 2018. The IRS noted on Wednesday that the interest on a home equity loan or home equity line of credit would still be deductible on 2018 returns in many cases if the loan is used to buy, build or substantially improve the taxpayer's home that secures the loan.
But the interest would no longer be deductible on 2018 returns if you used the home equity loan to pay off credit card debt or buy a car. Again, though, these new rules don't apply to 2017 returns.
Myth No. 1: Calling the IRS, calling your tax professional or ordering a tax transcript will speed up your refund.
Taxpayers get a transcript of previously filed tax information via www.irs.gov. Such information is used when applying for a mortgage, student loan or small business loan.
But getting a transcript is not a "secret way" to get more information on when your refund will arrive. Or speed up that refund.
"If you order your tax transcript, it doesn't do anything to expedite your refund," said Luis D. Garcia, a spokesperson for the IRS In Detroit.
Go to "Where's My Refund?" on www.irs.gov to track your refund payment. Or download the IRS2Go app.
Myth No. 2: All refunds are being delayed.
Reality: All refunds won't be late. In fact, some earlier filers should see refunds soon.
Beginning this week, the IRS expects to make refunds available in bank accounts or on debit cards for early filers who claimed the Earned Income Tax Credit and the Additional Child Tax Credit.
In order to combat fraud, the IRS had to hold back the entire refund, not just the part related to the credits, early in the season.
But overall, the IRS said it issues more than nine out of 10 refunds in less than 21 days. Using e-file and direct deposit can speed up refunds.
Myth No. 3: All deductions are eliminated.
Reality: You could pay more than you owe in taxes, if you believe this one.
If you itemized your deductions on your 2016 return, you still may be able to itemize them on the 2017 return. Dig up your receipts for charitable contributions, find your paperwork for what you paid for state income taxes and property taxes.
Under the new tax law, a $10,000 limit will apply on 2018 returns as the maximum deduction for all state and local taxes combined. But the 2017 returns do not have this limit — so you need all your paperwork now.
Deductible expenses include home mortgage interest, state and local income taxes or sales taxes (but not both), real estate and personal property taxes, gifts to charity, casualty or theft losses, unreimbursed medical expenses, and unreimbursed employee business expenses. Special rules and limits can apply.
The standard deduction will nearly double under the new tax law but, again, that doesn't take place until the 2018 returns.
The standard deduction for single taxpayers and married couples filing separately is $6,350 in 2017, up from $6,300 in 2016.
For married couples filing jointly, the standard deduction is $12,700 on 2017 returns, up $100. And for heads of households, the standard deduction is $9,350 for 2017, up from $9,300.
Myth No. 4: Bigger paychecks mean you don't have to tinker with your withholding.
Reality: You're risking an unexpected, and possibly unpleasant, surprise next year — if you don't review your withholding now.
Alison Flores, principal tax research analyst at the Tax Institute at H&R Block, said some taxpayers will want to adjust the amount of money that's being withheld by their employers by updating their W-4 forms.
If they don't, some risk a smaller refund next year or maybe even a bigger than expected refund.
Many different outcomes are possible because unique circumstances in a taxpayer's life influence the appropriate withholding.
The changes in the withholding tables that took place as a result of tax reform do not mean that you're all set and should bank on a similar refund when you file your taxes next year.
Myth No. 5: You won't be penalized if you don't provide proof of health insurance.
Reality: You need that proof or you face a penalty on 2017 returns.
Flores said a big point of confusion involves future changes regarding the Affordable Care Act. Too many consumers mistakenly think changes apply to 2017 returns.
"For 2017, there's really no change," Flores said.
"On your tax return you're either going to report you had coverage all year, you qualify for an exemption or that you're liable for the individual shared responsibility payment and the amount that you will pay."
That's true for the 2017 tax return you file this year, as well as the 2018 tax return that you file next spring in 2019, she said.
The tax reform law repealed the Affordable Care Act mandate that requires Americans to have health insurance or pay a penalty. But such changes aren't immediate.
If you didn't have health insurance in 2017, and you don't claim a waiver or exemption, you'll still face a penalty.


text:
National Ignition Facility: Mother of All Boondoggles?
EnergyTopicNewsType
NIF may never work, and even if it does, it will accomplish nothing
Bill Sweet
nuclearpolicyfusionNational Ignition Facilityfusion powerNECmagnetic confinement
Five billion dollars over its original budget and years behind schedule, the National Ignition Facility (NIF) deserves to be recognized as perhaps the biggest and fattest white elephant of all time. The giant laser facility at Lawrence Livermore Lab in California first was conceived as a major project to demonstrate one of two alternative paths to harnessing the "energy of the stars" for power production, which is called inertial confinement fusion (the other, somewhat more credible path being magnetic confinement fusion).
Years ago, when the energy rationale for laser fusion began to look a little implausible and the projected cost of NIF already had ballooned from $2 billion to $4 billion, its promoters began to sell it to Congress and the Department of Energy as a means of simulation-testing nuclear weapons. The idea that the reliability of nuclear warheads could be evaluated by making laser beams collide in a microscopic point may never have seemed very plausible to the average layperson. As it happens, it didn't seem very plausible to most experts either: Richard Garwin, for decades the most highly regarded independent specialist on nuclear weaponry in the United States, told IEEE Spectrum six years ago that it would be "a mistake to assume that NIF experiments are going to be directly relevant to weapons testing.The temperatures in the NIF chamber are much lower than they are in actual nuclear weapons, and the amounts of material being tested are much smaller." But that didn't stop the U.S. Department of Energy from recommending the project and Congress from funding it.
With the total tab for NIF now running to an estimated $7 billion, the laboratory has been pulling out all the stops to claim success is just around the corner. At the beginning of July, it announced that 15 years of work had paid off in "an historic record-breaking laser shot," in which 192 beams delivered more than 500 trillion watts of peak power and 1.85 megajoules (MJ) of ultraviolet laser light to its target." The lab's leaders predict that "ignition"-—the point where the 192 lasers actually deliver more energy than they consume—could occur as early as next year.
But "next year" already is years behind schedule, and so far, as William Broad reported in the New York Times last week, NIF simply "has not worked." Donald L. Cook, an official at the National Nuclear Security Administration who oversees the laser project, told Broad—who for decades has been the Times's leading reporter on all matters relating to nuclear weapons—that "we're going to settle into a serious investigation" of what has gone wrong.
Having sold the fusion facility in its current incarnation as a device for testing the reliability of nuclear weapons, the lab's leaders now are back to selling it as an energy machine. The lab's director told CBS's "60 Minutes" earlier this year that NIF's aim is to generate "clean, limitless power." He said that would free the United States of greenhouse gas emissions and dependence on Mideast oil, and that commercialization of the technology could begin in ten years.
Unbelievable! For decades the joke about magnetic confinement fusion--much the more plausible approach to harnessing the energy of the sun--is that the technology is always 20 years away. So when will inertial confinement fusion be delivering commercial electricity? That one is easy. Never.
Fusion "Breakthrough" Won't Lead to Practical Fusion Energy - IEEE Spectrum ›
TransportationTopicEnergyTypeSpectrum CollectionsAnalysis
The EV Transition Explained: Policy Roadblocks
The EV Transition Explained: How to Meet Sales Targets?
The EV Transition Explained: Local Policies Shape Global Competition
EnergyTopicMagazineTypeFeatureSpecial ReportsJanuary 2023Telecommunications
13 Intriguing Engineering Milestones to Look for in 2023
Arctic Internet, AI vs. the EU, the Hot Air Balloon Defense, and more
Dina Genkina
Greg Mably
A Sea-Monster-Proof Internet
All illustrations: Greg Mably
The initial segment of what will be the first underwater fiber-optic link to skirt the North Pole, connecting Japan and Europe, will light up in early 2023. This stretch, called Iris, will link Iceland to Ireland. In subsequent years, the Far North Fiber project will lay down a cable through the Northwest Passage, connecting Iceland to Greenland, then Canada, Alaska, and finally Japan. Far North Fiber will help increase the geographic diversity of the world's fiber-optic network; currently, submarine cables are laid along a few well-trodden routes, leaving the network vulnerable to local hazards, like ship anchors, earthquakes, or fiber-eating sea monsters.
Balloons vs. Hypersonic Missiles
In a bid for the most MacGyver-worthy defense strategy, the Pentagon has planned a sevenfold increase in spending on hot-air balloons in 2023. These high-flying, low-tech aircraft are already in use for surveillance, hovering at 18,000 to 27,000 meters to track drug runners. The hope is, these floating leviathans will collaborate with satellites to detect hypersonic missiles, like those being developed by Russia and China. As a bonus, the tech onboard the balloons runs on solar power.
AI Regulations Are Coming
Regulation is set to ramp up on artificial intelligence uses online, as the European Parliament and Council's Digital Services Act went into effect at the end of 2022. The bill requires the largest platforms to implement anti-disinformation measures and protect against discriminatory targeted advertising. Perhaps most important, it requires transparency in the algorithms used to provide product and content recommendations. This is likely a precursor to the EU's larger AI Act, which is currently grinding through the legislative gears.
Revenge of the Geosynchronous Satellites!
Compared to Starlink's sky-cluttering swarms of tiny satellites, San Francisco–based Astranis's plans may seem old school. It aims to launch a humdrum, lone geostationary satellite. But this satellite is the first of a new breed, dubbed microGEO. It's about one-twentieth the size of the minibus-scale geostationary satellites already in orbit, allowing for cheap and quick deployment. This first microGEO will launch in early 2023, and start providing service to Alaska, tripling the state's satellite bandwidth while cutting its cost. That same year, the company plans to launch four more microGEOs. One will provide Internet to rural Peru, two will service airplanes and cruise liners, and the final satellite's use is yet to be disclosed.
Hurricane-Model Overhaul
U.S. hurricane tracking and prediction models will get a much needed upgrade ahead of the 2023 season. The U.S. model has been lagging in accuracy behind Europe's version, a problem that first became evident during Hurricane Sandy in 2012. Now, the U.S. National Oceanic and Atmospheric Administration has put a new set of supercomputers into operation to power the next generation of modeling. The improvements will include higher resolution, more realistic physics to represent clouds and precipitation, a larger number of simulations, and more effective use of observational data.
China's Big Hydro Plans
China is in the midst of a gigantic buildup of hydro-energy capabilities. The world's largest pumped-energy-storage station—a technique that stores energy by pumping it uphill to a reservoir—is set to complete phase two of its construction in 2023. The station, called Fengning and located about 200 kilometers north of Beijing, will store up to 40 gigawatt-hours of energy, and help keep the grid on clean energy when the wind isn't blowing or the sun's not shining. Separately, the Lianghekou hydropower station in Tibet is also set to come fully online in 2023, and is expected to generate a whopping 11 terawatt-hours of electricity annually (roughly the energy consumption of Lithuania). These massive construction projects are intended to help China meet its goal of going carbon neutral by 2060.
Prize Fight for Rain-Forest Tech
In the Spring of 2023, Singapore will welcome 15 teams to the jungle for the semifinals of the XPrize Rainforest competition. The semifinalists, hailing from all over the world, will show off their biodiversity-testing tech in the hopes of making the cut to the finals, set for 2024. Judges will be looking for "a process for improving autonomous operations, new detection methodologies, and methods for rapid data integration that provide unprecedented levels of detail in real time." The competition kicked off in 2019, and XPrize's net investment is US $10 million. XPrize is hoping that the incentive and competitive spirit will help save the rain forests.
Modular Nuclear Power is Nucleating
Korean manufacturer Doosan is set to start producing components of what could be the world's first modular nuclear power plant, in late 2023. The components are for startup NuScale, whose design promises to drastically reduce cost and installation time. Unlike today's power plants, which are constructed completely on-site, these reactors can be mass-produced in a factory and shipped to power stations worldwide. Each houses between 4 and 12 self-contained reactor modules depending on local needs. The first power plant using NuScale's technology is set to start generating electricity in 2029 at the Idaho National Laboratory, as part of the Carbon Free Power Project.
Out With Red Tape, In With the Fiber
Germany aims to triple the amount of fiber cable installed by the end of 2025, in an effort called Gigabitstrategie. One of the strategies the German government will use to accomplish this ambitious goal is to clear some of the red tape around fiber projects by the end of 2022. It plans to centralize the project-approval process, currently seen as a municipality-dependent bureaucratic nightmare, clearing the way for a massive ramp-up in construction in early 2023. The government also plans to use the innovative microtrenching technique to lay down fiber in narrow 5-centimeter-wide channels dug by the side of the road without interrupting traffic.
United States' Wind on the Wire
The largest renewable-energy infrastructure project in U.S. history— an $8 billion wind farm and transmission line—is set to begin construction in 2023. San Francisco–based Pattern Energy took over the projects, called SunZia Wind and SunZia Transmission, from Southwestern Power Group in July 2022. The wind part of the project plans a total of 3,000 megawatts from wind farms it will build in three counties in New Mexico. An 885-kilometer bidirectional high-voltage direct-current transmission line will run from New Mexico and south-central Arizona. The transmission line will sidestep the growing difficulties of connecting renewable-energy sources to the power grid.
NASCAR May Lean Electric
According to documents leaked earlier this year, auto-racing giant NASCAR plans to debut a prototype electric vehicle (EV) ahead of its season-opening race in February 2023. This prototype, the documents suggest, will then be used in an EV racing series later in the year. The series would consist of two races lasting 30 minutes apiece, with no battery swaps or charging allowed. This information, although unconfirmed, would be in line with NASCAR's previously stated plans to test out opportunities in the EV space. Amidst much pressure to move toward electric, NASCAR maintains that entertainment value for its fans is the top priority.
One charger to rule them all
The European Union has adopted a directive that mandates a range of devices charge using USB-C ports. Apple, with its unique lightning port, will be no exception: iPhones, iPads, and other small devices will be forced to migrate to USB-C by 2024. Laptops will have to follow sometime in 2026. This law is the first of its kind anywhere in the world. It's meant to improve convenience for the consumer, as well as cut down on electronics waste generated by different chargers, which is currently responsible for an estimated 11,000 tonnes per year. Several U.S. senators have pushed for similar legislation, so far to no avail.
The French Nuke Up
Over a decade behind schedule and billions of dollars over budget, France's next-generation nuclear reactor in Flamanville is finally expected to get fueled up in early 2024. The plant will be only the world's fourth EPR reactor—a third-generation pressurized water design that's meant to be safer and more efficient than its predecessors. The project has been plagued by safety concerns, engineering missteps, and most recently pandemic supply chain issues. But now, Électricité de France (EDF) says they are in the final stretch. The plant could not come too soon to help decrease Europe's reliance on Russian oil and gas.
Top Tech 2023
Top Tech 2023: A Special Report
Preview exciting technical developments for the coming year.
Can This Company Dominate Green Hydrogen?
Fortescue will need more electricity-generating capacity than France.
An Airship Resurgence
Pathfinder 1 could herald a new era for zeppelins
A New Way to Speed Up Computing
Blue microLEDs bring optical fiber to the processor.
The Personal-Use eVTOL Is (Almost) Here
Opener's BlackFly is a pulp-fiction fever dream with wings.
Baidu Will Make an Autonomous EV
Its partnership with Geely aims at full self-driving mode.
China Builds New Breeder Reactors
The power plants could also make weapons-grade plutonium.
Economics Drives a Ray-Gun Resurgence
Lasers should be cheap enough to use against drones.
A Cryptocurrency for the Masses or a Universal ID?
What Worldcoin's killer app will be is not yet clear.
IBM's Quantum Leap
The company's Condor chip will boast more than 1,000 qubits.
Arthritis Gets a Jolt
Vagus-nerve stimulation promises to help treat autoimmune disorders.
Smartphones Become Satphones
New satellites can connect directly to your phone.
Exascale Comes to Europe
The E.U.'s first exascale supercomputer will be built in Germany.
The Short List
A dozen more tech milestones to watch for in 2023.
10 Tantalizing Tech Milestones to Look for in 2020 ›
10 Exciting Engineering Milestones to Look for in 2021 ›
Milestones:List of Milestones - Engineering and Technology History ... ›


How many times do you pass multiple billboards on your way to work in Bartlett? Consider SEO in this same fashion, after seeing a billboard multiple times on the highway, you may be interested to stop in the store. The exact advertisement policy works with SEO. People searching online for a specific topic or information will be interested in a company that keeps on getting displayed on their search page.
The first thing business owners should do is to start seeing SEO as an investment, rather than a cost. Consider how an investment will produce some sort of profit. There are many who suggest that SEO is all a hoax and not a real process. However, there are many businesses who would not be surviving if it was not for the traffic that SEO has brought them.
Consider how you search the internet, are you going to choose a restaurant in Bartlett that is located on the first page or the fifth page? There's no such thing as a successful business without investments.
Several web users today look up items utilizing their mobile phone devices. Considering how convenient mobile devices are, it really should come as no surprise. However, mobile users totally neglect paid ads and look at the organic searches. This is a consequence of the fact that organic results cater to specific users, being therefore more inclined to suit their needs. Business owners who seize this huge opportunity to grab a nice slice of their market should invest in SEO.
The use of smartphones and tablets is tightly connected with the rise of social media platforms. It is not surprising to see full conversations about businesses on Facebook, Twitter, and Instagram. When searching online for solutions to their problems, people may choose your website, if it is useful and easy to access. If your establishment's site has reliable information, you are assured of getting recommendations from these internet users.
Local businesses in Bartlett can use this insight to get recommendations from local customers. If you are afraid that SEO is a waste of time and money, consider how many people move into your city on a yearly basis, all looking for something.
In the past, it was hard for a small business in Bartlett to compete with the big guys. SEO provides them an affordable solution to become available for their potential customers, and to obtain fast results that wouldn't be possible otherwise. There are many big businesses who are not concerned with SEO and it is allowing smaller businesses to sneak in a get a much bigger piece of the pie. In the long run, trust is built, and prospects become seasoned clients.


text:
Ману-Смріті або Манусмріті (, ), також відома як Ману-Самхіта, Манава-Дхармашастра () і Закони Ману — пам'ятник давньоіндійської літератури, збірник настанов благочестивому індійцеві для виконання ним свого громадського, релігійного і морального обов'язку. Є однією з найраніших та найважливіших Дхарма-Шастр, що також входить у літературу Смріті.

Назва Закони Ману () була запропонована перекладом британського (уельського) орієнталіста та судді верховного суду Бенгалії сера Вільяма Джонса, у 1794 році, і стала загальноприйнятою у багатьох країнах, проте вона не відповідає ані оригінальній назві пам'ятки, ані її загальному змістові; відповіднішою є Повчання Ману у дхармі (Манавадхармашастра).

Текст викладається у вигляді співбесіди між мудрецем Ману та групою ріші, що просять його розповісти про «закони всіх соціальних класів» (1.2). Починаючи з цього твору, Ману стає стандартним авторитетом і у всіх наступних Дхарма-Шастрах. Сам текст посилається на надприродні сили та в авторитетному тоні розповідає про Дхарму, на відміну від інших пов'язаних текстів, що в більшій мірі є спостереженнями або дослідженнями. За індуїстською традицією, Ману-Смірті є записом слів Брахми.

Датування тексту
Датування тексту є важливим для науки, так як «Ману-смріті» була написана в період, коли вплив брахманів був під загрозою неведійських рухів, після розпаду імперій Маур'їв і Шунга склався період соціальної нестабільності. Таким чином "Ману-смріті"та інші Дхарма-шастри були реакцією брахманів на ці загрози.

У науці утвердилася думка Георга Бюлера, що "Ману-смріті"в тому вигляді, в якому вона дійшла до нас, склалася в II столітті до н. е.. — II столітті н. е.. При цьому не весь матеріал, що міститься в збірнику, може ставитися саме до вказаного періоду. Відносно новими визнаються перша і остання (XII) глави. З інших глав найдавнішими вважаються II–VI глави, однак в них також зустрічаються вірші, які є пізнішими додаваннями. Пандуранг Вамана Кані обмежував датування періодом з II століття до н. е.. до I століття н. е.. К. П. Джаясвала вказує ще точнішу дату: 150–120 роки до н. е..

Структура тексту
«Ману-смріті» написана на санскриті, складається з 2684 віршів ("шлок" ), які розбиті на 12 розділів, що містять в собі:
 I — опис уявленнь про походження Всесвіту, станів (варн), людського суспільства;
 II — правила життя в період навчання;
 III–IV — правила життя сім'янина-господаря;
 V — деякі релігійні норми;
 VI — правила життя відлюдника;
 VII — повчання про обов'язки царя та управління державою;
 VIII — настанови щодо судочинства та юридичної практики
 IX–X настанови щодо сімейних відносин, покарань за різні злочини, обов'язків членів варн;
 XI — приписи про каяття та обітниці задля спокутування скоєних гріхів;
 XII — опис посмертних відплат за погані справи в цьому житті.

Правові настанови
Закони називають вісім можливих способів виникнення права власності:давність, спадкування, дарування, купівля, завоювання, лихварство, виконання роботи, а також одержання милостині (гл. X, ст.115). Стародавній Індії був відомий і такий спосіб набуття права власності, як давність володіння (гл. VIII, ст. 147). При цьому підкреслювалось, що тільки при законному підтвердженні людина із володільця перетворюється на власника. Купувати речі можна було тільки у власника. Доводити право власності, посилаючись на добросовісне володіння, заборонялось. Якщо у добросовісного набувача виявляли вкрадену річ, то вона поверталась попередньому власнику.

Примітки

Посилання
 Закони Ману  //
 http://www.sacred-texts.com/hin/manu.htm
 Laws Of Menu Volume I
 Законы Ману, Перевод С. Д. Эльмановича, проверенный и исправленный Г. Ф. Ильиным — Москва: Наука, 1992

Літературні твори Індії

redpajama_set_name: RedPajamaWikipedia


With so many things to do in Coimbatore, it's important to choose a good Hotel.
Situated at a 5-minute walk from the Karumathampatti Bus Station, Hotel Rithanns Karumathampatti operates a 24-hour front desk to welcome and assist guests. Free Wi-Fi access is available throughout the property.


It is important to get your site listed on popular search engines so that you may be able to attract free and targeted visitors while search engine marketing. Although most people want to get their website listed they do not do it correctly and this prevents them from reaching out to their existing and potential customers.
However, when you know how to do things correctly, you may be able to rank your web pages higher in the search engine and this can help you improve your business significantly. Before you start submitting your website, you need to understand what the search engines are looking for when ranking your site.
Keywords, meta description, page title, bounce rate and inbound links are some of the things that search engines us to rank the web pages. The higher you rank, the more traffic you receive. One of the things that you need to understand is that being listed does not necessarily attract traffic; you need to optimize the site.
Sitemaps are basic pages that list all URL links of a website. Whenever you publish new content on your site, it appears on the sitemap and this enables the search engines to see them. You can create a sitemap manually or install a special XML sitemap for the entire site so that all major search engines are notified whenever you post new content.
Each search engine works differently from the other as they use unique algorithms to rank web pages. All that you need to do is to sign up and add your site. For example, if you want to submit your site to Google, you need to sign up with Google webmaster tools and complete the process as specified. Search engine submission is a simple process that can be completed within minutes.
Good quality content can help generate more traffic. Readers like content that is useful and engaging and share this to generate additional back links. Share it on social networks so that it gains popularity and you are able to attract traffic to the site.
You may be able to rank the web pages of your site higher in the search engines when you optimize them. Make use of SEO (search engine optimization) techniques so that you may be able to list them higher and attract more traffic to your site.
Look for high PR directory submission sites to submit your site. This can help improve the popularity of your website and enable it to rank higher on the many popular search engines. When you learn to submit the site on your own, you may be able to speed up the process of getting added to the search engine database and this can enable you to attract targeted traffic to your site easily.


A British sparkling wine made in the traditional style with fermented elderflowers as opposed to grapes! Our original experiment showed that when it comes to sparkling wines, grapes aren't always best. Introducing Renegade & Longton's elderflower sparkling wine, made especially for all of you elderflower connoisseurs. This sparkling wine is made in East Sussex and is fresh and floral. It is the perfect fun drink for a celebration or just as a glass of bubbly after a hard days work. It works well on its own or paired with canapés and nibbles, fish and hard cheeses.


text:
Алексе́й Па́влович Троцю́к (род. 30 ноября 1978, Брест, СССР) — российский сценарист и продюсер, актёр.

Биография
Окончил Брестский политехнический институт по специальности «инженер-технолог машиностроения»..

1998—2002 — выступал в КВН, дважды становился чемпионом «Высшей лиги» в составе команды Белорусского государственного университета (в 1999 и 2001 годах).

2002—2005 — работал сценаристом на канале РЕН ТВ.

2005—2011 — работа на телеканале СТС в качестве сценариста и креативного продюсера. Занимался разработкой идей оригинальных ситкомов «Папины дочки» и «Игрушки», драмеди «Я лечу», скетчкома «ДаЁшь молодЁжь!».

С 2018 по 2020 год — генеральный продюсер телеканала «Супер».

Генеральный продюсер и член совета директоров студии «Yellow, Black and White».. Автор идеи скетчкома «Нереальная история».

Один из основателей и генеральный продюсер видеосервиса Start, запущенного в 2017 году. Автор идей скетчкома «Нереальная история», сериалов «Надежда», «Бывшие», «Большая секунда», «Вне игры».

Является генеральным продюсером сериалов: «Бывшие»", «Вне игры»", «Надежда», «Контейнер», «Кухня», «Лучше, чем люди», «Светофор», скетч-шоу «Даёшь молодёжь!» и «Одна за всех»; фильмов: «Холоп», «Текст», «Непосредственно Каха», «Кухня в Париже», «СуперБобровы», «Без границ», «Гуляй, Вася!», «Кухня. Последняя битва», «Последний Богатырь», «Последний богатырь. Корень зла», "Отель «Белград», «Вызов», Декабрь, «Отчаянные дольщики» и другие.

В июле 2021 года занял пост креативного директора «Мегафона».

Обладатель премий АПКиТ (сериалы «Шторм», «257 причин, чтобы жить»), ТЭФИ (сериал «ИП Пирогова»), НИКА (сериал «Шторм»), Золотой орел (фильм «Текст»).

Творческая деятельность

Продюсер

 — — 6 кадров (3—5, 7—8 сезоны)
 — — Даёшь молодёжь
 — — Одна за всех
 — — Видеобитва
  — Неоплачиваемый отпуск
 — — Шоу «Уральских пельменей»
  — Однажды в милиции
  — Галыгин.ру
  — Слава Богу, ты пришёл! (5 сезон)
  — Игрушки
 — — Случайные связи
 — — Светофор
  — Мосгорсмех
 — — Нереальная история
 — — Люди Хэ
  — Кто, если не я?
  — Со мною вот что происходит
 — — Папины дочки (19—20 сезоны)
 — — Кухня
  — Думай как женщина
  — Местные новости
 — — Последний из Магикян
 — — Два отца и два сына
  — Братья по обмену
 — — Корабль
  — Неформат
  — Рецепт на миллион
  — Кухня в Париже
 — — Анжелика
  — 17+
  — Сын за отца
  — Братья по обмену 2
  — Любит — не любит
  — Папа на вырост
  — Это любовь
  — Родители
  — Без границ
  — Как я стал русским
 — — Мамочки
  — Ставка на любовь
  — СуперБобровы
  — Страна чудес
 — — Крыша мира
 — — Отель Элеон
  — Стройка
  — Гуляй, Вася!
  — Везучий случай
  — Кухня. Последняя битва
  — Бесстыдники
  — Ивановы-Ивановы (1—2 сезоны)
  — Бумеранг
  — Последний богатырь
  — Лапси
  — Трудно быть боссом
  — Вне игры
  — Бывшие
  — Гранд
  — Смешное время
  — Фитнес
  — СуперБобровы. Народные мстители
  — Завод
  — Тобол
  — Содержанки
  — Лучше, чем люди
  — ИП Пирогова
  — Трезвый водитель
  — Короче
  — Шторм
  — Текст
  — Сторож
  — Холоп
  — Война семей
  — Отель «Белград»
  — 257 причин, чтобы жить
  — Надежда
  — Текст. Реальность
  — Хороший человек
  — Шерлок в России
  — Непосредственно Каха
  — Последний богатырь: Корень зла
  — Вампиры средней полосы
  — Последний богатырь: Посланник тьмы
  — Алиса не может ждать
  — Чёрная весна
  — Дыхание

Сценарист
 — — Всё для тебя
  — Факультет юмора
  — Дорогая передача
  — Студенты
  — Туристы
  — Фирменная история
 — — 6 кадров (1—2 сезоны)
 2006—2008 — шоу импровизаций Слава Богу, ты пришёл! (1—2 сезоны)
  — Папа на все руки
  — Игры разума
 — — Папины дочки (1—16 сезоны)
  — Я лечу
  — Однажды в милиции
  — Игрушки
  — Большая секунда

Актёр
  — Девять жизней Нестора Махно
  — Со мною вот что происходит — ''Игорь

Награды
 ТЭФИ 2009 — в номинации «Сценарист телевизионного художественного сериала» (за ситком «Папины дочки»).
 ТЭФИ 2011 — в номинации «Продюсер телевизионной программы» (за скетчком «Одна за всех»)

Примечания

Ссылки
 Алексей Троцюк на сайте kino-teatr.ru
 Алексей Троцюк на сайте радиостанции «Эхо Москвы»

Чемпионы Высшей лиги КВН
Выпускники Белорусского государственного университета


Hugo Award-nominated author Katherine Addison will talk about her 2014 novel The Goblin Emperor. The coming-of-age steampunk fantasy follows a young goblin suddenly made emperor of his people after a violent coup. He must quickly become a master of court politics and romance while fending off attempts on his life, as he navigates a rich fantasy world.
KATHERINE ADDISON's short fiction has been selected by The Year's Best Fantasy and Horror and The Year's Best Science Fiction. As Sarah Monette, she is the author of the Doctrine of Labyrinths series and co-author, with Elizabeth Bear, of the Iskryne series. She lives near Madison, Wisconsin.


Braid Ghana Weaving Hairstyle – This Simple Braid Ghana Weaving Hairstyle wallpapers was upload on December, 1 2018 by Waino Predovic. Here latest Braid Ghana Weaving Hairstyle images collection. Download other ideas about Braid Ghana Weaving Hairstyle in our other blog. Click on images to get Simple Braid Ghana Weaving Hairstyle in high resolution.
You can download this Simple Braid Ghana Weaving Hairstyle photos for your collection. Don't forget to rate and comment if you interest with this Braid Ghana Weaving Hairstyle wallpapers. Please contact us if it contains a copyright.
Related Post "Simple Braid Ghana Weaving Hairstyle"


text:
4 days left to save $150 on tickets to TC Sessions: Robotics + AI 2020
Emma Comeau	2 years
The countdown to savings continues, and you have just four days left to score the best price on tickets to TC Sessions: Robotics + AI 2020. Join 1,500 of the brightest minds and innovators in robotics and machine learning — technologists, founders, investors, engineers and researchers. Buy an early-bird ticket now before prices go up on January 31, and you'll keep $150 in your pocket. Why spend more when you don't have to?
Get ready for a full day focused on the future of two technologies with the potential to change everything about the way we live. We have an outstanding lineup of speakers, interviews and panel discussions covering a range of topics. And of course, plenty of demos, too.
We won't just parrot the hype, either. Our editors will ask the hard questions, and the conference agenda includes discussions about the ethics and ramifications inherent with these potent technologies.
Here's a just sample of what's on tap:
Saving Humanity from AI: Stuart Russell, a UC Berkeley professor and AI authority argues in his acclaimed new book, "Human Compatible," that AI will doom humanity unless technologists fundamentally reform how they build AI algorithms.
Bringing Robots to Life: This summer's Tokyo Olympics will be a huge proving ground for TRI-AD (Toyota Research Institute – Advanced Development). TRI-AD's CEO James Kuffner and its VP of Robotics, Max Bajracharya will join us to discuss the department's plans for assistive robots and self-driving cars.
There's plenty more waiting for you, including the finalists of our first Pitch Night. This group of intrepid robotics and AI startup founders made the cut (10 teams will pitch the night before the conference at a private event). The finalists will pitch again at the conference from the Main Stage. Think your startup has what it takes to throw down in a pitch-off? We're accepting applications until February 1. Talk about a once-in-a-lifetime opportunity for focused exposure — apply right here today!
TC Sessions: Robotics + AI 2020 draws the top people in the industry, which makes it prime networking territory. Whether you're looking for funding, hunting for the perfect startup to add to your portfolio or searching for the next generation of engineers, this is where you need to be. Come work it to your advantage.
TC Sessions: Robotics + AI 2020 takes place in Berkeley on March 3, and we've packed a lot of value and opportunity into one day. Make the most of it — and remember, you'll save $150 if you buy an early-bird ticket before prices go up on January 31.
Is your company interested in sponsoring or exhibiting at TC Sessions: Robotics & AI 2020? Contact our sponsorship sales team by filling out this form.


Ningbo GDoor provide make-to-measure service to two-wing Automatic revolving doors. The door wings of two-wing revolving doors are fixed by the H-girder. Additionally, Ningbo GDoor two-wing automatic revolving doors adopt unique "drum wall load-bearing" structure to cope with the emergency evacuation.
4. High speed adjustment range(revolving door) : 1~4r.p.m.
Looking for ideal Safe Design for Automatic Revolving Doors Manufacturer & supplier ? We have a wide selection at great prices to help you get creative. All the Two-wing Automatic Revolving Doors Photocells are quality guaranteed. We are China Origin Factory of Revolving Doors with Access Systems. If you have any question, please feel free to contact us.