├── java-aspects
├── .gitignore
├── settings.gradle
├── README.md
├── src
│ └── main
│ │ ├── resources
│ │ ├── META-INF
│ │ │ └── aop.xml
│ │ └── logback.xml
│ │ └── java
│ │ └── me
│ │ └── foat
│ │ └── articles
│ │ └── aspects
│ │ ├── annotations
│ │ ├── ChangeParam.java
│ │ └── AroundMethod.java
│ │ ├── Application.java
│ │ ├── AspectController.java
│ │ └── ExampleAspect.java
└── build.gradle
├── akka-example
├── project
│ ├── build.properties
│ └── plugins.sbt
├── README.md
├── build.sbt
└── src
│ └── main
│ └── scala
│ └── me
│ └── foat
│ └── akka
│ └── example
│ ├── Store.scala
│ ├── Sender.scala
│ └── Main.scala
├── akka-web-crawler
├── project
│ ├── plugins.sbt
│ └── build.properties
├── README.md
├── src
│ └── main
│ │ └── scala
│ │ └── me
│ │ └── foat
│ │ └── crawler
│ │ ├── crawler.scala
│ │ ├── Messages.scala
│ │ ├── StartingPoint.scala
│ │ ├── Indexer.scala
│ │ ├── SiteCrawler.scala
│ │ ├── Scraper.scala
│ │ └── Supervisor.scala
└── build.sbt
├── observing-futures
├── project
│ ├── build.properties
│ └── plugins.sbt
├── README.md
├── build.sbt
└── src
│ └── main
│ └── scala
│ └── article
│ └── BackToTheFuture.scala
├── scalacheck-generators
├── project
│ ├── plugins.sbt
│ └── build.properties
├── README.md
├── build.sbt
└── src
│ └── test
│ └── scala
│ └── example
│ └── MapExampleSpecification.scala
├── scala-js-reactive-mouse
├── project
│ ├── build.properties
│ └── plugins.sbt
├── build.sbt
├── README.md
└── src
│ └── main
│ ├── resources
│ ├── index.html
│ └── index-dev.html
│ └── scala
│ └── article
│ └── MousePosition.scala
└── README.md
/java-aspects/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | out/
--------------------------------------------------------------------------------
/akka-example/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version = 0.13.8
--------------------------------------------------------------------------------
/akka-example/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | logLevel := Level.Warn
--------------------------------------------------------------------------------
/akka-web-crawler/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | logLevel := Level.Warn
--------------------------------------------------------------------------------
/akka-web-crawler/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version = 0.13.8
--------------------------------------------------------------------------------
/java-aspects/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'java-aspects'
--------------------------------------------------------------------------------
/observing-futures/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version = 0.13.9
--------------------------------------------------------------------------------
/observing-futures/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | logLevel := Level.Warn
--------------------------------------------------------------------------------
/scalacheck-generators/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | logLevel := Level.Warn
--------------------------------------------------------------------------------
/scala-js-reactive-mouse/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version = 0.13.9
--------------------------------------------------------------------------------
/scalacheck-generators/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version = 0.13.9
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Source codes for articles from http://foat.me/articles
2 |
3 | ## License
4 | MIT: http://foat.mit-license.org
5 |
--------------------------------------------------------------------------------
/scala-js-reactive-mouse/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | logLevel := Level.Warn
2 |
3 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.4")
--------------------------------------------------------------------------------
/akka-example/README.md:
--------------------------------------------------------------------------------
1 | Source code for http://foat.me/articles/akka-example/
2 |
3 | ## License
4 | MIT: http://foat.mit-license.org
5 |
--------------------------------------------------------------------------------
/akka-web-crawler/README.md:
--------------------------------------------------------------------------------
1 | Source code for http://foat.me/articles/akka-web-crawler/
2 |
3 | ## License
4 | MIT: http://foat.mit-license.org
--------------------------------------------------------------------------------
/observing-futures/README.md:
--------------------------------------------------------------------------------
1 | Source code for http://foat.me/articles/observing-the-future-with-rxscala/
2 |
3 | ## License
4 | MIT: http://foat.mit-license.org
5 |
--------------------------------------------------------------------------------
/java-aspects/README.md:
--------------------------------------------------------------------------------
1 | Source code for http://foat.me/articles/java-aspects-using-spring-aop-and-aspectj/
2 |
3 | ## License
4 | MIT: http://foat.mit-license.org
5 |
--------------------------------------------------------------------------------
/akka-example/build.sbt:
--------------------------------------------------------------------------------
1 | name := "akka-example"
2 |
3 | version := "1.0"
4 |
5 | scalaVersion := "2.11.7"
6 |
7 | libraryDependencies +=
8 | "com.typesafe.akka" %% "akka-actor" % "2.4.0"
--------------------------------------------------------------------------------
/scalacheck-generators/README.md:
--------------------------------------------------------------------------------
1 | Source code for http://foat.me/articles/the-beginning-of-scala-journey-2/
2 |
3 | ## Run
4 | `sbt test`
5 |
6 | ## License
7 | MIT: http://foat.mit-license.org
--------------------------------------------------------------------------------
/scalacheck-generators/build.sbt:
--------------------------------------------------------------------------------
1 | name := "scalacheck-generators"
2 |
3 | version := "1.0"
4 |
5 | scalaVersion := "2.11.7"
6 |
7 | libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.12.4" % "test"
--------------------------------------------------------------------------------
/observing-futures/build.sbt:
--------------------------------------------------------------------------------
1 | name := "observing-futures"
2 |
3 | version := "1.0"
4 |
5 | scalaVersion := "2.11.7"
6 |
7 | libraryDependencies ++= Seq(
8 | "io.reactivex" %% "rxscala" % "0.25.0"
9 | )
10 |
--------------------------------------------------------------------------------
/scala-js-reactive-mouse/build.sbt:
--------------------------------------------------------------------------------
1 | enablePlugins(ScalaJSPlugin)
2 |
3 | name := "scala-js-reactive-mouse"
4 | version := "1.0"
5 | scalaVersion := "2.11.7"
6 |
7 | libraryDependencies ++= Seq(
8 | "org.scala-js" %%% "scalajs-dom" % "0.8.0",
9 | "com.lihaoyi" %%% "scalarx" % "0.2.8"
10 | )
--------------------------------------------------------------------------------
/java-aspects/src/main/resources/META-INF/aop.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/scala-js-reactive-mouse/README.md:
--------------------------------------------------------------------------------
1 | Source code for http://foat.me/articles/reactive-fun-with-scala-js/
2 |
3 | ## Build
4 | * `sbt fastOptJS` - for development,
5 | * `sbt fullOptJS` - for production.
6 | * `target/scala-2.11/classes/` - folder for output HTML files.
7 |
8 | ## License
9 | MIT: http://foat.mit-license.org
--------------------------------------------------------------------------------
/java-aspects/src/main/java/me/foat/articles/aspects/annotations/ChangeParam.java:
--------------------------------------------------------------------------------
1 | package me.foat.articles.aspects.annotations;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * @author Foat Akhmadeev
7 | * 03/06/15
8 | */
9 | @Documented
10 | @Retention(RetentionPolicy.RUNTIME)
11 | @Target({ElementType.PARAMETER})
12 | public @interface ChangeParam {
13 | }
--------------------------------------------------------------------------------
/java-aspects/src/main/java/me/foat/articles/aspects/annotations/AroundMethod.java:
--------------------------------------------------------------------------------
1 | package me.foat.articles.aspects.annotations;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * @author Foat Akhmadeev
7 | * 03/06/15
8 | */
9 | @Documented
10 | @Retention(RetentionPolicy.RUNTIME)
11 | @Target({ElementType.METHOD})
12 | public @interface AroundMethod {
13 | int value() default 100;
14 | }
--------------------------------------------------------------------------------
/akka-web-crawler/src/main/scala/me/foat/crawler/crawler.scala:
--------------------------------------------------------------------------------
1 | package me.foat
2 |
3 | import java.net.URL
4 |
5 | import scala.language.implicitConversions
6 |
7 | /**
8 | * @author Foat Akhmadeev
9 | * 17/01/16
10 | */
11 | package object crawler {
12 | implicit def string2url(s: String): URL = new URL(s)
13 |
14 | implicit def string2urlWithSpec(s: (String, String)): URL = new URL(new URL(s._1), s._2)
15 | }
16 |
--------------------------------------------------------------------------------
/akka-web-crawler/build.sbt:
--------------------------------------------------------------------------------
1 | name := "akka-web-crawler"
2 |
3 | version := "1.0"
4 |
5 | scalaVersion := "2.11.7"
6 |
7 | libraryDependencies ++= {
8 | val akkaV = "2.4.0"
9 | Seq(
10 | "com.typesafe.akka" %% "akka-actor" % akkaV,
11 | "org.jsoup" % "jsoup" % "1.8+",
12 | "commons-validator" % "commons-validator" % "1.5+"
13 | )
14 | }
--------------------------------------------------------------------------------
/akka-web-crawler/src/main/scala/me/foat/crawler/Messages.scala:
--------------------------------------------------------------------------------
1 | package me.foat.crawler
2 |
3 | import java.net.URL
4 |
5 | /**
6 | * @author Foat Akhmadeev
7 | * 17/01/16
8 | */
9 | case class Start(url: URL)
10 | case class Scrap(url: URL)
11 | case class Index(url: URL, content: Content)
12 | case class Content(title: String, meta: String, urls: List[URL])
13 | case class ScrapFinished(url: URL)
14 | case class IndexFinished(url: URL, urls: List[URL])
15 | case class ScrapFailure(url: URL, reason: Throwable)
16 |
--------------------------------------------------------------------------------
/akka-example/src/main/scala/me/foat/akka/example/Store.scala:
--------------------------------------------------------------------------------
1 | package me.foat.akka.example
2 |
3 | import akka.actor.Actor
4 |
5 | /**
6 | * @author Foat Akhmadeev
7 | * 27/12/15
8 | */
9 | class Store extends Actor {
10 | var list = List.empty[String]
11 |
12 | def receive: Receive = {
13 | case msg: String =>
14 | list = msg :: list
15 | }
16 |
17 | @throws[Exception](classOf[Exception])
18 | override def postStop(): Unit = {
19 | super.postStop()
20 | println(list.reverse)
21 | }
22 | }
--------------------------------------------------------------------------------
/akka-example/src/main/scala/me/foat/akka/example/Sender.scala:
--------------------------------------------------------------------------------
1 | package me.foat.akka.example
2 |
3 | import akka.actor.{Actor, ActorRef, PoisonPill}
4 |
5 | /**
6 | * @author Foat Akhmadeev
7 | * 27/12/15
8 | */
9 | class Sender(store: ActorRef, id: Int) extends Actor {
10 | var count = 0
11 |
12 | def receive: Receive = {
13 | case "start" =>
14 | println(s"$id sends $count to the store")
15 | store ! s"$id => $count"
16 | count += 1
17 | if (count < 5)
18 | self ! "start"
19 | else self ! PoisonPill
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/akka-web-crawler/src/main/scala/me/foat/crawler/StartingPoint.scala:
--------------------------------------------------------------------------------
1 | package me.foat.crawler
2 |
3 | import akka.actor.{ActorSystem, PoisonPill, Props}
4 |
5 | import scala.concurrent.Await
6 | import scala.concurrent.duration._
7 | import scala.language.postfixOps
8 |
9 | /**
10 | * @author Foat Akhmadeev
11 | * 17/01/16
12 | */
13 | object StartingPoint extends App {
14 | val system = ActorSystem()
15 | val supervisor = system.actorOf(Props(new Supervisor(system)))
16 |
17 | supervisor ! Start("https://foat.me")
18 |
19 | Await.result(system.whenTerminated, 10 minutes)
20 |
21 | supervisor ! PoisonPill
22 | system.terminate
23 | }
24 |
--------------------------------------------------------------------------------
/java-aspects/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | java-aspects
4 |
5 |
6 |
7 |
8 | %d{yyyy-MM-dd HH:mm:ss} %-5level %class{0}.%method:%L - %msg%n
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/akka-web-crawler/src/main/scala/me/foat/crawler/Indexer.scala:
--------------------------------------------------------------------------------
1 | package me.foat.crawler
2 |
3 | import java.net.URL
4 |
5 | import akka.actor.{Actor, ActorRef}
6 |
7 | /**
8 | * @author Foat Akhmadeev
9 | * 17/01/16
10 | */
11 | class Indexer(supervisor: ActorRef) extends Actor {
12 | var store = Map.empty[URL, Content]
13 |
14 | def receive: Receive = {
15 | case Index(url, content) =>
16 | println(s"saving page $url with $content")
17 | store += (url -> content)
18 | supervisor ! IndexFinished(url, content.urls)
19 | }
20 |
21 | @throws[Exception](classOf[Exception])
22 | override def postStop(): Unit = {
23 | super.postStop()
24 | store.foreach(println)
25 | println(store.size)
26 | }
27 | }
--------------------------------------------------------------------------------
/akka-example/src/main/scala/me/foat/akka/example/Main.scala:
--------------------------------------------------------------------------------
1 | package me.foat.akka.example
2 |
3 | import akka.actor.{ActorSystem, PoisonPill, Props}
4 |
5 | import scala.concurrent.ExecutionContext.Implicits.global
6 | import scala.concurrent.duration._
7 | import scala.language.postfixOps
8 |
9 | /**
10 | * @author Foat Akhmadeev
11 | * 27/12/15
12 | */
13 | object Main extends App {
14 | val system = ActorSystem()
15 | val store = system.actorOf(Props(new Store))
16 |
17 | val sender1 = system.actorOf(Props(new Sender(store, 1)))
18 | val sender2 = system.actorOf(Props(new Sender(store, 2)))
19 | val sender3 = system.actorOf(Props(new Sender(store, 3)))
20 |
21 | sender1 ! "start"
22 | sender2 ! "start"
23 | sender3 ! "start"
24 |
25 | system.scheduler.scheduleOnce(2 seconds)({store ! PoisonPill; system.terminate})
26 | }
27 |
--------------------------------------------------------------------------------
/java-aspects/build.gradle:
--------------------------------------------------------------------------------
1 | group 'me.foat.articles.aspects'
2 | version '1.0'
3 |
4 | apply plugin: 'java'
5 |
6 | apply plugin: 'application'
7 | mainClassName = "me.foat.articles.aspects.Application"
8 |
9 | sourceCompatibility = 1.8
10 |
11 | repositories {
12 | mavenCentral()
13 | }
14 |
15 | configurations {
16 | aspectjweaver
17 | }
18 |
19 | dependencies {
20 | compile "org.springframework:spring-webmvc:4.+"
21 | compile "org.springframework:spring-aop:4.+"
22 | compile "org.springframework.boot:spring-boot-starter-web:1.+"
23 | compile "org.aspectj:aspectjrt:1.+"
24 | compile "org.slf4j:slf4j-api:1.+"
25 | aspectjweaver "org.aspectj:aspectjweaver:1.+"
26 | runtime configurations.aspectjweaver.dependencies
27 | }
28 |
29 | // enables native aspectj
30 | //applicationDefaultJvmArgs = [
31 | // "-javaagent:${configurations.aspectjweaver.asPath}"
32 | //]
--------------------------------------------------------------------------------
/java-aspects/src/main/java/me/foat/articles/aspects/Application.java:
--------------------------------------------------------------------------------
1 | package me.foat.articles.aspects;
2 |
3 | import org.aspectj.lang.annotation.Aspect;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
6 | import org.springframework.context.annotation.ComponentScan;
7 | import org.springframework.context.annotation.EnableAspectJAutoProxy;
8 | import org.springframework.stereotype.Controller;
9 |
10 | /**
11 | * @author Foat Akhmadeev
12 | * 02/06/15
13 | */
14 | @EnableAutoConfiguration
15 | @EnableAspectJAutoProxy
16 | @ComponentScan(
17 | value = "me.foat.articles.aspects",
18 | includeFilters = @ComponentScan.Filter({Controller.class, Aspect.class}),
19 | useDefaultFilters = false)
20 | public class Application {
21 | public static void main(String[] args) {
22 | SpringApplication.run(Application.class, args);
23 | }
24 | }
--------------------------------------------------------------------------------
/scala-js-reactive-mouse/src/main/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Scala.js and Scala.rx for mouse position
5 |
6 |
22 |
23 |
24 |
25 |
26 | Mouse position:
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
--------------------------------------------------------------------------------
/scala-js-reactive-mouse/src/main/resources/index-dev.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Scala.js and Scala.rx for mouse position
5 |
6 |
22 |
23 |
24 |
25 |
26 | Mouse position:
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
--------------------------------------------------------------------------------
/scalacheck-generators/src/test/scala/example/MapExampleSpecification.scala:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import org.scalacheck.Arbitrary._
4 | import org.scalacheck.Gen._
5 | import org.scalacheck.Prop.forAll
6 | import org.scalacheck.{Arbitrary, Gen, Properties}
7 |
8 | class MapExample[T](val base: List[T]) {
9 | def map[V](f: T => V): MapExample[V] = MapExample(base.map(f))
10 |
11 | override def toString: String = base.toString()
12 | }
13 |
14 | object MapExample {
15 | def apply[T](base: List[T]) = new MapExample[T](base)
16 | }
17 |
18 | object MapExampleSpecification extends Properties("MapExample") {
19 | type T = MapExample[Int]
20 |
21 | val generator: Gen[T] = for {
22 | l <- arbitrary[Int]
23 | v <- oneOf(const(MapExample(Nil)), generator)
24 | } yield MapExample(l :: v.base)
25 |
26 | implicit lazy val arbT: Arbitrary[T] = Arbitrary(generator)
27 |
28 | property("map example") = forAll { a: T =>
29 | a.map(v => v * 2).base == (for {v <- a} yield v * 2).base
30 | }
31 | }
--------------------------------------------------------------------------------
/observing-futures/src/main/scala/article/BackToTheFuture.scala:
--------------------------------------------------------------------------------
1 | package article
2 |
3 | import java.util.concurrent.CountDownLatch
4 |
5 | import rx.lang.scala.Observable
6 |
7 | import scala.concurrent.ExecutionContext.Implicits.global
8 | import scala.concurrent._
9 | import scala.concurrent.duration._
10 |
11 | /**
12 | * @author Foat Akhmadeev
13 | * 07/09/15
14 | */
15 | object BackToTheFuture extends App {
16 | val intervals: Observable[Long] = Observable.interval(100 millis).take(10)
17 |
18 | intervals subscribe {
19 | v => println(s"value = $v")
20 | }
21 | Await.result(Future { Thread.sleep(1500) }, 2 seconds)
22 |
23 | Observable.just(5, 4, 2).subscribe(print(_))
24 | List(5, 4, 2).foreach(print(_))
25 |
26 | println()
27 |
28 | val asyncEmulation = Observable
29 | .just(1, 2, 3)
30 | .map(e => e + 1)
31 | .flatMap(e => Observable.from(Future { Thread.sleep(400 - 100 * e); e }))
32 |
33 | val cd = new CountDownLatch(3)
34 | asyncEmulation subscribe {
35 | v => println(s"received = $v"); cd.countDown()
36 | }
37 | cd.await()
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/akka-web-crawler/src/main/scala/me/foat/crawler/SiteCrawler.scala:
--------------------------------------------------------------------------------
1 | package me.foat.crawler
2 |
3 | import java.net.URL
4 |
5 | import akka.actor.{Actor, Props, _}
6 | import akka.pattern.{ask, pipe}
7 | import akka.util.Timeout
8 |
9 | import scala.concurrent.ExecutionContext.Implicits.global
10 | import scala.concurrent.Future
11 | import scala.concurrent.duration._
12 | import scala.language.postfixOps
13 |
14 | /**
15 | * @author Foat Akhmadeev
16 | * 17/01/16
17 | */
18 | class SiteCrawler(supervisor: ActorRef, indexer: ActorRef) extends Actor {
19 | val process = "Process next url"
20 |
21 | val scraper = context actorOf Props(new Scraper(indexer))
22 | implicit val timeout = Timeout(3 seconds)
23 | val tick =
24 | context.system.scheduler.schedule(0 millis, 1000 millis, self, process)
25 | var toProcess = List.empty[URL]
26 |
27 | def receive: Receive = {
28 | case Scrap(url) =>
29 | // wait some time, so we will not spam a website
30 | println(s"waiting... $url")
31 | toProcess = url :: toProcess
32 | case `process` =>
33 | toProcess match {
34 | case Nil =>
35 | case url :: list =>
36 | println(s"site scraping... $url")
37 | toProcess = list
38 | (scraper ? Scrap(url)).mapTo[ScrapFinished]
39 | .recoverWith { case e => Future {ScrapFailure(url, e)} }
40 | .pipeTo(supervisor)
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/java-aspects/src/main/java/me/foat/articles/aspects/AspectController.java:
--------------------------------------------------------------------------------
1 | package me.foat.articles.aspects;
2 |
3 | import me.foat.articles.aspects.annotations.AroundMethod;
4 | import me.foat.articles.aspects.annotations.ChangeParam;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RequestMethod;
9 | import org.springframework.web.bind.annotation.RequestParam;
10 | import org.springframework.web.bind.annotation.RestController;
11 |
12 | import javax.servlet.http.HttpServletRequest;
13 |
14 | /**
15 | * @author Foat Akhmadeev
16 | * 02/06/15
17 | */
18 | @RestController
19 | public class AspectController {
20 | private static final Logger log = LoggerFactory.getLogger(ExampleAspect.class);
21 |
22 | @RequestMapping(value = "/multiply", method = RequestMethod.GET)
23 | @AroundMethod
24 | public String multiply(HttpServletRequest request, @RequestParam @ChangeParam String number) {
25 | log.info("Processing multiply method with a number parameter = {}", number);
26 |
27 | // number = internalMethodAdd(number);
28 | // log.info("Internal method returned a result after aspect processing = {}", number);
29 |
30 | return number + " * ";
31 | }
32 |
33 | @AroundMethod(value = 200)
34 | private String internalMethodAdd(@ChangeParam String number) {
35 | log.info("Processing internalMethodAdd method with a number parameter = {}", number);
36 | return number + " + ";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/akka-web-crawler/src/main/scala/me/foat/crawler/Scraper.scala:
--------------------------------------------------------------------------------
1 | package me.foat.crawler
2 |
3 | import java.net.URL
4 |
5 | import akka.actor.{Actor, ActorRef}
6 | import org.apache.commons.validator.routines.UrlValidator
7 | import org.jsoup.Jsoup
8 |
9 | import scala.collection.JavaConverters._
10 |
11 | /**
12 | * @author Foat Akhmadeev
13 | * 17/01/16
14 | */
15 | class Scraper(indexer: ActorRef) extends Actor {
16 | val urlValidator = new UrlValidator()
17 |
18 | def receive: Receive = {
19 | case Scrap(url) =>
20 | println(s"scraping $url")
21 | val content = parse(url)
22 | sender() ! ScrapFinished(url)
23 | indexer ! Index(url, content)
24 | }
25 |
26 | def parse(url: URL): Content = {
27 | val link: String = url.toString
28 | val response = Jsoup.connect(link).ignoreContentType(true)
29 | .userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1").execute()
30 |
31 | val contentType: String = response.contentType
32 | if (contentType.startsWith("text/html")) {
33 | val doc = response.parse()
34 | val title: String = doc.getElementsByTag("title").asScala.map(e => e.text()).head
35 | val descriptionTag = doc.getElementsByTag("meta").asScala.filter(e => e.attr("name") == "description")
36 | val description = if (descriptionTag.isEmpty) "" else descriptionTag.map(e => e.attr("content")).head
37 | val links: List[URL] = doc.getElementsByTag("a").asScala.map(e => e.attr("href")).filter(s =>
38 | urlValidator.isValid(s)).map(link => new URL(link)).toList
39 | Content(title, description, links)
40 | } else {
41 | // e.g. if this is an image
42 | Content(link, contentType, List())
43 | }
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/scala-js-reactive-mouse/src/main/scala/article/MousePosition.scala:
--------------------------------------------------------------------------------
1 | package article
2 |
3 | import scala.scalajs.js
4 | import scala.scalajs.js.annotation.JSExport
5 | import org.scalajs.dom.{Node, html}
6 | import org.scalajs.dom
7 |
8 | import rx._
9 |
10 | import scala.language.implicitConversions
11 |
12 | case class Point(x: Int, y: Int) {
13 | def +(p: Point) = Point(x + p.x, y + p.y)
14 | def -(p: Point) = Point(x - p.x, y - p.y)
15 | def /(d: Int) = Point(x / d, y / d)
16 | }
17 |
18 | @JSExport
19 | object MousePosition {
20 |
21 | implicit def rxNode[T](r: Rx[T]): Node = {
22 | def rSafe: dom.Node = {
23 | val node = dom.document.createElement("div")
24 | node.textContent = r().toString
25 | node
26 | }
27 | var last = rSafe
28 | Obs(r, skipInitial = true) {
29 | val newLast = rSafe
30 | js.Dynamic.global.last = last
31 | last.parentNode.replaceChild(newLast, last)
32 | last = newLast
33 | }
34 | last
35 | }
36 |
37 | @JSExport
38 | def start(div: html.Div, canvas: html.Canvas): Unit = {
39 | val h = dom.window.innerHeight
40 | val w = dom.window.innerWidth
41 | canvas.height = h
42 | canvas.width = w
43 |
44 | // default rectangle size
45 | val s = 10
46 | val half = Point(s, s) / 2
47 |
48 | val ctx = canvas.getContext("2d")
49 | .asInstanceOf[dom.CanvasRenderingContext2D]
50 |
51 | val mousePos = Var(Point(0, 0))
52 |
53 | val center = Rx { mousePos() - half }
54 |
55 | Obs(center, skipInitial = true) {
56 | ctx.fillStyle = "gray"
57 | ctx.fillRect(center().x, center().y, s, s)
58 | }
59 |
60 | def clear = {
61 | ctx.fillStyle = "white"
62 | ctx.fillRect(0, 0, w, h)
63 | }
64 |
65 | div.appendChild(mousePos)
66 | div.appendChild(center)
67 |
68 | dom.window.onkeypress = { e: dom.KeyboardEvent => if (e.keyCode == 27) clear }
69 | dom.window.onmousemove = { e: dom.MouseEvent => mousePos() = Point(e.pageX.toInt, e.pageY.toInt) }
70 | }
71 | }
--------------------------------------------------------------------------------
/akka-web-crawler/src/main/scala/me/foat/crawler/Supervisor.scala:
--------------------------------------------------------------------------------
1 | package me.foat.crawler
2 |
3 | import java.net.URL
4 |
5 | import akka.actor.{Actor, ActorSystem, Props, _}
6 |
7 | import scala.language.postfixOps
8 |
9 | /**
10 | * @author Foat Akhmadeev
11 | * 17/01/16
12 | */
13 | class Supervisor(system: ActorSystem) extends Actor {
14 | val indexer = context actorOf Props(new Indexer(self))
15 |
16 | val maxPages = 100
17 | val maxRetries = 2
18 |
19 | var numVisited = 0
20 | var toScrap = Set.empty[URL]
21 | var scrapCounts = Map.empty[URL, Int]
22 | var host2Actor = Map.empty[String, ActorRef]
23 |
24 | def receive: Receive = {
25 | case Start(url) =>
26 | println(s"starting $url")
27 | scrap(url)
28 | case ScrapFinished(url) =>
29 | println(s"scraping finished $url")
30 | case IndexFinished(url, urls) =>
31 | if (numVisited < maxPages)
32 | urls.toSet.filter(l => !scrapCounts.contains(l)).foreach(scrap)
33 | checkAndShutdown(url)
34 | case ScrapFailure(url, reason) =>
35 | val retries: Int = scrapCounts(url)
36 | println(s"scraping failed $url, $retries, reason = $reason")
37 | if (retries < maxRetries) {
38 | countVisits(url)
39 | host2Actor(url.getHost) ! Scrap(url)
40 | } else
41 | checkAndShutdown(url)
42 | }
43 |
44 | def checkAndShutdown(url: URL): Unit = {
45 | toScrap -= url
46 | // if nothing to visit
47 | if (toScrap.isEmpty) {
48 | self ! PoisonPill
49 | system.terminate()
50 | }
51 | }
52 |
53 | def scrap(url: URL) = {
54 | val host = url.getHost
55 | println(s"host = $host")
56 | if (!host.isEmpty) {
57 | val actor = host2Actor.getOrElse(host, {
58 | val buff = system.actorOf(Props(new SiteCrawler(self, indexer)))
59 | host2Actor += (host -> buff)
60 | buff
61 | })
62 |
63 | numVisited += 1
64 | toScrap += url
65 | countVisits(url)
66 | actor ! Scrap(url)
67 | }
68 | }
69 |
70 | def countVisits(url: URL): Unit = scrapCounts += (url -> (scrapCounts.getOrElse(url, 0) + 1))
71 | }
--------------------------------------------------------------------------------
/java-aspects/src/main/java/me/foat/articles/aspects/ExampleAspect.java:
--------------------------------------------------------------------------------
1 | package me.foat.articles.aspects;
2 |
3 | import me.foat.articles.aspects.annotations.AroundMethod;
4 | import me.foat.articles.aspects.annotations.ChangeParam;
5 | import org.aspectj.lang.ProceedingJoinPoint;
6 | import org.aspectj.lang.annotation.Around;
7 | import org.aspectj.lang.annotation.Aspect;
8 | import org.aspectj.lang.reflect.MethodSignature;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import java.lang.annotation.Annotation;
13 | import java.lang.reflect.Method;
14 | import java.util.Arrays;
15 | import java.util.NoSuchElementException;
16 | import java.util.OptionalInt;
17 | import java.util.stream.IntStream;
18 |
19 | /**
20 | * @author Foat Akhmadeev
21 | * 03/06/15
22 | */
23 | @Aspect
24 | public class ExampleAspect {
25 | private static final Logger log = LoggerFactory.getLogger(ExampleAspect.class);
26 |
27 | @Around("execution(@me.foat.articles.aspects.annotations.AroundMethod * *.*(..)) && @annotation(ann)")
28 | public Object process(ProceedingJoinPoint joinPoint, AroundMethod ann) throws Throwable {
29 | log.info("Annotation value = {}", ann.value());
30 |
31 | // all method parameters
32 | final Object[] args = joinPoint.getArgs();
33 | // method information
34 | final Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
35 | final Annotation[][] annotations =
36 | method.getParameterAnnotations();
37 |
38 | // get index of a parameter with ChangeParam annotation
39 | int idx = getParameterIdx(annotations, method.getName());
40 | Object arg = args[idx];
41 |
42 | if (!(arg instanceof String)) {
43 | throw new IllegalArgumentException(String.format(
44 | "Incorrect argument class in a method %s, class is %s, required String",
45 | method.getName(), arg.getClass()));
46 | }
47 |
48 | String number = (String) arg;
49 | log.info("Input number = {}", number);
50 |
51 | // change input parameter
52 | number = "(" + number;
53 | args[idx] = number;
54 |
55 | // display result of a method processing
56 | final Object result = joinPoint.proceed(args);
57 | log.info("Method {} returned a result = {}", method.getName(), result);
58 |
59 | // override method return value
60 | return "" + result + ann.value() + ")";
61 | }
62 |
63 | private int getParameterIdx(Annotation[][] annotations, String methodName) {
64 | OptionalInt optIdx = IntStream
65 | .range(0, annotations.length)
66 | .filter(i ->
67 | Arrays
68 | .stream(annotations[i])
69 | .filter(a -> a instanceof ChangeParam)
70 | .findAny()
71 | .isPresent())
72 | .findFirst();
73 |
74 | if (!optIdx.isPresent()) {
75 | throw new NoSuchElementException(String.format(
76 | "Parameter with annotation ChangeParam was not found in a method %s", methodName));
77 | }
78 |
79 | return optIdx.getAsInt();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------