Getting started with Preact : helloworld standalone example

Preact looks to be the most closest React alternative in terms of code similarity. There official motto: "Fast 3kB alternative to React with the same ES6 API". You almost have to change nothing in the codes if you look to switch your React application to Preact. Lets have a quick look at a simplest Preact standalone helloworld component example with JSX/babel embedded in single html page, the very 'clock' example in their documentation :

  1. <html>
  2. <head></head>
  3. <body>
  4. <div id="abcd"></div>
  5. <script src="https://npmcdn.com/preact@2.8.3/dist/preact.js"></script>
  6. <script src="https://npmcdn.com/preact-compat@0.6.1/preact-compat.js"></script>
  7. <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
  8. <script>
  9. window.React = preactCompat;
  10. window.ReactDOM = preactCompat;
  11. </script>
  12. <script type="text/babel">
  13. const { h, render, Component } = preact; // normally this would be an import statement.
  14. class Clock extends Component {
  15. constructor() {
  16. super();
  17. // set initial time:
  18. this.state.time = Date.now();
  19. }
  20. componentDidMount() {
  21. // update time every second
  22. this.timer = setInterval(() => {
  23. this.setState({ time: Date.now() });
  24. }, 1000);
  25. }
  26. componentWillUnmount() {
  27. // stop when not renderable
  28. clearInterval(this.timer);
  29. }
  30. render(props, state) {
  31. let time = new Date(state.time).toLocaleTimeString();
  32. return <span>{ time }</span>;
  33. }
  34. }
  35. render(<Clock/>, document.getElementById('abcd'));
  36. </script>
  37. </body>
  38. </html>

Reference:

Simple Java Interview Spring Batch ETL Problem and Solution

Problem:
========
The goal is to write a parser in Java that parses web server access log file, loads the log to MySQL and checks if a given IP makes more than a certain number of requests for the given duration.

(1) Create a java tool that can parse and load the given log file to MySQL. The delimiter of the log file is pipe (|)

(2) The tool takes "startDate", "duration" and "threshold" as command line arguments. "startDate" is of "yyyy-MM-dd.HH:mm:ss" format, "duration" can take only "hourly", "daily" as inputs and "threshold" can be an integer.

(3) This is how the tool works:

    java "parser.jar" --startDate=2017-01-01.13:00:00 --duration=hourly --threshold=100

The tool will find any IPs that made more than 100 requests starting from 2017-01-01.13:00:00 to 2017-01-01.14:00:00 (one hour) and print them to console AND also load them to another MySQL table with comments on why it's blocked.

java "parser.jar" --startDate=2017-01-01.13:00:00 --duration=daily --threshold=250

The tool will find any IPs that made more than 250 requests starting from 2017-01-01.13:00:00 to 2017-01-02.13:00:00 (24 hours) and print them to console AND also load them to another MySQL table with comments on why it's blocked.

Example input file:
================

2017-01-01 00:00:11.763|192.168.234.82|"GET / HTTP/1.1"|200|"swcd (unknown version) CFNetwork/808.2.16 Darwin/15.6.0"
2017-01-01 00:00:21.164|192.168.234.82|"GET / HTTP/1.1"|200|"swcd (unknown version) CFNetwork/808.2.16 Darwin/15.6.0"
2017-01-01 00:00:23.003|192.168.169.194|"GET / HTTP/1.1"|200|"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393"
2017-01-01 00:00:40.554|192.168.234.82|"GET / HTTP/1.1"|200|"swcd (unknown version) CFNetwork/808.2.16 Darwin/15.6.0"
..................................
...................................
...................................
...................................
...................................
Full input file: https://drive.google.com/file/d/1pKtnO-2k9pmXw96akmcgYhAlhzuf8Iy2/view?usp=sharing


Input file description:
=================
Date, IP, Request, Status, User Agent (pipe delimited, open the example file in text editor)

Date Format: "yyyy-MM-dd HH:mm:ss.SSS"

The log file assumes 200 as hourly limit, meaning:

When you run your parser against this file with the following parameters

java "parser.jar" --startDate=2017-01-01.15:00:00 --duration=hourly --threshold=200

The output will have 192.168.11.231. If you open the log file, 192.168.11.231 has 200 or more requests between 2017-01-01.15:00:00 and 2017-01-01.15:59:59

Solution:
=======

The solution is simple Spring Batch ETL (Extract, Transform, Load) where we carefully going to implement READER, PROCESSOR & WRITER interfaces:

   @Bean

    public FlatFileItemReader<Consumer> reader() {

        FlatFileItemReader<Consumer> reader = 

           new FlatFileItemReader<Consumer>();

        reader.setResource(new ClassPathResource(Parser.ACCESS_LOG));

        reader.setLineMapper(new DefaultLineMapper<Consumer>() {{

            setLineTokenizer(new DelimitedLineTokenizer("|") {{

                setNames(new String[] { "date", "ip","request","status",
                                        "userAgent" });

            }});

            setFieldSetMapper(new BeanWrapperFieldSetMapper<Consumer>()
           
            {{

                setTargetType(Consumer.class);

            }});

        }});

        return reader;

    }



    @Bean

    public ConsumerRecordProcessor processor() {

        return new ConsumerRecordProcessor();

    }



public class ConsumerRecordProcessor implements ItemProcessor<
Consumer, Consumer> {

    private static final Logger log = LoggerFactory.
            getLogger(ConsumerRecordProcessor.class);

    @Override
    public Consumer process(final Consumer consumer) {

        Consumer transformedConsumer = new Consumer(consumer);
        String ip = consumer.getIp();

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"yyyy-MM-dd HH:mm:ss.SSS");
        LocalDateTime dateTime = LocalDateTime.parse(consumer.
getDateTime().toString(), formatter);

        if(dateTime.toInstant(
                ZoneOffset.ofTotalSeconds(0)).toEpochMilli() >= Parser
.START_TIMESTAMP.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli()
 && dateTime.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli() <= Parser
.END_TIMESTAMP.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli()) {
    if (Parser.blackList.contains(ip)) {
        //already blocked.
        transformedConsumer.setComment(
                Parser.DURATION + " limit exceeded.");
    } else {
        Parser.requestCounter.merge(ip, 1, Integer::sum);
        if (Parser.THRESHOLD <= Parser.requestCounter.get(ip)) {
            log.debug(ip + " reached " + Parser.DURATION + " limit!");
            Parser.blackList.add(ip);//block
            transformedConsumer.setComment(Parser.DURATION
                    + " limit exceeded.");
        }
    }
}
        return transformedConsumer;
    }
}
@Bean public JdbcBatchItemWriter<Consumer> writer() { JdbcBatchItemWriter<Consumer> writer =

               new JdbcBatchItemWriter<Consumer>();

        writer.setItemSqlParameterSourceProvider(
       new BeanPropertyItemSqlParameterSourceProvider<Consumer>());

        writer.setSql("INSERT INTO parser_data (
        date_time, ip, request, status, user_agent, comment) 
        VALUES (:dateTime, :ip, :request, :status,
        :userAgent, :comment)");

        writer.setDataSource(dataSource);

        return writer;

    }



Initial MySql Schema:
=================

DROP TABLE parser_data IF EXISTS;


create table parser_data(

 date_time timestamp,

 ip varchar(100),

 request varchar(100),

 status varchar(100),

 user_agent varchar(1000),

 comment varchar(5000));

Test:
====

 @Test
 public void testParseArgsPlusETL() throws ParseException {
  //java -jar parser.jar com.ef.Parser --startDate=2017-01-01.13:00:00 
--accesslog=access.log --duration=hourly --threshold=100
 Parser.main(new String[]{ --startDate=2017-01-01.13:00:00,
--accesslog=access.log,--duration=hourly,--threshold=100 });
 Assert.assertEquals(hourly,Parser.DURATION);
 Assert.assertEquals(100,Parser.THRESHOLD);
 Assert.assertEquals(Parser.blackList.size(),2);
 }

Full working code Download .

Codeforces 914B : Conan and Agasa play a Card Game Problem Analysis


The key point in this problem is no one can pick more than one cards in every turn.
Because of this, if there are multiple cards with same big numbers it is a matter of sequence and decides the winning professor/detective depending whether the number of cards of same big numbers are even or odd.

Example 1:

6
4 5 2 5 4 5

Case 1. odd number of cards having same & highest number:

Turn 1:
5c 5  5       //Nc --> Conan picks card with value N
4  4 //Na --> Agasa picks card with value N
2

Turn 2:
5c 5a 5
4  4
2

Turn 3:
5c 5a 5c //All highest value cards have been
4  4 //picked up. No cards left for
2 //Agasa in next turn

//Conan wins.

Example 2:

9
3 9 3 5 9 5 9 5 9

Case 2. odd number of cards having same (but not highest) number:

Turn 1:
9  9  9  9   //There is an even number of 9s. Conan predicts
5c 5  5 //his defeat. So he picks second highest card
3  3 //that has an odd number of counts. Conan
// always has this advantage because he is
// picking first. Because both Conan & Agasa
//playing optimally, they can not make mistakes.

Turn 2,3:
9  9  9  9
5c 5a 5c //All 5s and 3s are now gone. Leaving 4 9s onboard.
3  3

Turn 4:
9a  9  9  9      //Agasa is now forced to pick these even
//number of 9s.

Turn 5,6,7:
9a  9c  9a  9c

//Conan wins.

In our example Case 1 in fact belongs within Case 2.


Example 3:

12
8 6 4 8 4 8 6 8 6 6 8 8

Case 3. even number of cards having same number:

8  8  8  8  8  8 //There are no odd number of occurances
6  6  6  6 //of cards with same value (Conan's
4  4 //only chance to change sequence of
//turns)
//Agasa wins.


Solution (.CPP) Codeforces compiler C++ 17 (7.3.0):
==============================================

#include <iostream>

using namespace std;

int cardCounts[100005];       // we can have a 1-dimensional array for storing every card count
                                              // since a <= 10^5 ( < 10^8 )

int main() {

  int n;
  cin >> n;

  while(n--) {
    int a;
    cin >> a;
    cardCounts[a]++;
  }

  for (int i = 1; i <= 1e5; i++) {
    if (cardCounts[i] % 2) {
      cout << "Conan\n";
      return 0;
    }
  }

  cout << "Agasa\n";
  return 0;
}