name: main-template layout: true class: left, top --- class: center
# Use Applicative # where applicable!
## © 2020 Hermann Hueck
https://github.com/hermannhueck/use-applicative-where-applicable --- # Abstract
Most Scala developers are familiar with monadic processing. Monads provide *flatMap* and hence for-comprehensions (syntactic sugar for *map* and *flatMap*). Often we don't need Monads. Applicatives are sufficient in many cases. In this talk I examine the differences between monadic and applicative processing and give some guide lines when to use which. After a closer look to the Applicative trait I will contrast the gist of *Either* and *cats.data.Validated* (the latter being an Applicative but not a Monad). I will also look at traversing and sequencing which harness Applicatives as well. .footnote[ (The code examples are implemented with *Cats*.) ] --- # Agenda
1. Monadic Processing 1. Aside: Effects 1. Aside: Curried functions 1. Where Functor is too weak 1. Applicative Processing 1. Comparing Monad with Applicative 1. The Applicative trait 1. Either vs. Validated 1. Traversals need Applicative 1. Resources --- class: middle, center # 1. Monadic Processing
.footnote[ See: *examples.MonadicProcessing* ] --- ## The Problem: ### How to compute values wrapped in a context?  Aside: Effects
--- ## What is *F[_]* ?
*F[_]* is a type constructor. It represents the
__computational context__
of the operation, also called the
__effect__
of the operation. .center[ ## effect != side effect ]
With the context bound *F[_]: Monad* we constrain the effect to be a Monad. This makes *F* a place holder for any Monad which provides us *map* and *flatMap*. --- ## Some Effects
|
F[_]
|
Effect
|----------------------|----------------------------------------------- | Option | a possibly missing value | List | an arbitrary number of values of the same type (non-determinism) | Future | an asyncronously computed value | Either | either a value of a type or a value of another type | Id | the effect of having no effect | IO | the effect of having a side effect | Tuple2 | two adjacent values of possibly different type | Function1 | a pure computation on a (yet unknown) input producing an output | Reader | a wrapped Function1 | Writer | a values that has another value attached which acts as a log message accumulator --- class: middle, center # 3. Aside: Curried functions
.footnote[ See: *examples.CurriedFunctions* ] --- ## Every function is a *Function1* ... -- ```scala val sum3Ints : (Int, Int, Int) => Int = _ + _ + _ val sum3Ints2: Function3[Int, Int, Int, Int] = _ + _ + _ ``` -- ... if we curry it. -- ```scala val sumCurried: Int => Int => Int => Int = sum3Ints.curried // sumCurried: Int => (Int => (Int => Int)) = scala.Function3$$Lambda$4346/99143056@43357c0e ``` -- The type arrow ( => ) is right associative. Hence we can omit the parentheses. -- The type arrow ( => ) is syntactic sugar for Function1.
*A => B* is equivalent to *Function1[A, B]*. -- ```scala val sumCurried2: Function1[Int, Function1[Int, Function1[Int, Int]]] = sumCurried // sumCurried2: Int => (Int => (Int => Int)) = scala.Function3$$Lambda$4346/99143056@7567ab8 ``` -- If uncurried again, we get the original function back. ```scala val sumUncurried: (Int, Int, Int) => Int = Function.uncurried(sumCurried) // sumUncurried: (Int, Int, Int) => Int = scala.Function$$$Lambda$6605/301079867@1589d895 ``` --- ## Partial application of curried functions
-- ```scala val sum3Ints: (Int, Int, Int) => Int = _ + _ + _ val sumCurried: Int => Int => Int => Int = sum3Ints.curried ``` -- ```scala val applied1st: Int => Int => Int = sumCurried(1) ``` -- ```scala val applied2nd: Int => Int = applied1st(2) ``` -- ```scala val applied3rd: Int = applied2nd(3) ``` -- ```scala val appliedAllAtOnce: Int = sumCurried(1)(2)(3) ``` --- ## Advantages of curried functions
-- 1. As curried functions can be partially applied.
They are better
composable
than their uncurried counterparts. -- 2. Curried functions help the compiler with type inference. The compiler infers types by argument lists from left to right. -- ```scala def filter1[A](la: List[A], p: A => Boolean) = ??? // uncurried scala> filter1(List(0,1,2), _ < 2)
:50: error: missing parameter type for expanded function ((x$1:
) => x$1.$less(2)) filter1(List(0,1,2), _ < 2) ^ ``` -- ```scala def filter2[A](la: List[A])(p: A => Boolean) = ??? // curried scala> filter2(List(0,1,2))(_ < 2) res5: List[Int] = List(0,1) ``` --- ## Curring in Java? -- (Sorry, I couldn't resist ;-) -- ```java // Curring with lambdas Function
>> sum3IntsCurried = a -> b -> c -> a + b + c; Integer result = sum3IntsCurried.apply(1).apply(2).apply(3); ``` -- ```java // Curring without lambdas Function
>> sum3IntsCurried = new Function
>>() { @Override public Function
> apply(Integer a) { return new Function
>() { @Override public Function
apply(Integer b) { return new Function
() { @Override public Integer apply(Integer c) { return a + b + c; } }; } }; } }; Integer result = sum3IntsCurried.apply(1).apply(2).apply(3); ``` --- ## Curring in Haskell?
-- ### No extra currying! -- ### Every function is already curried.
It can take only one parameter ...
... and returns only one value which might be another function. -- Invoking functions with more than one parameter is possible.
That is just syntactic sugar for curried functions. --- ## Partial application in Haskell
```haskell sum3Ints :: Int -> Int -> Int -> Int -- function already curried sum3Ints x y z = x + y + z applied1st = sum3Ints 1 :: Int -> Int -> Int applied2nd = applied1st 2 :: Int -> Int applied3rd = applied2nd 3 :: Int appliedAll = sum3Ints 1 2 3 :: Int ``` --- class: middle, center # 4. Where Functor is too weak
.footnote[ See: *examples.WhereFunctorIsTooWeak* ] --- ## Where Functor is too weak ... -- What to do if we want to fuse two Options to one by summing up the contained values? Option(1) + Option(2) == Option(3) // ??? -- ```scala val add1: Int => Int = 1 + _ val sum2Ints: (Int, Int) => Int = _ + _ ``` -- ```scala Option(1) map add1 // res1: Option[Int] = Some(2) ``` -- ```scala // Option(1) map sum2Ints // [error] found : (Int, Int) => Int // [error] required: Int => ? // [error] Option(1) map sum2Ints // [error] ^ ``` -- ```scala Option(1) map sum2Ints.curried // res2: Option[Int => Int] = Some(scala.Function2$$Lambda$4648/454529628@7c9e8cef) ``` -- *map* doesn't help us to fuse another Option(2) to that. --- ## ... Applicative can help us out -- ```scala Option(1) map sum2Ints.curried ap Option(2) // res3: Option[Int] = Some(3) ``` -- ```scala sum2Ints.curried.pure[Option] ap Option(1) ap Option(2) // res4: Option[Int] = Some(3) ``` -- ```scala sum2Ints.curried.pure[Option] ap 1.pure[Option] ap 2.pure[Option] // res5: Option[Int] = Some(3) // pure is the same as Option.apply ``` -- ```scala Applicative[Option].ap2(sum2Ints.pure[Option])(Option(1), Option(2)) // res6: Option[Int] = Some(3) // no currying with ap2 ``` -- ```scala Applicative[Option].map2(Option(1), Option(2))(sum2Ints) // res7: Option[Int] = Some(3) // no pure with map2 ``` -- ```scala (Option(1), Option(2)) mapN sum2Ints // res8: Option[Int] = Some(3) // Tuple2#mapN ``` --- ## Cartesian Product When working with Applicative we always get the Cartesian product of two or more contexts. That isn't immediately obvious when working with the *Option* context but becomes evident when we work with *List*. -- ```scala val add2: Int => Int => Int = ((_:Int) + (_:Int)).curried val mult2: Int => Int => Int = ((_:Int) * (_:Int)).curried val concat: (String, String) => String = _ ++ _ ``` -- ```scala List((_:Int) * 0, (_:Int) + 100, (x:Int) => x * x) ap List(1, 2, 3) // res10: List[Int] = List(0, 0, 0, 101, 102, 103, 1, 4, 9) ``` -- ```scala List(add2, mult2) <*> List[Int](1, 2) <*> List[Int](100, 200) // res11: List[Int] = List(101, 201, 102, 202, 100, 200, 200, 400) ``` -- ```scala concat.curried.pure[List] <*> List("ha", "heh", "hmm") <*> List("?", "!", ".") // res12: List[String] = List(ha?, ha!, ha., heh?, heh!, heh., hmm?, hmm!, hmm.) ``` -- ```scala List("ha", "heh", "hmm") map concat.curried ap List("?", "!", ".") // res13: List[String] = List(ha?, ha!, ha., heh?, heh!, heh., hmm?, hmm!, hmm.) ``` --- class: middle, center # 5. Applicative Processing
.footnote[ See: *examples.ApplicativeProcessing* ] --- ## Trait Applicative
-- Applicative is stronger than Functor, but weaker than Monad.
-- ```scala trait Functor[F[_]] { // simplified def map[A, B](fa: F[A])(f: A => B): F[B] } ``` -- ```scala trait Applicative[F[_]] extends Functor[F] { // simplified def pure[A](a: A): F[A] def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] } ``` -- ```scala trait Monad[F[_]] extends Applicative[F] { // simplified def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] } ``` --- ## Replacing monadic with applicative context
-- Applicative is strong enough for the problem
we solved before with a monad-comprehension. --
Monadic context: *F[_]* constrained to be a *Monad* ```scala def processABC[F[_]: Monad, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]): F[D] = ??? // monadic solution ```
-- Applicative context: *F[_]* constrained to be an *Applicative* ```scala def processABC[F[_]: Applicative, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]): F[D] = ??? // applicative solution ```
-- Let's start with *Option[Int]* again and then abstract the solution. --- ## Solution with *Applicative#ap*: ### Example context/effect: *Option*
```scala def processInts(compute: (Int, Int, Int) => Int) (oi1: Option[Int], oi2: Option[Int], oi3: Option[Int]) : Option[Int] = { val f3Curried: Int => Int => Int => Int = compute.curried val of3: Option[Int => Int => Int => Int] = Some(f3Curried) // lifting val of2: Option[Int => Int => Int] = of3 ap oi1 // same as: oi1 map of3 val of1: Option[Int => Int] = of2 ap oi2 val result: Option[Int] = of1 ap oi3 result } ``` *Some(f3Curried)* lifts the curried function into the *Option* context. --- ## Abstracting *Option* to *F[_]: Applicative*
```scala def processInts[F[_]: Applicative](compute: (Int, Int, Int) => Int) (fi1: F[Int], fi2: F[Int], fi3: F[Int]) : F[Int] = { val fCurried: Int => Int => Int => Int = compute.curried val ff: F[Int => Int => Int => Int] = Applicative[F].pure(fCurried) // lifting ff ap fi1 ap fi2 ap fi3 } ``` *Applicative[F].pure(fCurried)* lifts the curried function into the generic *F* context. --- ## Abstracting away the *Int*s
```scala def processABC[F[_]: Applicative, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]) : F[D] = { val fCurried: A => B => C => D = compute.curried val ff: F[A => B => C => D] = Applicative[F].pure(fCurried) ff ap fa ap fb ap fc } ``` --- ## Using *pure* syntax and _<*>_ (alias for *ap*)
```scala def processABC[F[_]: Applicative, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]) : F[D] = { compute.curried.pure[F] <*> fa <*> fb <*> fc } ``` --- ## *Applicative#ap3* saves us from currying
```scala def processABC[F[_]: Applicative, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]) : F[D] = { Applicative[F].ap3(compute.pure[F])(fa, fb, fc) } ``` --- ## *Applicative#map3* avoids lifting with *pure*
```scala def processABC[F[_]: Applicative, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]) : F[D] = { Applicative[F].map3(fa, fb, fc)(compute) } ``` *map2*, *map3* .. *map22* are available for *Applicative*. --- ## *Apply* is just *Applicative* without *pure*
```scala def processABC[F[_]: Apply, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]) : F[D] = { Apply[F].map3(fa, fb, fc)(compute) } ``` *map2*, *map3* .. *map22* come from *Apply*. *Apply* is a base trait of *Applicative* and provides us *map3*. --- ## Using *Tuple3#mapN* for convenience
```scala def processABC[F[_]: Apply, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]) : F[D] = { (fa, fb, fc) mapN compute } ``` We just tuple up the three *F*'s and invoke *mapN* with a function that takes three parameters. *mapN* fuses the *F*'s into an *F*-result. Cats provides *mapN* as an enrichment for *Tuple2*, *Tuple3* .. *Tuple22*. --- ## Comparing the solutions
-- ### Monadic solution: ```scala def processABC[F[_]: Monad, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]): F[D] = for { a <- fa b <- fb c <- fc } yield compute(a, b, c) ``` -- ### Applicative solution: ```scala def processABC[F[_]: Apply, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]) : F[D] = (fa, fb, fc) mapN compute ``` --- ## Currying again
-- We provided *processABC* with two parameter lists. ```scala def processABC[F[_]: Apply, A, B, C, D](compute: (A, B, C) => D) (fa: F[A], fb: F[B], fc: F[C]) : F[D] = (fa, fb, fc) mapN compute ``` -- This improves
composability
and allows us provide the *compute* function and the effectful *F*'s in independent steps. -- ```scala // providing the computation def processEffectfulInts[F[_]: Apply](fi1: F[Int], fi2: F[Int], fi3: F[Int]) : F[Int] = processABC(sum3Ints)(fi1, fi2, fi3) ``` -- ```scala // providing the 'effectful' parameters val result1 = processEffectfulInts(Option(1), Option(2), Option(3)) // result1: Option[Int] = Some(6) val result2 = processEffectfulInts(List(1, 2), List(10, 20), List(100, 200)) // result2: List[Int] = List(111, 211, 121, 221, 112, 212, 122, 222) ``` --- class: middle, center # 6. Comparing Monad with Applicative
--- ## Sequential vs. parallel
-- ### Monads enforce sequential operation! Imagine a for-comprehension.
The generators are executed in sequence, one after the other.
The yield clause is executed after all generators have finished.
-- ### Applicatives allow for parallel/independent operations! The operations are by nature
independent
of each other.
(That does not mean, they are asynchronous.)
--- ## Fail-fast semantics
-- ### Monads enforce short-circuiting! If an 'erraneous' value (e.g. *None*, *Nil* or *Left*) is found in a monadic computation, the computation stops immediately, because the result will not change if processing were continued.
That is why we are not able to collect errors. -- ### Applicatives do not short-circuit! As applicative operations are independent of each other, processing does not stop if an error occurs.
It is possible to collect errors (see: *cats.data.Validated*)
*cats.data.Validated* has an Applicative instance, but no Monad instance. We will come to that later. --- ## Composition
-- ### Monads do not compose! In order to kind of 'compose' Monads we need an extra construct such as a Monad Transformer which itself is a Monad. I.e.: If we want to compose two Monads we need a third Monad to stack them up. (Another way to compose Monads is Kleisli composition.) -- ### Applicatives compose! Composition of (Functor and) Applicative is a breeze.
It is genuinely supported by these type classes. .footnote[ See: *examples.Composition* ] --- ## Composition - Code ```scala val loi1 = List(Some(1), Some(2)) val loi2 = List(Some(10), Some(20)) ``` ### Monads do not compose! ```scala def processMonadic(xs: List[Option[Int]], ys: List[Option[Int]]): List[Option[Int]] = { val otli: OptionT[List, Int] = for { x <- OptionT[List, Int](xs) y <- OptionT[List, Int](ys) } yield x + y otli.value } val result1 = processMonadic(loi1, loi2) // result1: List[Option[Int]] = List(Some(11), Some(21), Some(12), Some(22)) ``` ### Applicatives compose! ```scala def processApplicative(xs: List[Option[Int]], ys: List[Option[Int]]): List[Option[Int]] = Applicative[List].compose[Option].map2(xs, ys)((_:Int) + (_:Int)) val result2 = processApplicative(loi1, loi2) // result2: List[Option[Int]] = List(Some(11), Some(21), Some(12), Some(22)) ``` --- ## When to use which
### Use Applicative if all computations are
independent
of each other. Howto: - Write a monadic solution with a for-comprehension. - If the generated values (to the left of the generator arrow *<-* ) are only used in the *yield* clause at the end (not in an other generator) the computations are independent and allow for an applicative solution. - Tuple up the computations and *mapN* them with a function which fuses the computation results to a final result. (This howto is applicable only if the effect in question also has a Monad instance.) --- ## When to use which - counter example
```scala val result = for { x <- Future { computeX } y <- Future { computeY(x) } z <- Future { computeZ(x, y) } } yield resultFrom(z) ``` In this for-comprehension the subsequent computations depend on the previous ones. Hence this for-comprehension cannot be substituted by applicative processing. --- ## Principle of Least Power
**Given a choice of solutions,**
**pick the least powerful solution**
**capable of solving your problem.** \-- Li Haoyi --- class: middle, center # 7. The Applicative trait
--- ## Typeclass Functor *Functor* is the base trait of *Applicative*.
```scala trait Functor[F[_]] { // ----- primitive map def map[A, B](fa: F[A])(f: A => B): F[B] // ----- implementations in terms of the primitive map def fmap[A, B](fa: F[A])(f: A => B): F[B] = map(fa)(f) // alias for map def lift[A, B](f: A => B): F[A] => F[B] = fa => map(fa)(f) def as[A, B](fa: F[A], b: B): F[B] = map(fa)(_ => b) def void[A](fa: F[A]): F[Unit] = as(fa, ()) def compose[G[_]: Functor]: Functor[Lambda[X => F[G[X]]]] = ??? } ``` --- ## Typeclass Applicative with primitives *pure* and *ap*
```scala trait Applicative[F[_]] extends Functor[F] { // ----- primitives def pure[A](a: A): F[A] def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] // ----- implementations in terms of the primitives def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) ⇒ Z): F[Z] = ap(map(fa)(a => f(a, _: B)))(fb) override def map[A, B](fa: F[A])(f: A => B): F[B] = ap(pure(f))(fa) def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = map2(fa, fb)((_, _)) } ``` --- ## Typeclass Applicative with primitives *pure* and *map2*
```scala trait Applicative[F[_]] extends Functor[F] { // ----- primitives def pure[A](a: A): F[A] def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) ⇒ Z): F[Z] // ----- implementations in terms of the primitives def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = map2(ff, fa)((f, a) => f(a)) // or: map2(ff, fa)(_(_)) override def map[A, B](fa: F[A])(f: A => B): F[B] = map2(fa, pure(()))((a, _) => f(a)) def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = map2(fa, fb)((_, _)) } ``` --- ## Typeclass Applicative with primitives *pure* and *map* and *product*
```scala trait Applicative[F[_]] extends Functor[F] { // ----- primitives def pure[A](a: A): F[A] override def map[A, B](fa: F[A])(f: A => B): F[B] def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] // ----- implementations in terms of the primitives def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z] = map(product(fa, fb)) { case (a, b) => f(a, b) } def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = map2(ff, fa)((f, a) => f(a)) // or: map2(ff, fa)(_(_)) } ``` --- ## Typeclass Applicative ```scala trait Applicative[F[_]] extends Functor[F] { // ----- primitives def pure[A](a: A): F[A] def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] // ----- implementations in terms of the primitives override def map[A, B](fa: F[A])(f: A => B): F[B] = ap(pure(f))(fa) def <*>[A, B](ff: F[A => B])(fa: F[A]): F[B] = ap(ff)(fa) // alias for ap def ap2[A, B, Z](ff: F[(A, B) => Z])(fa: F[A], fb: F[B]): F[Z] = { val ffBZ: F[B => Z] = ap(map(ff)(f => (a:A) => (b:B) => f(a, b)))(fa) ap(ffBZ)(fb) } // also: ap3, ap4 .. ap22 def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) ⇒ Z): F[Z] = ap(map(fa)(a => f(a, _: B)))(fb) // also: map3, map4 .. map22 def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = map2(fa, fb)((_, _)) def tuple2[A, B](fa: F[A], fb: F[B]): F[(A, B)] = product(fa, fb) // also: tuple3, tuple4 .. tuple22 def compose[G[_]: Applicative]: Applicative[Lambda[X => F[G[X]]]] = ??? } ``` --- class: center ## Cats typeclass hierarchy (a small section of it) ![typeclass hierarchy](cats-typeclass-hierarchy.png "Cats typeclass hierarchy") .footnote[ .tiny-font[ Complete hierarchy [here](https://camo.githubusercontent.com/e29cc3587dd331d1af177c8ed163de3b15ea04f2/68747470733a2f2f63646e2e7261776769742e636f6d2f74706f6c656361742f636174732d696e666f677261706869632f6d61737465722f636174732e7376673f783d31) ] ] --- class: middle, center # 7. Either vs. Validated
.footnote[ See: *examples.EitherVsValidated* ] --- ## Monadic processing with *Either*
Monadic processing enforces fail-fast semantics.
After an erraneous operation subsequent operations are not executed.
Hence we get only the first of possibly multiple errors.
-- ```scala val result: Either[List[String], Int] = for { x <- 5.asRight[List[String]] y <- List("Error 1").asLeft[Int] z <- List("Error 2").asLeft[Int] // List("Error 2") is lost! } yield x + y + z // result: Either[List[String],Int] = Left(List(Error 1)) ``` --- ## Applicative processing with *Either*
Applicative processing disables fail-fast semantics.
But with *Either* we get the same result as before.
Because *Either* has a Monad instance.
-- ```scala val result: Either[List[String], Int] = ( 5.asRight[List[String]], List("Error 1").asLeft[Int], List("Error 2").asLeft[Int] // List("Error 2") is lost! ) mapN ((_: Int) + (_: Int) + (_: Int)) // result: Either[List[String],Int] = Left(List(Error 1)) ``` --- ## Applicative processing with *Validated*
*cats.data.Validated* is designed in analogy to *Either*.
Instead of *Right* and *Left* it has *Valid* and *Invalid*.
*Validated* has an Applicative instance but no Monad instance.
-- ```scala val result: Validated[List[String], Int] = ( 5.valid[List[String]], List("Error 1").invalid[Int], List("Error 2").invalid[Int] // List("Error 2") is preserved! ) mapN ((_: Int) + (_: Int) + (_: Int)) // result: cats.data.Validated[List[String],Int] = Invalid(List(Error 1, Error 2)) ``` --- ## Conversions between *Either* and *Validated*
Conversion is supported in both directions
*Either#toValidated* converts an *Either* to a *Validated*.
*Validated#toEither* converts a *Validated* to an *Either*.
-- ```scala val result: Validated[List[String], Int] = ( 5.asRight[List[String]].toValidated, List("Error 1").asLeft[Int].toValidated, List("Error 2").asLeft[Int].toValidated // List("Error 2") is preserved! ) mapN ((_: Int) + (_: Int) + (_: Int)) // result: cats.data.Validated[List[String],Int] = Invalid(List(Error 1, Error 2)) val resultAsEither = result.toEither // resultAsEither: Either[List[String],Int] = Left(List(Error 1, Error 2)) ``` --
An elaborated example of form validation with *Validated* (contrasted to a solution with *Either*) can be found in the Cats documentation:
https://typelevel.org/cats/datatypes/validated.html --- class: middle, center # 9. Traversals need Applicative
.footnote[ See: *examples.Traversals* ] --- ## Recap: *Future.traverse* and *Future.sequence* Most Scala devs know these methods defined in the *Future* companion object. -- Let's start with *Future.sequence*.
Future.sequence API doc:
*Simple version of Future.traverse. Asynchronously and non-blockingly transforms a IterableOnce[Future[A]] into a Future[IterableOnce[A]]. Useful for reducing many Futures into a single Future.* -- Simply spoken: *sequence* turns a *List[Future[A]]* into a *Future[List[A]]*. ```scala val lfd: List[Future[Double]] = List(Future(2.0), Future(4.0), Future(6.0)) val fld: Future[List[Double]] = Future.sequence(lfd) ``` -- Typically in an application we don't have a *List[Future[B]]*, but we produce it by processing a *List[A]* asynchronously.
We can first map the *List[A]* with the function *A => Future[B]* and then invoke *sequence* on the resulting *List[Future[B]]* in order to get a *Future[List[B]]*. -- ```scala val li: List[Int] = List(1, 2, 3) val doubleItAsync: Int => Future[Double] = x => Future { x * 2.0 } val lfi: List[Future[Double]] = li.map(doubleItAsync) val fld: Future[List[Double]] = Future.sequence(lfi) ``` --- ## Recap: *Future.traverse* and *Future.sequence* Mapping and sequencing traverses the list twice.
*traverse* fuses mapping and sequencing into a single traversal. -- *Future.traverse* takes a *List[A]* and a mapping function from *A => Future[B]* and returns a *Future[List[B]]*. ```scala val li: List[Int] = List(1, 2, 3) val doubleItAsync: Int => Future[Double] = x => Future { x * 2.0 } val fld: Future[List[Double]] = Future.traverse(li)(doubleItAsync) ``` -- Providing *identity* as mapping function to *traverse* has the same effect as *sequence*. ```scala val lfd: List[Future[Double]] = List(Future(2.0), Future(4.0), Future(6.0)) val fld: Future[List[Double]] = Future.traverse(lfd)(identity) ``` --- ## Typeclass *Traverse* Cats generalizes this concept into the *Traverse* typeclass. -- ```scala trait Traverse[F[_]] extends Foldable[F] with Functor[F] { // simplified def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]) : G[F[B]] def sequence[G[_]: Applicative, A](fga: F[G[A]]): G[F[A]] = traverse(fga)(identity) // map in terms of traverse using the Id context override def map[A, B](fa: F[A])(f: A => B): F[B] = traverse(fa)(f: A => Id[B]) } ``` -- *traverse* and *sequence* require the *G[_]* to be an Applicative (*Future* before). -- The structure traversed over (*List* before) must be *Foldable with Functor*. Hence *Traverse* extends these two traits. -- The *traverse* function can indeed be implemented with *map* and *foldLeft* or *foldRight*. On the other hand *foldLeft*, *foldRight* and *map* can be implemented with *traverse*. --- ## *Traverse[List].sequence\[Future, A]*
Instead of *Future.sequence* we can use *Traverse[List].sequence*.
-- ```scala val lfd: List[Future[Double]] = List(Future(2.0), Future(4.0), Future(6.0)) val fld1: Future[List[Double]] = Traverse[List].sequence(lfd) // fld1: scala.concurrent.Future[List[Double]] = Future(Success(List(2.0, 4.0, 6.0))) import cats.syntax.traverse._ // supports 'sequence' as an enrichment of List val fld2: Future[List[Double]] = lfd.sequence // fld2: scala.concurrent.Future[List[Double]] = Future(Success(List(2.0, 4.0, 6.0))) ``` --- ## *Traverse[List].traverse\[Future, A, B]*
Instead of *Future.traverse* we can use *Traverse[List].traverse*.
-- ```scala val li: List[Int] = List(1, 2, 3) val doubleItAsync: Int => Future[Double] = x => Future { x * 2.0 } val fld1: Future[List[Double]] = Traverse[List].traverse(li)(doubleItAsync) // fld1: scala.concurrent.Future[List[Double]] = Future(Success(List(2.0, 4.0, 6.0))) import cats.syntax.traverse._ // supports 'traverse' as an enrichment of List val fld2: Future[List[Double]] = li traverse doubleItAsync // fld2: scala.concurrent.Future[List[Double]] = Future(Success(List(2.0, 4.0, 6.0))) ``` --- ## *Traverse[Vector].traverse\[Option, A, B]*
With *cats.Traverse* can traverse not only over *List*s but over any other *Foldable with Functor* that has a *Traverse* instance, e.g. *Vector*. The mapping function may produce any applicative effect, e.g. *Option* instead of *Future*.
-- ```scala val vi1: Vector[Int] = Vector(3, 2, 1) val vi2: Vector[Int] = Vector(3, 2, 0) val divideBy: Int => Option[Double] = x => if (x == 0) None else Some { 6.0 / x } val ovd1_1 = Traverse[Vector].traverse(vi1)(divideBy) // ovd1_1: Option[Vector[Double]] = Some(Vector(2.0, 3.0, 6.0)) val ovd1_2 = Traverse[Vector].traverse(vi2)(divideBy) // ovd1_2: Option[Vector[Double]] = None import cats.syntax.traverse._ // supports 'traverse' as an enrichment of Vector val ovd2_1 = vi1 traverse divideBy // ovd2_1: Option[Vector[Double]] = Some(Vector(2.0, 3.0, 6.0)) val ovd2_2 = vi2 traverse divideBy // ovd2_2: Option[Vector[Double]] = None ``` --- class: middle, center # 10. Resources
--- ## Scala Resources (1/2)
- Code and Slides of this Talk:
https://github.com/hermannhueck/use-applicative-where-applicable - Cats documentation:
https://typelevel.org/cats/typeclasses/applicative.html
https://typelevel.org/cats/typeclasses/traverse.html
https://typelevel.org/cats/datatypes/validated.html - Herding Cats, Day 2 and 3:
http://eed3si9n.com/herding-cats/Functor.html
http://eed3si9n.com/herding-cats/Semigroupal.html
http://eed3si9n.com/herding-cats/Apply.html
http://eed3si9n.com/herding-cats/Applicative.html - "Scala with Cats", Chapters 6 and 7
Book by Noel Welsh and Dave Gurnell
https://underscore.io/books/scala-with-cats/ --- ## Scala Resources (2/2)
- Live Coding Tutorial on Functor and Applicative by Michael Pilquist
FSiS Part 1 - Type Constructors, Functors, and Kind Projector
https://www.youtube.com/watch?v=Dsd4pc99FSY
FSiS Part 2 - Applicative type class
https://www.youtube.com/watch?v=tD_EyIKqqCk --- ## Haskell Resources
- Learn You a Haskell for Great Good!, Chapter 11
Online book by Miran Lipovaca
http://learnyouahaskell.com/functors-applicative-functors-and-monoids - Applicative Programming with Effects
Conor McBride and Ross Paterson in Journal of Functional Programming 18:1 (2008), pages 1-13
http://www.staff.city.ac.uk/~ross/papers/Applicative.pdf - The Essence of the Iterator Pattern
Jeremy Gibbons and Bruno C. d. S. Oliveira, Oxford University Computing Laboratory
https://www.cs.ox.ac.uk/jeremy.gibbons/publications/iterator.pdf --- class: middle, center ## Thanks for Listening
# Q & A
https://github.com/hermannhueck/use-applicative-where-applicable


Why has Javascript claimed the throne as the king of web scripting languages?
- The first and most obvious answer is ease of use. The learning curve isn't very high with javascript, new programmers can learn it quickly while advanced programmers can easily jump into the more powerful features. Since it is run on the web there is no need to compile, making it as easy as writing HTML or CSS.
- So its easy, but what can it do? Javascript takes your boring html page from simply displaying information to a full fledged website with user interaction. The most common uses for javascript include log in systems, form autocompleting, drop down menus, interactive graphics, and much more.
- Finally, front end Javascript is entirely client side. This means that none of these awesomely interactive features are clogging up your server. Also Javascript is universally supported on every browser so you can develop your page once and be confident it will work across the board.


The grid system is split into 12 little columns.
Breakpoints are the screen size at which the page changes.
Class: col-sm-4 means we want a column that is 4 of the mini-columns wide. And the sm means that the breakpoint will occur at a small distance. If you use lg, then the columns will stack earlier when the screen is smaller.
A 50/50 width layout that collapse when the screen size is less than 720px.
Different width columns.


Contains classes to use reflection.
Dependencies
Depends on
gnu.bytecode
,
gnu.mapping
, and
gnu.expr
. Also uses
gnu.kawa.util.FString
. Uses
kawa.standard.Scheme
, but that is a bug. (It should be using
gnu.expr.Interpreter
instead.)
Author
Per Bothner
<
<EMAIL_ADDRESS>>


Home
(current)
View All Items
Sign Up
(current)
Login
Rental Item
Country
Bangladesh
State / Division
Dhaka
City / Town
Dhaka City
Area
Dhanmondi
Search
Apple Mac Book Pro 15``
Laptop
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
Love Hut for Couples
Hotel
$100.00/day
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: n/a
DJI Mavic 2 Pro
Drone
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
Room for rent
Household
$400.00/month
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 60 Months
Nikkon CN5007
Camera
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
Musical Instruments
Musical Instruments
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
DJI Mavic 2 Pro
Drone
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
Profoto A1X AirTTL-N
Camera Accessories
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
Profoto A1X AirTTL-N
Camera Accessories
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
Classic Musical Instruments
Musical Instruments
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
Musical Instruments
Musical Instruments
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
Apple Mac Book Pro 15``
Laptop
$80.00/hr
Address: Demo Street 123, Demo City 04312, NJ
Max-duration: 5 weeks
See More items
Electronics
Laptop
Desktop
Computer Accessories
Phone / Smartphone
Households
Furnitures
AC-Fan-Warmers
Fridges & Ovens
Energy - IPS - Generator
Decoration
Households
Furnitures
AC-Fan-Warmers
Fridges & Ovens
Energy - IPS - Generator
Decoration
Electronics
Laptop
Desktop
Computer Accessories
Phone / Smartphone
Electronics
Laptop
Desktop
Computer Accessories
Phone / Smartphone
Electronics
Laptop
Desktop
Computer Accessories
Phone / Smartphone
Households
Furnitures
AC-Fan-Warmers
Fridges & Ovens
Energy - IPS - Generator
Decoration
Electronics
Laptop
Desktop
Computer Accessories
Phone / Smartphone


Media
Table of Contents:
- Camcorder
- Camera
- ImagePicker
- Player
- Sound
- SoundRecorder
- SpeechRecognizer
- TextToSpeech
- Translator
- VideoPlayer
Camcorder
A component to record a video using the device’s camcorder. After the video is recorded, the
name of the file on the phone containing the clip is available as an argument to the
AfterRecording
event. The file name can be used, for example, to set the source
property of a VideoPlayer
component.
Properties
None
Events
- AfterRecording(clip)
- Indicates that a video was recorded with the camera and provides the path to the stored video.
Methods
- RecordVideo()
- Records a video, then raises the
AfterRecording
event.
Camera
Use a camera component to take a picture on the phone.
Camera
is a non-visible component that takes a picture using the device’s camera. After the
picture is taken, the path to the file on the phone containing the picture is available as an
argument to the AfterPicture
event. The path can be used, for example, as the
Picture
property of an Image
component.
Properties
None
Events
- AfterPicture(image)
- Called after the picture is taken. The text argument
image
is the path that can be used to locate the image on the phone.
Methods
- TakePicture()
- Takes a picture, then raises the
AfterPicture
event.
ImagePicker
A special-purpose button. When the user taps an ImagePicker
, the device’s image gallery
appears, and the user can choose an image. After an image is picked, it is saved, and the
Selection
property will be the name of the file where the image is stored. In order
to not fill up storage, a maximum of 10 images will be stored. Picking more images will delete
previous images, in order from oldest to newest.
Properties
- BackgroundColor
- Specifies the
ImagePicker
’s background color as an alpha-red-green-blue integer. If anImage
has been set, the color change will not be visible until theImage
is removed. - Enabled
- Specifies whether the
ImagePicker
should be active and clickable. - FontBold
- Specifies whether the text of the
ImagePicker
should be bold. Some fonts do not support bold. - FontItalic
- Specifies whether the text of the
ImagePicker
should be italic. Some fonts do not support italic. - FontSize
- Specifies the text font size of the
ImagePicker
, measured in sp(scale-independent pixels). - FontTypeface
- Specifies the text font face of the
ImagePicker
as default, serif, sans serif, or monospace. - Height
- Specifies the
ImagePicker
’s vertical height, measured in pixels. - HeightPercent
- Specifies the
ImagePicker
’s vertical height as a percentage of theScreen
’sHeight
. - Image
- Specifies the path of the
ImagePicker
’s image. If there is both anImage
and aBackgroundColor
specified, only theImage
will be visible. - Selection
- Path to the file containing the image that was selected.
- Shape
- Specifies the shape of the
ImagePicker
. The valid values for this property are0
(default),1
(rounded),2
(rectangle), and3
(oval). TheShape
will not be visible if anImage
is used. - ShowFeedback
- Specifies if a visual feedback should be shown when a
ImagePicker
with an assignedImage
is pressed. - Text
- Specifies the text displayed by the
ImagePicker
. - TextAlignment
- Specifies the alignment of the
ImagePicker
’s text. Valid values are:0
(normal; e.g., left-justified if text is written left to right),1
(center), or2
(opposite; e.g., right-justified if text is written left to right). - TextColor
- Specifies the text color of the
ImagePicker
as an alpha-red-green-blue integer. - Visible
- Specifies whether the
ImagePicker
should be visible on the screen. Value istrue
if theImagePicker
is showing andfalse
if hidden. - Width
- Specifies the horizontal width of the
ImagePicker
, measured in pixels. - WidthPercent
- Specifies the horizontal width of the
ImagePicker
as a percentage of theScreen
’sWidth
.
Events
- AfterPicking()
- Event to be raised after the
ImagePicker
activity returns its result and the properties have been filled in. - BeforePicking()
- Event to raise when the
ImagePicker
is clicked or the picker is shown using theOpen
method. This event occurs before the picker is displayed, and can be used to prepare the picker before it is shown. - GotFocus()
- Indicates the cursor moved over the
ImagePicker
so it is now possible to click it. - LostFocus()
- Indicates the cursor moved away from the
ImagePicker
so it is now no longer possible to click it. - TouchDown()
- Indicates that the
ImagePicker
was pressed down. - TouchUp()
- Indicates that the
ImagePicker
has been released.
Methods
- Open()
- Opens the
ImagePicker
, as though the user clicked on it.
Player
Multimedia component that plays audio and controls phone vibration. The name of a multimedia
file is specified in the Source
property, which can be set in the Designer or
in the Blocks Editor. The length of time for a vibration is specified in the Blocks Editor in
milliseconds (thousandths of a second).
For supported audio formats, see Android Supported Media Formats.
This component is best for long sound files, such as songs, while the Sound
component is
more efficient for short files, such as sound effects.
Properties
- IsPlaying
- Reports whether the media is playing.
- Loop
- If true, the
Player
will loop when it plays. SettingLoop
while the player is playing will affect the current playing. - PlayOnlyInForeground
- If true, the
Player
will pause playing when leaving the current screen; if false (default option), thePlayer
continues playing whenever the current screen is displaying or not. - Source
- Sets the audio source.
- Volume
- Sets the volume property to a number between 0 and 100.
Events
- Completed()
- Indicates that the media has reached the end
- OtherPlayerStarted()
- This event is signaled when another player has started (and the current player is playing or paused, but not stopped).
Methods
- Pause()
- Suspends playing the media if it is playing.
- Start()
- Plays the media. If it was previously paused, the playing is resumed. If it was previously stopped, it starts from the beginning.
- Stop()
- Stops playing the media and seeks to the beginning of the song.
- Vibrate(milliseconds)
- Vibrates for specified number of milliseconds.
Sound
A multimedia component that plays sound files and optionally vibrates for the number of milliseconds (thousandths of a second) specified in the Blocks Editor. The name of the sound file to play can be specified either in the Designer or in the Blocks Editor.
For supported sound file formats, see Android Supported Media Formats.
This Sound
component is best for short sound files, such as sound effects, while the
Player
component is more efficient for longer sounds, such as songs.
Properties
- MinimumInterval
- Specifies the minimum interval required between calls to
Play
, in milliseconds. Once the sound starts playing, all furtherPlay
calls will be ignored until the interval has elapsed. - Source
- The name of the sound file. Only certain formats are supported. See http://developer.android.com/guide/appendix/media-formats.html.
Events
None
Methods
- Pause()
- Pauses playing the sound if it is being played.
- Play()
- Plays the sound.
- Resume()
- Resumes playing the sound after a pause.
- Stop()
- Stops playing the sound if it is being played.
- Vibrate(millisecs)
- Vibrates for the specified number of milliseconds.
SoundRecorder
Multimedia component that records audio.
Properties
- SavedRecording
- Specifies the path to the file where the recording should be stored. If this property is the empty string, then starting a recording will create a file in an appropriate location. If the property is not the empty string, it should specify a complete path to a file in an existing directory, including a file name with the extension .3gp.
Events
- AfterSoundRecorded(sound)
- Provides the location of the newly created sound.
- StartedRecording()
- Indicates that the recorder has started, and can be stopped.
- StoppedRecording()
- Indicates that the recorder has stopped, and can be started again.
Methods
- Start()
- Starts recording.
- Stop()
- Stops recording.
SpeechRecognizer
Use a SpeechRecognizer
component to listen to the user speaking and convert the spoken sound
into text using the device’s speech recognition feature.
Properties
- Language
- Suggests the language to use for recognizing speech. An empty string (the default) will
use the system’s default language.
Language is specified using a language tag with an optional region suffix, such as en or es-MX. The set of supported languages will vary by device.
- Result
- Returns the last text produced by the recognizer.
- UseLegacy
- If true, a separate dialog is used to recognize speech (the default). If false, speech is
recognized in the background and updates are received as it recognizes words.
AfterGettingText
may get several calls withpartial
set totrue
. Once sufficient time has elapsed since the last utterance, orStopListening
is called, the last string will be returned withpartial
set tofalse
to indicate that it is the final recognized string and no more data will be provided until recognition is again started. SeeAfterGettingText
for more details on partial speech recognition.
Events
- AfterGettingText(result,partial)
- Simple event to raise after the SpeechRecognizer has recognized speech. If
UseLegacy
istrue
, then this event will only happen once at the very end of the recognition. IfUseLegacy
isfalse
, then this event will run multiple times as theSpeechRecognizer
incrementally recognizes speech. In this case,partial
will betrue
until the recognized speech has been finalized (e.g., the user has stopped speaking), in which casepartial
will befalse
. - BeforeGettingText()
- Simple event to raise when the
SpeechRecognizer
is invoked but before its activity is started.
Methods
- GetText()
- Asks the user to speak, and converts the speech to text. Signals the
AfterGettingText
event when the result is available. - Stop()
- Function used to forcefully stop listening speech in cases where
SpeechRecognizer cannot stop automatically.
This function works only when the
UseLegacy
property is set tofalse
.
TextToSpeech
The TextToSpeech
component speaks a given text aloud. You can set the pitch
and the rate of speech.
You can also set a language by supplying a language code. This changes the pronunciation of
words, not the actual language spoken. For example, setting the Language
to French
and speaking English text will sound like someone speaking English (en) with a French accent.
You can also specify a country by supplying a Country
code. This can affect the
pronunciation. For example, British English (GBR) will sound different from US English (USA).
Not every country code will affect every language.
The languages and countries available depend on the particular device, and can be listed with
the AvailableLanguages
and AvailableCountries
properties.
Properties
- AvailableCountries
- List of the country codes available on this device for use with TextToSpeech. Check the Android developer documentation under supported languages to find the meanings of these abbreviations.
- AvailableLanguages
- List of the languages available on this device for use with TextToSpeech. Check the Android developer documentation under supported languages to find the meanings of these abbreviations.
- Country
- Country code to use for speech generation. This can affect the pronunciation. For example, British English (GBR) will sound different from US English (USA). Not every country code will affect every language.
- Language
- Sets the language for TextToSpeech. This changes the way that words are pronounced, not the actual language that is spoken. For example, setting the language to French and speaking English text will sound like someone speaking English with a French accent.
- Pitch
- Sets the speech pitch for the TextToSpeech.
The values should be between 0 and 2 where lower values lower the tone of synthesized voice and greater values raise it.
The default value is 1.0 for normal pitch.
- Result
- Returns
true
if the text was successfully converted to speech, otherwisefalse
. - SpeechRate
- Sets the SpeechRate for TextToSpeech.
The values should be between 0 and 2 where lower values slow down the pitch and greater values accelerate it.
The default value is 1.0 for normal speech rate.
Events
- AfterSpeaking(result)
- Event to raise after the message is spoken. The
result
will betrue
if the message is spoken successfully, otherwise it will befalse
. - BeforeSpeaking()
- Event to raise when Speak is invoked, before the message is spoken.
Methods
- Speak(message)
- Speaks the given message.
Translator
Use this component to translate words and sentences between different languages. This component needs Internet access, as it will request translations from a server at MIT (which in turn will request translations from a commercial translation service). Specify the source and target language in the form source-target using two letter language codes. So “en-es” will translate from English to Spanish while “es-ru” will translate from Spanish to Russian. If you leave out the source language, the service will attempt to detect the source language. So providing just “es” will attempt to detect the source language and translate it to Spanish.
Note: Translation happens asynchronously in the background. When the translation is complete,
the GotTranslation
event is triggered.
Properties
- ApiKey
- The API Key to use. MIT App Inventor will automatically fill this value in. You should not need to change it.
Events
- GotTranslation(responseCode,translation)
- Event indicating that a request has finished and has returned data (translation).
Methods
- RequestTranslation(languageToTranslateTo,textToTranslate)
- By providing a target language to translate to (for instance, ‘es’ for Spanish, ‘en’ for
English, or ‘ru’ for Russian), and a word or sentence to translate, this method will request
a translation. Once the text is translated by the external
service, the event
GotTranslation
will be executed.Note: Translator will attempt to detect the source language. You can also specify prepending it to the language translation, e.g., es-ru will specify Spanish to Russian translation.
VideoPlayer
A multimedia component capable of playing videos. When the application is run, the VideoPlayer
will be displayed as a rectangle on-screen. If the user touches the rectangle, controls will
appear to play/pause, skip ahead, and skip backward within the video. The application can also
control behavior by calling the Start
, Pause
, and SeekTo
methods.
Video files should be in 3GPP (.3gp) or MPEG-4 (.mp4) formats. For more details about legal formats, see Android Supported Media Formats.
App Inventor only permits video files under 1 MB and limits the total size of an application to 5 MB, not all of which is available for media (video, audio, and sound) files. If your media files are too large, you may get errors when packaging or installing your application, in which case you should reduce the number of media files or their sizes. Most video editing software, such as Windows Movie Maker and Apple iMovie, can help you decrease the size of videos by shortening them or re-encoding the video into a more compact format.
You can also set the media source to a URL that points to a streaming video, but the URL must point to the video file itself, not to a program that plays the video.
Properties
- FullScreen
- Sets whether the video should be shown in fullscreen or not.
- Height
- Specifies the component’s vertical height, measured in pixels.
- HeightPercent
- Specifies the
VideoPlayer
’s vertical height as a percentage of theScreen
’sHeight
. - Source
- Sets the “path” to the video. Usually, this will be the name of the video file, which should be added in the Designer.
- Visible
- Specifies whether the
VideoPlayer
should be visible on the screen. Value istrue
if theVideoPlayer
is showing andfalse
if hidden. - Volume
- Sets the volume property to a number between 0 and 100. Values less than 0 will be treated as 0, and values greater than 100 will be treated as 100.
- Width
- Specifies the component’s horizontal width, measured in pixels.
- WidthPercent
- Specifies the horizontal width of the
VideoPlayer
as a percentage of theScreen
’sWidth
.
Events
- Completed()
- Indicates that the video has reached the end
Methods
- GetDuration()
- Returns duration of the video in milliseconds.
- Pause()
- Pauses playback of the video. Playback can be resumed at the same location by calling the
Start
method. - SeekTo(ms)
- Seeks to the requested time (specified in milliseconds) in the video. If the video is paused, the frame shown will not be updated by the seek. The player can jump only to key frames in the video, so seeking to times that differ by short intervals may not actually move to different frames.
- Start()
- Plays the media specified by the
Source
. - Stop()
- Resets to start of video and pauses it if video was playing.


|
|
|
|
|
| |
check
the domain name |
|
information about domains in .az zone |
|
|
|
|
|
|
|
|
|
|
|
Do an easy search below for your desired domain name, to check
for its availability before you proceed to register.
You can find info about the following domains :
az, com.az, net.az, int.az, org.az, .edu.az, .info.az,
.pp.az, .mil.az, .name.az and biz.az. |
| |
|
|
|
|
|
|
|
Info for domain GOOGLE.AZ
Status:
Name Servers: NS1.GOOGLE.COM,NS2.GOOGLE.COM
Type: Registrant Admin contact
Status: ok
Email<EMAIL_ADDRESS>Voice phone: +16503300100
Fax: +16506188571
International info:
Organisation: Google Inc.
Name: Admin,
Address:
Country Code: US
Province: CA
City: Mountain View
Street addr: 1600 Amphitheatre Parkway
Postal code: 94043
Type: Tech contact
Status: ok
Email<EMAIL_ADDRESS>Voice phone: +16503300100
Fax: +16506188571
International info:
Organisation: Google Inc.
Name: Admin,
Address:
Country Code: US
Province: CA
City: Mountain View
Street addr: 1600 Amphitheatre Parkway
Postal code: 94043
Type: Billing contact
Status: ok
Email<EMAIL_ADDRESS>Voice phone: +12083895740
Fax: +12083895799
International info:
Organisation: MarkMonitor
Name: Kevin Pearl,
Address:
Country Code: US
Province: ID
City: Boise
Street addr: 10400 OVerland Rd. PMB 155
Postal code: 83709
|
|
|
|


Provides a set of classes to ease the use of a file transfer or Get File
connection. More specifically, this package provides the data structure used as
a "header" over a file transfer connection as well as a related checksum class.
Note that the Get File and Send File protocols are very similar in that they
both use the same header structure. For details, see {@link
net.kano.joscar.rvproto.ft.FileTransferHeader}.
@see net.kano.joscar.rvproto.getfile


| as.character.polynomial | Polynomials |
| as.function.polynomial | Coerce a Polynomial to a Function |
| as.polylist | Lists of Polynomials |
| as.polynomial | Polynomials |
| c.polylist | Lists of Polynomials |
| change.origin | Change Origin for a Polynomial |
| coef.polynomial | Polynomials |
| deriv.polylist | Lists of Polynomials |
| deriv.polynomial | Differentiate a Polynomial |
| GCD | GCD and LCM for Polynomials |
| GCD.polylist | GCD and LCM for Polynomials |
| GCD.polynomial | GCD and LCM for Polynomials |
| integral | Integrate a Polynomial |
| integral.polylist | Lists of Polynomials |
| integral.polynomial | Integrate a Polynomial |
| is.polylist | Lists of Polynomials |
| is.polynomial | Polynomials |
| LCM | GCD and LCM for Polynomials |
| LCM.polylist | GCD and LCM for Polynomials |
| LCM.polynomial | GCD and LCM for Polynomials |
| lines.polynomial | Lines Method for Polynomials |
| Math.polynomial | Math Group Methods for Polynomials |
| monic | Monic Polynomials |
| Ops.polynomial | Arithmetic Ops Group Methods for Polynomials |
| plot.polylist | Lists of Polynomials |
| plot.polynomial | Plot Method for Polynomials |
| points.polynomial | Points Method for Polynomials |
| poly.calc | Calculate Polynomials from Zeros or Values |
| poly.from.roots | Calculate Polynomials from Zeros or Values |
| poly.from.values | Calculate Polynomials from Zeros or Values |
| poly.from.zeros | Calculate Polynomials from Zeros or Values |
| poly.orth | Construct Orthogonal Polynomials |
| polylist | Lists of Polynomials |
| polynomial | Polynomials |
| predict.polynomial | Evaluate a Polynomial |
| print.polylist | Lists of Polynomials |
| print.polynomial | Polynomials |
| print.summary.polynomial | Summary of a Polynomial |
| rep.polylist | Lists of Polynomials |
| solve.polynomial | Zeros of a Polynomial |
| Summary.polynomial | Summary Group Methods for Polynomials |
| summary.polynomial | Summary of a Polynomial |
| unique.polylist | Lists of Polynomials |
| [.polylist | Lists of Polynomials |


pollution is the process of making land, water, air or other parts of the environment dirty and not safe or suitable to use. This can be done through the introduction of a contaminant into a natural environment, but the contaminant doesn't need to be tangible. Things as simple as light, sound and temperature can be considered pollutants when introduced artificially into an environment. Toxic pollution affects more than 200 million people worldwide, according to Pure Earth, a non-profit environmental organization. In some of the world's worst polluted places, babies are born with birth defects, children have lost 30 to 40 IQ points, and life expectancy may be as low as 45 years because of cancers and other diseases.


{% extends 'layouts/default.html' %} {% block content %} {% include "../components/section-title/left/section-title.html" %}
This is the latest volunteer event. Come and join blah blah blah blah
This is the latest volunteer event. Come and join blah blah blah blah
This is the latest volunteer event. Come and join blah blah blah blahThis is the latest volunteer event. Come and join blah blah blah blahThis is the latest volunteer event. Come and join blah blah blah blah
Join Event


A mix of hikes completed, in progress, and those not yet traveled.
The first list consists of hikes which have been completed


My research interests lie in the intersection of machine learning, statistics, and genomics, with the goal of understanding underlying patterns of complex data. Checkout my Google scholar profile.
I believe in open-sourced programs, efficient algorithms, and well-documented codes. Most importantly, I am on Github and Sourceforge, where you can find a lot of amazing people.
Location: Stony Brook, NY
Title: Indel variant analysis of short-read sequencing data with Scalpel (View Paper).
Location: Menlo Park, CA
Title: Scikit-ribo—Accurate A-site prediction and robust modeling of translation control (View Slides).
Title: Scikit-ribo—Accurate A-site prediction and robust modeling of translation control (View Slides).
Title: Reducing INDEL calling errors in whole genome and exome sequencing data (View Slides).
Title: Reducing INDEL calling errors in whole genome and exome sequencing data (View Paper).
Title: Accurate de novo and transmitted indel detection in exome-capture data using microassembly(View Paper).
Han Fang is a PhD candidate in Applied Math and Statistics at Stony Brook University , in residence at Cold Spring Harbor Laboratory . He received his B.S. in Optical Informatics at Sun Yat-sen University. He is currently supervised by Dr. Michael Schatz and Dr. Gholson Lyon. His research interests intersect at machine learning, statistics, and genomics, with the goal of understanding underlying patterns of complex data.
Email: hanfang.cshl [at] gmail.com


many potential causes
half of all children will wheeze before schooll age
continuous, musical sound due to intrathoracic obstruction
contributing factors:
-
small phsyical size of respiratory system
-
developing immune system
-
Environmental
-
exposure to tobacco
- both before and after birth
-
damp homes
-
dust mites
-
pets
-
food allergies
-
air pollution
-
infections
-
Inhaled foreign body
-
acute onset wheeze
-
dry cough
-
decreased lung sounds
-
symptoms begin after episode of choking or severe coughing
-
not always observed
-
children may not volunteer information
-
-
if delayed:
-
dyspnoea
-
wet cough with sputum production
-
-
serious complications:
-
pneumonia
-
pneumothorax
-
subglottic oedema
-
more likely if diagnosis ≥24hrs post inhilation
-
-
long term complications:
-
recurrent pneumonia
-
lung abscesses
-
bronchiectasis
- more common longer diagnosis delayed
-
Bronchiolitis
-
acute infection fo lower respiratory tract
-
most common in winter
-
usually caused by RSV
-
tachypnoea, cough, hyperinflation
-
fine inspiratory crackles are likely
-
short tight cough
-
airway secretions play a signifiant role in obstruction
-
fever present
-
high-grade fever may indicate another diagnosis
-
pneumonia
-
wheeze rare with bacterial pneumonia
-
-
-
most common cuase of wheeze aged 1-6mo
-
by 10mo incidence much lower
-
rare after 1yr
Episodic viral wheeze
-
non-atopic wheeze
-
associated iwth viral URTI
-
do not usually display respiratory symptoms between episdoes
-
rhinovirus, corona viras, human metapnumovirus, parainfluenze virus, adenovirus
-
symptoms:
-
acute wheeze
-
dyspnoea
-
usualy with cough
-
-
shortly after viral urti
-
unlikely to have chest crackels
-
bronchiolitis = single episode
- compared to recurrent infections
-
common 10mo - 3yo
-
usually have fewer episodes over time
-
most children without concurrent atopy will grow out of their symptoms
-
some -> go on to have confirmed asthma
Atopic wheeze
-
aka multiple trigger wheeze
-
recurrent/persistent wheeze
-
associated atopic features
-
multiple exacerbating factors
-
cold iar
-
night time
-
exercise
-
allergen exposure
-
-
symptoms occur without viral illness
-
more severe exacerbations with viral illness
-
bilateral, widespread wheeze and/or rhonchi
- most prominent on exhalation
-
cough,
-
dyspnoea
-
prolonged expiration
-
increased RR
-
chest tightness
-
child with recurrent wheeze with sings of atopy/eczema, + skin-prick tests, family hsitory of asthma/atopy can be considered to have atopic wheeze
-
unusual in child \<2yo
-
dominant orm of wheeze after 3yo
-
almost all children with atopic wheeze go on to be diagnosed with asthma
Transient infant wheeze
-
epidemiological term for self-limiting wheeze
-
aged up to 3yo
-
used in literature to describe group who grow out of wheeze
-
cliniclaly unable to differentiate between wheeze
Assessment
-
history
-
define wheeze
-
nautre/duration
- constant/intermittent
-
other respiratory symptoms
-
exacerbating factors/triggers
-
previous episodes
-
smoking
-
eczema/atopy - personal & family
-
-
examination
-
gneeral assessment
-
concurrent upper resp tract signs
-
hyperinflation/respiratory distress
-
-
investigation
-
CXR
-
symptoms since birth
-
unusually severe wheeze
-
doens’t repsond to treatment
-
unusual clincial features
-
-
PEFR, Spiro,
-
not used under age of 5
-
not consistent
-
-
Management
Lifestyle interventions
-
smoking cessation
-
adress exacerbating factors
-
damp housing
-
heating
-
-
infection preventing strategies
-
immunisation
-
influenza vaccine
-
hand wahsing
-
good hygiene practise
-
-
Allergen avoidance
Treating acute episode of wheeze
Bronchodilators
-
bronchiolitis
-
not generally treated with bronchodilators
- provide minimal benefit
-
-
episodic viral wheeze/atopic wheeze \<5yo
- trialed on bronchodilators
-
SABA 100mcg prn (up to 800mcg/day)
-
spacer + mask
-
LABA not recommended as few strong studies
-
Theophylline not recommended
Oral corticosteroids
-
if require hospitalisation
-
recommended
-
given while awaiting transfer
-
-
if not hospitalisaiont
-
not clear
-
clincial judgement
-
evidence of efficacy limited
-
conflicting
-
most studies focus on older children
-
-
-
back-pocket corticosteroids not recommended
- not shown to prevent exacerbations or hosptial admisison in this group
-
prednisolone 1-2mg/kg /day for 3d
-
adverse effects:
-
appetitie
-
mood
-
behaviour changes
-
> 3mo
-
reduced growth
-
changes to skin
-
muscle weakness
-
Cushing’s syndrome
-
bone wewakening
-
increase risk of DM
-
-
Prevention between episodes
Inhaled corticosteroids
-
atopic wheeze
- consider ICS
-
episodeic viral wheeze
-
ICS less effective
-
not recommended
-
-
symptom control only
-
no effect of long-term natural history of condition
-
doens’t reduce likelihood that child will develpop persistent wheeze or progress to asthma over time
-
repsonese less thatn that seen in older children
-
ICS \< 5yo = fluticasone 50-100mcg bd via spacer for up to 3 mo
-
ICS should be stopped (after tapering) rather than just reduced once interval symptoms resolve
-
adverse effects;
-
reducedd height (may persist) - 1cm
-
Adrenal suppression
-
Montelukast
-
leukotriene receptor antagonist
-
apporpirate treatment for symptom and exacearbation control inc children with wheeze of any type
- “off label”
-
continuous use of montelukast appears to moderately decrease episodes of wheeze and
-
intermittent use
- when first signs of URTI may help control sypmtoms and reduce # of visiits to GP
-
used alone or alongside ICS
- to avoid having to increase dose of ICS
-
chewable tablet
-
2-5yo = 4mg od
-
ideal duration unknown
-
12mo continuous treatment appears to be effective in preventing exacerbation and controlling interval symptoms
-
short-term dosing - 7d cycles also effective
-
no clinically relevant adverse effects have been reported in children taking montelukast
-
special authrity
-
\<5yo
-
intermittent severe wheezing
-
at least 3 episodes of acute wheeze in previous 12 mo severe enough to seek medical attention
-


The day was raining, and Lee just broke up with Siri. Well, not technically a break up, but definitely a break. As usual, Lee went to the red plate bar, sit down at the counter and ordered a beer. Without looking around, he drank a dozen bottles straight. Whatever the bartender said, Lee just kept ordering drinks and never said a word. After the 12th drink, he turned around with a bloating red cheek and said to the girl sitting next to him,"Nice ***". The girl sitting next to him was Jana and she ignored him the first time since she could easily tell Lee was drunk. But Lee's eyebrows locked when she turned her back on him and grabbed her arm. Then, Lee lost consciousness to a punch on the face.


{% load staticfiles %}
Please wait...
access_time 14 mins ago
access_time 22 mins ago
access_time 3 hours ago
access_time 2 hours ago
access_time 4 hours ago
access_time Yesterday


Sorry for the poor shot of the wireframe. I was unable to get enough light to compose a proper shot. I will start to dig into using balsamic in the future for better framing!


Cyclone forces govt to defer JSC, JDC math tests
by bdnews24.comThe government has once again suspended the Junior School Certificate and Junior Dakhil Certificate math examinations set for Nov 12 due to Cyclone Bulbul.
The JSC test has been rescheduled for 10am on Nov 14, the education ministry said on Sunday. The madrasa board announced that the JDC test will now be held at 9am on Nov 15.
The JSC and JDC math exams were originally slated for Nov 9 before being rescheduled for Nov 12 and Nov 14, respectively, in light of the cyclone threat.
Later, the government also postponed the JSC and JDC exams scheduled for Nov 13 and Nov 16 due to the cyclone.


These are the things we are currently testing
{# Start of prototype write up #}- Date of prototype
- 10 February 2018
- Feature
- New Payments navigation
- Prototype version
- V6
Hypothesis
If, we change the Payments view to a tabbed navigation for payment history, element detail and payees
then, the Payment Officers will easily be able to find and use the relevant information needed to make a payment claim
because, the screen won't be as cluttered with information
Changes
Changes to the payments views on the back of user research insights from Harrow Dec 2017
Updates to the Unallocted views for the release of the allocate feature.
Research notes
None yet
View prototypeAll versions
{# Start of hidden panel #}Show all versions
- Date of prototype
- 20 December 2017
- Feature
- Award build and Payment screens
- Prototype version
- V5
Hypothesis
If we add drop down options for award types to the build an award screen,
then it will enable advisers to easily select the correct item,
because all award types will be clearly presented.
If we make the page inputs relevant to each award type selection,
then advisers will only enter the data needed for that item,
because only enetring data which is needed will make efficiencies processing the application.
If we put more information of the award on to payments views,
then payments staff will be able to check that the payments claim is valid,
because having better information to check against will reduce error and save time.
Changes
Make each selection from the award drop down menu present a tailored input screen relevant to the option chosen.
Explore and create input screens relevant to award item chosen from the drop down menu.
Make the information on the payments screens relevant to the award item the customer has accepted an offer on. Add better payee deatils showing the live payee(s)
Research notes
Designs have been tested with payments staff at Harrow and with SME's
Further work needed to improve the information on the live award views, better use of column headers in the table views
More work needed on the payee deatils
View prototype- Date of prototype
- 3 October 2017
- Feature
- Adding MI views
- Trying new language convetions
- Prototype version
- V4
Hypothesis
If we make the Management Information details available and easy to read,
then advisers, team leaders and performance staff can easily view the current status of the service,
because having this information visible and easy to read will enable all staff to monitor performance
If we change the naming of parts of the service,
then we will ensure commonality and consistency across the service,
because having different names/titles for the same entity causes confusion
Changes
Added in the MI banner to Adviser view, team leader view, regional and national views
Renaming of teams to specialisms, renaming Brought Forwrad (BF) to Next Action Date
Research notes
User testing session in Harrow and regular testing with the SME's
New proposition namings have been received well by staff in testing
Further work to complete on the content of views and screens, full content review suggested
View prototype{# Start of prototype write up #}
- Date of protptype
- 25 July 2017
- Feature
- Adding in a payment page to explore need of Payments staff
- Eligibility
- Iterating the evidience gather screens
- Multiple cases view
- Prototype version
- v3
Hypothesis
If we add the award support types to a drop down down menu,
then users will be able to pick the correct award type for the customer application,
because identifying the item in this way will save time processing
Changes
Adding support types to the drop down on award build
Inital view of the payments screens
Exploring how customers with multiple applications will be shown
Research notes
...
View prototype{# Start of prototype write up #}
- Date of prototype
- 20 March 2017
- Feature
- Adding a Search function
- Creating the screens and function for a specialist user to allocate work
- Prototype version
- v2
Hypothesis
If... then... because.
Changes
Setting up the allocate function for agent side service
Routing the start/log in view so that users see the unallocated cases first
Setting up a Search function
Research notes
The allocate function was tested in Halifax with staff who perform this role. Initial feedback was good as it met their needs
View prototype


Salmon Cookies
Return to home page
Location Information
Store name
Minimum customers
Maximum customers
Store Average of customers


ThroneStats
ThroneStats is a service to gather and display statistics on runs in Nuclear Throne by Vlambeer.
ThroneStats is not trying to be another "ThroneButt", but provides various statistics on your current run, primarily for streamers, in the form of an overlay you can use with OBS or Xsplit.
You can also view collected statistics on global and per-player basis in the "View stats" -tab.
Stats gathered and shown
- Weapon pickup rate (Most popular: )
- Causes of death (Most common: )
- Mutation choices (Most popular: )
- Crowns (Most popular: )
- Character use (Most popular: )
- Levels players die on (Most common: )
How does it look like?
The Twitch logo is a bit annoyingly in the way on the embedded player. You can try fullscreen if you can't see properly otherwise.
How do I get it
Click on the "Get overlay" -tab at the top of the page for full setup instructions.
What if I'm not a streamer?
While this was done primarily for streamers, you might still get something out if it even if you don't stream.
Firstly, for ThroneStats to track your runs you need to open it in a browser window. Go to the "Get overlay" -tab above and use the "View live stats" -feature to view the statistical information as things are happening and ensure that ThroneStats is collecting the data.
However you'll have to keep this on another screen, or beside the Nuclear Throne window if you want to see it.
You can view both global and per-player statistics on the "View stats" -tab above.
What browsers does this work on?
After quick testing it looks like it works on Chrome, Firefox and Edge. Didn't test others, but it's fairly likely any WebKit based browser (e.g. Safari) also works, and hopefully any reasonably modern browser should work. If you have issues with any MODERN browser, let me know, and I might fix it.
I'm not seeing any data, why?
First and foremost ThroneStats can only track players if they have given their SteamID64 and Streamkey CORRECTLY and have the tracker overlay or "View live stats" -screen open while they are playing.
Also, you should start a run on Nuclear Throne and let it run for at least 15-30 seconds before ThroneStats can get data from the API.
There is also the small chance that the backend is down. Maybe Tweet to @lietux.
Can I contribute somehow?
Maybe. The source code is publicly available at https://github.com/lietu/thronestats. If you want to contribute code, graphics, or just have feature requests, go there.
There are some assets that are possibly wrong and some that are missing, and help with fixing the issues there would be greatly appreciated.
Who made this?
Lietu made this.
Special thanks to:
- Gieron for help with getting the graphics from Nuclear Throne!
Other Nuclear Throne goodies
- ThroneButt - Statistics for dailies, weeklies, etc.
- Throne2Speech - Virtual commentator as a service
- ThroneFeed - Real-time overlay for streamers
Legal stuff
Nuclear Throne is (probably) a trademark of Vlambeer. ThroneStats is not affiliated with Vlambeer and vice-versa. Neither is the creator of ThroneStats.
ThroneStats -service saves your run information to keep global stats. It shouldn't contain any private information, but if you're cautious you can always just get the source code and run it locally for yourself. Up to you.
Copyright © 2015-infinity Janne "Lietu" Enberg.
Get overlay
You only need to fill in your SteamID64 and Stream Key to get a custom link that you can show in your OBS/Xsplit to get your notifications running.
OBS Setup
For OBS you'll likely want to use CLR Browser and the guide is written with it in mind.
- Fill in the information above and click on "Get overlay link" to get the URL for your overlay.
-
In OBS add a new CLR Browser source to your scene (or as a
Global Source).
- In the "URL" -field add your overlay URL.
- Set your preferred dimensions for the overlay. Try out width 300 and set height to your stream height (e.g. 720).
Xsplit Setup
This is unfortunately based on hearsay but you should be able to add a "webpage URL source" to your scene, which should function similarly to CLR Browser in OBS. If you can provide full set of instructions, please contact me.
View statistics
General information
| Recorded runs | |
| Favorite character | |
| Favorite weapon | |
| Favorite crown | |
| Favorite mutation | |
| Most deaths caused by | |
| Most deaths in |
Characters
| Character | Runs | % | |
|---|---|---|---|
Mutations
| Mutation | Runs | % | |
|---|---|---|---|
Crowns
| Crown | Runs | % | |
|---|---|---|---|
Weapons
| Weapon | Runs | % | |
|---|---|---|---|
Causes of death
| Enemy | Runs | % | |
|---|---|---|---|
Deaths
| Level | Runs | % |
|---|---|---|
Easiest way to get your SteamID64 is to go to https://steamid.io/lookup and click on "Sign in through Steam", and then authenticate yourself with your Steam user account. After that click on your profile image and choose "profile" and look for the the "steamID64" -line.
Locating your stream key from Nuclear Throne is easy. Just go to Settings -> Game, and click on "Stream Key" if it says "Disabled" to generate one.


As ghostsigns around the world fall victim to decay and debate about what constitutes ethical restoration, Sam Roberts explores the collision of public and private interests, and the ways cities around the world have attempted to protect and revive fading works of signwriting.
In Butte, Montana, a debate currently rages over what to do with the city’s many ‘ghostsigns’: the fading remains of advertising painted on walls. Jim Jarvis and the Historic Preservation Office have proposed having these repainted by the contemporary collective of mural artists and sign painters known as ‘The Walldogs’. However, local opposition has surfaced, objecting to what is perceived as the ‘Disneyfication’ of the town and a lack of public consultation.
This debate is not unique to Butte, which is just one example of attempts around the world to resolve the question of what, if anything, should be done about ghostsigns. The repainting of a sign for Bile Beans in York, England, provoked reactions both extreme (‘an act of public vandalism’) and acerbic (‘like an old friend having bad plastic surgery’), in addition to widespread praise for the job done. In the absence of any comprehensive and authoritative guidance in this relatively new area of historical interest, the decisions taken are typically at a local level. Community groups and property owners adopt approaches that they believe are right, often gaining support and inciting opposition in equal measure.
The character of things like this is essentially ephemeral, and it is the fact that such things survive only rarely and accidentally that gives them their charm and fascination.
As the evidence from Butte and York shows, these signs exist at an intersection of public and private interests. They are typically ‘hosted’ on the walls of private properties, and subject to the whim of building owners. However, the reactions to proposed or actual changes to their appearance demonstrate a parallel sense of public ownership. The signs serve as way markers – often perceived as ‘public art’ – and are records of local advertising and craft history. Conflict between these different groups, with their respective claims to ownership, is brought about when decisions are taken that affect the signs.
These contentious interventions vary in degrees of extremity, from doing nothing, through to plans to repaint the signs en masse as in Butte. Some actions lead to the loss of ghostsigns; the demolition of buildings, whitewashing and sandblasting of walls are all more final than the gradual weathering that usually takes them away. A whitewashing in Clapham led to a question being asked of London’s Mayor about what he was doing to protect these pieces of cultural and commercial history. His response delegated responsibility to local council level and, in this case, Michael Copeman, on behalf of Kate Hoey MP, responded that:
“The character of things like this is essentially ephemeral, and it is the fact that such things survive only rarely and accidentally that gives them their charm and fascination. Although their loss may be regretted, perhaps it is necessary to allow such changes to happen, untouched by a regulatory framework, so that in another hundred years’ time, people may be able to look at different but equally curious survivals – of early 21st century ephemera.”
In 1960 Howard Gossage observed that billboards exist ‘for the sole and express purpose of trespassing on your field of vision’, representing widespread resentment of overbearing outdoor advertising.
There is much to commend in this response, although the longevity of today’s billboards and digital displays is clearly inferior to that of the ghostsigns that have survived. Further, it is interesting that the value placed upon the signwriting craft is in some way less than crafts which create more permanent artefacts such as furniture, jewellery and books. Many of these signs are antiques, yet the skills involved in producing them aren’t celebrated in the same way as those of jewellers, cabinet makers and book binders.
Their commercial intent is the main point of difference between ghostsigns and these other crafts, making the motivations of those passionate about them even more intriguing. There isn’t a comparable lobby arguing for the protection and restoration of contemporary billboards, yet ghostsigns once served exactly the same advertising purpose. In 1960 Howard Gossage observed that billboards exist ‘for the sole and express purpose of trespassing on your field of vision’, representing widespread resentment of overbearing outdoor advertising. Further back, in 1855, the ‘One Who Thinks Aloud’ lamented the form, although on very different grounds, ‘Amid all the changes which this changing age has produced, that of the walls superceding the town’s bell-man is perhaps the most melancholy.’
The age of ghostsigns (most are from the early 20th century) triggers a similar nostalgia which, in turn, leads people to cherish them. However, in their day, they provoked opposition similar to that of Gossage and the One Who Thinks Aloud. Although they are often resented now, it is entirely conceivable that the revealing of a printed billboard in 50 years could provoke a similarly nostalgic response, and calls for protection, in a future world dominated by digital advertising.
The point at which ghostsigns assume value is subjective and, currently, a matter of debate. By contrast, most would agree with the preservation of the 2,000-year-old remains of painted advertising in Pompeii and Herculaneum. Likewise, the painted caves of the Ardèche in France, and the rock art of Australia. While not explicitly advertising, they also served some communicative purpose and hold obvious value as cultural relics. Ghostsigns are one among many examples of humankind’s desire to leave a mark, whether for commercial, community or individual ends. The age at which they assume the same value as these older inscriptions is arbitrary and disputed.
Ghostsigns are one among many examples of humankind’s desire to leave a mark, whether for commercial, community or individual ends.
Given their ambiguous value, ghostsigns currently fall outside of approaches taken to preserving cultural heritage artefacts. They are not architectural features of note and are, ultimately, just advertising ephemera. In addition, unlike other forms of advertising and printed matter, they cannot be collected and displayed in archives and museums, at least not in their original form. Photographic archiving projects, such as the UK-based History of Advertising Trust Ghostsigns Archive, do catalogue and document material, but say nothing about how ghostsigns ‘in the wild’ should be treated. Attempts to develop systematic approaches to protection and restoration all face the problem of defining which signs have merit: one person’s artwork is another’s eyesore. Further, ghostsigns often exhibit multiple layers of text, known as ‘palimpsests’, with some seeing a beautiful historical ‘onion’ , while others perceive nothing more than a mess.
The signs often fall victim to today’s graffiti and street artists, getting whitewashed in efforts to ‘clean up’ this more contemporary work. In some instances this coverage is only partial. In Stamford Hill, London, advertising for a cigarette brand is still visible above a painted strip covering graffiti. There is a tension given that tobacco advertising (albeit for a defunct brand) is now just as illegal as graffiti in the UK. The lack of formal guidance for protecting and restoring ghostsigns results in something akin to the Wild West i.e. anything goes provided you have the resources to do it.
...ghostsigns often exhibit multiple layers of text, known as ‘palimpsests’, with some seeing a beautiful historical ‘onion’ , while others perceive nothing more than a mess.
Protection, legal or otherwise, is an obvious starting point for those who value ghostsigns. The city of Bath, in England, has inadvertently protected many of its well-preserved signs. This is due to strict planning regulations that apply to their English Heritage listed ‘host’ buildings. A similar situation is found in conservation areas like London’s Stoke Newington and the Jewellery Quarter in Birmingham. Two signs in Hackney, London, have recently been given more explicit protection. They have ‘local listed’ status in recognition of their ‘aesthetic or artistic merit’. This stipulates that the signs must ‘be considered’ in planning applications affecting them but this protection is relatively limited in legal terms. Efforts to protect ghostsigns are necessarily piecemeal and constrained by the need to develop an agreed means of assessing the worth of individual signs.
Conservation and restoration present additional options for managing ghostsigns. Conservation is quite rare but a well-known example exists in Fort Collins. In 2011 Deborah Uhl and Lisa Capano ‘rehabilitated’ a 1958 Coca-Cola sign, bringing it back to a legible state, while keeping its faded essence. This approach shows sensitivity but requires judgements about which parts are touched up, or not. These considerations are not particular to ghostsigns; conservation in the art world is a highly contentious issue. The ‘restoration’ of the Sistine Chapel in the 1990s led James Beck to conclude that ‘the authentic masterpiece of Michelangelo...is now severely damaged’. Treatments that affect the natural decay of ghostsigns can be subject to similar assessments of authenticity to avoid such ‘damage’.
The lack of formal guidance for protecting and restoring ghostsigns results in something akin to the Wild West
Many consider the widespread, and increasing, repainting of ghostsigns as hugely damaging. This was done routinely when they were ‘in service’ to ensure they remained bright and eye-catching. However, there is a superficiality in re applying the paint when they are devoid of their intended advertising purpose. (An exception is the many Coca-Cola restorations funded by the company itself.) For many, the appeal of ghostsigns is their faded appearance and this is lost when they are repainted. The connection with the past is mediated through the surviving paintwork and this is diminished to some extent with its reapplication years afterwards. While repainting projects do demonstrate what impact the signs would once have had, this could also be achieved by creating new signs, and allowing the craft skills to flourish and develop in new ways.
For the foreseeable future these repainting projects will continue outside of any regulatory framework. Lessons can be learned from the Netherlands where repainting work is carried out in a disciplined and considered manner. Under the guidance of the umbrella group, Tekens Aan de Wand (Writing on the Wall), projects are completed through the use of thorough archival research and professional signwriters with knowledge of traditional methods. This approach is also found elsewhere but there are plenty of examples where little or no thought has been given to undertaking the work in an authentic and considerate manner.
The debate about what should be done with ghostsigns will not go away. Indeed, it is important to nurture it so that opposing views can be subjected to scrutiny and discussed among those with an interest in these pieces of painted history. Study of cases such as those highlighted in this article can contribute to this debate, and allow those initiating future projects to learn from what has been done before. However, for now, the realm of ghostsigns protection and restoration remains a free for all, but beware the backlash if your project fails to consult with those whose field of vision it trespasses on.


| uiw.mixin - MATLAB File Help |
Contents of uiw.mixin package: AssignPVPairs - Mixin to assign PV pairs to public properties DisplayNonScalarObjectAsTable - HasCallback - Mixin to provide a callback for a widget HasContainer - Mixin class for a graphical widget container HasEditableText - Mixin for editable text field capabilities HasEditableTextField - Mixin for controls with a single editable text field HasKeyEvents - Mixin to provide key events for a widget HasListSortingButtons - Mixin to provide list editing and ordering buttons HasLogger - Mixin for classes that contain a Logger HasPreferences - Mixin class for managing app preferences HasValueEvents - Mixin to provide key events for a widget
Copyright 2018-2019 The MathWorks, Inc.


Get a password from the terminal. Sounds simple? Sounds like the readline
module should be able to do it? NOPE.
bash
npm install --save getpass
javascript
const mod_getpass = require('getpass');
mod_getpass.getPass([options, ]callback)
Gets a password from the terminal. If available, this uses /dev/tty
to avoid
interfering with any data being piped in or out of stdio.
This function prints a prompt (by default Password:
) and then accepts input
without echoing.
Parameters:
options
, an Object, with properties:
prompt
, an optional Stringcallback
, a Func(error, password)
, with arguments:
error
, either null
(no error) or an Error
instancepassword
, a String


{% extends 'base.html' %} {% block content %}
KEEP THIS KEY SECRET!
This access key will only be shown once. Treat it as if it were a password to your bank account. Write it down and put it somewhere safe. We do not store API access tokens in our database. We use a form of encryption that protects your key, even from us. We can only validate that this is the correct key for you, but we cannot ever make one exactly like it again.


ORG_2000009 - has organizational part
Label
has organizational part
Alternate name
parent of
Sub property of
Definition
The property that associates an organization with one of its organizational parts
Definition source
Michael Conlon https://orcid.org/0000-0002-1304-8448
Domain
Inverse of
Example
The University of Florida has organizational part College of Medicine; The College of Medicine has organizational part Department of Anesthesiology
Term editor
Michael Conlon https://orcid.org/0000-0002-1304-8448


Check that all NOT NULL columns were presented in the INSERT instruction.
DECLARE @Products TABLE
(
Id INT IDENTITY PRIMARY KEY,
Name VARCHAR(100) NOT NULL,
IsAvailable BIT NOT NULL,
Color VARCHAR(100) DEFAULT 'White',
Price DECIMAL(20, 2),
Description AS Name + ' ' + CONVERT(VARCHAR(50), Price, 111)
);
INSERT INTO @Products (Price) -- There must be Name and IsAvailable
VALUES (100.0);


You are viewing an historical archive of past issues. Please
report new issues to the appropriate project issue tracker on
GitHub.
Comments
-
powderskier
OK - my apology. somehow I ended up putting this issue on 3 times. I couldn't figure out how to remove 2. I wanted to add product name.
-
Greg Hurrell
Closing this one and will comment on ticket #1169.
Add a comment
Comments are now closed for this issue.


A day in the studio with YouTube star Doctor Mike, who now has 4 million subscribers after gaining initial fame for being attractive on Instagram
by Amanda Perelli, Business Insider US- Doctor Mikhail (Mike) Varshavski is a board-certified primary care physician and popular YouTube influencer with 4 million subscribers.
- Varshavski’s Instagram page went viral in 2015 after he was featured in a Buzzfeed article, and then again in People magazine’s 2015 Sexiest Man Alive issue.
- Today, Varshavski told Business Insider that he mainly splits his time between filming videos for YouTube and working as a doctor.
- He shared what an average filming day is like and took Business Insider inside his high-tech home studio.
- Visit Business Insider’s homepage for more stories.
Mike Varshavski is a board-certified primary care physician who went viral in 2015 after he was featured in a BuzzFeed article about how attractive he was, and then again in People magazine’s 2015 Sexiest Man Alive issue.
Accepting his sudden fame, he launched a YouTube channel in 2017 while in his residency, and hired a videographer to film and edit the videos for him. He’s known as “Doctor Mike” online, and now has millions of YouTube subscribers with videos that often appear on the trending page of YouTube.
Yet his YouTube channel was not an immediate success.
“I launched the channel and it picked up like 15,000 subscribers,” he told Business Insider. “It didn’t go anywhere, even though I told 2 million people on Instagram to come watch it.”
Varshavski said he realized the key to growing an audience was consistency (he’s never missed a single posting day) and figuring out what content would appeal to a wider audience.
From hospital to filming studio, how Varshavski does it
In his second year of YouTube, while keeping up with his career as a doctor, Varshavski started posting videos twice a week instead of once.
“The first half of the week I am making YouTube videos,” he said. “The second half of the week I’m in the hospital actually doing the things I’m talking about.”
His videos gain an average 500,000 views to around 4 million views, depending on if a video is picked up by YouTube’s algorithm and recommended to viewers.
He puts his own spin on concepts like PewDiePie‘s popular “Meme Review,” where Varshavski reacts to medical memes, or shows like “Grey’s Anatomy.”
To keep track of his growing online business, Varshavski signed with the digital talent agency, Abrams Artists Agency three years ago. His agent works to build up the business aspects of his social media, like landing public speaking appearances and producing a line of products (that will be coming out soon, Varshavski said).
With the help of his videographer, Dan, Varshavski films a batch of videos during filming days, which Dan will later edit throughout the week.
Most people think Varshavski has a large team helping him out, he said. But he really only has Dan and his agent.
Business Insider spent a day with Doctor Mike to see the process of filming his YouTube videos:
Doctor Mike lives in New York City and films videos for his 4.47 million subscribers in a spare room in his apartment. Here’s the view:
When you walk inside his filming room, you are greeted by medical books and filming equipment.
Doctor Mike’s editor Dan films and edits the YouTube videos from Mike’s desk, and uses high-end equipment.
The equipment:
- Camera – Canon 1DX Mark II
- Tripod – Manfrotto
- Monitor – SmallHD 501
- Lights – Aputure 120dII (x3)
- Light reflectors
- Mic – Rode Videomic Pro+
- Post Production – Adobe Premiere


Welcome to the Travel Survey Form!
Please click on the appropriate button:
Pre School to Pre Primary
Class 1st to 8th
Class 9th to 12th