Friday, 31 March 2017

Spectacle "Juste pour rire”

“Juste pour rire” / “Just for laughs”

1- “La lettre d’amour” de Karl Valentin (James Carter)
A man sits finishing his letter to his faraway “lover” complaining that she never writes to him as she promised she would.

2- “Mr Badin” de George Courteline (Loris Pergod & Tim Azzopardi)
Mr Badin’s boss invites him into his office to confront him about his absence from work for weeks at time,  knowing that he goes to drink in a nearby bar all the time.
Mr Badin makes his usual excuse of a death in the family. His boss points out that it's one of on many in a few weeks including weddings and baptisms too.
His boss gives him two choices, he resigns or he comes to work every day. The boss, convinced he can get Mr badin to resign starts signing the necessary paperwork.  Mr Badin now desperate tries both seduction and tears to persuade his boss how hard his life is. Eventually the boss thinks that Mr Badin is too upset to do anything but resign and asks him to sign his resignation letter. Instead Mr Badin asks for a raise.

3- “Vivons heureux” de Jean Paul Alègre (Frances Priest & Valeria Luciani)
A “great” actress has a last minute change of acting partner, who turns out to be a drama student with no idea of what is expected of her. The student thinks she has just come to watch the great actress at work. Completely misunderstanding that she is supposed to be acting with her partner, the student joins the audience to watch the now “one woman show”, only to be highly critical of the poor performance of the “great” actress.

4- “L’affaire se complique” de Jean Tardieu - (Tim Azzopardi)
This “poem” is very short, surreal and impossible to describe.

5- “Gros chagrin” de George Courteline (Saki Kunimoto & Frances Priest)
Two society ladies who “lunch”, Gabrielle and Caroline: Gabrielle  arrives at Caroline’s house distraught because her husband Fernand is cheating on her. Caroline is at her wits end because she has had to let go of her maid (“bonne”) who she has caught stealing. Gabrielle  claims to have found a love letter in Fernand pocket from Rose Mouseron a singer/dancer. Caroline want to hear all the gossip and encourages her friend Gabrielle  to tell all - and Gabrielle  loves the attention claiming to be suicidal but quickly relents when she remembers that she has a society ball to go to with Fernand and wants Caroline to teach her some dance moves.


6- “Le gora” de George Courteline (Foteini Manolaraki& Tim Azzopardi)
A photographer GUSTAVE and his lover BOBÉCHOTTE have an impromptu photo shoot. While taking photos BOBÉCHOTTE  tells Gustave that the concierge has given her a “Un Gora”, which Gustave does not understand  as she means an “Un--Angora” - a cat. Gustave corrects her pronunciation. But as she continues to describe the cat she keeps making small mistakes which Gustave keeps correcting. While Boéchotte goes along with Gustave pedantry for a while, eventually she gets annoyed and we all know hell hath no fury like a woman who has her grammar corrected!

7- “Le dromadaire mécontent” de Jacques Prévert (Loris Pergod)
A young dromedary (camel one hump) tells us the story  of how he went to a conference about camels and dromedaries and how ridiculous it was,

8- “L’ours” de Anton Tchekhov (Saki Kunimoto & James Carter)
Elena Popova is a grieving widow grieving on the seven-month anniversary of her husband's death.  A retired army man, Grigory Stepanovitch Smirnov arrives and wishes to see Elena Popova. Smirnov explains to her that her late husband owes him a sum of 1,200 roubles. Because he is a landowner, Smirnov explains that he needs the sum paid to him on that same day to pay for the mortgage of a house due the next day. Popova explains that she has no money with her and that she will settle her husband's debts when her steward arrives the day after tomorrow. Smirnov gets angered by her refusal to pay him back and mocks the supposed 'mourning' of her husband.  
Smirnov decides that he will not leave until his debts are paid off, even if that means waiting until the day after tomorrow. He and Popova get into another argument when he starts yelling at the footman to bring him kvass to drink. During this argument Popova insults Smirnov by calling him a bear, a monster!"
Smirnov, insulted, calls for a duel, not caring that Elena is a woman. Elena , in turn, enthusiastically agrees and goes off to get a pair of guns her husband owned. Meanwhile, Smirnov says to himself how impressed he is by Popova's audacity and slowly realizes that he has actually fallen in love with her and her dimpled cheeks. When Elena returns with the pistols, Smirnov makes his love confession…. And … dot dot dot

Friday, 12 August 2016

Subscribe to an IBM MQ Topic using Spring


This code works to subscribe to an IBM MQ Topic called TESTTOPIC set up with MQExplorer 7.5.0.1 using the defaults. Code uses uses Spring SimpleMessageListenerContainer

Keywords: JMS DefaultMessageListenerContainer SimpleMessageListenerContainer MQTopicConnectionFactory MQQueueConnectionFactory

 package poc;  
 import javax.jms.JMSException;  
 import javax.jms.Message;  
 import javax.jms.MessageListener;  
 import org.junit.Test;  
 import org.springframework.jms.listener.AbstractMessageListenerContainer;  
 import org.springframework.jms.listener.SimpleMessageListenerContainer;  
 import com.ibm.mq.jms.MQTopicConnectionFactory;  
 public class PubSub2Test {  
   @Test  
   public void test() throws InterruptedException, JMSException {  
     MQTopicConnectionFactory connectionFactory = new MQTopicConnectionFactory(); // MQQueueConnectionFactory does not work here  
     connectionFactory.setHostName("localhost");  
     connectionFactory.setPort(1414);  
     connectionFactory.setQueueManager("AAA.QMGR");  
     connectionFactory.setChannel("AAA.SVRCONN");  
     connectionFactory.setTransportType(1);  
     AbstractMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer(); // a DefaultMessageListenerContainer does not work here  
     listenerContainer.setPubSubDomain(true);  
     listenerContainer.setConnectionFactory(connectionFactory);  
     listenerContainer.setDestinationName("TESTTOPIC");  
     MessageListener listener = new MessageListener() {  
       @Override  
       public void onMessage(Message arg0) {  
         System.out.println("\nMessage received: " + arg0.toString() + "\n");  
       }  
     };  
     listenerContainer.setMessageListener(listener);  
     listenerContainer.start();  
     while (true) {  
       Thread.sleep(3000);  
       System.out.print(".");  
     }  
   }  
 }  

Monday, 31 March 2014

Becoming really rich with Java 8

Disclaimer: the C#, Scala and Java 8 algorithms shown and referenced here implement a "momentum investing" algorithm. This is purely for computer language comparison purposes and should definitely not be taken as investment advice.

In 2009, I saw this post Becoming really rich with C# showcasing the new features in C#  4.5 and was impressed with C# with its hybrid Object-Functional approach and collection APIs to give collection operations a SQL-like feel:

var adjustedPrices =
    e.Result
    .Split(new[] { '\n' })
    .Skip(1)
    .Select(l => l.Split(new[] { ',' }))
    .Where(l => l.Length == 7)
    .Select(v => new Event(DateTime.Parse(v[0]), Double.Parse(v[6])));

Now lets do that in 7 lines of code in Java 5, 6, or 7. Er no, sorry.

At the time, I was learning Scala. So I translated Becoming really rich with C# into Scala and compared them side by side. Result:  See http://quoiquilensoit.blogspot.com/2009/10/becoming-really-rich-with-scala.html The result surprised me. I thought C# held up pretty well overall.

So, a full four years later, Oracle owns Java and Java8 is out with some of the same features that C# was offering in dot net 4.5 in 2010. There is obvious missing stuff that Java 8 still does not have: LINQ,  Output parameters. Vars. Tuples. Optional/Nullable numerics. But I tried the same exercise, trying to keep in the spirit of the C# code.

The code is on github: https://github.com/azzoti/get-rich-with-java8

git clone https://github.com/azzoti/get-rich-with-java8.git

Its an eclipse maven project, but you can run straight from the command line with:

mvn exec:java

(Make sure you have JDK 8 set up!)




Original C#Java 8
See notes after the table

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

namespace ETFAnalyzer {






















struct Event {
  internal Event(DateTime date, double price) { Date = date; Price = price; }
  internal readonly DateTime Date;
  internal readonly double Price;
}










class Summary {
  internal Summary(string ticker, string name, string assetClass,
          string assetSubClass, double? weekly, double? fourWeeks,
          double? threeMonths, double? sixMonths, double? oneYear,
          double? stdDev, double price, double? mav200) {
    Ticker = ticker;
    Name = name;
    AssetClass = assetClass;
    AssetSubClass = assetSubClass;
    // Abracadabra ...
    LRS = (fourWeeks + threeMonths + sixMonths + oneYear) / 4;
    Weekly = weekly;
    FourWeeks = fourWeeks;
    ThreeMonths = threeMonths;
    SixMonths = sixMonths;
    OneYear = oneYear;
    StdDev = stdDev;
    Mav200 = mav200;
    Price = price;
  }
  internal readonly string Ticker;
  internal readonly string Name;
  internal readonly string AssetClass;
  internal readonly string AssetSubClass;
  internal readonly double? LRS;
  internal readonly double? Weekly;
  internal readonly double? FourWeeks;
  internal readonly double? ThreeMonths;
  internal readonly double? SixMonths;
  internal readonly double? OneYear;
  internal readonly double? StdDev;
  internal readonly double? Mav200;
  internal double Price;

  internal static void Banner() {
    Console.Write("{0,-6}", "Ticker");
    Console.Write("{0,-50}", "Name");
    Console.Write("{0,-12}", "Asset Class");
    Console.Write("{0,4}", "RS");
    Console.Write("{0,4}", "1Wk");
    Console.Write("{0,4}", "4Wk");
    Console.Write("{0,4}", "3Ms");
    Console.Write("{0,4}", "6Ms");
    Console.Write("{0,4}", "1Yr");
    Console.Write("{0,6}", "Vol");
    Console.WriteLine("{0,2}", "Mv");
  }

  internal void Print() {

    Console.Write("{0,-6}", Ticker);
    Console.Write("{0,-50}", new String(Name.Take(48).ToArray()));
    Console.Write("{0,-12}", new String(AssetClass.Take(10).ToArray()));
    Console.Write("{0,4:N0}", LRS * 100);
    Console.Write("{0,4:N0}", Weekly * 100);
    Console.Write("{0,4:N0}", FourWeeks * 100);
    Console.Write("{0,4:N0}", ThreeMonths * 100);
    Console.Write("{0,4:N0}", SixMonths * 100);
    Console.Write("{0,4:N0}", OneYear * 100);
    Console.Write("{0,6:N0}", StdDev * 100);
    if (Price <= Mav200)
      Console.WriteLine("{0,2}", "X");
    else
      Console.WriteLine();
  }
}

class TimeSeries {
  internal readonly string Ticker;
  readonly DateTime _start;
  readonly Dictionary<DateTime, double> _adjDictionary;
  readonly string _name;
  readonly string _assetClass;
  readonly string _assetSubClass;

  internal TimeSeries(string ticker, string name, string assetClass, string assetSubClass, IEnumerable<event> events) {
    Ticker = ticker;
    _name = name;
    _assetClass = assetClass;
    _assetSubClass = assetSubClass;
    _start = events.Last().Date;
    _adjDictionary = events.ToDictionary(e => e.Date, e => e.Price);
  }










  bool GetPrice(DateTime when, out double price, out double shift) {
    // To nullify the effect of hours/min/sec/millisec being different from 0
    when = new DateTime(when.Year, when.Month, when.Day);
    var found = false;
    shift = 1;
    double aPrice = 0;
    while (when >= _start && !found) {
      if (_adjDictionary.TryGetValue(when, out aPrice)) {
        found = true;
      }
      when = when.AddDays(-1);
      shift -= 1;
    }
    price = aPrice;
    return found;
  }

  double? GetReturn(DateTime start, DateTime end) {
    var startPrice = 0.0;
    var endPrice = 0.0;
    var shift = 0.0;
    var foundEnd = GetPrice(end, out endPrice, out shift);
    var foundStart = GetPrice(start.AddDays(shift), out startPrice, out shift);
    if (!foundStart || !foundEnd)
      return null;
    else
      return endPrice / startPrice - 1;
  }

  internal double? LastWeekReturn() {
    return GetReturn(DateTime.Now.AddDays(-7), DateTime.Now);
  }
  internal double? Last4WeeksReturn() {
    return GetReturn(DateTime.Now.AddDays(-28), DateTime.Now);
  }
  internal double? Last3MonthsReturn() {
    return GetReturn(DateTime.Now.AddMonths(-3), DateTime.Now);
  }
  internal double? Last6MonthsReturn() {
    return GetReturn(DateTime.Now.AddMonths(-6), DateTime.Now);
  }
  internal double? LastYearReturn() {
    return GetReturn(DateTime.Now.AddYears(-1), DateTime.Now);
  }






  internal double? StdDev() {
    var now = DateTime.Now;
    now = new DateTime(now.Year, now.Month, now.Day);
    var limit = now.AddYears(-3);
    var rets = new List<double>();
    while (now >= _start.AddDays(12) && now >= limit) {
      var ret = GetReturn(now.AddDays(-7), now);
      rets.Add(ret.Value);
      now = now.AddDays(-7);
    }
    var mean = rets.Average();
    var variance = rets.Select(r => Math.Pow(r - mean, 2)).Sum();
    var weeklyStdDev = Math.Sqrt(variance / rets.Count);
    return weeklyStdDev * Math.Sqrt(40);
  }
  internal double? MAV200() {
    return _adjDictionary.ToList()
           .OrderByDescending(k => k.Key)
           .Take(200).Average(k => k.Value);
  }
  internal double TodayPrice() {
    var price = 0.0;
    var shift = 0.0;
    GetPrice(DateTime.Now, out price, out shift);
    return price;
  }
  internal Summary GetSummary() {
    return new Summary(Ticker, _name, _assetClass, _assetSubClass,
           LastWeekReturn(), Last4WeeksReturn(), Last3MonthsReturn(),
           Last6MonthsReturn(), LastYearReturn(), StdDev(), TodayPrice(), 
           MAV200());
  }
}

class Program {

  static string CreateUrl(string ticker, DateTime start, DateTime end)
  {
    return @"http://ichart.finance.yahoo.com/table.csv?s=" + ticker + 
      "&a="+(start.Month - 1).ToString()+"&b="+start.Day.ToString()+"&c="+start.Year.ToString() + 
      "&d="+(end.Month - 1).ToString()+"&e="+end.Day.ToString()+"&f="+end.Year.ToString() + 
      "&g=d&ignore=.csv";
  }

  static void Main(string[] args) {
    // If you rise this above 5 you tend to get frequent connection closing on my machine
    // I'm not sure if it is msft network or yahoo web service
    ServicePointManager.DefaultConnectionLimit = 10;

    var tickers =
      File.ReadAllLines("ETFTest.csv")
      .Skip(1)
      .Select(l => l.Split(new[] { ',' }))
      .Where(v => v[2] != "Leveraged")
      .Select(values => Tuple.Create(values[0], values[1], values[2], values[3]))
      .ToArray();

    var len = tickers.Length;

    var start = DateTime.Now.AddYears(-2);
    var end = DateTime.Now;
    var cevent = new CountdownEvent(len);
    var summaries = new Summary[len];
    
    for(var i = 0; i < len; i++)  {
      var t = tickers[i];
      var url = CreateUrl(t.Item1, start, end);
      using (var webClient = new WebClient()) {
        webClient.DownloadStringCompleted +=
                        new DownloadStringCompletedEventHandler(downloadStringCompleted);
        webClient.DownloadStringAsync(new Uri(url), Tuple.Create(t, cevent, summaries, i));
      }
    }

    cevent.Wait();
    Console.WriteLine("\n");

    var top15perc =
        summaries
        .Where(s => s.LRS.HasValue)
        .OrderByDescending(s => s.LRS)
        .Take((int)(len * 0.15));
    var bottom15perc =
        summaries
        .Where(s => s.LRS.HasValue)
        .OrderBy(s => s.LRS)
        .Take((int)(len * 0.15));

    Console.WriteLine();
    Summary.Banner();
    Console.WriteLine("TOP 15%");
    foreach(var s in top15perc)
      s.Print();

    Console.WriteLine();
    Console.WriteLine("Bottom 15%");
    foreach (var s in bottom15perc)
      s.Print();
      
  }

  static void downloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) {
    var bigTuple = (Tuple<Tuple<string, string, string, string>, CountdownEvent, Summary[], int>)e.UserState;
    var tuple = bigTuple.Item1;
    var cevent = bigTuple.Item2;
    var summaries = bigTuple.Item3;
    var i = bigTuple.Item4;
    var ticker = tuple.Item1;
    var name = tuple.Item2;
    var asset = tuple.Item3;
    var subAsset = tuple.Item4;

    if (e.Error == null) {
      var adjustedPrices =
          e.Result
          .Split(new[] { '\n' })
          .Skip(1)
          .Select(l => l.Split(new[] { ',' }))
          .Where(l => l.Length == 7)
          .Select(v => new Event(DateTime.Parse(v[0]), Double.Parse(v[6])));

      var timeSeries = new TimeSeries(ticker, name, asset, subAsset, adjustedPrices);
      summaries[i] = timeSeries.GetSummary();
      cevent.Signal();
      Console.Write("{0} ", ticker);
    } else {
      Console.WriteLine("[{0} ERROR] ", ticker);
      summaries[i] = new Summary(ticker,name,"ERROR","ERROR",0,0,0,0,0,0,0,0); 
      cevent.Signal();
    }
  }
}
}

package etf.analyzer;

import static java.lang.System.out;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.*;

import java.io.IOException;
import java.nio.file.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Stream;

class Event {
  public Event(LocalDate date, double price) {
    this.date = date;
    this.price = price;
  }
  public LocalDate getDate() {
    return date;
  }
  public double getPrice() {
    return price;
  }
  private LocalDate date;
  private double price;
}
class Summary {
  public Summary(String ticker, String name, String assetClass,
      String assetSubClass, OptionalDouble weekly, OptionalDouble fourWeeks, 
      OptionalDouble threeMonths, OptionalDouble sixMonths, OptionalDouble oneYear,
      OptionalDouble stdDev, double price, OptionalDouble mav200) {
    this.ticker = ticker;
    this.name = name;
    this.assetClass = assetClass;
    // this.assetSubClass = assetSubClass;
    // Abracadabra ...
    this.lrs = fourWeeks.add(threeMonths).add(sixMonths).add(oneYear).divide(OptionalDouble.of(4.0d));
    this.weekly = weekly;
    this.fourWeeks = fourWeeks;
    this.threeMonths = threeMonths;
    this.sixMonths = sixMonths;
    this.oneYear = oneYear;
    this.stdDev = stdDev;
    this.mav200 = mav200;
    this.price = price;
  }
  private String ticker;
  private String name;
  private String assetClass;
  // private String assetSubClass;
  public OptionalDouble lrs;
  private OptionalDouble weekly;
  private OptionalDouble fourWeeks;
  private OptionalDouble threeMonths;
  private OptionalDouble sixMonths;
  private OptionalDouble oneYear;
  private OptionalDouble stdDev;
  private OptionalDouble mav200;
  private double price;

  static void banner() {
    out.printf("%-6s", "Ticker");
    out.printf("%-50s", "Name");
    out.printf("%-12s", "Asset Class");
    out.printf("%4s", "RS");
    out.printf("%4s", "1Wk");
    out.printf("%4s", "4Wk");
    out.printf("%4s", "3Ms");
    out.printf("%4s", "6Ms");
    out.printf("%4s", "1Yr");
    out.printf("%6s", "Vol");
    out.printf("%2s\n", "Mv");
  }
  void print() {
    out.printf("%-6s", ticker);
    out.printf("%-50s", name);
    out.printf("%-12s", assetClass);
    out.printf("%4.0f", lrs.orElse(0.0d) * 100);
    out.printf("%4.0f", weekly.orElse(0.0d) * 100);
    out.printf("%4.0f", fourWeeks.orElse(0.0d) * 100);
    out.printf("%4.0f", threeMonths.orElse(0.0d) * 100);
    out.printf("%4.0f", sixMonths.orElse(0.0d) * 100);
    out.printf("%4.0f", oneYear.orElse(0.0d) * 100);
    out.printf("%6.0f", stdDev.orElse(0.0d) * 100);
    if (price <= mav200.orElse(-Double.MAX_VALUE))
      out.printf("%2s\n", "X");
    else
      out.println();
  }
}

class TimeSeries {
  private String ticker;
  private LocalDate _start;
  private Map<LocalDate, Double> _adjDictionary;
  private String _name;
  private String _assetClass;
  private String _assetSubClass;

  public TimeSeries(String ticker, String name, String assetClass, String assetSubClass, List<Event> events) {
    this.ticker = ticker;
    this._name = name;
    this._assetClass = assetClass;
    this._assetSubClass = assetSubClass;
    this._adjDictionary = events.stream().collect(toMap(Event::getDate, Event::getPrice));
    this._start = events.size() - 1 > 0 ? events.get(events.size() - 1).getDate() : LocalDate.now().minusYears(99);
  }

  private static final class FindPriceAndShift {
    public FindPriceAndShift(boolean found, double aPrice, int shift) {
        this.found = found;
        this.price = aPrice;
        this.shift = shift;
    }
    private boolean found;
    private double price;
    private int shift;
  }
  
  private FindPriceAndShift getPrice(LocalDate when) {
    boolean found = false;
    int shift = 1;
    double aPrice = 0.0d;
    while ((when.equals(_start) || when.isAfter(_start)) && !found) {
      if (found = _adjDictionary.containsKey(when)) {
        aPrice = _adjDictionary.get(when);
      }
      when = when.minusDays(1);
      shift -= 1;
    }
    return new FindPriceAndShift(found, aPrice, shift);
  }
  
  OptionalDouble getReturn(LocalDate start, LocalDate endDate) {
    FindPriceAndShift foundEnd = getPrice(endDate);
    FindPriceAndShift foundStart = getPrice(start.plusDays(foundEnd.shift));
    if (!foundStart.found || !foundEnd.found)
      return OptionalDouble.empty();
    else {
      return OptionalDouble.of(foundEnd.price / foundStart.price - 1.0d);
    }
  }

  private OptionalDouble lastWeekReturn() {
    return getReturn(LocalDate.now().minusDays(7), LocalDate.now());
  }
  private OptionalDouble last4WeeksReturn() {
    return getReturn(LocalDate.now().minusDays(28), LocalDate.now());
  }
  private OptionalDouble last3MonthsReturn() {
    return getReturn(LocalDate.now().minusMonths(3), LocalDate.now());
  }
  private OptionalDouble last6MonthsReturn() {
    return getReturn(LocalDate.now().minusMonths(6), LocalDate.now());
  }
  private OptionalDouble lastYearReturn() {
    return getReturn(LocalDate.now().minusYears(1), LocalDate.now());
  }
  private Double sum(Collection<Double> d) {
    return d.parallelStream().reduce(0d, Double::sum);
  }
  private Double avg(Collection<Double> d) {
    return sum(d) / d.size();
  }
  private OptionalDouble stdDev() {
    LocalDate now = LocalDate.now();
    LocalDate limit = now.minusYears(3);
    List<Double> rets = new ArrayList<>();
    while (now.compareTo(_start.plusDays(12)) >= 0 && now.compareTo(limit) >= 0) {
      OptionalDouble ret = getReturn(now.minusDays(7), now);
      rets.add(ret.orElse(0d));
      now = now.minusDays(7);
    }
    Double mean = avg(rets);
    Double variance = avg(rets.parallelStream().map(r -> Math.pow(r - mean, 2)).collect(toList()));
    Double weeklyStdDev = Math.sqrt(variance);
    return OptionalDouble.of(weeklyStdDev * Math.sqrt(40));
  }
  private OptionalDouble MAV200() {
    return OptionalDouble.of( 
      _adjDictionary.entrySet().parallelStream()
      .sorted(comparing((Entry<LocalDate,Double> p) -> p.getKey()).reversed())
      .limit(200).mapToDouble(e -> e.getValue()).average().orElse(0d)
    );
  }
  private double todayPrice() {
    return getPrice(LocalDate.now()).price;
  }
  public Summary getSummary() {
    return new Summary(ticker, _name, _assetClass, _assetSubClass,
      lastWeekReturn(), last4WeeksReturn(), last3MonthsReturn(),
      last6MonthsReturn(), lastYearReturn(), stdDev(), todayPrice(),
      MAV200());
  }
}

public class Program {

  static String createUrl(String ticker, LocalDate start, LocalDate end) {
    return "http://ichart.finance.yahoo.com/table.csv?s=" + ticker + "&a="
      + (start.getMonthValue() - 1) + "&b=" + start.getDayOfMonth()
      + "&c=" + start.getYear() + "&d=" + (end.getMonthValue() - 1)
      + "&e=" + end.getDayOfMonth() + "&f=" + end.getYear()
      + "&g=d&ignore=.csv";
  }
  
  public static void main(String[] args) throws IOException, InterruptedException {

    List<String[]> tickers = Files.lines(FileSystems.getDefault().getPath("ETFs.csv"))
      .skip(1)
      .parallel()
      .map(line -> line.split(",", 4))
      .filter(v -> !v[2].equals("Leveraged"))
      .collect(toList());
    
    int len = tickers.size();
    
    LocalDate start = LocalDate.now().minusYears(2);
    LocalDate end = LocalDate.now();
    CountDownLatch cevent = new CountDownLatch(len);
    Summary[] summaries = new Summary[len]; 
    
    try (WebClient webClient = new WebClient()) {
      for (int i = 0; i < len; i++) {
        String[] t = tickers.get(i);
        final int index = i;
        webClient.downloadStringAsync(createUrl(t[0], start, end), result -> {
            summaries[index] = downloadStringCompleted(t[0], t[1], t[2], t[3], result);
            cevent.countDown();
        }); 
      }
      cevent.await();
    }
    
    Stream<Summary> top15perc =
      Arrays.stream(summaries)
      .filter(s -> s.lrs.isPresent())
      .sorted(comparing((Summary p) -> p.lrs.get()).reversed())
      .limit((int)(len * 0.15));
    Stream<Summary> bottom15perc =
      Arrays.stream(summaries)
      .filter(s -> s.lrs.isPresent())
      .sorted(comparing((Summary p) -> p.lrs.get()))
      .limit((int)(len * 0.15));
    
    System.out.println();
    Summary.banner();
    System.out.println("TOP 15%");
    top15perc.forEach(
        s -> s.print());
    
    System.out.println();
    Summary.banner();
    System.out.println("BOTTOM 15%");      
    bottom15perc.forEach(
        s -> s.print());

  }

  public static Summary downloadStringCompleted(String ticker, String name, String asset, String subAsset, 
      DownloadStringAsyncCompletedArgs e
  ) {
      Summary summary;
      if (e.getError() == null) {
          List<Event> adjustedPrices = 
            Arrays.stream(e.getResult().split("\n"))
            .skip(1)
            .parallel()
            .map(line -> line.split(",", 7))
            .filter(l -> l.length == 7)
            .map(v -> new Event(LocalDate.parse(v[0], DateTimeFormatter.ISO_LOCAL_DATE), Double.valueOf(v[6]))).collect(toList());
          TimeSeries timeSeries = new TimeSeries(ticker, name, asset, subAsset, adjustedPrices);
          summary = timeSeries.getSummary();
      } else {
          System.err.printf("[%s ERROR]", ticker);
          final OptionalDouble zero = OptionalDouble.of(0d);
          summary = new Summary(ticker, name, "ERROR", "ERROR", zero, zero, zero, zero, zero, zero, 0d, zero);
      }
      return summary;
  }
}

Some observations:
  • The code depends on the yahoo to get historical stock prices and sometimes Yahoo is not available for stock prices. Wait five minutes and run the program again. 
  • The Java code is much much faster than the C# code, but it is going to yahoo to get historical stock prices which is going to be the limiting factor.  I don't think the C# should be slower than the Java code but it is and I'm not sure why it is. I'm pretty sure the poor C# performance is to do with the dot net WebClient configuration but I might be wrong.
  • In Java 8, just to show how easy it is, I've used parallelStream() and .parallel() in a couple of places, but these can be removed for the equivalent functionality. I can see no noticeable difference in performance with or without these calls when using an 8 core machine. As I said above I believe that the limiting factor is going to yahoo to get historical stock prices. There is not that much number crunching to do and I suspect the time taken to do it pales into insignificance next to the internet fetch time. Doing the calculations in parallel just isn't worth it. But its good to see how easy it is to parallelize work if you want to. Being able to simply say Collection.parallelStream() and Stream.parallel() is incredible if you find a sensible use case for it.
      • The Java 8 code is a little longer than the C# code. In Java 7, I'm guessing the code would be at least two times longer and very very ugly if written in a similar style. The Java8 code is not as concise as C# or Scala but at least its in the same ball park. Partly this is due to Java POJO boilerplate (e.g. the FindPriceAndShift class and the Event class getter and setters) but thats is no big deal (IMO). The Java code is also more verbose because types must be declared unlike in C# where you can use "var" instead of a type declaration and usually the C# compiler infers what you mean. 
      • Tuples. C# has Tuples, Scala has Tuples but apparently their use is the spawn of satan and civilization will collapse if they are used in Java even to hold temporary results when parsing comma separated values into another class. (Oracle will be removing HashMap from Java9 apparently for similar reasons ;)) In order not to be arrested by the Java thought police I avoided succumbing to this. The C# code uses them, but I've managed to avoid them.
      • Output parameters.  In my scala translation in 2009, my translation to Scala used a return tuple instead of the C# output parameters (which I personally found confusing in the C# algorithm). In the Java 8 version I used a POJO FindPriceAndShift rather than sell my soul to wicked tuple monster.
      • The C# code uses the "double?" type which is a double that can have an empty value and it means you can write LRS = (fourWeeks + threeMonths + sixMonths + oneYear) / 4 and any of fourWeeksthreeMonthssixMonths, and oneYear can be empty without causing a null pointer exception etc.  Java 8 does ship with OptionalDouble. But, strangely, you can't say a.add(b).add(c).divide(d). So I wrote an OptionalDouble class which does do this, so you can say lrs = fourWeeks.add(threeMonths).add(sixMonths).add(oneYear).divide(OptionalDouble.of(4.0d). If you look at the code you can see its almost trivially simple. Writing lrs = fourWeeks.add(threeMonths).add(sixMonths).add(oneYear).divide(OptionalDouble.of(4.0d) is  not very pretty compared to the C# or Scala equivalent but a lot of Java people are used to doing this method chaining with BigDecimal: but with OptionalDouble now it can be null/emptyValue safe. (The same thing can easily be done to create a an OptionalBigDecimal class obviously.) (And this OptionalDouble stuff could easily have been done in Java7 too.)
      • Java does not have a C# style WebClient, so I have taken the open source jetty http client and wrapped it in a simple wrapper to make it look like the C# WebClient. See git hub for the WbClient class.
      • Java lives on open source. If the C# code is slow because the dot net WebClient is doing something stupid, its hard to find out as its closed source. If the Jetty's Java http client is  broken, you can debug the source or switch to apache's http client: the best open source libraries emerge through natural selection. [Update: reaction from Reddit (I love reddit!): Sorry, that is pure bullshit. It is perfectly feasible to debug .Net Framework source code:
        http://msdn.microsoft.com/en-us/library/cc667410.aspx And no, it doesn't have a bug. They've been working on that for generations, and Microsoft puts serious money and has serious people working on stuff, as opposed to a bunch of unknown random hippie weed smokers financed by random coin slot donations. and even if java was faster it doesn't change the fact that it is a useless dinosaur which gets improvements 10 years after the rest of the mainstream languages. All that crappy bloated unmaintainable event-based async code can be converted to a beautiful sequence of async / await in C# 5.0, whereas you will probably not see anything like that in java in the next 20 years due to it's complete lack of evolution and retardedness.]
      • There is some surprising missing functionality from the Stream and or Collections. There is no Zip or takeWhile or dropWhile for sequential streams. I'm guessing Java9, guava and others will fill this gap pretty fast.
        • When I showed the code below to an experienced colleague who has only used Java <= 6 he said "that looks like C++ to me: thats completely unmaintainable". Sigh.
          • Stream<Summary> top15perc =
              Arrays.stream(summaries)
                      .filter(s -> s.lrs.isPresent())
                      .sorted(comparing((Summary p) -> p.lrs.get()).reversed())
                      .limit((int)(len * 0.15)); 



          Thursday, 6 September 2012



          Force maven 3.x dependency resolution to local repository jars - just as a temporary measure.
          Tore hair out for an hour...


          mvn package
          [INFO] Scanning for projects...
          [ERROR] The build could not read 1 project -> [Help 1]
          [ERROR]
          [ERROR]   The project org.foo.repositories:xyz-customer-inventory-repository-parent:2.0.52.1.3-SNAPSHOT (C:\Users\bazbaz\workspaces\abc\xyz-customer-inventory
          -repository-parent\pom.xml) has 1 error
          [ERROR]     Non-resolvable parent POM: Failure to find org.foo.common:foo-common-parent:pom:2.0.7 in http://repo.maven.apache.org/maven2 was cached in the l
          ocal repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced and 'parent.relativePath' points at w
          rong local POM @ line 2, column 10 -> [Help 2]

          See: https://cwiki.apache.org/confluence/display/MAVEN/Maven+3.x+Compatibility+Notes#Maven3.xCompatibilityNotes-ResolutionfromLocalRepository

          Just delete all the _maven.repositories files from your local repository and the problems goes away!




          Sunday, 20 May 2012

          Using Spring Stored Procedure Support to call Oracle anonymous PL/SQL blocks

          The code for what follows can be found on github: git://github.com/azzoti/CallAnonymousPLSQLUsingSpring.git


          Its an eclipse maven project and is easy to run the Main class in Eclipse but it can be run as a vanilla maven project.   (mvn test).


          Prerequisites:
          1) You need to manually download the oracle jdbc driver jar and put it in the lib folder.
          2) You need to have an oracle instance running localhost:1521:XE with user "system" password "manager" (or change the code)

          With a small amount of fiddling Spring's StoredProcedure class can be used to call an anonymous PL/SQL block. The fiddling is class OraclePLSQLBlock which extends Spring's  StoredProcedure class and overrides it to stop spring messing the sql up:

          There is not much to it:


           
          public class OraclePLSQLBlock extends StoredProcedure {
           
           public OraclePLSQLBlock(JdbcTemplate jdbcTemplate, String plsql) {
            super(jdbcTemplate, plsql);
           }
          
           public OraclePLSQLBlock(DataSource datasource, String plsql) {
            super(datasource, plsql);
           }
           
           @Override
           public String getCallString() {
            // we control the creation of the sql string that is actually sent to the database
            // (by default spring will construct a string {call xxx} where xxx is the sql that 
            // we set in the contructor) 
            return getSql();
           }
           
           @Override
           public boolean isSqlReadyForUse() {
            // stop spring from adding ? parameter placeholders to the sql
            return true;
           }
          }
          

          The simplest example of using OraclePLSQLBlock to call a PL/SQL block is in class ExampleSpringStoredProcedureCallingPLSQLBlockWithStringReturn which has an IN string parameter and and OUT string parameter.

           
          
          public class ExampleSpringStoredProcedureCallingPLSQLBlockWithStringReturn extends OraclePLSQLBlock {
           
           private static final String PLSQL = "" +
           " declare " +  
           "      p_id varchar2(20) := null; " +
           " begin " +
           "    p_id := :inputParameter; " +
           "    ? := 'input parameter was = ' || p_id;" +
           " end;";
           
           @Autowired
           public ExampleSpringStoredProcedureCallingPLSQLBlockWithStringReturn(DataSource datasource) {
            super(datasource, PLSQL);
                  declareParameter(new SqlParameter("inputParameter", Types.VARCHAR));
                  declareParameter(new SqlOutParameter("outputParameter", Types.VARCHAR));
           }
           
           public Map< String, Object > executePLSQLBlock(String id) {
            return this.execute(id);
           }
          }
          
          

          There are other examples, which get progressively more complex including: ExampleSpringStoredProcedureCallingComplexPLSQLBlockWithCursorReturn which passes in an Array of Students and returns a cursor query which maps results to a list of Person.




          Sunday, 6 May 2012

          Java, PowerMock and the slow death of pointless Interfaces


          Back in the day, say around 2000, the use of Java interfaces were pushed as the one true way (tm) for expressing dependecies between classes. The established wisdom was that if one class needs another then it should be expressed as a dependency on an interface. There are two advantages to expressing dependencies via interfaces: (1) you can have a test implementation of the interface so you can unit test a class without using the real dependency (2) you can have multiple implementations of the interface, which might be chosen at runtime. In practice, (2) happens quite rarely, but  remains a completely valid case for interfaces use.


          And so, the wisdom went, you were condemned to eternal damnation called a static method on another class. A call to a static method is hard wired like concrete and steel. No way to stub it out for unit testing.


          Enter PowerMock in about 2008/2009 which works with EasyMock or Mockito and which allows you to mock pretty much anything:


          "PowerMock is a framework that extend other mock libraries such as EasyMock with more powerful capabilities. PowerMock uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more. By using a custom classloader no changes need to be done to the IDE or continuous integration servers which simplifies adoption. Developers familiar with the supported mock frameworks will find PowerMock easy to use, since the entire expectation API is the same, both for static methods and constructors. PowerMock aims to extend the existing API's with a small number of methods and annotations to enable the extra features. Currently PowerMock supports EasyMock and Mockito."


          I have seen PoweMock used a lot in several organizations. It just works(tm). I have noticed that it simplifies the way people write code. 


          So, with PowerMock in hand, here is some advice for writing Java, that goes against established wisdom.


          1) Don't write to interfaces unless you really need multiple implementations! Why create an interface and a class when just a class will do? If you find you really need an interface later then create one and use it. But remember most of the time, YAGNI for unit testing thanks to PowerMock. (where YAGNI means "you ain't gonna need interfaces" as opposed to the more traditional "you ain't gonna need it".)


          2) Use EasyMock or Mockito for unit testing and the extras that PowerMock gives you if you need to. (I have nothing against JMock, and perhaps JMock has the equivalent features that PowerMock provides. )


          3) Do not be afraid to use static methods if appropriate. When is appropriate? Now there's a question Rich Hickey would be happy to answer. 


          Thanks to PowerMock, we are free to use interfaces where they are really needed.





          Saturday, 5 May 2012

          Examples of Java calling Oracle PLSQL anonymous blocks


          Why would you do this? Answer: Developement agility

          An Oracle DBA might say that Java should not use anonymous plsql blocks as (a) it embeds embeds database logic into Java code,  and (b) is bad for performance as a stored procedure would have a precompiled execution plan.

          But in the organization where I am currently consulting:
          •  iBatis and hibernate (arguably)  embed database logic into Java applications. In theory its done in a "portable" way that is not tied to the database implementation. Like thats ever going to change!
          • Logistically and bureaucratically, it takes weeks to get a packaged stored procedure created and installed. In my experience this is typical of most large organizations that separate Java developers from database developers and dbas. The human communication in itself between the teams, creates a bottleneck.
          • The PLSQL blocks are stored in seperate files and loaded from files. Database gurus tweak the SQL and hand it over for complex queries and updates. 
          • Performance is actually not bad, because Oracle bind variables are used in the plsql. This means that oracle sees the same text every time and reuses execution plans.
          • Over time, if found to be durable, the PLSQL can be converted to a stored procedure and the anonmous plsql files are replaced with simple procedure calls.


          Example 1: Call an anonymous PLSQL Block with one input string and one output string parameter :
            
          import java.sql.CallableStatement;
          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.SQLException;
          import java.sql.Types;
          
          public class CallPLSQLBlockWithOneInputStringAndOneOutputStringParameter {
          
              // Warning: this is a simple example program : In a long running application,
              // exception handlers MUST clean up connections statements and result sets.
              public static void main(String[] args) throws SQLException {
          
                  DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
          
                  final Connection c = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "system", "manager");
                  String plsql = "" +
                  " declare " +  
                  "      p_id varchar2(20) := null; " +
                  " begin " +
                  "    p_id := ?; " +
                  "    ? := 'input parameter was = ' || p_id;" +
                  " end;";
                  CallableStatement cs = c.prepareCall(plsql);
                  cs.setString(1, "12345");
                  cs.registerOutParameter(2, Types.VARCHAR);
                  cs.execute();
                  
                  System.out.println("Output parameter was = '" + cs.getObject(2) + "'");
                  
                  cs.close();
                  c.close();
              }
          
          }
          
          Java: Call an anonymous PLSQL Block with one input string and one output string parameter and one output cursor (query result) parameter :
          
          
          import java.sql.CallableStatement;
          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.ResultSet;
          import java.sql.Types;
          
          import oracle.jdbc.OracleTypes;
          
          public class CallPLSQLBlockWithOneInputStringAndOneOutputStringParameterAndOneOutputCursorParameter {
          
          
          
              // Warning: this is a simple example program : In a long running application,
              // exception handlers MUST clean up connections statements and result sets.
          
          public static void main(String[] args) throws Exception { DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); final Connection c = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "system", "manager"); String plsql = "" + " declare " + " p_id varchar2(20) := null; " + " l_rc sys_refcursor;" + " begin " + " p_id := ?; " + " ? := 'input parameter was = ' || p_id;" + " open l_rc for " + " select 1 id, 'hello' name from dual " + " union " + " select 2, 'peter' from dual; " + " ? := l_rc;" + " end;"; CallableStatement cs = c.prepareCall(plsql); cs.setString(1, "12345"); cs.registerOutParameter(2, Types.VARCHAR); cs.registerOutParameter(3, OracleTypes.CURSOR); cs.execute(); System.out.println("Result = " + cs.getObject(2)); ResultSet cursorResultSet = (ResultSet) cs.getObject(3); while (cursorResultSet.next ()) { System.out.println (cursorResultSet.getInt(1) + " " + cursorResultSet.getString(2)); } cs.close(); c.close(); } }
          Example:  Call an anonymous PLSQL Block with one input string array and one output string parameter and one output cursor (query result) parameter :

          import java.sql.Array;
          import java.sql.CallableStatement;
          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.ResultSet;
          import java.sql.Types;
          
          import oracle.jdbc.OracleTypes;
          import oracle.sql.ARRAY;
          import oracle.sql.ArrayDescriptor;
          
          public class CallPLSQLBlockWithOneInputStringArrayAndOneOutputStringParameterAndOneOutputCursorParameter {
          
              // Warning: this is a simple example program : In a long running application,
              // exception handlers MUST clean up connections statements and result sets.
          public static void main(String[] args) throws Exception { DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); // Warning: this is a simple example program : In a long running application, // error handlers MUST clean up connections statements and result sets. final Connection c = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "system", "manager"); String plsql = "" + " declare " + " p_id string_array := null; " + " l_rc sys_refcursor;" + " begin " + " p_id := ?; " + " ? := 'input parameter first element was = ' || p_id(1);" + " open l_rc for select * from table(p_id) ; " + " ? := l_rc;" + " end;"; String[] stringArray = new String[]{ "mathew", "mark"}; // MUST CREATE THIS IN ORACLE BEFORE RUNNING System.out.println("(This should be done once in Oracle)"); c.createStatement().execute("create or replace type string_array is table of varchar2(32)"); ArrayDescriptor descriptor = ArrayDescriptor.createDescriptor( "STRING_ARRAY", c ); Array array_to_pass = new ARRAY( descriptor, c, stringArray ); CallableStatement cs = c.prepareCall(plsql); cs.setArray( 1, array_to_pass ); cs.registerOutParameter(2, Types.VARCHAR); cs.registerOutParameter(3, OracleTypes.CURSOR); cs.execute(); System.out.println("Result = " + cs.getObject(2)); ResultSet cursorResultSet = (ResultSet) cs.getObject(3); while (cursorResultSet.next ()) { System.out.println (cursorResultSet.getString(1)); } cs.close(); c.close(); } }

          Example: Call an anonymous PLSQL Block with one input structure array and one output string parameter and one output cursor (query result) parameter :

          import java.sql.Array;
          import java.sql.CallableStatement;
          import java.sql.Connection;
          import java.sql.DriverManager;
          import java.sql.ResultSet;
          import java.sql.SQLException;
          import java.sql.Types;
          
          import oracle.jdbc.OracleTypes;
          import oracle.sql.ARRAY;
          import oracle.sql.ArrayDescriptor;
          import oracle.sql.STRUCT;
          import oracle.sql.StructDescriptor;
          
          public class CallPLSQLBlockWithOneInputStructureArrayAndOneOutputStringParameterAndOneOutputCursorParameter {
          
              public static void main(String[] args) throws Exception {
          
                  DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
                  
                  // Warning: this is a simple example program : In a long running application,
                  // error handlers MUST clean up connections statements and result sets.
                  
                  final Connection c = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "system", "manager");
                  String plsql = "" +
                  " declare " +  
                  "    p_id student_array := null; " +
                  "     l_rc sys_refcursor;" +
                  " begin " +
                  "    p_id := ?; " +
                  "    ? := 'input parameter first element was = (' || p_id(1).id_num || ', ' || p_id(1).name || ')'; " +
                  "    open l_rc for select * from table(p_id) ; " +
                  "    ? := l_rc;" +
                  " end;";
          
                  
                  // MUST CREATE ORACLE TYPES BEFORE RUNNING
                  setupOracleTypes(c);
                  
                  StructDescriptor structDescr = StructDescriptor.createDescriptor("STUDENT", c);
                  STRUCT s1struct = new STRUCT(structDescr, c, new Object[]{1, "mathew"});
                  STRUCT s2struct = new STRUCT(structDescr, c, new Object[]{2, "mark"});
                  ArrayDescriptor arrayDescr = ArrayDescriptor.createDescriptor( "STUDENT_ARRAY", c );
                  Array array_to_pass = new ARRAY( arrayDescr, c, new Object[]{s1struct, s2struct} );
                  
                  CallableStatement cs = c.prepareCall(plsql);
                  cs.setArray( 1, array_to_pass );
                  cs.registerOutParameter(2, Types.VARCHAR);
                  cs.registerOutParameter(3, OracleTypes.CURSOR);
                  
                  cs.execute();
                  
                  System.out.println("Result = " + cs.getObject(2));
                  
                  ResultSet cursorResultSet = (ResultSet) cs.getObject(3);
                  while (cursorResultSet.next ())
                  {
                      System.out.println (cursorResultSet.getInt(1) + " " + cursorResultSet.getString(2));
                  } 
                  cs.close();
                  c.close();
              }
          
              private static void setupOracleTypes(final Connection c)
                      throws SQLException {
                  System.out.println("(This should be done once in Oracle)");
                  try {
                      c.createStatement().execute("drop type student_array ");
                  } catch (Exception e) {
                      // ignore
                  }
                  c.createStatement().execute("create or replace type student as object (id_num integer(4), name varchar2(25))");
                  c.createStatement().execute("create or replace type student_array is table of student");
              }  
          
          }  
          

          Wednesday, 23 March 2011

          An example of why C# kicks Java's butt: Fluent NHibernate


          “From the horses mouth (I'm the lead developer on Fluent NHibernate): the reason Fluent Hibernate doesn't exist is exactly because of the lack of lambda expressions [in Java]. It's not just the lack of basic lambdas, but the ability to parse those expressions that FNH relies heavily on; without which you'd need to resort to strings and that's no better than XML in my opinion. It's always a possibility for the future though. – James Gregory Oct 22 '09 at 9:08

          Monday, 28 June 2010

          Release port 8080 after tomcat crash on windows 7

          Check which process is using port 80

          On the command prompt window, type the following command.

          netstat -o -n -a | findstr 0.0:8080

          C:\dev>netstat -o -n -a | findstr 0.0:8080
            TCP    0.0.0.0:8080           0.0.0.0:0              LISTENING       6352


          Open Task Manager to check the process ID
          1. Right click on the taskbar to open the the task manager.
          2. Go to the Processes tab.
          3. Click the View menu
          4. And make sure you select the PID (Process Identifier)
          Find the process and kill it

          Tuesday, 27 April 2010

          Oracle: convert a varchar2 to a CLOB without dropping the table

          Current defn of column in table NOTIFICATION

          DETAIL VARCHAR2(4000),

          Want it to be a CLOB.

          create a temporary table 'NOTIFICATION2' with the required column defintions. This is then used as a template to convert the table column.

          exec dbms_redefinition.start_redef_table('TSUSER','NOTIFICATION','NOTIFICATION2','ID, RECIPIENT, SUBJECT, TO_CLOB(DETAIL) DETAIL, FOOTER, ISSUE_DATE, SENT_DATE, SENT_STATUS, RETRY_COUNT, ROLE',dbms_redefinition.cons_use_pk);
          exec dbms_redefinition.finish_redef_table('TSUSER','NOTIFICATION','NOTIFICATION2');

          Thursday, 15 April 2010

          Scala asymmetrical function definitions

          I was impressed by the clarity of the "Better Haskell solution" to this Odd Word problem. (Disclaimer: I don't know haskell, but I can just about read a simple example like the one in this problem.)

          haskell:
          import Data.List
          
           enumerate = zip $ cycle [0,1]
          
           oddwords x = foldl' add "" (enumerate ws) ++ "."
               where add "" (_,t) = t
                     add s (0, t) = s ++ " " ++ t
                     add s (1, t) = s ++ " " ++ reverse t
                     ws = words $ takeWhile (/= '.') x
          


          So I added a Scala version that is a translation of the Haskell which I'm repeating here which copies the essence of the Haskell algorithm as well as the names used:
          object OddWordProblem1 {
            
              // define cycle as per Haskell as Scala does not define it 
              def cycle[T](seq: Seq[T]) = Stream.continually(seq).flatten
          
              def enumerate[T](words: Seq[T]) = cycle(List(0,1)) zip words   
              
              def oddwords(input : String) = {
                  
                  def add(stringSoFar : String, wordAndOddIndicator : (Int,String)) = 
                      (stringSoFar, wordAndOddIndicator) match {
                          case ("", (_, t)) => t
                          case (s, (0, t)) => s + " " + t
                          case (s, (1, t)) => s + " " + t.reverse
                      }
                  
                  def ws(words : Seq[String]) = words takeWhile ("." !=)
                  
                  // split the string into words,  first making sure that "kansas." always becomes "kansas ."
                  val words =  input.replaceFirst("""\.""", " .").split(" +").toList
                  
                  enumerate(ws(words)).foldLeft("")(add) + "."
              }
          
              
              def main(args : Array[String]) = {
                  println(oddwords("whats the matter with kansas."))
              }
          }
          



          The core logic is a bit longer than the Haskell version because
          (a) Its doing IO(!) and handling input corner cases and is self contained and runnable.
          (b) It defines cycle which is no big deal
          (c) It defines method parameters and their types
          (d) It has more brackets than haskell as haskell does not use brackets for function application. Not much we can do about that.

          So, we have to define method parameters and their types, or do we? Now it could be argued that defining the parameters and types is good for readability, but it would be nice to have the choice. But of course with inline anonymous functions, the parameters and types are not required. So instead of defining the add method separately, we can write,

          def oddwords(input : String) = {
          
            def ws(words : Seq[String]) = words takeWhile ("." !=)
          
            val words =  input.replaceFirst("""\.""", " .").split(" +").toList
          
            enumerate(ws(words)).foldLeft(""){
              (_, _) match {
                case ("", (_, t)) => t
                case (s, (0, t)) => s + " " + t
                case (s, (1, t)) => s + " " + t.reverse
              }
            } + "."
          } 
          

          or to name the parameters without declaring the types,

          // ...
            enumerate(ws(words)).foldLeft(""){
              (stringSoFar, wordAndOddIndicator) => 
                (stringSoFar, wordAndOddIndicator) match {
                  case ("", (_, t)) => t
                  case (s, (0, t)) => s + " " + t
                  case (s, (1, t)) => s + " " + t.reverse
                }
            } + "."
          


          So that's the asymmetry: Scala named function definitions require parameter names and types, and the anonymous functions don't, because the parameter types can usually be inferred by usage. The Haskell "where" syntax is rather nice and a similar feature in Scala would be great...

          An imaginary Scala syntax for haskell style context based method definition:

          // ... 
          enumerate(ws(words)).foldLeft("")(add)
          where {
            def add = 
              (_, _) match {
                 case ("", (_, t)) => t
                 case (s, (0, t)) => s + " " + t
                 case (s, (1, t)) => s + " " + t.reverse
              }
            }  
            // other defs
          }
          

          It would just be an aliased anonymous functions which could (a) be used more than once in the expression and (b) simplify the overall expression compared to usage with anonymous functions.

          Just a thought!

          Friday, 26 March 2010

          The method getJspApplicationContext(ServletContext) is undefined for the type JspFactory

          I got this error after redeploying a web app to tomcat6 in myeclipse 8.

          org.apache.jasper.JasperException: Unable to compile class for JSP:

          An error occurred at line: 22 in the generated java file
          The method getJspApplicationContext(ServletContext) is undefined for the type JspFactory

          Stacktrace:
          at org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:92)
          at org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:330)
          at org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:423)
          at org.apache.jasper.compiler.Compiler.compile(Compiler.java:317)

          The reason was that
          javax.servlet.jsp.jar
          javax.servlet.jar

          had been copied to

          ...\webapps\myapp\WEB-INF\lib

          And the versions conflicted with the tomcat versions

          Deleting
          javax.servlet.jsp.jar
          javax.servlet.jar
          from
          ...\webapps\myapp\WEB-INF\lib

          fixed the problem

          Tuesday, 23 February 2010

          Dynamically create spring bean

          I used this in a dbunit test to create a dummy service layer bean dynamically.

          The rest of the beans were configured in xml files. I created this bean dynamically in the test so that I didn't have to pollute the xml config.

          // Dynamically create a DummyServiceToMakeCodeTransactional bean and register with spring
               DefaultListableBeanFactory autowireCapableBeanFactory = (DefaultListableBeanFactory) getApplicationContext().getAutowireCapableBeanFactory();
               AbstractBeanDefinition beanDefinition =
                    BeanDefinitionBuilder.rootBeanDefinition(
                         DummyServiceToMakeCodeTransactional.class.getName()).getBeanDefinition();
               autowireCapableBeanFactory.registerBeanDefinition("DummyService", beanDefinition);
               DummyServiceToMakeCodeTransactional bean = (DummyServiceToMakeCodeTransactional) 
               getApplicationContext().getBean("DummyService");
          
          

          Thursday, 5 November 2009

          C# Linq OrderBy, Scala SortWith and SortBy (and Scary Implicits)

          Here is a tiny example of a little bit of linq at work in Visual Studio 2010 Beta2. Lets order a list of names in C#

          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Text;
          
          namespace TestOrderBy
          {
              class Person
              {
                  public Person(string firstName, string lastName, DateTime dateOfBirth)
                  {
                      FirstName = firstName;
                      LastName = lastName;
                      DateOfBirth = dateOfBirth;
                  }
                  public readonly string FirstName;
                  public readonly string LastName;
                  public readonly DateTime DateOfBirth;
                  override public string ToString()
                  {
                      return FirstName + ", " + LastName + " " + DateOfBirth.ToShortDateString();
                  }
              }
              class Program
              {
                  static void Main(string[] args)
                  {
                      var people = new List() {
                          new Person("Alan", "Kay", new DateTime(1973,12,1)),
                          new Person("James", "Gosling", new DateTime(1991,12,1)),
                          new Person("Anders", "Hejlsberg", new DateTime(1999,12,1)),
                          new Person("Martin", "Odersky", new DateTime(2000,12,1)),
                          new Person("Guido", "Van Rossum", new DateTime(2002,12,1)),
                          new Person("Yukihiro", "Matsumoto", new DateTime(1990,12,1))
                      };
          
                      var peopleOrderedByDob = people.OrderBy(person => person.DateOfBirth);
                      foreach (var p in peopleOrderedByDob)
                          Console.WriteLine(p);
                      Console.WriteLine();
          
                      var peopleOrderedNaturally = people.OrderBy(person => person);
                      foreach (var p in peopleOrderedNaturally)
                          Console.WriteLine(p);
                      Console.WriteLine();
          
                      Console.ReadLine();
                  }
              }
          }
          

          What happens when we run it: We get:

          Alan, Kay 01/12/1973
          Yukihiro, Matsumoto 01/12/1990
          James, Gosling 01/12/1991
          Anders, Hejlsberg 01/12/1999
          Martin, Odersky 01/12/2000
          Guido, Van Rossum 01/12/2002
          
          

          So the clause "OrderBy(person => person.DateOfBirth)" worked. Cool. C# knows how to compare birthdays.

          But then Kaboom! The debugger stops at line 42 with ArgumentExeption "At least one object must implement IComparable". So "people.OrderBy(person => person)" was not checked at compile time. Wow! So lets implement IComparable on Person sorting on LastName:

          class Person  : IComparable
          {
              ...
              int IComparable.CompareTo(object obj)
              {
                  Person otherPerson = obj as Person;
                  if (otherPerson != null)
                      return this.LastName.CompareTo(otherPerson.LastName);
                  else
                      throw new ArgumentException("Object is not a Person");
              }
          }
          

          And hey presto, C# knows how to sort people.

          Alan, Kay 01/12/1973
          Yukihiro, Matsumoto 01/12/1990
          James, Gosling 01/12/1991
          Anders, Hejlsberg 01/12/1999
          Martin, Odersky 01/12/2000
          Guido, Van Rossum 01/12/2002
          
          James, Gosling 01/12/1991
          Anders, Hejlsberg 01/12/1999
          Alan, Kay 01/12/1973
          Yukihiro, Matsumoto 01/12/1990
          Martin, Odersky 01/12/2000
          Guido, Van Rossum 01/12/2002
          
          

          These clauses: "person => person.DateOfBirth" and "person => person" are known in C# are known as keySelector and are part of the .net linq library. If you want to drink the full linq Kool-Aid you can write

          var peopleOrderedByDob = 
                from p in people
                orderby p.DateOfBirth
                select p;
          
          foreach (var p in peopleOrderedByDob)
            Console.WriteLine(p);
          

          But its just doing the same thing under the covers.

          So lets do the same thing in Scala, using the sortWith method, which until 22 Oct 2009 was the only thing available. Lets sort by DateOfBirth first

          import org.scala_tools.time.Imports._
          
          object TestSortBy {
          
            case class Person(firstName: String, lastName: String, dateOfBirth: DateTime) 
            { 
              override def toString() = {
                firstName + ", " + lastName + " " + DateTimeFormat.shortDate().print(dateOfBirth);
              }
            }
          
            def main(args : Array[String]) : Unit = {    
              val people = 
                Person("Alan", "Kay", new DateTime(1973,12,1,0,0,0,0))::
                Person("James", "Gosling", new DateTime(1991,12,1,0,0,0,0))::
                Person("Anders", "Hejlsberg", new DateTime(1999,12,1,0,0,0,0))::
                Person("Martin", "Odersky", new DateTime(2000,12,1,0,0,0,0))::
                Person("Guido", "Van Rossum", new DateTime(2002,12,1,0,0,0,0))::
                Person("Yukihiro", "Matsumoto", new DateTime(1990,12,1,0,0,0,0))::Nil
             
              val peopleOrderedByDob = people.sortWith((p1,p2) => p1.dateOfBirth < p2.dateOfBirth) 
              peopleOrderedByDob foreach println
              println
            }
          }
          
          Which works just fine: 
          Alan, Kay 01/12/73
          Yukihiro, Matsumoto 01/12/90
          James, Gosling 01/12/91
          Anders, Hejlsberg 01/12/99
          Martin, Odersky 01/12/00
          Guido, Van Rossum 01/12/02
          

          So now for the ordering naturally too

          val peopleOrderedNaturally = people.sortWith((p1,p2) => p1 < p2) 
              peopleOrderedNaturally foreach println
              println
          
          
          but line 2 does not compile (unlike c# where this is a runtime error) because the compiler does not know how to compare one Person with another. Doh! So lets add Ordered[Person] to Person to tell the compiler how to judge people :)
          case class Person(firstName: String, lastName: String, dateOfBirth: DateTime) 
              extends Ordered[Person]
            { 
              override def toString() = {
                firstName + ", " + lastName + " " + DateTimeFormat.shortDate().print(dateOfBirth);
              }
              def compare(otherPerson: Person) = {
                lastName.compareTo(otherPerson.lastName)
              }
            }
          
          And hey presto, same results as C#
          Alan, Kay 01/12/73
          Yukihiro, Matsumoto 01/12/90
          James, Gosling 01/12/91
          Anders, Hejlsberg 01/12/99
          Martin, Odersky 01/12/00
          Guido, Van Rossum 01/12/02
          
          James, Gosling 01/12/91
          Anders, Hejlsberg 01/12/99
          Alan, Kay 01/12/73
          Yukihiro, Matsumoto 01/12/90
          Martin, Odersky 01/12/00
          Guido, Van Rossum 01/12/02
          
          
          Well that was easy. But if you look at Scala sortWith compared to C# OrderBy, you realize that in Scala you have to say how to do a comparison, whereas in C# you say what thing to order by.
          Scala
            val peopleOrderedByDob = people.sortWith((p1,p2) => p1.dateOfBirth < p2.dateOfBirth) 
          C#
            var peopleOrderedByDob = people.OrderBy(person => person.DateOfBirth);
          
          When the Scala team saw that the C# version was shorter, and worse still, more functional than Scala's imperativeness, there was a great silence of the lambdas and then they recursed and recursed until they'd invented the entire Scala implicits system described well here and here. (Well maybe that wasn't quite how it happened...) So, very recently the sortBy method got added to the SeqLike trait as was kindly pointed out to me by Ismael Juma in an earlier post. So now we can write
          val peopleOrderedNaturallyWithSortBy = people.sortBy(person => person) 
            peopleOrderedNaturallyWithSortBy foreach println
            println    
          
          and this works fine. (Note that if you take the "extends Ordered[Person]" away from Person then "people.sortBy(person => person)" will not compile.) So how does it do it. Lets look at the signature of SortBy on the SeqLike trait.
          def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Repr
          
          I'm not sure what Repr is, but the "implicit ord: Ordering[B])" is a suitable "thing" that knows how to order a B. In our case a B is a Person, which is an Ordered[Person] but not an Ordering[Person]. But Ordering.scala contains a trait LowPriorityOrderingImplicits with an implicit def that know how to "upgrade" an Ordered[Person] to an Ordering[Person] "thing" and that is then passed to the sortBy method to be used to get-the-job-done-tm.

          My head is about to explode. If you followed that last paragraph well done. If you didn't then read the next one instead.

          Anyhow, the compiler inserts an "implicit" "thing" into the last parameter of the sortBy method. And that "implicit" "thing" knows how to order people about into neat lines. It just works.

          So what about ordering by say firstName?
          val peopleOrderedByDobWithSortBy = people.sortBy(person => person.firstName) 
              peopleOrderedNaturallyWithSortBy foreach println
              println 
          
          Well that works fine. Turns out its because there is a whole stack of implicit object defs in Ordering.scala that provide instances of Ordering traits for the basic value types like String and Int etc.

          So what about ordering by say dateOfBirth?
          val peopleOrderedByDobWithSortBy = people.sortBy(person => person.dateOfBirth) 
              peopleOrderedNaturallyWithSortBy foreach println
              println    
          
          It doesn't compile at line 2: "type arguments [org.scala_tools.time.imports.DateTime] do not conform to method ordered's type parameter bounds [A <: Ordered[A]]". Silly me, bah humbug! Its because a org.joda.time.DateTime isn't an Ordered[DateTime]. Now Scala-Time uses the pimp-my-library technique to upgrade org.joda.time.DateTime to RichDateTime, so we can try changing Scala-Time's RichDateTime to
          class RichDateTime(val underlying: DateTime) extends Ordered[RichDateTime]  {
            def compare(y: RichDateTime): Int = {
              return underlying.compareTo(y.underlying)
            }
            ...
          
          but that still doesn't compile "people.sortBy(person => person.dateOfBirth)" because, the compiler is not "upgrading" DateTime to RichDateTime.
          But we can say:
          val peopleOrderedByDobWithSortBy = people.sortBy(person => RichDateTime(person.dateOfBirth)) 
          
          but thats not very pretty. So what's the answer? Put in an implicit object that knows how to order DateTime.
          implicit object DateTimeOrderingObject extends Ordering[DateTime] {
            def compare(x: DateTime, y: DateTime) = x.compareTo(y)
          } 
          
          That definition should live in the Scala-Time library, but for now, it can be in my program. Now this will compile:
          val peopleOrderedByDobWithSortBy = people.sortBy(person => person.dateOfBirth) 
          
          and the code works.

          But now for something scary. If I accidentally import this definition from some library that I happen to be using
          implicit object SomeOtherPersonOrderingObjectInadvertentlyImported extends Ordering[Person] {
          def compare(p1: Person, p2: Person) = 
          (p1.firstName+p1.lastName).compareTo(p2.firstName+p2.lastName)
          }
          
          Then my code breaks because the people are printed in a different order. The code still compiles, but I get the SomeOtherPersonOrderingObjectInadvertentlyImported object used to do the sorting of the People instead of People's normal ordering.

          If People line up in the wrong order then nobody cares, but lets call that class StocksToShortRightNow instead. Bang goes my Christmas bonus!

          I hope I am somehow wrong here, and this is a bug or I am thinking about this the wrong way. But it makes me nervous.

          Here is the complete code with the scary implicit commented out.

          import org.scala_tools.time.Imports._
          
          object TestSortBy {
            case class Person(firstName: String, lastName: String, dateOfBirth: DateTime) 
              extends Ordered[Person]
            { 
              override def toString() = {
                firstName + ", " + lastName + " " + DateTimeFormat.shortDate().print(dateOfBirth);
              }
              def compare(otherPerson: Person) = {
                lastName.compareTo(otherPerson.lastName)
              }
            }
          
            // Comment this is and watch the behaviour change. This could be imported accidentally
            // implicit object SomeOtherPersonOrderingObjectInadvertentlyImported 
            //   extends Ordering[Person] {
            //   def compare(p1: Person, p2: Person) =
            //    (p1.firstName+p1.lastName).compareTo(p2.firstName+p2.lastName)
            // }
          
            
            implicit object DateTimeOrderingObject extends Ordering[DateTime] {
               def compare(x: DateTime, y: DateTime) = x.compareTo(y)
            }
            
            def main(args : Array[String]) : Unit = {
              
              val people = 
                Person("Alan", "Kay", new DateTime(1973,12,1,0,0,0,0))::
                Person("James", "Gosling", new DateTime(1991,12,1,0,0,0,0))::
                Person("Anders", "Hejlsberg", new DateTime(1999,12,1,0,0,0,0))::
                Person("Martin", "Odersky", new DateTime(2000,12,1,0,0,0,0))::
                Person("Guido", "Van Rossum", new DateTime(2002,12,1,0,0,0,0))::
                Person("Yukihiro", "Matsumoto", new DateTime(1990,12,1,0,0,0,0))::Nil
              
              val peopleOrderedByDob = people.sortWith((p1,p2) => p1.dateOfBirth < p2.dateOfBirth) 
              peopleOrderedByDob foreach println
              println
              
              val peopleOrderedNaturally = people.sortWith((p1,p2) => p1 < p2) 
              peopleOrderedNaturally foreach println
              println
          
              val peopleOrderedNaturallyWithSortBy = people.sortBy(person => person) 
              peopleOrderedNaturallyWithSortBy foreach println
              println    
          
              val peopleOrderedByDobWithSortBy = people.sortBy(person => person.dateOfBirth) 
              peopleOrderedNaturallyWithSortBy foreach println
              println    
          
          
            }
          
          }
          

          [Update: 2009-11-05]
          I posted a question about the SomeOtherPersonOrderingObjectInadvertentlyImported overriding the Person extends Ordered[Person] natural ordering. Here is Martin Odersky's response:
          Implicits that are explicitly declared or imported take precedence over implicits that come with the type. Btw you can find out what implicits are inserted by running scalac with option -Xprint:typer. This will print out the tree after type checking.

          Tuesday, 3 November 2009

          Using arithmetic expressions with Option[..] in Scala

          Fire and motion: Here is how it works. You fire at the enemy. That's the fire part. And you move forward at the same time. That's the motion. Get it?

          Scala's answer to the "null" that everybody loves to hate is to use is the Option[T] types. The Option thing is described here in section "Option, Some, and None: Avoiding nulls".
          Despite all the waffle, Option types are simple. A variable called v of class Option[Int] can have a value of either None or Some(123) where 123 is an example of the underlying value you actually care about. The value None is a real value, rather than an invalid reference as null is in Java or C#. If I want to test is whether v is None I can say v==None or v.isDefined() or !v.isEmpty(). If I want its value 123, I say v.getOrElse(0) where 0 is a default if its None. Easy. Or I can use a patten match. Easy too.

          A scenario I hit was doing various bits of arithmetic with stock prices. Now a stock price may not exists on a given date. But I may still want to write the code to try to do some calculation with the price. In Java I probably use a lot of null checks or set the price to a special value early on or something. C# gives you Nullable types which lets you say
          double? price1 = null;
          double? ratio1 = 0.7;
          double? result = ratio1 * price1; // or some other complex expression
          Console.Write("{0,7:N2}", result);
          
          In C#, if either price1 or ratio1 is null then result is null. The operators == and != do the right thing. Comparison using < and > requires a little care.

          So how do I do this in Scala? Well, if the Option type is what we are supposed to use then lets do it.
          val price1:Option[Double] = None
            val ratio1:Option[Double] = Some(0.7)
            val result:Option[Double] = price1 * ratio1
            printf("%7.2f", result getOrElse -99999.99)
          
          but line 3 does not compile because * is not a member of Option[Double].
          So a bit of googling and I find this clever-but-obscure trick:
          val result = 
              for (ratio1_alias <- ratio1; price1_alias <- price1)
              yield ratio1_alias * price1_alias 
          
          It seems that you can iterate over an Option[..]: Its a sequence of either zero (for the None case) or one element (for the Some(123.0) case). The expression returns None if anything is None or Some(ratio1_alias * price1_alias) if not. Tricksy stuff. It works but boy does it suck from a readability point of view. Oh and all the vals need to be aliased. Can I have my C# nullable types back please? So after a question on the Scala-User mailing list "Rex Kerr-2" suggested using the pimp-my-library techique to add functionality to the Option[Double] class, by "upgrading" it to a RichOptionDouble to which I can add arithmetic operators. So I ended up with the non-generic (but simple and, better still, working) code:
          package org.scala_tools.option.math
          class RichOptionDouble(od:Option[Double]) extends Ordered[Option[Double]] {
            def +(o:Option[Double]) = if (o==None) o else Some(numeric.plus(od.get,o.get))
            def unary_-():Option[Double] = Some(-od.get) 
            def -(o:Option[Double]) = if (o==None) o else Some(od.get-o.get)
            def *(o:Option[Double]) = if (o==None) o else Some(od.get*o.get)
            def /(o:Option[Double]) = if (o==None) o else Some(od.get/o.get)
            def compare(y: Option[Double]): Int = {
              if (od.isEmpty) return if (y.isEmpty) 0 else 1 
              if (y.isEmpty) return -1 
              // This is what Scala RichDouble does
              return java.lang.Double.compare(od.getOrElse(0d), y.getOrElse(0d))
            }
          }
          
          object RichOptionDoubleNone extends RichOptionDouble(None) { 
            override def +(o:Option[Double]) = None
            override def unary_-() = None
            override def -(o:Option[Double]) = None
            override def *(o:Option[Double]) = None
            override def /(o:Option[Double]) = None
          }
          
          trait Implicits {
            implicit def optiondouble2richoptiondouble(od:Option[Double]) = {
              if (od==None) RichOptionDoubleNone else new RichOptionDouble(od)
            }
            implicit def double2optiondouble(d:Double) = Some(d)
            implicit def int2optiondouble(i:Int) = Some(i.toDouble) 
            implicit def double2richoptiondouble(d:Double) = new RichOptionDouble(Some(d)) 
            implicit def int2richoptiondouble(i:Int) = new RichOptionDouble(Some(i.toDouble)) 
          }
          
          // Modelled on technique in Scala-Time
          object Imports extends Implicits
          
          So now I can say:
          import org.scala_tools.option.math.Imports._  
           
          object Bar {
            def main(args : Array[String]) : Unit = {
              val price1 = None
              val price2 = Some(123.45)
              val ratio1 = Some(0.7)
              val result1 = price1 * ratio1
              val result2 = price2 * ratio1 / 2 + 7.0
              printf("%7.2f", result1 getOrElse -99999.99)
              printf("%7.2f", result2 getOrElse -99999.99) 
              printf(" %s\n", result1 > result2) 
            }
          }
          
          Which prints
          -99999.99  86.41 true
          

          Not ground breaking stuff. But still nice to get there in the end. It feels something like this (probably in generic form) should be in the core libraries,