static L<CreatedDeletedChanged<ConceptShadow>> diffConceptShadows(L<ConceptShadow> l1, L<ConceptShadow> l2) {
  new L<CreatedDeletedChanged<ConceptShadow>> diffs;
  int i1 = 0, i2 = 0;
  while (i1 < l(l1) && i2 < l(l2)) {
    ConceptShadow s1 = l1.get(i1), s2 = l2.get(i2);
    long id1 = s1.id(), id2 = s2.id();
    if (id1 < id2) {
      diffs.add(new CreatedDeletedChanged.Deleted(s1));
      ++i1;
    } else if (id1 > id2) {
      diffs.add(new CreatedDeletedChanged.Created(s2));
      ++i2;
    } else {
      if (!eq(s1, s2))
        diffs.add(new CreatedDeletedChanged.Changed(s1, s2));
      ++i1;
      ++i2;
    }
  }
  while (i1 < l(l1))
    diffs.add(new CreatedDeletedChanged.Deleted(l1.get(i1++)));
  while (i2 < l(l2))
    diffs.add(new CreatedDeletedChanged.Created(l2.get(i2++)));
  ret diffs;
}