text:
package org.platanios.tensorflow.api.ops

import org.platanios.tensorflow.api.core.exception.InvalidDataTypeException
import org.platanios.tensorflow.api.ops
import org.platanios.tensorflow.api.ops.control_flow.{Context, ControlFlow, GradientState}
import org.platanios.tensorflow.api.types._
import org.platanios.tensorflow.jni.{Graph => NativeGraph, Output => NativeOutput}

import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory

import scala.collection.mutable

/**
  * @author Emmanouil Antonios Platanios
  */
private[ops] object Gradients {
  val logger = Logger(LoggerFactory.getLogger("Gradients"))

  private[ops] trait API {
    val Gradients        : ops.Gradients.type          = ops.Gradients
    val GradientsRegistry: ops.Gradients.Registry.type = ops.Gradients.Registry
  }

  // TODO: [API] Expose in "tf".
  // TODO: [DOC] Document the "gradients" function.
  def gradients(
      ys: Seq[Output],
      xs: Seq[Output],
      dys: Seq[OutputLike] = null,
      gateGradients: Boolean = false,
      aggregationMethod: AggregationMethod = AddAggregationMethod,
      colocateGradientsWithOps: Boolean = false,
      name: String = "Gradients"
  ): Seq[OutputLike] = Op.currentGraph.synchronized {
    // The `accumulatedGradients` variable collects the gradients received on each output endpoint of the op. The
    // gradients for each endpoint are initially collected as a sequence. When it is time to call the op's gradient
    // function, for each endpoint we aggregate the list of received gradients into a "add" operation, if there is more
    // than one.
    val accumulatedGradients = mutable.Map.empty[Op, mutable.Seq[Seq[OutputLike]]]

    val ops = ys.map(_.op).toSet ++ xs.map(_.op).toSet ++ (if (dys != null) dys.map(_.op).toSet else Set.empty)
    Op.createWithNameScope(name, ops) {
      // Get a UID for this call to gradients that can be used to help cluster ops for compilation.
      val gradientUID = Op.currentGraph.uniqueName("GradientUID")

      // The approach we take here is as follows: Create a list of all ops in the sub-graph between the ys and xs. Visit
      // these ops in reverse order of ids to ensure that when we visit an op the gradients with respect to its outputs
      // have been collected. Then, aggregate these gradients if needed, call the op's gradient function, and add the
      // generated gradients to the gradients for its input.

      // Initialize the pending counts for ops in the connected sub-graph between the ys and xs.
      val sourceOps = xs.map(_.op).toSet
      val destinationOps = {
        if (ys.lengthCompare(1) > 0)
          ys.map(y => if (y.consumers.nonEmpty) Basic.identity(y).op else y.op).toSet
        else
          ys.map(_.op).toSet
      }

      // `pendingCounts(op)` is a count-down counter for the expected gradients to accumulate for `op`. When
      // `pendingCounts(op)` becomes zero, we have collected all the backpropagation gradients for all outputs of `op`.
      val (pendingCounts, controlFlowGradientState) = initialPendingCounts(
        sourceOps, destinationOps, colocateGradientsWithOps)

      // `readyOps` keeps track of ops that have been completely processed. We initialize it with the destination ops.
      // We filter the destination ops based on whether one output gradient relies on another output's gradient.
      val readyOps = mutable.Queue[Op](destinationOps.filter(pendingCounts.getOrElse(_, 0) == 0).toSeq: _*)

      // Add the initial gradients for the ys.
      val dyInitial = initialGradients(ys, dys, colocateGradientsWithOps, gradientUID)
      for ((y, dy) <- (ys, dyInitial).zipped)
        setGradient(accumulatedGradients, y, dy)

      controlFlowGradientState.foreach(state => {
        state.processUnusedLoopExits(pendingCounts, destinationOps).filter(isTrainable).foreach(loopExit => {
          setGradient(accumulatedGradients, loopExit, state.zerosLikeForExit(loopExit))
          readyOps.enqueue(loopExit.op)
        })
      })

      // Stop ops form the frontier of the forward graph before which back-propagation should stop. Ops in this set will
      // not be differentiated. This set is defined as the subset of `sourceOps` containing ops that have no predecessor
      // in `sourceOps`. An op has predecessors in `sourceOps` if and only if `pendingCounts(op) > 0`.
      val stopOps = sourceOps.filter(_.inputs.forall(i => pendingCounts.getOrElse(i.op, 0) <= 0))

      while (readyOps.nonEmpty) {
        val op = readyOps.dequeue()
        maybeColocateWith(op, colocateGradientsWithOps, gradientUID) {
          controlFlowGradientState.foreach(_.enterGradientWhileLoopContext(op, before = true))
          val opGradients = aggregationMethod.aggregateGradients(accumulatedGradients, op, gradientUID)
          controlFlowGradientState.foreach(_.exitGradientWhileLoopContext(op, before = true))
          val hasOutputGradients = opGradients.nonEmpty
          val gradientFunction: Registry.GradientFunction = {
            if (hasOutputGradients && !stopOps.contains(op)) {
              Registry(op.opType)
            } else {
              null
            }
          }

          controlFlowGradientState.foreach(_.enterGradientWhileLoopContext(op, before = false))
          if (hasOutputGradients && gradientFunction != null) {
            // Note that, the gradient aggregation not computing a value for the i'th output, means that the cost does
            // not depend on output i and therefore the gradient with respect to that output is 0.
            for ((gradient, outputIndex) <- opGradients.zipWithIndex) {
              // Only floating-point outputs get a zero gradient. Gradient functions should ignore the gradient for
              // other outputs.
              val output = op.outputs(outputIndex)
              if (gradient.isEmpty && isTrainable(output))
              // TODO: !!! [GRADIENTS] Gradients of resource handles might be an issue here because of the zeros.
                opGradients(outputIndex) = Seq({
                  controlFlowGradientState
                      .map(_.zerosLike(op, outputIndex))
                      .getOrElse(Some(Context.zerosLikeOutsideLoop(op, outputIndex)))
                      .orNull
                })
            }

            // Compute the actual op gradients.
            Op.createWith(nameScope = s"${op.name}Gradient") {
              // TODO: [CONTEXT] Add support for original op context.
              val outputGradients = opGradients.map(_.headOption.orNull)
              var inputGradients = maybeCompile(name, op, () => gradientFunction(op, outputGradients))
              if (gateGradients && inputGradients.count(_ != null) > 1) {
                Op.createWith(device = null) {
                  Op.colocateWithForGradient(Set.empty[Op], Some(gradientUID), ignoreExisting = true) {
                    inputGradients = ControlFlow.tuple(inputGradients.toArray).toSeq
                  }
                }
              }
              val nInp = op.inputs.length
              val nGrd = inputGradients.length
              assert(nInp == nGrd, s"Gradients size ($nGrd) for op '$op' does not match inputs size ($nInp).")
              logGradients(op, outputGradients, inputGradients)
              // TODO: Report somehow the non-differentiable ops in the graph. This is currently hard to debug.
              op.inputs.zip(inputGradients).filter(_._2 != null).foreach(i => {
                i._2 match {
                  case gradient: Output if i._1.dataType != RESOURCE => gradient.setShape(i._1.shape)
                  case _ =>
                }
                setGradient(accumulatedGradients, i._1, i._2)
              })
            }
          }
          controlFlowGradientState.foreach(_.exitGradientWhileLoopContext(op, before = false))
        }

        // Update the pending counts for the inputs of `op` and enqueue ready ops.
        op.inputs.foreach(input => {
          pendingCounts.update(input.op, pendingCounts.getOrElse(input.op, 0) - 1)
          var ready = pendingCounts(input.op) == 0
          if (!ready)
            controlFlowGradientState.foreach(_ => {
              ready = pendingCounts(input.op) > 0 && ControlFlow.isLoopSwitch(input.op)
            })
          if (ready) {
            if (ControlFlow.isLoopExit(input.op)) {
              // If `input` is an exit without real gradient, defer processing them.
              controlFlowGradientState.flatMap(_.getGradientLoopState(input.op, before = false)).foreach(state => {
                state.deferredExits += input
                state.pendingExitsCount -= 1
                if (state.pendingExitsCount == 0) {
                  // We now have all the exits and so we process them.
                  var hasRealGradient = false
                  state.deferredExits.foreach(exit => {
                    if (accumulatedGradients.get(exit.op).exists(_.exists(_.exists(_ != null)))) {
                      hasRealGradient = true
                      readyOps.enqueue(exit.op)
                    } else {
                      state.unusedExits += exit
                    }
                  })
                  if (hasRealGradient) {
                    // For an unused exit, if it has floating-point outputs, we back-propagate a zero gradient.
                    // Otherwise, we just ignore it.
                    state.unusedExits.foreach(exit => {
                      if (isTrainable(exit))
                        setGradient(accumulatedGradients, exit, controlFlowGradientState.get.zerosLikeForExit(exit))
                      readyOps.enqueue(exit.op)
                    })
                  } else {
                    // All exits are "unused" and so we use `null` as the gradient.
                    state.unusedExits.foreach(exit => readyOps.enqueue(exit.op))
                  }
                }
              })
            } else {
              readyOps.enqueue(input.op)
            }
          }
        })
      }

      controlFlowGradientState.foreach(_.postProcess())
    }

    // Collect the aggregated gradients for the requested tensors and return them.
    xs.map(x => {
      val gradients = accumulatedGradients.get(x.op).map(_.apply(x.index))
      if (gradients.isDefined && gradients.get.lengthCompare(1) > 0)
        throw new IllegalArgumentException("The gradients should have been aggregated by now.")
      gradients.map(_.head).orNull
    })
  }

  /** If `colocateGradientsWithOps` is `true`, then all ops created within `block` will be colocated with `op`.
    *
    * @param  op                       Op to maybe colocate with.
    * @param  colocateGradientsWithOps Boolean value indicating whether to colocate the gradient ops with the original
    *                                  ops.
    * @param  gradientUID              Unique identifier within the graph indicating which invocation of gradients is
    *                                  being executed. Used to cluster ops for compilation.
    * @param  block                    Block of code to execute using the specified colocation ops.
    * @return Return value of `block`.
    */
  private[this] def maybeColocateWith[R](
      op: Op,
      colocateGradientsWithOps: Boolean,
      gradientUID: String
  )(block: => R): R = {
    if (colocateGradientsWithOps)
      Op.colocateWithForGradient(Set(op), Some(gradientUID))(block)
    else
      block
  }

  // TODO: [FUNCTIONAL] Symbolic gradient ('_SymGrad').

  /** If the op was marked as compiled, this function compiles the calculation in `gradientFunction` (using XLA) and
    * returns the result of `gradientFunction`. Otherwise, it simply returns the result of `gradientFunction`.
    *
    * @param  nameScope        Name scope to use for the gradient ops.
    * @param  op               Op whose gradients are being computed.
    * @param  gradientFunction Function that computes the gradients for `op`.
    * @return Created gradients op.
    */
  private[this] def maybeCompile(
      nameScope: String,
      op: Op,
      gradientFunction: () => Seq[OutputLike]
  ): Seq[OutputLike] = {
    // TODO: [FUNCTIONAL] Add extra 'func' argument.
    val cleanNameScope = nameScope.stripSuffix("/").replace('/', '_')
    try {
      val xlaCompile = op.booleanAttribute("_XlaCompile")
      if (!xlaCompile) {
        gradientFunction() // Exit early
      } else {
        val xlaSeparateCompileGradient = op.booleanAttribute("_XlaSeparateCompiledGradients")
        val xlaScope = op.stringAttribute("_XlaScope")
        // If the gradients are supposed to be compiled separately, we give them an '_XlaScope' name that is based on
        // the name_scope of the gradients. Otherwise, they just inherit the existing '_XlaScope' name, which lets them
        // be merged together with the non-gradient computation.
        val xlaGradientsScope = if (xlaSeparateCompileGradient) s"${xlaScope}_grad_$cleanNameScope" else xlaScope
        Op.createWith(attributes = Map("_XlaCompile" -> xlaCompile, "_XlaScope" -> xlaGradientsScope)) {
          gradientFunction()
        }
      }
    } catch {
      case _: IllegalArgumentException => gradientFunction() // Something went wrong and so we exit
    }
  }

  /** Returns a boolean value indicating whether the data type of `tensor` is trainable. This means whether its
    * gradients can be computed. */
  private[this] def isTrainable(tensor: OutputLike): Boolean = {
    Set[DataType](FLOAT16, FLOAT32, FLOAT64, COMPLEX64, COMPLEX128).contains(tensor.dataType)
  }

  /** Computes initial values for the provided gradients, and checks whether their data types are correct.
    *
    * @param  ys                       Sequence containing the variables corresponding to `dys`.
    * @param  dys                      Sequence containing tensor gradients.
    * @param  colocateGradientsWithOps Boolean value indicating whether to colocate the gradient ops with the original
    *                                  ops.
    * @param  gradientUID              Unique identifier within the graph indicating which invocation of gradients is
    *                                  being executed. Used to cluster ops for compilation.
    * @return Sequence containing the default gradient values.
    * @throws InvalidDataTypeException If the gradient tensor data types are not compatible with the input data types.
    */
  @throws[InvalidDataTypeException]
  private[this] def initialGradients(
      ys: Seq[OutputLike],
      dys: Seq[OutputLike],
      colocateGradientsWithOps: Boolean,
      gradientUID: String = "__unsupported__"
  ): Seq[OutputLike] = {
    ys.zip(if (dys != null) dys else Seq.fill[OutputLike](ys.length)(null)).zipWithIndex.map {
      case ((y, dy), index) =>
        if (dy == null) {
          if (y.dataType.isComplex)
            throw InvalidDataTypeException(
              s"Gradients of complex tensors must set 'gradients' (variable.dataType = '${y.dataType}').")
          maybeColocateWith(y.op, colocateGradientsWithOps, gradientUID) {
            y match {
              case o: Output => Basic.onesLike(o, name = s"Gradients_$index")
              case o: OutputIndexedSlices =>
                if (o.denseShape == null)
                  throw new IllegalArgumentException(
                    "The dense shape of output indexed slices must be known in order to obtain their gradients.")
                Basic.ones(o.dataType, o.denseShape, name = s"Gradients_$index")
              case o: SparseOutput =>
                Basic.ones(o.dataType, o.denseShape, name = s"Gradients_$index")
            }
          }
        } else {
          if (y.dataType.isFloatingPoint || y.dataType.isInteger) {
            if (!dy.dataType.isFloatingPoint && !dy.dataType.isInteger)
              throw InvalidDataTypeException(
                s"Gradient data type '${dy.dataType}' generated for real or integer-valued tensor '$y' with data type " +
                    s"'${y.dataType}' must be real or integer.")
          } else if (y.dataType.isComplex) {
            if (!dy.dataType.isComplex)
              throw InvalidDataTypeException(
                s"Gradient data type '${dy.dataType}' generated for complex-valued tensor '$y' with data type " +
                    s"'${y.dataType}' must be complex.")
          } else {
            throw InvalidDataTypeException(
              s"Tensor '$y' with data type '${y.dataType}' must be numeric in order to obtain a default gradient.")
          }
          // Create a gradients tensor in the name scope of the gradients. This is required in order for tensor arrays
          // to identify which gradient call a gradient value is coming from.
          dy match {
            case o: Output => Basic.identity(o, name = s"Gradients_$index")
            case o: OutputIndexedSlices =>
              OutputIndexedSlices(
                Basic.identity(o.indices, name = s"Gradients_${index}_Indices"),
                Basic.identity(o.values, name = s"Gradients_${index}_Values"),
                if (o.denseShape == null)
                  o.denseShape
                else
                  Basic.identity(o.denseShape, name = s"Gradients_${index}_DenseShape"))
            case o: SparseOutput =>
              SparseOutput(
                Basic.identity(o.indices, name = s"Gradients_${index}_Indices"),
                Basic.identity(o.values, name = s"Gradients_${index}_Values"),
                if (o.denseShape == null)
                  o.denseShape
                else
                  Basic.identity(o.denseShape, name = s"Gradients_${index}_DenseShape"))
          }
        }
    }
  }

  /** Initializes the back-propagation input counts for ops between two sets of ops.
    *
    * 'outputMap(op)' indicates the number of back-propagation inputs to this op.
    *
    * @param  sourceOps                Set of source ops.
    * @param  destinationOps           Set of destination ops.
    * @param  colocateGradientsWithOps Boolean value indicating whether to colocate the gradient ops with the original
    *                                  ops.
    * @return Tuple containing: (1) Map from op to the number of back-propagation inputs to this op, and (2) a control
    *         flow gradient state object which is not `None` if the ops between `sources` and `destinations` contain
    *         control flow loops.
    */
  private[this] def initialPendingCounts(
      sourceOps: Set[Op],
      destinationOps: Set[Op],
      colocateGradientsWithOps: Boolean
  ): (mutable.Map[Op, Int], Option[GradientState]) = {
    // Mark ops reached when going from 'sources' to 'destinations'
    val reached = mutable.Set[Op](destinationOps.toSeq: _*)
    val reachedQueue = mutable.Queue[Op](sourceOps.toSeq: _*)
    while (reachedQueue.nonEmpty) {
      val op = reachedQueue.dequeue()
      if (!reached.contains(op)) {
        reached += op
        op.outputs.foreach(o => reachedQueue.enqueue(o.consumers.map(_.op): _*))
      }
    }

    // Mark ops between 'sources' and 'destinations'
    val between = mutable.Set.empty[Op]
    // TODO: [CONTROL_FLOW] Do we need the list aside from the set?
    val betweenList = mutable.ListBuffer.empty[Op]
    val betweenQueue = mutable.Queue[Op](destinationOps.toSeq: _*)
    while (betweenQueue.nonEmpty) {
      val op = betweenQueue.dequeue()
      if (reached.contains(op)) {
        between += op
        betweenList += op
        reached -= op // Done so we don't go through the same ops twice
        op.inputs.foreach(i => betweenQueue.enqueue(i.op))
      }
    }

    // `controlFlowGradientState` is `None` if there are no while loops.
    val controlFlowGradientState = GradientState.maybeCreate(between, betweenList, colocateGradientsWithOps)

    // Initialize the pending counts for the between ops
    val pendingCounts = mutable.Map.empty[Op, Int]
    betweenList.flatMap(_.inputs).map(_.op).filter(between.contains).foreach(input => {
      pendingCounts.update(input, pendingCounts.getOrElse(input, 0) + 1)
    })

    (pendingCounts, controlFlowGradientState)
  }

  /** Adds the provided `gradient` to the sequence of `output`'s gradients that have been collected so far.
    *
    * @param  gradients Map where the collected gradients are stored.
    * @param  output    Op output whose gradient is provided.
    * @param  gradient  Gradient of `output` to add to the collected gradients.
    */
  private[this] def setGradient(
      gradients: mutable.Map[Op, mutable.Seq[Seq[OutputLike]]],
      output: Output,
      gradient: OutputLike
  ): Unit = {
    val opGradients = gradients.getOrElseUpdate(
      output.op, mutable.Seq(output.op.outputs.map(_ => Seq.empty[OutputLike]): _*))
    if (ControlFlow.isLoopSwitch(output.op))
      opGradients(output.index) = Seq(gradient)
    else
      opGradients(output.index) :+= gradient
  }

  /** Logs the input and output gradients of the provided op.
    *
    * @param  op              Op.
    * @param  outputGradients Output gradients of op.
    * @param  inputGradients  Input gradients of op.
    */
  private[this] def logGradients(op: Op, outputGradients: Seq[OutputLike], inputGradients: Seq[OutputLike]): Unit = {
    logger.debug(s"Gradients for op '${op.name}':")
    logger.debug(s"  in  --> ${outputGradients.filter(_ != null).map(_.name).mkString(", ")}")
    logger.debug(s"  out --> ${inputGradients.filter(_ != null).map(_.name).mkString(", ")}")
  }

  sealed trait GatingMethod
  object NoGating extends GatingMethod
  object OpGating extends GatingMethod
  object GraphGating extends GatingMethod

  /** Aggregation method used to combine gradients.
    *
    * Computing partial derivatives can require aggregating gradient contributions. All such aggregation methods are
    * represented as objects extending this trait.
    */
  sealed trait AggregationMethod {
    /** Aggregate the gradients for op `op`.
      *
      * @param  gradients   Map where the collected gradients are stored. The gradient sequences corresponding to `op`
      *                     will be replaced with sequences containing a single element corresponding to the aggregated
      *                     gradient.
      * @param  op          Op whose gradients to aggregate.
      * @param  gradientUID Unique identifier within the graph indicating which invocation of gradients is being
      *                     executed. Used to cluster ops for compilation.
      */
    private[Gradients] def aggregateGradients(
        gradients: mutable.Map[Op, mutable.Seq[Seq[OutputLike]]],
        op: Op,
        gradientUID: String
    ): mutable.Seq[Seq[OutputLike]] = {
      val opGradients = gradients.getOrElse(op, mutable.Seq.empty[Seq[OutputLike]])
      if (ControlFlow.isLoopSwitch(op)) {
        opGradients
      } else {
        opGradients.zipWithIndex.foreach {
          case (grads, index) =>
            if (grads.length < 2) {
              grads
            } else {
              opGradients(index) = Seq[OutputLike](aggregateGradients(grads.filter(_ != null), gradientUID))
            }
        }
        opGradients
      }
    }

    /** Aggregates the gradients in `gradient` into a single gradient tensor.
      *
      * @param  gradients   Sequence of gradients to aggregate.
      * @param  gradientUID Unique identifier within the graph indicating which invocation of gradients is being
      *                     executed. Used to cluster ops for compilation.
      * @return Aggregated gradient tensor.
      */
    private[Gradients] def aggregateGradients(gradients: Seq[OutputLike], gradientUID: String): OutputLike
  }

  /** Gradient aggregation method that simply adds up the collected gradients. */
  object AddAggregationMethod extends AggregationMethod {
    override private[Gradients] def aggregateGradients(gradients: Seq[OutputLike], gradientUID: String): OutputLike = {
       if (gradients.forall(_.isInstanceOf[Output])) {
        // This function adds op outputs from potentially different devices.
        // We add the tensors of each device separately first, and we then add up the partial results.
        val deviceContributions = gradients.groupBy(_.device).toSeq.sortBy(_._1).map {
          case (_, outputs) =>
            Op.colocateWithForGradient(Set[Op](gradients.head.op), Some(gradientUID), ignoreExisting = true) {
              Math.addN(outputs.map(_.asInstanceOf[Output]))
            }
        }
        Math.addN(deviceContributions)
      } else if (gradients.forall(_.isInstanceOf[OutputIndexedSlices])) {
         def addNOutputIndexedSlices(gradients: Seq[OutputIndexedSlices]): OutputIndexedSlices = {
           if (gradients.isEmpty) {
             throw new IllegalArgumentException(
               "Can not aggregate empty gradients list.")
           } else if (gradients.length == 1) {
             gradients.head
           } else {
             OutputIndexedSlices(
               Basic.concatenate(gradients.map(_.indices)),
               Basic.concatenate(gradients.map(_.values)),
               gradients.head.denseShape)
           }
         }
         val deviceContributions = gradients.groupBy(_.device).toSeq.sortBy(_._1).map {
           case (_, outputs) =>
             Op.colocateWithForGradient(Set[Op](gradients.head.op), Some(gradientUID), ignoreExisting = true) {
               addNOutputIndexedSlices(outputs.map(_.asInstanceOf[OutputIndexedSlices]))
             }
         }
         addNOutputIndexedSlices(deviceContributions)
      } else {
        throw new IllegalArgumentException(
          "The gradients being aggregated need to be all of type 'Output' or 'OutputIndexedSlices'.")
      }
    }
  }

  /** Gradient aggregation method that simply adds up the collected gradients, without first waiting for all of them to
    * become available at once.
    *
    * The benefit of using this method is that its inputs can be combined in any order and this can allow the expression
    * to be evaluated with a smaller memory footprint. With this method, it is possible to compute a sum of terms which
    * are much larger than total GPU memory.
    */
  object AccumulateAggregationMethod extends AggregationMethod {
    override private[Gradients] def aggregateGradients(gradients: Seq[OutputLike], gradientUID: String): OutputLike = {
      if (gradients.forall(_.isInstanceOf[Output])) {
        Math.accumulateN(gradients.map(_.asInstanceOf[Output]))
      } else if (gradients.forall(_.isInstanceOf[OutputIndexedSlices])) {
        def addNOutputIndexedSlices(gradients: Seq[OutputIndexedSlices]): OutputIndexedSlices = {
          if (gradients.isEmpty) {
            throw new IllegalArgumentException(
              "Can not aggregate empty gradients list.")
          } else if (gradients.length == 1) {
            gradients.head
          } else {
            OutputIndexedSlices(
              Basic.concatenate(gradients.map(_.indices)),
              Basic.concatenate(gradients.map(_.values)),
              gradients.head.denseShape)
          }
        }
        val deviceContributions = gradients.groupBy(_.device).toSeq.sortBy(_._1).map {
          case (_, outputs) =>
            Op.colocateWithForGradient(Set[Op](gradients.head.op), Some(gradientUID), ignoreExisting = true) {
              addNOutputIndexedSlices(outputs.map(_.asInstanceOf[OutputIndexedSlices]))
            }
        }
        addNOutputIndexedSlices(deviceContributions)
      } else {
        throw new IllegalArgumentException(
          "The gradients being aggregated need to be all of type 'Output' or 'OutputIndexedSlices'.")
      }
    }
  }

  /** Registry that contains the gradient functions to be used when creating gradient ops. Gradient functions for all
    * types of ops that are being differentiated need to be registered using either the [[Registry.register]] or the
    * [[Registry.registerNonDifferentiable]] functions. In an attempt to obtain the gradient of an op whose type has no
    * gradient function registered, a [[NoSuchElementException]] will be thrown. */
  object Registry {
    type GradientFunction = (Op, Seq[OutputLike]) => Seq[OutputLike]

    private[this] val registry = mutable.Map.empty[String, GradientFunction]

    /** Registers the provided gradient function to the gradient function registry.
      *
      * Note that if a gradient function for an op of the same type already exists in the registry, then it will be
      * overriden by the provided gradient function.
      *
      * @param  opType   Op type for which a gradient function is being registered.
      * @param  function Gradient function (takes op and output gradients as inputs and returns the input gradients).
      */
    def register(opType: String, function: GradientFunction): Unit = registry.update(opType, function)

    /** Registers the provided op type as non-differentiable (i.e., having `null` as its registered gradient function).
      *
      * This function should *not* be used for ops that have a well-defined gradient that is not yet implemented. It
      * should only be used when defining a new op type. It may be used for ops such as `size` that are not
      * differentiable.
      *
      * The gradient computed for 'opType' will then propagate zeros.
      *
      * For ops that have a well-defined gradient but are not yet implemented, no declaration should be made, and an error
      * *must* be thrown if an attempt to request their gradient is made.
      *
      * @param  opType Op type to register as non-differentiable.
      */
    def registerNonDifferentiable(opType: String): Unit = registry.update(opType, null)

    /** Gets the registered gradient function for the provided op type.
      *
      * @param  opType Op type whose gradient function is being looked up.
      * @return Gradient function registered for the provided op type.
      * @throws NoSuchElementException If no gradient has been registered for the provided op type.
      */
    @throws[NoSuchElementException]
    def apply(opType: String): GradientFunction = {
      if (!registry.contains(opType))
        throw new NoSuchElementException(s"No gradient registered for op type '$opType'.")
      registry(opType)
    }
  }

  /** Adds ops to the graph to compute the partial derivatives of the sum of `y`s with respect to the `x`s, using the
    * C++ gradients support of the TensorFlow native library.
    *
    * Note that the C++ gradients support of the TensorFlow native library is incomplete and will not be sufficient for
    * many use cases. It is mainly exposed as means of comparison to the Scala API functionality.
    *
    * The result of this function is an array containing: `d(y_1 + y_2 + ...)/dx_1`, `d(y_1 + y_2 + ...)/dx_2`, `...`.
    *
    * @param  y  Tensors whose partial derivatives are computed.
    * @param  x  Tensors with respect to which the gradients are computed.
    * @param  dx Tensors to use as the initial gradients. They represent the symbolic partial derivatives of some loss
    *            function `L` with respect to `y`. If `null`, then ones are used. The number of tensors in `dx` must
    *            match the number of tensors in `y`.
    * @return Partial derivatives of the `y`s given each one of the `x`s.
    */
  def ccGradients(y: Array[Output], x: Array[Output], dx: Array[Output] = null): Array[Output] = {
    // TODO: Overload this method with all possible uses for it.
    if (dx != null && dx.length != y.length)
      throw new IllegalArgumentException(s"The number of ys (${y.length}) must match the number of dxs (${dx.length}).")

    // Obtain the graph and verify that all provided op outputs are defined over the same graph
    val graph = y.head.graph
    y.foreach(o => Op.assertSameGraph(o.op, y.head.op))
    x.foreach(o => Op.assertSameGraph(o.op, y.head.op))
    if (dx != null)
      dx.foreach(o => Op.assertSameGraph(o.op, y.head.op))

    // Map all arrays to the corresponding data structures used by the JNI layer
    val yJNI = y.map(o => NativeOutput(o.op.nativeHandle, o.index))
    val xJNI = x.map(o => NativeOutput(o.op.nativeHandle, o.index))
    val dxJNI = if (dx == null) null else dx.map(o => NativeOutput(o.op.nativeHandle, o.index))

    // Add the gradients to the graph and collect them to the array that is returned
    val jniGradients = NativeGraph.addGradients(graph.nativeHandle, yJNI, xJNI, dxJNI)
    jniGradients.map(o => {
      val op = graph.opsCache.getOrElseUpdate(o.opHandle, Op(graph, o.opHandle))
      Output(op, o.outputIndex)
    })
  }
}


Would you recommend 21st Century Auto Insurance to your friends?
Where does 21st Century Auto Insurance do business?
21st Century Auto Insurance is an insurance carrier based in Wilmington, DE. The company was founded in 1958 and offers auto insurance in 2 states in the USA.
What types of auto insurance coverage does 21st Century Auto Insurance offer?
What benefits does 21st Century Auto Insurance offer?
What discounts can you ask for when applying for a policy with 21st Century Auto Insurance?
When you ask for a quote with 21st Century Auto Insurance, make sure you ask for all the discounts you qualify for. These are the discounts currently available that are specific to boat insurance.
Internal Safety Features: 21st Century Auto Insurance offers additional savings if you have seatbelts, airbags, and similar safety features. Ask what other safety features on your car will trigger a discount.
Want more discounts? Check the discounts tab for a full list of general policy discounts you can qualify for with 21st Century Auto Insurance.


text:
require 'time'
require 'json'
require 'jlo/version'
require 'jlo/json_event'

module J
  # Fancy alias for the formatter.
  def self.Lo
    JLo::JSONEvent
  end
end

redpajama_set_name: RedPajamaGithub


text:
Posts tagged 'Streets'
Two Gentlemen in Verona, Part II: The Gardens which Beguiled Us
It's funny. When I think back to my first encounter with Verona, some 17 years ago in the prime of my youth, touring from one art historical Italian treasure to another, I can remember very little of the city. I remember the balcony purported to be that of Shakespeare's fictional Juliet, and the street where I purchased my first Burberry scarf. I remember the relief which blue skies and a bustling living city afforded after 10 days or so ensconced in the fog-filled fantasy land of Venice. But I remember little of the stunning streets and grand piazzas which dominated this most recent reconnaissance with Verona. But of all the highlights I remember with absolute clarity, despite the passing of the years, it is the wonder of the Giardino Giusti, arguably the best Renaissance garden in all of Italy.
Just beyond the bustling centre, housed between the Mannerist walls of the Giusti palace and the higher hilltops of the upper gardens, the Giardino Giusti is a place of almost mystical quality. With perfectly trimmed box-hedge mazes and prim parterres punctuated by moss-covered statues from the ancient realms, the Giusti gardens is at once a Lewis Carroll wonderland as it is a perfect example of the Renaissance style. A sense of perfectly manicured order provided by sweeping central paths and cypress tree-bordering is yet tempered by the pure poetry which comes of patios lined by potted cypress trees and half-hidden structures such as the rose-pink colonnaded belvedere, which affords the most unbeatable view over the labyrinth of hedges and collections of ancient statuary.
In fact it was in that same belvedere where my fondest memory of Verona was born. There, in 2001 in the autumn sunshine, my friends and I picnicked on fresh pesto and salumi, with a little wine, and some recitals to accompany the scene. Is it possible to ever beat such epiphanaic perfection? I don't think I ever have. But this visit to the Giardino Giusti was just as I remembered it – a memory in no way diluted by the joy of my return, to a paradise garden which remains, for me, the highlight of any visit to Verona.
Two Gentlemen in Verona, Part I: The Streets which Ensnared Us
Don't accuse me of being repetitive. It's not my fault that Italy is such a beautiful country. But if I've gone on about the beauty of Rome, of Bologna, of Sicilia, of Siena, who can blame me? Charm oozes from their every cobble and paint-flaking wall, from the tolling of cathedral bells and the trickling of their ancient fountains. And now I have another stunner to add to the set of Italian cities which are quite frankly spectacular: Verona.
In fair Verona, where we lay our scene, two Gentlemen arrived in the golden light of a creamy sunset to an apartment overlooking the imposing walls of the ancient Roman arena, and knew that they had entered a new Elysium; a city perfectly compact but wide in impact, whose ancient charm extends far beyond the Renaissance but back to the splendid time of the Emperors, whose grand triumphal arches and magnificent arenas characterise the city to this day.
The city which ensnared William Shakespeare and inspired the greatest love story ever known has now caught these two Gentlemen inside it's luxurious web. But if we are prey to its abundance of good food, splendid piazzas, quaint little cobbled streets and cases of the most velvety Valpolicella wine, then I say: catch me web, I'm hanging around for more.
The Daily Norm's new Veronese adventure starts in the sumptuous streets which inject the city with such a cosmopolitan buzz. They are the pulsing veins which carry a continuous and energetic stream of lifeblood around a city whose very existence burns with the vivacity of an aperol spritz, but which conversely exudes something of the tranquility of a lazy Sunday everyday.
The ancient marble pavements which run throughout Verona have been polished to a fine gloss by the millions of feet who have trod them throughout history. In places you can even see grooves marked by carts over millennia of history. Today, those same shiny roads glitter with the veritable glow of cake-filled patisseries and chic fashion outlets. Verona is, after all, a city in which to see and be seen; where sparks of romance resonate everywhere as tourists and locals alike take inspiration from the fabled Romeo and his Juliet.
A trip to Verona doesn't require an itinerary. Just walk, explore, and waft amongst the little streets which wind like arteries across the packed historical core of this great city. From one end to another, your stroll will lead you to all the monuments and majestic sights any guidebook will require you to see. But in the meantime, the streets will give you the best Veronese experience of all: one of cafes and couture, of people perambulating and history unfurling.
This post is in made in homage to those wonderful streets of Verona. At points, of course, those streets widen into the most perfect of piazzas – the real gems around which they wind. But there's time yet for the piazzas, which will be explored in their turn.

redpajama_set_name: RedPajamaCommonCrawl


text:
2020 Review of canine dilated cardiomyopathy in the wake of diet-associated concerns
Dilated Cardiomyopathy in Leonberger Dogs.
In the summer of 2004, the Leonberger Club of Great Britain invited Dr Joanna Dukes-McEwan, ( BVMS, MVM, PhD, DVC, Dip. ECVIM-CA (Cardiology), MRCVS, RCVS and European Recognised Specialist in Veterinary Cardiology), to present a seminar on Dilated Cardiomyopathy for the benefit of club members. The event was generously hosted at the Guide Dogs for the Blind centre. The following is a summary of the discussion, drawn from a video recording done at the time. It has since been revised by Dr. Dukes-McEwan to bring it up to date.
This was the second time Dr Dukes-McEwan has made a presentation to the LCGB, the previous having been sometime in 1996.
Her work in DCM research was originally supported by the Kennel Club (1996-1999), with an initial focus on echocardiogram diagnosis. It then developed into looking at familial relations in the Newfoundland, as there were a number of cases then apparent to trace genealogies through. The British Heart Foundation also gave huge support, with three years funding (1999 – 2002), with a genome wide search for a marker linked to Newfie DCM. Unfortunately, the marker has not yet been discovered. Further funding from the Kennel Club and a researcher called Anje Wiersma (2004-5) looked at some candidate genes for Newfie DCM, but again, the gene or a marker has proved elusive!
The initial work started at the University of Edinburgh, but it has moved now to the University of Liverpool (since 2004).
DCM in Leonbergers:
The Leo Watch health survey (USA), dated 2002 showed 3% heart disease across all US Leonbergers. That survey showed DCM as the most common heart related cause of death in leos. There is also some incidence of congenital heart disease as well, but nowhere near as common as DCM. Dilated Cardiomyopathy is acquired during the lifetime of the dog and so often shows in older dogs. Overall, heart failure showed up as the cause of death in 9% of the respondants in this 2002 survey. A further 8% showed as suffering from so-called 'sudden death' with uncertain cause, and she suspects that a proportion of these may also be due to DCM.
What is DCM:
The disease is characterised by dilation and impaired contraction of the left or in some cases both ventricles. The heart is grossly enlarged, rounded and loses its form and firmness. It is a progressive condition. The condition affects hearts at a cellular level, causing individual muscle fibres to separate and take on a lax and 'wavy' appearance, with greatly increased fluid levels within them. In some breeds, such as Boxers and Dobermans, the cellular changes differ, in that they show a great deal of fibrous or fatty materials within the individual muscle cells. These fatty deposits actually begin to replace muscle tissues, separating the individual fibres, reducing their ability to function and often leading to sudden death. She does not know if this form is present in leos, but suggests that it should be looked for in post mortem examinations on those leos who suffer these unexplained, so-called 'sudden deaths'.
In Humans, DCM can be caused by a number of known factors. These include:
Coronary artery disease- if the vessels of the heart begin to 'fur up' with fatty deposits it can cause changes in the heart tissues themselves, causing them to become flabby and weak. This is probably the most common cause in humans.
Following some flu-like illnesses the heart muscles can be seen to change in ways similar to DCM. It is thought that this is either because of viral damage to the heart cells themselves, or through auto-immune response targeting viral affected cells. In either case, the cells are damaged, leading to expansion and impaired function.
Alcohol consumption can also cause dilation of the heart through depression of heart muscle function.
However, recent evidence (since 1992), indicates that in as many as 30% of human sufferers, DCM can be a genetic disease, with clear familial inheritance. In humans, there are thought to be at multiple possible modes of inheritance; Autosomal Dominant, x-linked, and Mitochondrial and Autosomal recessive. Most cases are autosomal dominant.
Dr. Dukes-McEwan then reviewed the specific efforts being undertaken to locate the mode of inheritance in humans, specifically which genes were being investigated, such as those that control the structural formation of each heart muscle cell. She then ran through an explanation of cellular anatomy.
In dogs, DCM has only really been recognised within the veterinary literature since the 1970s. Since most breeds are relatively recently evolved, (within the last 200 years), and since knowledge of pedigrees is now quite extensive, breed predisposition and familial predisposition within breeds for DCM are well recognised. Whereas it is thought that cases of 'non-genetic' DCM in humans are very rare, (e.g. caused by excess alcohol, viral agent, etc.), these are presumed to be virtually non-existent in dogs. In other words, DCM in dogs is always assumed to have a genetic element.
Investigation into the genetic basis of DCM in dogs did not start until the mid 1990s. It was prompted by reports of familial DCM in humans. Until that time, DCM in humans was considered to be a 'sporadic' disease, with numerous causes.
In Human cases, DCM is most commonly thought to be autosomal dominantly transmitted.
Autosomal dominant:
An affected parent will have at least one affected grand parent, and will produce offspring where an average of 50% are affected. There are no skipped generations and males and females are affected equally. If the gene is present, the condition will also ultimately manifest, unless there is a prior cause of death. However, non-affected offspring are clear of the condition and will not be carriers of the affected gene. For our purposes, this means that if these individuals can be identified, they will be safe to breed from, as there is no transmission of the faulty gene.
Autosomal recessive:
If the condition proves to be autosomal recessive, then an individual will need two copies of the affected gene, one from each parent, to succumb to the condition. However, if they have one healthy and one faulty gene, they may live their entire lives free of the affects of the disease, but will carry a faulty copy of the gene, which can be passed on to the next generation. Two such silent carriers will produce a litter where on average 25% will be affected, 50% will be carriers, and the remainder 25% will be completely clear. Also, this condition can appear to skip a generation.
X-linked:
Essentially, this condition produces female carriers with affected sons. Since males have only one x-chromosome, if their one copy is affected, the condition will manifest. Females carry two x-chromosomes, so if they have one healthy and one faulty, the healthy one will override and produce a normal life. If, on the other hand, she is unfortunate enough to inherit a faulty x chromosome from both parents, then she too will be affected. This mode of inheritance can also appear to skip a generation.
There is also the more obscure mitochondrial mode of inheritance, which is carried through the female line, but can affect males as well as females. This involves the portion of the cell concerned with energy production.
In dog studies with Irish wolfhounds, Dobermans, Boxers and Newfoundlands, evidence so far indicates an autosomal dominant mode of inheritance. Males tend to become affected at an earlier age, which can give a false impression that there is an x-link, but she is fairly confident that this is ultimately based on incomplete evidence and that autosomal dominant is the likely mode. In Dobermans, there has been a suggestion of both a dominant and recessive mode of inheritance however. In Portuguese Waterdogs there is a juvenile form of Cardiomyopathy which can cause death in puppies of 8 weeks old. They have found that in this case it is a recessive condition, liked through pedigree analysis to one founder dog in the United States. There has been a suggestion in Great Danes that there might be an x-linked inheritance, but she thinks this is likely just a reflection of the pattern of males becoming affected on average at an earlier age than females. She sees equal numbers of male and female Great Danes affected in the UK.
She then showed us a more complex genetic analysis of 4 generations in a Newfoundland family with some incidence of DCM, which she talked through in detail. Many dogs showed cardiac abnormalities and some were diagnosed positive with DCM. This sort of overview of entire family trees and health screening of entire litters is an invaluable aspect of the ongoing research into this condition and an essential part of building up a full understanding of its patterns of inheritance.
In her experience, she feels that males and females are equally likely to be affected by DCM.
Sudden unexplained deaths in leos also appears to be uncomfortably common, especially in young males it seems.
Confirmed cases of DCM do seem to be able to demonstrate a relation to other known cases, which underlines the likely genetic basis of the condition, but clearly more details needed to build up a complete pattern for analysis.
More details are needed, and for this one must start with confirmed diagnosis, which means that if a dog is suspected of having a heart condition, a qualified veterinary cardiologist should be sought to get positive confirmation of the condition. This, along with the affected dog's pedigree, then becomes a valuable piece of evidence in trying to decipher the mode of inheritance of this illness. Only then can efforts move on to trying to positively identify the gene or genes responsible, their mode of inheritance, and from there a method of screening that might eventually lead to the elimination of this devastating condition.
At present, because it is an acquired condition, (one which only emerges over time), screening must be ongoing to be of any value. In other words, screening a 2-year-old dog will only show if the condition is apparent at that age, not whether it will emerge in years to come.
Dr Dukes-McEwan mentioned the recent establishment of the UK Companion Animal DNA Archive, which could help in this and other areas of research by building up a genetic history of the breeds for current and future researchers to tap into in their efforts to find a genetic marker for these conditions. What is essential for this to be most effective is to get a confirmed diagnosis of the condition and then submit a DNA sample, which is verifiably from the known affected individual. 'The pedigree goes with the DNA from the confirmed case'. If the blood sample and DNA is taken from a young dog, it is very helpful for owners to update the archive with any illnesses their pet is diagnosed with over time. The DNA archive is keen to collect samples from both healthy and diseased dogs of a wide range of breeds, and for a wider variety of conditions. More information is available on the web-site:
http://pcwww.liv.ac.uk/DNA_Archive_for_Companion_Animals/
Abnormal Heart Rhythms are common in DCM and can be a helpful first-step diagnostic tool. Dukes-McEwan went on to give a complex explanation of ECG traces and what to look out for, especially in the giant breeds such as leos that are vulnerable to DCM. Atrial Fibrillation in particular is commonly seen in DCM case. It is characterised by a very fast (200-220 beats per minute), irregular heart rate.
In some cases, notably Irish Wolfhounds, some rather more slow Atrial Fibrillation (so-called "Lone"), may be seen in otherwise asymptomatic individuals years before they then go on to develop full-blown cases of cardio myopathy. Their heart rates will be irregular when examined via ECG, but they otherwise appear in everyway to be normal healthy dogs, and hear rates may be only 90 – 120 beats per minute, so normal. This allows a fairly good tool for pre-diagnosis of this condition.
Ventricular Premature Complexes or VPCs are caused by the build-up of scar tissues within the cells as the condition progresses. These cause abnormal electrical firing disrupting the normal heart rhythm. If they take over the heart rhythm, it can lead to ventricular tachycardia, a very rapid inefficient heart rhythm, which does not allow for the effective pumping of blood throughout the body. This can cause collapse or even sudden death. Abnormal ventricular rhythms are most common in cardiomyopathy in Dobermanns and boxers, but are seen in other giant breeds such as great Danes. Again, the ECG trace (or a 24 hour ECG trace called a Holter monitor) can help make this diagnosis. The abnormal rhythms can occur before the heart chambers are dilated.
What are they symptoms of DCM?
There may be none at all. Many affected dogs show no clinical signs in the early phases of the disease and will appear in everyway to be fit healthy individuals. Once they are into actual stages of acute heart failure, one or all of the following signs may be apparent:
Weight loss and muscle wasting,
Exercise intolerance,
Collapsing,
Coughing and breathlessness, due to fluid within the lungs (pulmonary oedema), or in the space surrounding the lungs (pleural fluid).
Fluid retention in the belly (Ascites): this is one of the clearest signs of final stages of the condition. If the right ventricle is more affected, the dog's abdomen will expand as excess fluids build up, showing clear signs of a distended stomach.
She then gave a quick overview of the two main functions of the heart and how right side activity has a greater affect on draining blood and excess fluids from the body, whereas left side function is more closely associated with the lungs, so failure here results in fluid build-up within the lungs themselves, hence the coughing.
Listening for heart murmurs (auscultation) is not necessarily the best way to diagnose early onset DCM, as affected dogs usually do not manifest a murmur until well on into the condition. So, even a fully affected dog may only present with a very slight murmur, and such slight murmurs could be caused by a wide range of other things. Early cases of DCM are unlikely to be picked up through basic stethoscope examination.
An effective diagnostic tool for left-sided heart failure is a simple chest x-ray, which will show the outline and size of the dog's heart as well as any excess fluid build-up within the lungs. A chest X-ray will not be abnormal in very early cases, and so this is not a screening tool in asymptomatic dogs.
The most sensitive way of positively diagnosing DCM is however through the use of Cardiac Ultrasound (Doppler Echocardiography). This is a completely safe and non-invasive technology - essentially the same as is used for checking pregnancies. Dogs normally need not even be sedated for this examination, but are simply positioned lying on their sides quietly. She reports that many find the whole experience so relaxing that they may fall asleep during the procedure. A small amount of the coat will need to be clipped from the chest overlying the heart, behind the elbow and forearm.
This form of examination allows for a live real-time moving image of the heart. The walls can be seen, and how well and how synchronously they are moving, and the blood filled chamber can be measured. Each heart valve is visualised. With colour flow Doppler, the pattern and speed of blood moving through the heart can be assessed, and whether flow is normal or turbulent (such as a leaky valve, resulting in a heart murmur). All of this information can be recorded and retained for comparison with future examinations.
Dr. Dukes-McEwan showed a number of visual examples from the Doppler echocardiograph, both healthy and ill, to illustrate the technique and its value as a diagnostic tool. One of the things that she pointed to as being needed by the research community is echocardiography data from healthy examples of the vulnerable breeds gathered over the course of their lifetimes, or so-called serial scans. These would provide a valuable model of the lifespan of a normal heart, against which to compare future data from affected individuals.
Although echocardiography can be the best tool for early diagnosis of the condition, it must be kept in mind that this condition evolves slowly over a long time with only very gradual changes building up. Therefore, for this device to be used for an effective early diagnostic tool, one must compare results over time and look for gradual changes. In other words, serial testing is necessary for early detection to even be possible. Also, it must be kept in mind that a dog that scans as being clear at one stage in its life, may still go on in later years to develop the condition, so it is not a method that can certify a dog as being clear for life, only clear at the time of the scan. In this way, it is not a "one-off" screening test. The older a dog is that scans clear, the more likely you are to have a dog that is free of the condition, but it is still not guaranteed.
There is no cure for DCM. As the condition progresses the rate of degeneration in the heart accelerates and things worsen rapidly. The main emphasis of the treatment available is aimed specifically at slowing this rate of degeneration and hopefully prolonging the dog's life.
Treatment options include:
Drugs to counteract the fluid retention in lungs and abdomen. These are the diuretics, such as Frusemide. Spironolactone is also sometimes proscribed in addition as it has been shown to counteract some of the scarring of the heart muscle, which are caused by the disease.
ACE inhibitors are used to counteract the body's hormones which are elevated in response to the cardiomyopathy and heart failure, which are known to accelerate and exacerbate the deterioration of the disease. For example, these hormones can constrict blood vessels against which the already weakened heart has to work against, so it has to work even harder against that resistance. There are a number of these ACE Inhibitors available to us in the UK and although not cheap, they are proven to significantly extend survival times and quality of life in DCM. They have also been shown to slow the progression of DCM even in its earliest stages.
Atrial fibrillation is one of the main dangers of this condition in giant breeds and to help control these hazardous heart rates, vets will prescribe Digoxin, possibly with other drugs working together, which helps to slow, steady and regulate heartbeat, so that each beat is more efficient in transporting blood around the body.
Finally, a relatively new drug called Vetmedin, (Pimobendan), is now available which has been shown to improve the heart's ability to pump efficiently, and also dilated blood vessels, reducing the work-load of the failing heart. It is proving to be a very effective drug for this condition and has been shown to slow the rate of progression of the disease.
In conclusion, Dr. Dukes-McEwen reiterated that if there is a concern about DCM within the Leonberger community, then screening is advised, particularly of all living relatives and descendants of known affected animals, so that results can be added to pedigrees and used to analyse possible patterns of inheritance. Remember that they do need to be serial exams, not one-offs. The clear advantage of early diagnosis is to be able to start treatment that will provide your dog with the best quality of life as the condition progresses, and of course to help make decisions about possible breeding. If, as is currently believed, DCM is an autosomal dominant condition, then up to 50% of the progeny of an affected dog can also be affected, and will suffer the devastating consequences. The other 50% however will be completely free and therefore could be perfectly safe to breed from. What we ultimately need of course is a genetic screening test, but sadly, this is still some time off, although it is possible that such a test for one breed may apply to leos as well, but this is by no means certain.
Note: There was a great deal more technical detail presented in this seminar. Anyone interested in the full content should seek a DVD copy of the recording, which should soon be available through the leo club shop.
Dr. Dukes-McEwen then took some questions- some of which are summarised here:
"How many leos would need to be scanned to gather a useful amount of information to study this disease in the breed?"
…..To do a proper linkage analysis, looking at positive diagnosis and pedigrees, one needs to have a fairly thorough set of data from at least three generations of dogs, and as much information as possible about ALL the progeny within those generations. Not simply results from the odd individual….
"How can the club organise an annual echo-doppler testing event with a cardiologist that would allow a wide set of dogs to have serial testing?"
….The equipment is expensive and costs are steep, not less than £100, but through approaching a qualified veterinary cardiologist one might be able to reduce the costs from a group of examinations and arrange such a service. It is a time consuming examine, so doing more than 10 in a day would not be likely. This would also be a limiting factor. ….
"Over how many years would one start to see signs of abnormality (via the echo-cardiogram) in a dog developing this disease until they have full blown DCM?"
…..A dog might test clear at 4 or five years and then go on to develop this illness and so still end up passing it on to his progeny. Listening for a heart murmur is not an effective screening method. If however, you are doing serial testing you would be likely to see the condition developing over the course of 5 or 6 years before it becomes critical. The gradual changes in the heart would be apparent through such a series of exams, and in Newfoundlands, time periods of between 2 and 6 years can from the earliest abnormality on the scan to heart failure have been recorded. The younger the dog is at first abnormality on the scan, the more rapid the progression; an older dog often has a slower rate of progression…
"Is there value in doing echo-Doppler scans on older dogs after their breeding age has passed?"
…The older a dog is when it is scanned, the more reliable the results in that it is less likely that they will develop the condition the more years pass. If they do eventually show positive, then their progeny can be looked at more closely. Even if they never show signs of the illness, this alone is a valuable piece of data for future analysis ……
"Is it useful to give Taurine and L-carnitine supplements?"
….Cats can develop DCM if they are deficient of taurine, and they are cured with supplementing the taurine. In some breeds of dog (Newfies included0, they may have low blood taurine levels, and supplementing taurine improves them, but this is not cause and effect, we do not cure them. L-Carnitine is more helpful in boxers, (certain families only however). L-carnitiine is very expensive. Taurine is cheap, Neither supplement will do any harm and may help, no clear evidence as yet in Leos. Too low meat-based protein (20% or less), could contribute to low taurine, chicken better than lamb as a source….
"Is there evidence of a cumulative effect of DCM?"
This is not the way inheritance works. Sometimes offspring are affected before parent, but not always.
No evidence of environment making a difference outside of diet points already mentioned.
"How far off from DNA test?"
For other heart diseases, such as hypertrophic cardiomyopathy in Maine coon cats, there is now a genetic test available.
There are genetic tests for a range of dog diseases, particularly some of the eye diseases.
It will come in for DCM in dogs…. But more work is needed. Despite spending over three years looking in Newfoundlands, we have not yet found a gene-based test yet. Some degree of luck is needed as well! Also, we need to be aware that finding a gene for DCM in one breed does not mean that this applies to other breeds (and we can presume that Newfie and Leos and St. Bernards may have a similar gene….).
Let us collect echo data, clinical data and DNA and pedigrees from normal and DCM leonbergers, so we can be ready if a test become available, to see if it applies to Leos as well.
If you have any information either on affected Leos, or any relevant echo-doppler results that you would like to submit to Dr. Dukes-McEwan, she can be reached at the newly established Small Animal Teaching Hospital from the 1st of April 2007. Details here:
Small Animal Teaching Hospital,
Leahurst, Chester High Road,
CH64 7TE
Fax. +44 (0)151 795 6101
www.liv.ac.uk/sath


Analytical spectroscopic methods such as XRF, OES, and IR often require samples in the form of a round, flat-surfaced discs. Our laboratory pellet presses are ideal for preparing sample discs for these methods. Our range includes manual and automatic hydraulic presses and an air-actuated press. In addition, our presses are designed to fit on the benchtop, requiring less space than standard floor model presses.


text:
Media | Yas Marina Circuit 1
Yas Marina Circuit 1
Here you can see a board of Yas Marina Circuit of Abu Dhabi. While this circuit explodes into life amid the Abu Dhabi Grand Prix each November, it's an intriguing spot to investigate whenever of year. Guests can go in the background of this marina-divert, stops at the bolster pit carports, the media focus and the enclosure zone incorporated into the visit. Visits are masterminded through Yas Central, the portal to the Yas Marina Circuit. You can likewise drive and cycle on the track in different guided and solo encounters, and running lovers can run along the circuit from 6pm to 9pm on Tuesdays. United Arab Emirates is situated on the Arabian Gulf southern coast, boarded by Oman and Saudi Arabia. They have in expanding populace of 1.8 million and numbering. Of those, just 20% are Emirates. The capital Abu Dhabi is situated in top Northern focal point of the UAE. The present ruler is Sheik Khalifa Bin Zayed Al Nahyan, who likewise happens to be the President of United Arab Emirates. Albeit, each of the seven Emirates has their own particular ruler and laws, the entire of United Arab Emirates has a Supreme Council of Rulers, which are the leaders of the 7 Emirates. Yas Island, an expansive chunk of sand off the bank of Abu Dhabi, has the Abu Dhabi Formula 1 Grand Prix engine race, on 01 November 2009 surprisingly, on the Yas Marina Circuit, under development from 2007-2009. The Abu Dhabi Yas Island circuit will be around 5.5 - 5.6 long (marginally distinctive figures found in public statements and news reports yet 5.55 km is on the authority F1 site). In the event that aggregate race length is the ordinary 300 km, which should mean the Abu Dhabi Formula One race will be around 55 laps. On the off chance that F1 drivers are anything like a portion of the insane people tearing down the Abu Dhabi - Dubai thruway, it shouldn't take them longer than an hour or somewhere in the vicinity. The race circuit was initially to have three areas - a rapid course segment, a road segment, and a Monaco style road segment yet the road segment was dropped for a more extended appropriate circuit section.
Spare Parts in the Yas Marina Circuit Garage in Yas Island, Abu Dhabi
The Yas Marina Circuit is where the Abu Dhabi Grand Prix Formula One is held every year.
Abu Dhabi Unique Architecture of the Yas Marina Circuit
Experience the racing thrill when you go karting with your friends in the beautiful renowned Yas Marina Circuit race track.
The Elegant Yas Marina in Abu Dhabi
Enjoy a glass of champagne and toast to the winners of the Formula One Etihad Grand Prix race.
The Modern Yas Marina Circuit on the Port of Yas Island, Abu Dhabi
If you are on vacation in Abu Dhabi in UAE, then the Yas Island Marina should not be missed!
The Famous Sun Tower Landmark at the Yas Marina Circuit in Abu Dhabi
This VIP suite is the pure definition of luxury on the Yas Island Marina. Look no further when you are on holiday in UAE!
Sun Setting over the Yas Marina Circuit on the Yas Island of Abu Dhabi
There are lovely white tents protecting the audience crowd at the race track of the circuit from the sun in the summer time!
Yas Island Marina Architecture in Abu Dhabi
Spend some quality father son time on the race track of the Yas Marina Circuit this summer when you are on vacation in Abu Dhabi.
Abu Dhabi - Ferrari world - Yas Marina Circuit - state of the art design
The Yas Marina Circuit is the venue for the Abu Dhabi Grand Prix. With state-of-the-art facilities and numerous track configurations, Yas Marina Circuit is also a premium Corporate Event venue, the ideal place for a range of events, from car launches and vehicle testing, to team building days, as well as photo shoots and much more.
Building on the Yas Marina Circuit Site
Yas Island, Abu Dhabi, UAE
Empty Stands Before the F1 Event on the Yas Marina Circuit in Abu Dhabi
Be a part of history in action in Abu Dhabi in the annual racing event of Formula One hosted by Etihad!
Yas Marina Circuit Sign Post Landmark
by Mourad Hakimi
category: Autos


SUMMERLAND, CA –The Summerland Post Office located at 2245 Lillie Ave, Summerland, CA 93067 remains closed due to the recent mudslides.
Even though Summerland Post Office is normally closed on Saturdays, customers can begin picking up their mail from Summerland Post Office on Saturday, January 13, 2018 at 12 noon. Retail services will commence on Tuesday, January 16, 2018.
Montecito postal customers can retrieve their Post Office Box mail and obtain retail services at the Milpas (East Beach) Post Office located at 107 Nopalitos Way, Santa Barbara, CA 93103. Hours: 10:00 a.m. to 5:00 p.m. Monday through Friday and 10:00 a.m. to 2:00 p.m. Saturday.
As a reminder, Post Offices nationwide will be closed on Monday, January 15 in honor of the Martin Luther King Jr. holiday.


text:
Washington Decoded
Assassinations (49)
Contemporary History (24)
Corrections (1)
Index of Articles (1)
Index of Authors (1)
Political Economy (19)
Presidential Commissions (10)
Press Clips (1)
Secrecy & Classification (4)
Watergate (13)
Center for the Study of Intelligence
Cold War International History Project
Conelrad
Deep Capture
Economic Principals
Education & Research Institute
Harvard Project on Cold War Studies
Kennedy Assassination Home Page
Mary Ferrell Foundation
Nixon Tapes
Presidential Recordings Program
RealityChek
The Reporters Committee for Freedom of the Press
Rosemary Sullivan:
The Betrayal of Anne Frank
Joseph McBride:
Political Truth
Harald Jähner:
Carl Bernstein:
Chasing History
Thomas Kent:
Striking Back
Tim Weiner:
The Folly and the Glory
Cyril Wecht:
The JFK Assassination Dissected
Jefferson Morley:
Scorpions' Dance
Rebecca Donner:
All the Frequent Troubles of Our Days
Tim Tate:
Agent Sniper
Helen Fry:
M. E. Sarotte:
Not One Inch
Dwight Chapin:
The President's Man
Elizabeth D. Samet:
Looking for the Good War
Barna William Donovan:
Conspiracy Films
Avner Barnea:
We Never Expected That
Fiona Hill:
There Is Nothing for You Here
David Perry:
Tales of Deception and Imagination
James M. Boughton:
Harry White and the American Creed
Deborah Bauer:
Marianne Is Watching
Casey Michel:
American Kleptocracy
David McKean:
Watching Darkness Fall
David S. Wills:
High White Notes
Walter Pincus:
Blown to Hell
Andrew L. Yarrow:
Christopher D. Kolenda:
Zero-Sum Victory
John Pomfret:
From Warsaw with Love
Patrick J. Garrity
& Erin R. Mahan:
Averting Doomsday
David Wessel:
Only the Rich Can Play
Adam Schiff:
Midnight in Washington
Ellen Schrecker:
The Lost Promise
Joseph Weisberg:
Russia Upside Down
Alison Lewis:
A State of Secrecy
Tim Gruenewald:
Curating America's Painful Past
Tricia Jenkins & Tom Secker:
Superheroes, Movies, and the State
Vladislav M. Zubok:
Stephen H. Norwood:
Prologue to Annihilation
William M. Arkin:
On That Day
Craig Whitlock:
The Afghanistan Papers
Alex Wellerstein:
John E. Schmitz:
Enemies Among Us
Irwin F. Gellman:
Campaign of the Century
Aram Goudsouzian:
The Men and the Moment
Alecia P. Long:
Cruising for Conspirators
David Albright:
Iran's Perilous Pursuit of Nuclear Weapons
Lawrence J. Haas:
The Kennedys in the World
Carolyn Cox:
The Snatch Racket
Geoffrey Cain:
The Perfect Police State
Nigel West:
Spy Swap
Jonathan Stevenson:
A Drop of Treason
Christopher M. Elias:
Gossip Men
The Spy Who Was Left Out in the Cold
Garrett M. Graff:
Louis Menand:
The Free World
Vernon L. Pedersen:
The Communist Party on the American Waterfront
The Generals Have No Clothes
Timothy Frye:
Weak Strongman
Lee C. Bollinger
& Geoffrey R. Stone:
National Security, Leaks & Freedom of the Press
Richard H. Cummings:
Cold War Frequencies
Serhii Plokhy:
Nuclear Folly
Jonathan Marshall:
Dark Quadrant
Philippe Sands:
Brad Williams:
Japanese Foreign Intelligence and Grand Strategy
Shaul Bakhash: The Fall of Reza Shah
Carl W. Ford Jr.:
Jack Devine:
Spymaster's Prism
Anne Sebba:
Ethel Rosenberg
Cass R. Sunstein:
Jed S. Rakoff:
Why the Innocent Plead Guilty and the Guilty Go Free
Joby Warrick:
Ira Rosen:
Ticking Clock
Colin Dickey:
The Unidentified
Jeff Testerman
& Daniel Freed:
Call Me Commander
Eliot Higgins:
We Are Bellingcat
Craig Unger:
American Kompromat
Kevin Riehle:
Soviet Defectors
Donald A. Ritchie:
The Columnist
Vernon L. Pedersen, James G. Ryan & Katherine A. S. Sibley, eds.:
Post-Cold War Revelations and the American Communist Party
Richard J. Kerr:
The Kompromat Conspiracy
Bernice Lerner:
All the Horrors of War
Barnes Carr:
The Lenin Plot
Susan Ronald:
John Ferris:
Behind the Enigma
Anthony R. Wells:
Between Five Eyes
Fred Litwin:
On The Trail of Delusion
Nina Jankowicz:
How to Lose the Information War
Norman M. Naimark:
Stalin and the Fate of Europe
Ian Buruma:
The Churchill Complex
Ali Soufan:
The Black Banners (Declassified)
Edward Mickolus, ed.:
More Stories from Langley
Tom Burgis:
Ami Ayalon:
Friendly Fire
Thomas A. Schwartz:
Henry Kissinger and American Power
JPat Brown, B.C.D. Lipton, Michael Morisy, eds.:
Activists Under Surveillance
Kurt Andersen:
Robert Draper:
To Start a War
Rhodri Jeffreys-Jones:
The Nazi Spy Ring in America
Nina Schick:
Deepfakes
Marc Gallicchio:
Francine Hirsch:
Soviet Judgment at Nuremberg
William Lazonick
& Jang-Sup Shin:
Predatory Value Extraction
Lawrence Roberts:
Eric A. Posner:
The Demagogue's Playbook
Robert A. Caro:
Mira Rapp-Hooper:
Shields of the Republic
Tracy Campbell:
The Year of Peril
Peniel E. Joseph:
The Sword and the Shield
William R. Casto:
Advising the President
Nancy Sinkoff:
From Left to Right
Molly Pucci:
Security Empire
Robert Richardson:
Spying from the Sky
Steven H. Miles:
The Torture Doctors
Jerome R. Corsi:
Coup d'État
Stephan Talty:
The Good Assassin
Larry Tye:
Elizabbeth Shackelford:
The Dissent Channel
Nancy Thorndike Greenspan:
Atomic Spy
David P. Hadley:
The Rising Clamor War
Brian E. Crim:
Our Germans
Willard M. Oliver:
The Birth of the FBI
Theresa Payton:
Archie Brown:
Joshua Kastenberg:
The Campaign to Impeach Justice William O. Douglas
James D. Zirin:
Plaintiff in Chief
Andrew C. McCarthy:
Ball of Collusion
Secrecy & Classification
Once More 'Round the Plaza
By Robert Reynolds
Once again the National Archives is preparing to release previously redacted documents from the John F. Kennedy Assassination Records Collection (JFK ARC). And once again the idea is becoming rampant that significant and newsworthy information on the assassination of President Kennedy 58 years ago will soon be revealed.
News coverage of the coming releases started out muted this time around compared to the last big releases, which occurred from July 2017 to April 2018. It picked up markedly, however, when President Biden released a memo on October 22 that spelled out short- to long-range plans for the collection.
The memo called for a first release of redacted documents that agencies no longer wish to withhold in mid-December, then another, larger, release by December next year. The memo also mandated a boat-load of paperwork for agencies to fill out if they want to postpone anything past that date. A longer-range element of the plan calls for the National Archives and Records Administration (NARA), the federal agency that houses assassination-related materials, to scan the entire collection and put it on-line. How long that will take is not spelled out in the memo.
Reaction to Biden's memo ranged from yawns to apoplectic complaints that Biden has sold out to pressure from the Central Intelligence Agency (CIA) and is suppressing incriminating documents.
That a collection of mostly paper documents can stimulate such passions is a tribute to the depth of the national trauma inflicted by the assassination. Given the confusing result of the last releases, it is also understandable that people might think there are still important documents left unreleased. A closer look at NARA's latest data on the ARC, however, reveals just how unlikely this is.
The JFK Database
The 2017-2018 releases from NARA were confusing, first, because it was unclear how much material was from documents previously withheld in full, and second, because it was equally unclear how much was from documents that had been previously released in part. This should not have been the case.[1]
The primary reason for the uncertainty was outdated information in the JFK database, the computer listing of metadata for most records in the collection. The creation of the database had been mandated by the President John F. Kennedy Assassination Records Collection Act, the 1992 public law that established the JFK archival collection in the first place. The purpose of the database was to provide a detailed index to the contents of the collection, including basic information for every record, such as the title and date of the document, the agency that generated the record, number of pages, and so on.
The main problem that led to the confusion was a failure to update the release status of each record. Why was this data field not better maintained? During the five years the database was being assembled, 1993 to 1998, there were frequent changes in the status of records. Agencies argued with the Assassination Records Review Board (ARRB), the limited-term panel created to oversee the assembly and release of the JFK records, about which documents counted as assassination-related records, and what standards should apply for withholding documents in full or redacting portions of their text. These status changes were not always recorded in the database. With more than three hundred thousand records in the database, that should not be surprising.
Continue reading "Once More 'Round the Plaza" »
Posted at 05:45 PM in Assassinations, Current, Secrecy & Classification | Permalink | Comments (0)
Tags: AMSPELL, ARC, ARRB, Assassination Records Review Board, Biden, CIA, Cuba, David S. Ferriero, DRE, FBI, Fidel Castro, IRS, Jefferson Morley, JFK, JMWAVE, Kennedy assassination, Lee Harvey Oswald, NARA, National Archives, Public Law 102-526, Robert Reynolds, The President John F. Kennedy Assassination Records Collection Act of 1992
Credit Where Credit Is Due
By Max Holland
Newspapers constantly make mistakes.[1]
Anyone who works on an issue that makes news knows this. Reporters, in their haste to convey the gist, invariably gloss over nuances that mean everything to the people who follow an issue closely. Complexities are reduced to inaccurate simplicities, that is, when there is any kind of effort to describe them at all.
Yet sometimes it is not reporters' fault. A case in point was the recent release of tens of thousands of historical records from the Richard M. Nixon Presidential Library. The release was portrayed as if it were the Nixon Library's initiative, when in fact, the most arresting documents only came to light because of the diligence of individual requesters and independent institutions, like the National Security Archive.
The November 28 release totaled approximately 122,800 pages of records, which were made publicly available for the first time at the National Archives in College Park, Maryland.[2] The Nixon presidential records have been the subject of contentious litigation for decades (lawsuits were filed by parties ranging from Professor Stanley Kutler to Nixon himself), and documents that otherwise might have been released years ago are only now being opened to the public and garnering the attention they deserve.
This cache of documents covered a variety of newsworthy topics, ranging from the White House's file on W. Mark Felt, aka "Deep Throat," to National Security Council (NSC) memos about US policy toward Saudi Arabia, Egypt, Soviet Union, and Salvador Allende's Chile. Some issues have changed so little in 35 years that many of the documents read like they had been ripped from today's headlines. Consequently, major news organizations, including The New York Times, Los Angeles Times, Washington Post, and the Associated Press prepared good-sized stories about the documents.
The caveat to the release was that its most interesting portion by far — some 10,000 pages — was not initiated by the Nixon Library, but came about solely because of requests submitted by researchers under the mandatory declassification provision of the Executive Order governing classification of federal documents. This provision permits individual requesters to press the government to review classified documents to see if they merit continued secrecy.
With the exception of the AP, which ran a story about FBI agents' campaigning to have Mark Felt appointed as director, the news organizations zeroed in on the NSC documents relating to the Middle East, all of which were released because of mandatory review requests. The lede from The Washington Post's story concerned messages between Saudi Arabia's King Faisal and the US government about terrorism and Israel's occupation of the Palestinian territories. Articles in the Los Angeles Times and New York Times, meanwhile, focused on another issue that still reverberates: Israel's nuclear arsenal, which ran counter to established US policy on weapons proliferation during the Nixon administration, and complicates US diplomacy in the region to this day.
What these stories all had in common, though, was that they suggested the impetus for release came from the Nixon Library or National Archives, when in fact the documents were only disclosed because of the initiative of requesters.[3] As the director of the National Security Archive, Tom Blanton, later noted, "Without those requests, which compelled the government's review, the documents could have remained secret indefinitely." Analysts working at the National Security Archive had submitted about half of all the mandatory requests reflected in the November 28 release, and still had many more requests pending — approximately 75 — that had yet to be processed by the Nixon Library. Some of the requests dated as far back as 1993!
Who or what was responsible for incompletely informing the reporters? The National Archives and Nixon Library were apparently so eager to claim credit for the releases's most interesting portion that both agencies, in their respective press releases, glossed over the instrumental role played by requesters.[4] This self-congratulatory posture was underscored during the November 28 press conference held to publicize the documents' availability.
The sole speaker, Tim Naftali, executive director of the Nixon Library since 2006, effusively complimented the archives and library staff for making the once-classified documents available. Indeed, Naftali seemed to be praising everyone in sight except the requesters who had actually initiated the mandatory review requests — that is, until he was reminded of that fact by one of the requesters, who was in attendance.
[1] Michael Bugeja and Jane Peterson, "How Complete Are Newspaper Corrections?: An Analysis of the 2005 'Regret the Error' Compilation," Media Ethics, Spring 2007.
[2] The Nixon Library in Yorba Linda, California, which became part of the federal presidential library system only this past July, is undergoing an expansion so that it may accommodate the enormous trove of documents generated during Nixon's six-year presidency. Previously, the privately-operated Nixon Library housed only a small portion of the total volume of Nixon papers, some 6.2 million pages of pre- and post-presidential records. Incorporating the presidential records alone will add 42 million pages to the previous collection, not to mention an enormous quantity of still photographs, film, video, and audio recordings. For an account of the Nixon Library's unusual history, see James Worsham, "Nixon's Library Now a Part of NARA: California Facility Will Hold All Documents and Tapes from a Half-Century Career in Politics," Prologue, Fall 2007, Vol. 39, No. 3.
[3] The initial New York Times story on its website dated November 28 stated the "documents . . . were released today by the National Archives." A subsequent version (and the version published in the newspaper on November 29) was amended to read " . . . released today by the National Archives under an executive order that requires that classified documents be reviewed and possibly declassified after 25 years. The latter explanation was an improvement, but still neglected to mentioned that mandatory review requests must be initiated by outsiders. To its credit, on December 7 the newspaper of record published a clarification, which stated that the release of previously classified documents was "the result of declassification requests by researchers at the National Security Archive . . . and elsewhere." David Stout, "Nixon Papers Recall Concerns on Israel's Weapons," NYT, 28 November 2007; David Stout, "Israel's Nuclear Arsenal Vexed Nixon," NYT, 29 November 2007; For the Record, NYT, 7 December 2007. Accounts of the records' release in the Los Angeles Times, Washington Post, and by AP were virtually identical to the initial NYT story, describing only that historical materials were released by the National Archives. Theo Milonopoulos, "Nixon White House Opposed Israeli Nuclear Efforts," LAT, 29 November 2007; AP, "Nixon Papers Illuminate Deep Throat Link," CBS News, 28 November 2007; Walter Pincus, "1973 US Cable on Mideast Mirrors Current Events," WP, 29 November 2007.
[4] Media Alert, "Nixon Presidential Library to Release New Materials at the National Archives," National Archives & Records Administration, 21 November 2007; "Mandatory Review Documents," Nixon Presidential Library & Museum, 28 November 2007.
© 2007 by Max Holland
Posted at 12:11 AM in Secrecy & Classification | Permalink | Comments (0) | TrackBack (0)
Tags: Los Angeles Times, Max Holland, National Archives, New York Times, Richard M. Nixon Library, Richard Nixon, Stanley Kutler, Tim Naftali, Washington Post
The Making of a Washington Expert
See also: "The Politics (and Profits) of Information: The 9/11 Commission"
Designating W.W. Norton as the publisher of the 9/11 Report was not the only plum handed out during Philip Zelikow's tenure as director of the 9/11 Commission. Zelikow engaged in some blatant cronyism when he arranged for a colleague from the University of Virginia, Tim Naftali, to write a history of US counterterrorism policy from the Johnson to the Clinton administrations.
The commission's prime directive was to investigate the 9/11 attacks, of course, but a historical account of counterterrorism policy is the kind of ancillary study that comparable commissions have published. As part of its final report, the Church Committee, which investigated activities of US intelligence agencies, included an invaluable 106-page study of the CIA that was based upon access to classified internal histories.
But like other aspects of the commission's work, the Naftali study was not published as part of the commission's output; it was not even deemed fit for posting on the Internet. Why was it commissioned in the first place? Naftali, a Canadian citizen at the time, could not review classified materials. His study would have to depend entirely on open sources, meaning that at best it would represent a marginal addition to public knowledge. Naftali was not even a noted expert on the subject.
Naftali's unfamiliarity with the topic probably contributed to what happened next: he belatedly turned in a work that was way too long. Indeed, because of its tone and perspective it was quickly deemed unusable, according to sources on the commission. Since there was no time left to edit it, the commissioners would not even agree to have it posted on-line as a monograph.
There's an interesting coda to this story, too. Months before the commission closed its doors, in August 2004, some staff members found it odd that Naftali was engaged in research that clearly seemed tangential to his assignment. Sure enough, once the commissioners decided to "pass" on Naftali's history and gave him permission to use the study any way he liked, he took his manuscript—which had cost US taxpayers at least $15,000—and nine months later published Blind Spot: The Secret History of American Counterterrorism.
Naftali advertises the book as having been written partly "at the request of the 9/11 Commission," and markets himself as "the official historian" of the commission, as this description from the CI Centre website reveals. The commissioners reportedly have gagged over this self-aggrandizement, brazen even by Washington standards. They are nonplussed that someone should have secured work from the commission through a personal favor, produced work of no usefulness to the commission, yet managed to exploit the opportunity for his own professional and financial gain.
Postscript: One of the reviewers who noticed that Naftali's history of counterterrorism was slap-dash, and bordering on laughable, was Hayden B. Peake, who reviews books for Studies in Intelligence. Writing in the March 2006 of Studies, Peake noted Naftali's "curious interpretation of intelligence history." Peake's review can be read in full here.
In the fall of 2006, Naftali became the director of the Richard M. Nixon Presidential Library.
This article first appeared in The Washington Spectator, 1 November 2005
Tags: 9/11 Commission, Blind Spot, Hayden B. Peake, Max Holland, Philip Zelikow, Richard M. Nixon Library, Tim Naftali
Erasing History at the National Archives
In December 20, 1960, representatives from U.S. corporations with business interests in Cuba—including Exxon, ITT and Domino Sugar—met with then-CIA director Allen Dulles. The meeting was called, according to an agency history written in the late 1970s, so that Dulles could hear the executives' grievances about Fidel Castro's regime. Without hinting that the CIA was at that moment training a small army of exiles, Dulles listened as the corporate chieftains suggested ways to sabotage Cuba's economy and precipitate military intervention. Their message was simple: "It was time for the U[nited] S[tates] to get off of dead center and take some direct action against Castro."
Without such documents as this partly declassified CIA history, the American public would have been left in the dark about the "sometimes overactive" role corporate interests played in Washington's anti-Castro efforts in the 1960s. Yet if some elements of the federal government now have their way at the National Archives, such blank spots in the archival record will become increasingly common.
The tampering with history has been documented most extensively by Matthew Aid, a scholar writing what promises to be a definitive history of the National Security Agency. Aid, who has been conducting extensive research into intelligence-related holdings at the National Archives since 1979, began noticing something strange in the summer of 2005. Individual documents, and sometimes entire files, that he had read in full 10 years ago were mysteriously disappearing from the open shelves. Eventually, and despite a virtual gag order imposed on archivists familiar with the withdrawals, Aid was able to piece together the story about a secret reclassification program in existence since 1999. Several agencies, most prominently the CIA, the Defense Intelligence Agency (DIA), and the U.S. Air Force (USAF), have been conducting a broad effort in total secrecy to prevent public access to previously released government documents.
The roots of this issue go back to a reform promulgated by President Clinton in 1995 to break the logjam over classified records from the Cold War. Clinton's Executive Order 12958 represented an ambitious effort to force federal agencies to disgorge vast amounts of records while keeping a limited number secret that fell into specific categories. It mandated that within five years, all records 25 years or older would automatically be declassified, regardless of whether they had been reviewed. Inevitably, the effort ran into some hurdles. A document from the State Department, for instance, might also contain sensitive information from the CIA. Often the CIA's "equity" in the document would be obvious, but sometimes not. To be declassified "under the proper authority," both agencies had to review the document.
Within three years, a significant problem cropped up with respect to the inadvertent release of information about nuclear weapons in open archival records. One category of information, known as "restricted data," is considered so sensitive it is "born classified." To its credit, the Department of Energy (DOE) openly sought a modification of Clinton's EO, which had banned the reclassification of documents once they became public. In late 1998 Congress authorized the DOE to scour the records of other agencies under stringent conditions, which included the filing of regular reports about documents the DOE had reclassified.
So far, so good. But in 1999, other federal agencies found instances of unrecognized "equities" in State Department documents, and by 2001 these agencies were insisting on the right to re-review, in secret, any records that had been declassified if they contained defense, foreign affairs, or intelligence information. After The New York Times broke the news on February 21 about Aid's discovery of this secret reclassification program, an embarrassed National Archives declared an instant moratorium on the process. By that time, however, 9,500 documents, totaling 55,500 pages, had been surreptitiously reclassified. Because the CIA, DIA, and USAF have operated, unlike the DOE, under a shroud of secrecy, their efforts have resulted in dozens of absurdities, all of which make a mockery of EO 12958, which was modified but not rescinded by the Bush administration in 2003.
One ridiculous outcome is the attempt, apparently by the CIA, to reclassify documents that were not only declassified years ago but published (with CIA consent!) in the State Department's Foreign Relations of the United States series. These volumes are available on-line, and hard copies are held by libraries all over the world, including the National Archives' own library. Now the original documents have been deemed too secret to read. Not to be outdone, overzealous USAF reviewers have reclassified intelligence, and policy papers, and reportedly even newspaper clippings, about the strategic bombing of Japan during World War II.
The Information Security Oversight Office, which was established at the National Archives under the 1995 executive order, is currently conducting an audit of all the withdrawn documents. When those findings are released as scheduled in late April, more egregious examples of reclassification-run-amok are bound to surface. The question then will be, What were these reclassifiers thinking? And why were tax dollars used to have them think it?
This article first appeared in The Washington Spectator, 15 April 2006
Posted at 08:12 PM in Secrecy & Classification | Permalink | Comments (0) | TrackBack (0)
Tags: Classification, Max Holland, National Archives
washingtondecoded.com


An acoustic-folk remake of the Corner Laughers song.
We walked together from Jerusalem to Rome.
Followed in your footsteps from the train station to home.
And I could see us on Midsummer's Day in circles heralded by stones.
And I could cast us in a mummer's play and we would never feel alone.
You and I are stained-glass windows, not surprised the way that wind blows.
And out among the megaliths I wish that we could stay like this.
We spun together under orbs of stormy stars.
The lights of Swindon overheard, the fields of clover for our bed.
Followed in the drumbeats of those druids in the yard.