text:
#include "mirtk/PointCorrespondence.h"

#include "mirtk/Vtk.h"
#include "mirtk/Math.h"
#include "mirtk/Pair.h"
#include "mirtk/Array.h"
#include "mirtk/Algorithm.h"
#include "mirtk/Vector.h"
#include "mirtk/Matrix.h"
#include "mirtk/SparseMatrix.h"
#include "mirtk/Parallel.h"
#include "mirtk/Profiling.h"
#include "mirtk/Transformation.h"
#include "mirtk/SpectralDecomposition.h"
#include "mirtk/PointSetIO.h"

#include "mirtk/CommonExport.h"

#include "vtkSmartPointer.h"
#include "vtkDataArray.h"
#include "vtkPointData.h"
#include "vtkOctreePointLocator.h"
#include "vtkPMaskPoints.h"
#include "vtkFloatArray.h"
#include "vtkCharArray.h"
#include "vtkPolyData.h"
#include "vtkPolyDataNormals.h"
#include "vtkWindowedSincPolyDataFilter.h"

#include "mirtk/FiducialMatch.h"
#include "mirtk/ClosestPoint.h"
#include "mirtk/ClosestPointLabel.h"
#include "mirtk/ClosestCell.h"
#include "mirtk/SpectralMatch.h"
#include "mirtk/RobustClosestPoint.h"
#include "mirtk/RobustPointMatch.h"

namespace mirtk {

// Global debug level (cf. mirtk/Options.h)
MIRTK_Common_EXPORT extern int debug;

// =============================================================================
// Factory method
// =============================================================================

// -----------------------------------------------------------------------------
PointCorrespondence *PointCorrespondence::New(TypeId type)
{
  switch (type) {
    case FiducialMatch:       return new class FiducialMatch();
    case ClosestPoint:        return new class ClosestPoint();
    case ClosestPointLabel:   return new class ClosestPointLabel();
    case ClosestCell:         return new class ClosestCell();
    case SpectralMatch:       return new class SpectralMatch();
    case RobustClosestPoint:  return new class RobustClosestPoint();
    case RobustPointMatch:    return new class RobustPointMatch();
    default:
      cerr << "PointCorrespondence::New: Unknown type = " << type << endl;
      exit(1);
  }
}

// -----------------------------------------------------------------------------
PointCorrespondence *PointCorrespondence::New(const char *type_name)
{
  TypeId type = Unknown;
  if (!FromString(type_name, type)) {
    cerr << "PointCorrespondence::New: Unknown type = " << type_name << endl;
    exit(1);
  }
  return New(type);
}

// -----------------------------------------------------------------------------
template <> bool FromString(const char *str, PointCorrespondence::TypeId &type)
{
  if (strcmp(str, "Index") == 0 || strcmp(str, "Fiducial") == 0) {
    type = PointCorrespondence::FiducialMatch;
  } else if (strcmp(str, "CP")            == 0 ||
             strcmp(str, "ClosestPoint")  == 0 ||
             strcmp(str, "Closest Point") == 0 ||
             strcmp(str, "Closest point") == 0) {
    type = PointCorrespondence::ClosestPoint;
  } else if (strcmp(str, "ClosestPointLabel")   == 0 ||
             strcmp(str, "Closest Point Label") == 0 ||
             strcmp(str, "Closest point label") == 0) {
    type = PointCorrespondence::ClosestPointLabel;
  } else if (strcmp(str, "CSP")                   == 0 ||
             strcmp(str, "ClosestCell")           == 0 ||
             strcmp(str, "Closest Cell")          == 0 ||
             strcmp(str, "Closest cell")          == 0 ||
             strcmp(str, "Closest Surface Point") == 0 ||
             strcmp(str, "Closest surface point") == 0 ||
             strcmp(str, "Closest")               == 0) {
    type = PointCorrespondence::ClosestCell;
  } else if (strcmp(str, "SM")                   == 0 ||
             strcmp(str, "SpectralMatch")   == 0 ||
             strcmp(str, "Spectral Match") == 0 ||
             strcmp(str, "Spectral match") == 0) {
    type = PointCorrespondence::SpectralMatch;
  } else if (strcmp(str, "RCP")                  == 0 ||
             strcmp(str, "RobustClosestPoint")   == 0 ||
             strcmp(str, "Robust Closest Point") == 0 ||
             strcmp(str, "Robust closest point") == 0) {
    type = PointCorrespondence::RobustClosestPoint;
  } else if (strcmp(str, "RPM")                == 0 ||
             strcmp(str, "RobustPointMatch")   == 0 ||
             strcmp(str, "Robust Point Match") == 0 ||
             strcmp(str, "Robust point match") == 0) {
    type = PointCorrespondence::RobustPointMatch;
  } else {
    type = PointCorrespondence::Unknown;
  }
  return (type != PointCorrespondence::Unknown);
}

// -----------------------------------------------------------------------------
template <> string ToString(const PointCorrespondence::TypeId &type, int w, char c, bool left)
{
  string str;
  switch (type) {
    case PointCorrespondence::FiducialMatch:      str = "Index";              break;
    case PointCorrespondence::ClosestPoint:       str = "ClosestPoint";       break;
    case PointCorrespondence::ClosestPointLabel:  str = "ClosestPointLabel";  break;
    case PointCorrespondence::ClosestCell:        str = "ClosestCell";        break;
    case PointCorrespondence::SpectralMatch:      str = "SpectralMatch";      break;
    case PointCorrespondence::RobustClosestPoint: str = "RobustClosestPoint"; break;
    case PointCorrespondence::RobustPointMatch:   str = "RobustPointMatch";   break;
    default:                                      str = "Unknown";            break;
  }
  return ToString(str, w, c, left);
}

// =============================================================================
// Auxiliary functions
// =============================================================================

namespace PointCorrespondenceUtils {

// -----------------------------------------------------------------------------
/// Auxiliary functor used by SamplePoints
class FindIndicesOfPointsClosestToSamples
{
  vtkPointSet             *_Samples;
  vtkAbstractPointLocator *_Locator;
  Array<int>              *_Index;

public:

  void operator()(const blocked_range<vtkIdType> &re) const
  {
    double pt[3];
    Array<int> &index = (*_Index);
    for (vtkIdType i = re.begin(); i != re.end(); ++i) {
      _Samples->GetPoint(i, pt);
      index[i] = _Locator->FindClosestPoint(pt);
    }
  }

  static void Run(vtkAbstractPointLocator *locator, vtkPointSet *samples, Array<int> &index)
  {
    index.resize(samples->GetNumberOfPoints());
    FindIndicesOfPointsClosestToSamples body;
    body._Samples = samples;
    body._Locator = locator;
    body._Index   = &index;
    blocked_range<vtkIdType> pts(0, samples->GetNumberOfPoints());
    parallel_for(pts, body);
    sort(index.begin(), index.end());
    index.erase(unique(index.begin(), index.end()), index.end());
  }
};

// -----------------------------------------------------------------------------
void SamplePoints(vtkPointSet *pointset, Array<int> &indices,
                  int maxnum, double maxdist, bool stratified)
{
  MIRTK_START_TIMING();

  // Reset set of drawn samples (empty --> use all points)
  indices.clear();

  // Skip if input data set contains no points (failsafe)
  if (pointset->GetNumberOfPoints() == 0) return;

  // Build point locator
  //
  // Due to a bug in vtkKdTreePointLocator, calling BuildLocator
  // is not sufficient to make FindClosestPoint thread-safe as it does
  // not call vtkBSPIntersections::BuildRegionsList
  // (cf. http://www.vtk.org/Bug/view.php?id=15206 ).
  vtkSmartPointer<vtkOctreePointLocator> locator;
  if (maxnum > 0 || maxdist > .0) {
    locator = vtkSmartPointer<vtkOctreePointLocator>::New();
    locator->SetDataSet(pointset);
    locator->BuildLocator();
  }

  // Determine maximum number of samples
  int nsamples;
  if (maxnum == 0 && maxdist > .0) {
    const double r = maxdist / 2.0;
    // Count number of points within radius r of each input point
    double p[3];
    vtkSmartPointer<vtkIdList> ids = vtkSmartPointer<vtkIdList>::New();
    double sum = .0;
    for (vtkIdType i = 0; i < pointset->GetNumberOfPoints(); ++i) {
      pointset->GetPoint(i, p);
      locator->FindPointsWithinRadius(r, p, ids);
      sum += ids->GetNumberOfIds();
    }
    // Divide number of points by average number of points within radius r
    nsamples = iround(pointset->GetNumberOfPoints() / (sum / pointset->GetNumberOfPoints()));
  } else {
    nsamples = maxnum;
  }

  // Extract specified maximum number of samples
  if (nsamples > 0) {
    vtkSmartPointer<vtkPMaskPoints> sampler;
    sampler = vtkSmartPointer<vtkPMaskPoints>::New();
    sampler->GenerateVerticesOff();
    sampler->SetMaximumNumberOfPoints(nsamples);
    sampler->SetRandomModeType(stratified ? 2 : 1);
    sampler->RandomModeOn();
    sampler->ProportionalMaximumNumberOfPointsOn();
    SetVTKInput(sampler, pointset);
    MIRTK_START_TIMING();
    sampler->Update();
    MIRTK_DEBUG_TIMING(6, "uniformly subsampling point set");
    MIRTK_RESET_TIMING();
    FindIndicesOfPointsClosestToSamples::Run(locator, sampler->GetOutput(), indices);
    MIRTK_DEBUG_TIMING(6, "finding closest sample points");
  }

  MIRTK_DEBUG_TIMING(5, "subsampling of point set (#samples = " << nsamples << ")");
}

// -----------------------------------------------------------------------------
/// Maximum range of spatial coordinates
double MaxSpatialRange(vtkPointSet *target, vtkPointSet *source)
{
  double target_range[6], source_range[6], range[3];
  target->GetBounds(target_range);
  source->GetBounds(source_range);
  range[0] = max(target_range[1] - target_range[0], source_range[1] - source_range[0]);
  range[1] = max(target_range[3] - target_range[2], source_range[3] - source_range[2]);
  range[2] = max(target_range[5] - target_range[4], source_range[5] - source_range[4]);
  return max(max(range[0], range[1]), range[2]);
}

// -----------------------------------------------------------------------------
vtkSmartPointer<vtkPointSet> SpectralPoints(vtkPointSet *input)
{
  vtkDataArray *eigenmodes = input->GetPointData()->GetArray("eigenmodes");
  if (!eigenmodes) return NULL;

  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
  points->SetNumberOfPoints(input->GetNumberOfPoints());

  double *p = new double[max(3, eigenmodes->GetNumberOfComponents())];
  for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i) {
    eigenmodes->GetTuple(i, p);
    points->SetPoint(i, p);
  }
  delete[] p;

  vtkSmartPointer<vtkPointSet> output;
  output.TakeReference(input->NewInstance());
  output->DeepCopy (input);
  output->SetPoints(points);
  return output;
}

// -----------------------------------------------------------------------------
int ComputeNormals(vtkPolyData *dataset)
{
  // Smooth polydata
  vtkSmartPointer<vtkWindowedSincPolyDataFilter> smoother;
  smoother = vtkSmartPointer<vtkWindowedSincPolyDataFilter>::New();
  smoother->FeatureEdgeSmoothingOff();
  smoother->SetNumberOfIterations(25);
  smoother->SetPassBand(.1);
  smoother->NormalizeCoordinatesOn();
  SetVTKInput(smoother, dataset);
  // Calculate normals
  vtkSmartPointer<vtkPolyDataNormals> calculator;
  calculator = vtkSmartPointer<vtkPolyDataNormals>::New();
  calculator->SplittingOff();
  calculator->ConsistencyOn();
  calculator->AutoOrientNormalsOn();
  SetVTKConnection(calculator, smoother);
  calculator->Update();
  vtkDataArray *normals = calculator->GetOutput()->GetPointData()->GetNormals();
  normals->SetName("Normals");
  dataset->GetPointData()->SetNormals(normals);
  int i = -1;
  dataset->GetPointData()->GetArray("Normals", i);
  return i;
}

// -----------------------------------------------------------------------------
int ComputeSpectralNormals(vtkPolyData *dataset)
{
  vtkSmartPointer<vtkPointSet> spectral_pointset = SpectralPoints(dataset);
  vtkPolyData *spectral_polydata = vtkPolyData::SafeDownCast(spectral_pointset);
  int i = -1;
  if (spectral_polydata) {
    ComputeNormals(spectral_polydata);
    vtkDataArray *normals = dataset->GetPointData()->GetArray("spectral normals", i);
    if (normals) normals->DeepCopy(spectral_polydata->GetPointData()->GetNormals());
    else {
      i = dataset->GetPointData()->AddArray(spectral_polydata->GetPointData()->GetNormals());
    }
  }
  return i;
}

// -----------------------------------------------------------------------------
int GetEigenmodes(const RegisteredPointSet *dataset, int k, Matrix &m, Vector &v)
{
  int           i = -2;
  vtkDataArray *s = dataset->PointSet()->GetPointData()->GetArray("eigenmodes", i);
  if (dataset->Transformation() || s == NULL || s->GetNumberOfComponents() < k || v.Rows() < k) {
    vtkPolyData *polydata = vtkPolyData::SafeDownCast(dataset->PointSet());
    if (!polydata) {
      cerr << "PointCorrespondence: Can only compute eigenmodes of surface mesh" << endl;
      exit(1);
    }
    if (SpectralDecomposition::ComputeEigenmodes(polydata, k, m, v) != k) {
      cerr << "PointCorrespondence: Failed to compute " << k << " eigenmodes" << endl;
      exit(1);
    }
    return -2;
  } else {
    m.Initialize(static_cast<int>(s->GetNumberOfTuples()), k);
    double *row = new double[k];
    for (vtkIdType r = 0; r < s->GetNumberOfTuples(); ++r) {
      s->GetTuple(r, row);
      for (int c = 0; c < k; ++c) m(r, c) = row[c];
    }
    delete[] row;
    return i;
  }
}

// -----------------------------------------------------------------------------
void GetNormalizationParametersOfEigenmodes(double &slope, double &intercept,
                                            vtkDataArray *m1, vtkDataArray *m2,
                                            Vector w = Vector())
{
  const int k = min(m1->GetNumberOfComponents(), m2->GetNumberOfComponents());
  if (w.Rows() < k) w.Resize(k, 1.0);
  double range[2], minval = numeric_limits<double>::infinity(), maxrange = .0;
  for (int c = 0; c < k; ++c) {
    m1->GetRange(range, c);
    minval   = min(minval,   w(c) * range[0]);
    maxrange = max(maxrange, w(c) * (range[1] - range[0]));
    m2->GetRange(range, c);
    minval   = min(minval,   w(c) * range[0]);
    maxrange = max(maxrange, w(c) * (range[1] - range[0]));
  }
  slope     = 2.0 / maxrange;
  intercept = - slope * minval - 1.0;
}

// -----------------------------------------------------------------------------
/// (Re-)compute eigenmodes of datasets independent of each other and
/// correct for sign ambiguity and order afterwards using bipartite matching
void UpdateEigenmodes(const RegisteredPointSet         *target,
                      Vector                           &target_eigenvalues,
                      PointCorrespondence::FeatureList &target_features,
                      const RegisteredPointSet         *source,
                      Vector                           &source_eigenvalues,
                      PointCorrespondence::FeatureList &source_features,
                      int                               k)
{
  using namespace SpectralDecomposition;
  // Get feature entries
  PointCorrespondence::FeatureList::iterator target_info;
  for (target_info = target_features.begin(); target_info != target_features.end(); ++target_info) {
    if (target_info->_Name == "eigenmodes") break;
  }
  if (target_info == target_features.end()) return;
  PointCorrespondence::FeatureList::iterator source_info;
  for (source_info = source_features.begin(); source_info != source_features.end(); ++source_info) {
    if (source_info->_Name == "eigenmodes") break;
  }
  if (source_info == source_features.end()) return;
  // Cast to vtkPolyData
  vtkPolyData *target_polydata = vtkPolyData::SafeDownCast(target->PointSet());
  vtkPolyData *source_polydata = vtkPolyData::SafeDownCast(source->PointSet());
  if (!target_polydata || !source_polydata) {
    cerr << "FiducialRegistrationError::UpdateEigenmodes: Point sets must be surface meshes" << endl;
    exit(1);
  }
  // Get/compute eigenmodes of each dataset
  Matrix m1, m2;
  target_info->_Index = GetEigenmodes(target, k, m1, target_eigenvalues);
  source_info->_Index = GetEigenmodes(source, k, m2, source_eigenvalues);
  // Match sign and order of eigenmodes
  if (source->Transformation() != NULL && target->Transformation() == NULL) {
    MatchEigenmodes(target->Points(), m1, target_eigenvalues,
                    source->Points(), m2, source_eigenvalues);
    source_info->_Index = -2; // indicate that eigenmodes need to be updated
  } else {
    MatchEigenmodes(source->Points(), m2, source_eigenvalues,
                    target->Points(), m1, target_eigenvalues);
    target_info->_Index = -2; // indicate that eigenmodes need to be updated
  }
  // Set eigenmodes as point data of datasets to be registered
  if (target_info->_Index < 0) {
    target_info->_Index = SetEigenmodes(target_polydata, m1, 0, k, "eigenmodes");
  }
  if (source_info->_Index < 0) {
    source_info->_Index = SetEigenmodes(source_polydata, m2, 0, k, "eigenmodes");
  }
  // Set rescaling parameters s.t. eigenmodes are normalized to range [-1 +1]
  double slope, intercept;
  vtkDataArray *target_eigenmodes = target->PointSet()->GetPointData()->GetArray(target_info->_Index);
  vtkDataArray *source_eigenmodes = source->PointSet()->GetPointData()->GetArray(source_info->_Index);
  GetNormalizationParametersOfEigenmodes(slope, intercept, target_eigenmodes, source_eigenmodes);
  target_info->_Slope     = source_info->_Slope     = slope;
  target_info->_Intercept = source_info->_Intercept = intercept;
}

// -----------------------------------------------------------------------------
void UpdateEigenmodes(const RegisteredPointSet         *target,
                      PointCorrespondence::FeatureList &target_features,
                      const RegisteredPointSet         *source,
                      PointCorrespondence::FeatureList &source_features,
                      Vector                           &eigenvalues,
                      int                               k)
{
  using namespace SpectralDecomposition;
  typedef GenericSparseMatrix<double> SparseMatrix;
  vtkDataArray *target_eigenmodes, *source_eigenmodes;
  // Get feature entries
  PointCorrespondence::FeatureList::iterator target_info;
  for (target_info = target_features.begin(); target_info != target_features.end(); ++target_info) {
    if (target_info->_Name == "eigenmodes") break;
  }
  if (target_info == target_features.end()) return;
  PointCorrespondence::FeatureList::iterator source_info;
  for (source_info = source_features.begin(); source_info != source_features.end(); ++source_info) {
    if (source_info->_Name == "eigenmodes") break;
  }
  if (source_info == source_features.end()) return;
  // Cast to vtkPolyData
  vtkPolyData *target_polydata = vtkPolyData::SafeDownCast(target->PointSet());
  vtkPolyData *source_polydata = vtkPolyData::SafeDownCast(source->PointSet());
  if (!target_polydata || !source_polydata) {
    cerr << "FiducialRegistrationError::UpdateEigenmodes: Point sets must be surface meshes" << endl;
    exit(1);
  }
  // Compute initial spectral coordinates
  if (ComputeEigenmodes(target_polydata, source_polydata, k) < k) {
    cerr << "FiducialRegistrationError::UpdateEigenmodes: Failed to find " << k << " initial eigenmodes" << endl;
    exit(1);
  }
  // Sample points for which inter-dataset links will be added
  Array<int> target_sample, source_sample;
  SamplePoints(target, target_sample, max(10, target->NumberOfPoints() / 10));
  SamplePoints(source, source_sample, max(10, source->NumberOfPoints() / 10));
  // Find initial point correspondences
  PointLocator::FeatureList target_match_features;
  PointLocator::FeatureList source_match_features;
  PointLocator::FeatureInfo feature;
  vtkPointData * const targetPD = target_polydata->GetPointData();
  vtkPointData * const sourcePD = source_polydata->GetPointData();
  // Use computed spectral coordinates for initial match
  int target_index, source_index;
  target_eigenmodes = targetPD->GetArray(feature._Name.c_str(), target_index);
  source_eigenmodes = sourcePD->GetArray(feature._Name.c_str(), source_index);
  GetNormalizationParametersOfEigenmodes(feature._Slope, feature._Intercept,
                                         target_eigenmodes, source_eigenmodes);
  feature._Name   = "eigenmodes";
  feature._Weight = target_info->_Weight;
  feature._Index  = target_index;
  target_match_features.push_back(feature);
  feature._Weight = source_info->_Weight;
  feature._Index  = source_index;
  source_match_features.push_back(feature);
  // Optionally also use normals of 3D spectral points
  feature._Name = "spectral normals";
  for (size_t i = 0; i < target_features.size(); ++i) {
    if (target_features[i]._Name == feature._Name) {
      ComputeSpectralNormals(target_polydata);
      feature._Weight    = target_features[i]._Weight;
      feature._Slope     = target_features[i]._Slope;
      feature._Intercept = target_features[i]._Intercept;
      targetPD->GetArray(feature._Name.c_str(), feature._Index);
      target_match_features.push_back(feature);
      break;
    }
  }
  for (size_t i = 0; i < source_features.size(); ++i) {
    if (source_features[i]._Name == feature._Name) {
      ComputeSpectralNormals(source_polydata);
      sourcePD->GetArray(feature._Name.c_str(), feature._Index);
      feature._Weight    = source_features[i]._Weight;
      feature._Slope     = source_features[i]._Slope;
      feature._Intercept = source_features[i]._Intercept;
      source_match_features.push_back(feature);
      break;
    }
  }
  // Find nearest neighbors of point samples
  Array<int>    corr12, corr21;
  Array<double> dist12, dist21;
  corr12 = PointLocator::FindClosestPoint(target->PointSet(), &target_sample, &target_match_features,
                                          source->PointSet(), &source_sample, &source_match_features, &dist12);
  corr21 = PointLocator::FindClosestPoint(source->PointSet(), &source_sample, &source_match_features,
                                          target->PointSet(), &target_sample, &target_match_features, &dist21);
  // Set intra-mesh affinity weights
  const int m = target->NumberOfPoints();
  const int n = source->NumberOfPoints();
  SparseMatrix::Entries *cols = new SparseMatrix::Entries[m + n];
  AdjacencyMatrix(cols, SparseMatrix::CCS, 0, 0, vtkPolyData::SafeDownCast(target->InputPointSet()));
  AdjacencyMatrix(cols, SparseMatrix::CCS, m, m, vtkPolyData::SafeDownCast(source->InputPointSet()));
  // Set inter-mesh affinity weights
  const int ncorr12 = static_cast<int>(corr12.size());
  for (int i = 0; i < ncorr12; ++i) {
    dist12[i] = 1.0 / (sqrt(dist12[i]) + EPSILON);
    const int r = corr12[i] + m;
    const int c = PointCorrespondence::GetPointIndex(target, &target_sample, i);
    cols[c].push_back(MakePair(r, dist12[i]));
    cols[r].push_back(MakePair(c, dist12[i]));
  }
  const int ncorr21 = static_cast<int>(corr21.size());
  for (int i = 0; i < ncorr21; ++i) {
    dist21[i] = 1.0 / (sqrt(dist21[i]) + EPSILON);
    const int r = corr21[i];
    const int c = PointCorrespondence::GetPointIndex(source, &source_sample, i) + m;
    cols[c].push_back(MakePair(r, dist21[i]));
    cols[r].push_back(MakePair(c, dist21[i]));
  }
  // Compute graph Laplacian of joint connectivity graph
  SparseMatrix L(SparseMatrix::CCS);
  L.Initialize(m + n, m + n, cols);
  NormalizedLaplacian(L, L);
  delete[] cols;
  // Compute eigenmodes of joint graph Laplacian
  Matrix eigenmodes;
  if (ComputeEigenmodes(L, k+2, eigenmodes, eigenvalues) < k) {
    cerr << "FiducialRegistrationError::UpdateEigenmodes: Failed to compute " << k << " eigenmodes" << endl;
    exit(1);
  }
  eigenvalues.Resize(k);
  // Set eigenmodes as point data
  target_info->_Index = SetEigenmodes(target_polydata, eigenmodes, 0, k, "eigenmodes");
  source_info->_Index = SetEigenmodes(source_polydata, eigenmodes, m, k, "eigenmodes");
  target_eigenmodes   = targetPD->GetArray(target_info->_Index);
  source_eigenmodes   = sourcePD->GetArray(source_info->_Index);
  // Calculate weight of eigenmodes, more importance to lower frequencies
  double wsum = .0;
  for (int c = 0; c < k; ++c) {
    wsum += 1.0 / sqrt(eigenvalues(c));
  }
  Vector weight(k);
  for (int c = k; c >= 0; --c) {
    weight(c) = (1.0 / sqrt(eigenvalues(c))) / wsum;
  }
  // Set rescaling parameters s.t. eigenmodes are normalized to range [-1 +1]
  double slope, intercept;
  GetNormalizationParametersOfEigenmodes(slope, intercept, target_eigenmodes, source_eigenmodes, weight);
  target_info->_Slope     = source_info->_Slope     = slope;
  target_info->_Intercept = source_info->_Intercept = intercept;
}

// -----------------------------------------------------------------------------
void UpdateEigenmodesIfUsed(const RegisteredPointSet         *target,
                            Vector                           &target_eigenvalues,
                            PointCorrespondence::FeatureList &target_features,
                            const RegisteredPointSet         *source,
                            Vector                           &source_eigenvalues,
                            PointCorrespondence::FeatureList &source_features,
                            int k, bool diffeo)
{
  // Skip if no spectral coordinates used as features
  if (k == 0) {
    target_eigenvalues.Clear();
    source_eigenvalues.Clear();
    return;
  }
  size_t i;
  for (i = 0; i < target_features.size(); ++i) {
    if ((target_features[i]._Name == "eigenmodes" ||
         target_features[i]._Name == "spectral normals")
        && target_features[i]._Weight != .0) break;
  }
  if (i == target_features.size()) {
    target_eigenvalues.Clear();
    source_eigenvalues.Clear();
    return;
  }
  // Compute eigenmodes
  if (diffeo) {
    UpdateEigenmodes(target, target_features,
                     source, source_features, source_eigenvalues, k);
    target_eigenvalues = source_eigenvalues;
  } else {
    UpdateEigenmodes(target, target_eigenvalues, target_features,
                     source, source_eigenvalues, source_features, k);
  }
}

} // namespace PointCorrespondenceUtils
using namespace PointCorrespondenceUtils;

// =============================================================================
// Construction/Destruction
// =============================================================================

// -----------------------------------------------------------------------------
PointCorrespondence::PointCorrespondence(const RegisteredPointSet *target,
                                         const RegisteredPointSet *source)
:
  _M(0), _N(0), _NumberOfFeatures(0),
  _Target(target), _TargetSample(NULL), _TargetFeatures(),
  _Source(source), _SourceSample(NULL), _SourceFeatures(),
  _DimensionOfSpectralPoints(5),
  _DiffeomorphicSpectralDecomposition(true),
  _UpdateSpectralPoints(false),
  _FromTargetToSource(true),
  _FromSourceToTarget(true),
  _DefaultDirection(TargetToSource)
{
}

// -----------------------------------------------------------------------------
PointCorrespondence::PointCorrespondence(const PointCorrespondence &other)
:
  _M(other._M), _N(other._N), _NumberOfFeatures(other._NumberOfFeatures),
  _Target(other._Target), _TargetSample(other._TargetSample), _TargetFeatures(other._TargetFeatures),
  _Source(other._Source), _SourceSample(other._SourceSample), _SourceFeatures(other._SourceFeatures),
  _DimensionOfSpectralPoints(other._DimensionOfSpectralPoints),
  _DiffeomorphicSpectralDecomposition(other._DiffeomorphicSpectralDecomposition),
  _UpdateSpectralPoints (other._UpdateSpectralPoints),
  _FromTargetToSource(other._FromTargetToSource),
  _FromSourceToTarget(other._FromSourceToTarget),
  _DefaultDirection(other._DefaultDirection)
{
}

// -----------------------------------------------------------------------------
PointCorrespondence::~PointCorrespondence()
{
}

// =============================================================================
// Parameters
// =============================================================================

// -----------------------------------------------------------------------------
int PointCorrespondence::GetPointDataIndexByCaseInsensitiveName(vtkPointData *pd, const string &name)
{
  string lname = ToLower(name);
  for (int i = 0; i < pd->GetNumberOfArrays(); ++i) {
    const char *array_name = pd->GetArrayName(i);
    if (array_name == NULL) continue;
    string lower_name = ToLower(array_name);
    if (lower_name == lname) return i;
  }
  return -1;
}

// -----------------------------------------------------------------------------
bool PointCorrespondence::Set(const char *param, const char *value)
{
  if (strcmp(param, "No. of spectral coordinates")    == 0 ||
      strcmp(param, "Number of spectral coordinates") == 0 ||
      strcmp(param, "Dimension of spectral points")   == 0 ||
      strcmp(param, "Spectral coordinates number")    == 0) {
    return FromString(value, _DimensionOfSpectralPoints);
  }
  if (strcmp(param, "Diffeomorphic spectral matching")      == 0 ||
      strcmp(param, "Diffeomorphic spectral coordinates")   == 0 ||
      strcmp(param, "Diffeomorphic spectral decomposition") == 0) {
    return FromString(value, _DiffeomorphicSpectralDecomposition);
  }
  if (strcmp(param, "Spectral coordinates update") == 0) {
    return FromString(value, _UpdateSpectralPoints);
  }

  size_t len = strlen(param);
  if (len > 7 && strcmp(param + len - 7, " weight") == 0) {
    double weight;
    if (!FromString(value, weight) || weight < .0) return false;
    string feature_name(param, param + len - 7);
    AddFeature(feature_name.c_str(), weight);
    return true;
  }

  return false;
}

// -----------------------------------------------------------------------------
ParameterList PointCorrespondence::Parameter() const
{
  ParameterList params = Observable::Parameter();
  Insert(params, "Diffeomorphic spectral decompositon", ToString(_DiffeomorphicSpectralDecomposition));
  Insert(params, "No. of spectral coordinates", ToString(_DimensionOfSpectralPoints));
  Insert(params, "Spectral coordinates update", ToString(_UpdateSpectralPoints));
  string name;
  for (size_t i = 0; i < _TargetFeatures.size(); ++i) {
    name = _TargetFeatures[i]._Name;
    if (name.empty()) continue;
    if (name == "eigenmodes") name = "spectral coordinates";
    name += " weight";
    Insert(params, name, ToString(_TargetFeatures[i]._Slope));
  }
  return params;
}

// -----------------------------------------------------------------------------
static string TransformFeatureName(const char *name)
{
  string feature_name = ToLower(name);
  if (feature_name == "spatial normals") {
    feature_name = "normals";
  } else if (feature_name == "spectral coordinates" ||
             feature_name == "spectral points") {
    feature_name = "eigenmodes";
  } else if (feature_name == "spatial coordinates" ||
             feature_name == "spatial point"       ||
             feature_name == "spatial points"      ||
             feature_name == "points") {
    feature_name = "spatial coordinates";
  }
  return feature_name;
}

// -----------------------------------------------------------------------------
bool PointCorrespondence::AddFeature(const char *name, double weight, double slope, double intercept)
{
  const string feature_name = TransformFeatureName(name);
  int index = -2; // < -1: determined after data is set by CompleteFeatureInfo
  if (feature_name == "spatial coordinates") index = -1;
  _TargetFeatures.push_back(FeatureInfo(feature_name, index, weight, slope, intercept));
  _SourceFeatures.push_back(FeatureInfo(feature_name, index, weight, slope, intercept));
  return true;
}

// -----------------------------------------------------------------------------
void PointCorrespondence::RemoveFeature(const char *name)
{
  const string feature_name = TransformFeatureName(name);
  for (FeatureList::iterator i = _TargetFeatures.begin(); i != _TargetFeatures.end(); ++i) {
    if (i->_Name == feature_name) {
      FeatureList::iterator pos = i; --i;
      _TargetFeatures.erase(pos);
    }
  }
  for (FeatureList::iterator i = _SourceFeatures.begin(); i != _SourceFeatures.end(); ++i) {
    if (i->_Name == feature_name) {
      FeatureList::iterator pos = i; --i;
      _SourceFeatures.erase(pos);
    }
  }
}

// -----------------------------------------------------------------------------
void PointCorrespondence::CompleteFeatureInfo(const RegisteredPointSet *input, FeatureList &feature)
{
  vtkPointData * const inputPD = input->PointSet()->GetPointData();
  for (FeatureList::iterator i = feature.begin(); i != feature.end(); ++i) {
    if (i->_Index < -1) {
      if (i->_Name.empty()) {
        cerr << "PointCorrespondence::CompleteFeatureInfo: Encountered feature without name" << endl;
        exit(1);
      }
      i->_Index = GetPointDataIndexByCaseInsensitiveName(inputPD, i->_Name.c_str());
      // Spectral features are computed and added by UpdateEigenmodesIfUsed when missing
      if (i->_Index < 0 && i->_Name != "eigenmodes" && i->_Name != "spectral normals") {
        cerr << "PointCorrespondence::CompleteFeatureInfo: Missing point data " << i->_Name << endl;
        exit(1);
      }
    } else if (i->_Index >= inputPD->GetNumberOfArrays()) {
      cerr << "PointCorrespondence::CompleteFeatureInfo: Feature index is out of bounds" << endl;
      exit(1);
    }
  }
}

// =============================================================================
// Correspondences
// =============================================================================

// -----------------------------------------------------------------------------
void PointCorrespondence::Initialize()
{
  // Check that all inputs are set
  if (_Target == NULL) {
    cerr << "PointCorrespondence::Initialize: Target data set not set" << endl;
    exit(1);
  }
  if (_Source == NULL) {
    cerr << "PointCorrespondence::Initialize: Source data set not set" << endl;
    exit(1);
  }

  // Ensure that correspondences in at least one direction are requested
  if (!_FromTargetToSource && !_FromSourceToTarget) {
    cerr << "PointCorrespondence::Initialize: At least one direction,"
            " either FromTargetToSource or FromSourceToTarget must be enabled" << endl;
    exit(1);
  }

  // Fill missing feature info which requires inspection of the input dataset
  CompleteFeatureInfo(_Target, _TargetFeatures);
  CompleteFeatureInfo(_Source, _SourceFeatures);

  // Determine size of feature vectors
  _NumberOfFeatures = GetPointDimension(_Target, &_TargetFeatures);
  if (GetPointDimension(_Source, &_SourceFeatures) != _NumberOfFeatures) {
    cerr << "PointCorrespondence::Initialize: Mismatching feature vector size" << endl;
    exit(1);
  }

  // Initialize this class
  PointCorrespondence::Init();
}

// -----------------------------------------------------------------------------
void PointCorrespondence::Reinitialize()
{
  // Reinitialize this class
  PointCorrespondence::Init();
}

// -----------------------------------------------------------------------------
void PointCorrespondence::Init()
{
  // Determine number of points (samples)
  _M = GetNumberOfPoints(_Target, _TargetSample);
  _N = GetNumberOfPoints(_Source, _SourceSample);
  if (_M == 0) {
    cerr << "PointCorrespondence::Initialize: Target data set has no points!" << endl;
    exit(1);
  }
  if (_N == 0) {
    cerr << "PointCorrespondence::Initialize: Source data set has no points!" << endl;
    exit(1);
  }

  // Compute spectral coordinates if needed
  UpdateEigenmodesIfUsed(_Target, _TargetEigenvalues, _TargetFeatures,
                         _Source, _SourceEigenvalues, _SourceFeatures,
                         _DimensionOfSpectralPoints, _DiffeomorphicSpectralDecomposition);
}

// -----------------------------------------------------------------------------
void PointCorrespondence::Update()
{
  // Recompute spectral coordinates (optional/experimental)
  if (_UpdateSpectralPoints) {
    UpdateEigenmodesIfUsed(_Target, _TargetEigenvalues, _TargetFeatures,
                           _Source, _SourceEigenvalues, _SourceFeatures,
                           _DimensionOfSpectralPoints, _DiffeomorphicSpectralDecomposition);
  }
}

// -----------------------------------------------------------------------------
bool PointCorrespondence::Upgrade()
{
  return false;
}

// -----------------------------------------------------------------------------
int PointCorrespondence::GetTargetIndex(int) const
{
  return -1;
}

// -----------------------------------------------------------------------------
int PointCorrespondence::GetSourceIndex(int) const
{
  return -1;
}

// =============================================================================
// Debugging
// =============================================================================

// -----------------------------------------------------------------------------
void PointCorrespondence::WriteDataSets(const char *prefix, const char *suffix, bool all) const
{
  if (all || debug >= 4) {
    const int sz = 1024;
    char      fname[sz];
    snprintf(fname, sz, "%sspectral_target_points%s.vtp", prefix, suffix);
    this->WriteSpectralPoints(fname, _Target->PointSet());
    snprintf(fname, sz, "%sspectral_source_points%s.vtp", prefix, suffix);
    this->WriteSpectralPoints(fname, _Source->PointSet());
  }
}

// -----------------------------------------------------------------------------
void PointCorrespondence::WriteSpectralPoints(const char *fname, vtkPointSet *d) const
{
  vtkDataArray *modes = d->GetPointData()->GetArray("eigenmodes");
  if (!modes) return;

  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
  points->SetNumberOfPoints(d->GetNumberOfPoints());

  double *p = new double[max(3, int(modes->GetNumberOfComponents()))];
  for (int c = 0; c < 3; ++c) p[c] = .0;
  for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i) {
    modes ->GetTuple(i, p);
    points->SetPoint(i, p);
  }
  delete[] p;

  vtkSmartPointer<vtkPointSet> output;
  output.TakeReference(d->NewInstance());
  output->ShallowCopy(d);
  output->SetPoints(points);
  WritePointSet(fname, output);
}

} // namespace mirtk


text:
'You are whole and welcome here'
A Virginia Breakthrough Congregation builds community through Pride.
Andrea Dulanto Fall 2019 9/1/2019
Drag queen emcee Delta B Knyght entertains the crowd at Reston Pride 2019. (© 2019 Annalee Durland-Jones)
© 2019 Annalee Durland-Jones
On a Sunday morning during the first weekend of June, the choir of the Unitarian Universalist Church in Reston, Virginia, practices Lady Gaga's "Born This Way" before the service. By the church entrance, greeters stand by a table displaying "Side with Love" buttons with rainbow hearts. As congregants enter, some take a button, while others arrive already wearing one. Some also wear rainbow attire: a shawl, a scarf, a dress. This is Pride Sunday, and the Rev. Dr. Debra Haffner, UUCR's minister, stands outside to welcome all who enter. She wears glasses with rainbow frames and a rainbow dress that she also wore for the previous day's second annual Reston Pride at Lake Anne Plaza. "This is my favorite time, when I get to greet people," she says.
Many congregants on Pride Sunday volunteered at or attended Reston Pride, but the mood is one of elation rather than exhaustion. This may be from the excitement of celebrating Pride. It may also be from the new energy that's developed in the church over the past few years.
Reston Pride has a lot to do with this revitalization. Haffner and UUCR began planning the first Reston Pride in September 2017, and the event brought out the skills and leadership of the congregation. It was the first Pride event in the history of Reston, a city that was founded by Robert E. Simon in 1964 with the intention of building a more inclusive community. UUCR was the main organizer of Reston Pride, but it focused on a collaborative planning process by engaging the cosponsorship and participation of local faith communities, organizations, and businesses. "The decisions were made by the community," Haffner explains.
Next year, there will be even more focus on a community-driven event, and Haffner will not be a chair. The current goal is for Reston Pride to obtain independent nonprofit 501(c)(3) status within a few months, so the event can be organized by a diverse group of board members, chairs, and volunteers. "It won't be reliant on our church or any other particular church to shepherd it anymore," says Paul Baumgartner, program chair of Reston Pride. However, Haffner and UUCR's work over the past couple of years has built and continues to build a path towards a more inclusive community within as well as outside of the church. For their work on Reston Pride, the Unitarian Universalist Association named the UU Church in Reston a 2019 Breakthrough Congregation.
Flickr slideshow
Photo gallery: 2019 Reston Pride
Photographs © 2019 Annalee Durland-Jones for UU World
UUCR had been a Welcoming Congregation for LGBTQ people since May 2000, but when Haffner arrived as minister in 2016 she found there were "very few out gay people in the church." She had worked as a sexual rights advocate for over forty years, and as a cofounder and director of the Religious Institute. One of her first social justice interests at UUCR was "What are you all doing for the LGBT community?"
Baumgartner joined the congregation in 1992 and had always been supportive of LGBTQ issues. He was on the committee that assisted with the Welcoming Congregation certification process. Over the years, an Interweave chapter occasionally met at the church, and there was involvement in marches, but he admits there wasn't "an active push . . . to move the congregation towards becoming more welcoming."
Then Haffner got what she says was "the first and only freestanding rainbow flag in Reston" for the church's property. Gar Young, former chair and current member of the LGBTQ Task Force at UUCR, says the flag is one of the reasons the church appealed to him. "I am bisexual. To have a church that celebrates my sexuality and spirituality is just awesome."
The flag was only the beginning. There were very few gathering places for LGBTQ people in Reston and no Pride celebration, so Haffner proposed Reston Pride to the board, which wanted the church to be known for its social action and social justice. "Most people didn't know who we were, and the church has been here since 1970," says Julia Norrgard, who came to UUCR in 1980 and has served as its president twice. She notes that the board expressed enthusiasm for Reston Pride but also some hesitation because they weren't sure if the event would be well attended.
In September 2017, Haffner met with a few other clergy to discuss the Pride festival. Three of them joined UUCR in donating funds for Reston Pride. Haffner took on the role of lead organizer, and the event was to take place outdoors at UUCR. By January 2018, twenty community organizations were cosponsors. Eventually, twenty organizations, forty exhibitors, sixty volunteers, and twenty-five performers participated in Reston Pride in June 2018.
"[UUCR] put a stake in the ground to say what it means to be not just welcoming but to put that into action," shares Kerrie Wilson, CEO of Cornerstones, a community-based housing and human services nonprofit that the church had a previously established relationship with. "It's a model for other congregations and other groups."
Haffner's son, Greg, came from California to emcee as drag queen Mama Celeste. Virginia Delegate Ken Plum of Reston was a speaker. "You have LGBTQ folks who have an interest in the festival, but you have folks like myself who are very supportive of the community and want to make sure that they're included and that we demonstrate that in a public way," says Plum.
On the day of the event, the forecast called for thunderstorms. The exhibitor tables and the stage had to be moved inside the church, which was meant to hold 260 people. Haffner and the board agreed that 300 attendees would be a success—and 1,200 people showed up. Norrgard was struck by the look of joy on the faces of attendees.
Cornerstones, which often works with transgender individuals as well as youth who have been abandoned by their families, had an exhibitor table. For some Cornerstones clients, Wilson says, Reston Pride offered another way to find belonging. "What I love is that there was another place where people felt safe, and they could trust or talk to people," Wilson says.
Jen Dixon, current LGBTQ Task Force chair at UUCR, says Reston Pride was one reason she became a member of the church. During Haffner's ministry, membership has risen from 171 members to 244.
"We've grown a lot," says Baumgartner. "Part of that is [Haffner], part of that is the 2016 election, and part of that is this initiative she created to have this Pride celebration."
Haffner advocated for more "shared leadership" for the 2019 Pride. "It was never meant to be the UUCR Reston Pride," says Deb Stover, UUCR member and graphics chair for the event. "We were just getting this going so it could take wings and go."
St. Anne's Episcopal Church, United Christian Parish, and Leah Maier, a friend of UUCR, cochaired Reston Pride 2019 with UUCR. Paul Cohen, president and longtime member of UUCR, says having cochairs sends a message that "the religious community is reaching out to all people." Tim Barwick, outreach minister at St. Anne's, says UUCR used to be a "sleepy little place," and now it's known for energizing congregations.
Washington Plaza Baptist Church, a cosponsor of Reston Pride, is an inclusive, multicultural faith community. The Rev. Michelle Nickens of WPBC is the only African American clergyperson on the Pride planning committee at this time and shares that her church is "one of only four Baptist churches in northern Virginia that have made an emphatic statement or position around being fully welcoming and affirming." This year, Nickens became more involved by working on programming and performing as a vocalist at the festival. WPBC offered its location on Lake Anne Plaza as a meeting space, particularly for the volunteer orientation on the eve of Reston Pride. Of the sixty volunteers at the orientation, one-quarter were from UUCR.
The second annual Reston Pride brought sunshine and 5,000 attendees, as well as a Bollywood dance performance, faith leaders, vocalists from Howard University, and elected officials such as Plum and Virginia Delegate Danica Roem, the first openly transgender person to be elected to the Virginia House. Families spent time in the children's area, and teenagers draped all versions of Pride flags over their shoulders. Drag queens like emcee Delta B Knyght and performer Ophelia Bottoms stood by the "Virginia is for Lovers" LOVE sign as people lined up to take their pictures. Justine and Alli Dube came to Reston Pride with their three young children. They say they valued being in a place where they felt comfortable and their children could see families like theirs.
Congregations interested in this kind of event should look for people who can help with programming, exhibits, and designs. "All those people exist in your community even if they don't exist in your congregation," says Haffner.
UUCR continues to become more welcoming by offering copies of the LGBTQ newspaper the Washington Blade, providing a gender-neutral bathroom, and displaying the rainbow flag at the church's entrance (a flag which has been stolen, and replaced, three times in recent months). In addition, the LGBTQ Task Force is participating in the Welcoming Congregation recertification process. The congregation also displays a Black Lives Matter flag in the sanctuary, and Haffner envisions "the same kind of partnerships on racial justice," building from their social action on LGBTQ issues in order to "move it into . . . a different conversation around race."
On Pride Sunday, Haffner's sermon, "I Can't Believe I'm Still Protesting This #$%@!" relates the fight for LGBTQ rights with abortion rights access. She exudes a relentless energy as she closes with the declaration: "You are whole and welcome here." The congregation rises in a standing ovation.
Breakthrough Congregations, Lesbian/Gay/Bisexual/Transgender/Queer, LGBTQ Welcome & Equality, Membership Growth & Outreach, Pride Sunday, Sexuality, Life
Every Story Begins with a Word
Elizabeth J. Andrew 6/10/2022
From the UUA President: UUs Remain Committed to Reproductive Justice
Susan Frederick-Gray 6/24/2022
After Big Win in Kansas, Can Pro-Choice Advocates Prevail in Kentucky?
Jeff Milchen 9/9/2022
Andrea Dulanto
Andrea Dulanto is a Latina queer writer. Publications include South Florida Gay News, PopMatters, Women's International Perspective, and Elevate Difference.

redpajama_set_name: RedPajamaCommonCrawl


text:
ESSA's Fifth Indicator: Is Chronic Absenteeism Enough?
Anu Anand, AYPF Policy & Research Intern
The No Child Left Behind (NCLB) Act was notorious for its heavy reliance on standardized test scores to determine school quality. NCLB's successor, the Every Student Succeeds Act (ESSA), utilizes test performance as only one indicator of quality education. ESSA contains a total of five indicators to ensure that schools provide quality education: proficiency in reading and math, high school graduation rates, English language proficiency, student growth, and school quality/student success (SQSS). SQSS, often dubbed the "non-academic" or fifth indicator, is an unprecedented move by ESSA to place a value on elements of learning that are not traditionally associated with academics. States have a substantial amount of freedom to decide which SQSS indicator(s) they will use, and as of now, it appears that states are tackling this issue in many different ways.
The American Youth Policy Forum is in the process of conducting a scan of the fifty-two ESSA state plans for a broader understanding of how states are approaching accountability. As I have been conducting the scan, I have paid particularly close attention to which SQSS indicator(s) states have chosen. At least thirty-six states have chosen to measure chronic absenteeism as an SQSS indicator. At least twenty-seven of these states define chronic absenteeism as missing ten percent or more of the school year. Other states choose to measure the inverse of chronic absenteeism. For instance, the District of Columbia calculates the "percentage of enrolled students who were present/in attendance for 90% or more of enrolled days.". Chronic absenteeism's popularity as an SQSS indicator stems from its significant advantages as a measurement. First, it fulfills all criteria for a non-academic indicator (Figure 1). Second, most schools in the US currently calculate daily attendance, which means that the and systems to measure chronic absenteeism are already available.
Figure 1: ESSA Requirements and Chronic Absenteeism
Source: FutureEd, http://bit.ly/2wta1Lb
Third, there is a correlation between chronic absence and academic proficiency, school climate, and on-time graduation. Research conducted by The Hamilton Project demonstrates that fourth and eighth grade proficiency in math was nearly double in schools with the lowest rates of chronic absenteeism compared to schools having the highest rates of chronic absenteeism (Figure 2). The consequences are clear: if states do not address the issue of chronic absenteeism, results on their academic indicators will likely suffer.
Figure 2: Relationship between Chronic Absenteeism and School Outcomes in New York City
Source: The Hamilton Project, http://bit.ly/2z1F2aZ
The overwhelming adoption of chronic absenteeism as an SQSS indicator is therefore heartening to observe. However, there is much to improve upon in how states define and measure chronic absenteeism. Certain states choose to define chronic absenteeism based on the number of days of school that a student misses rather than the percentage of the school year. Nevada, for example, defines chronic absenteeism as a student missing at least eighteen days of the school year. Using days over percentages can be problematic because the length of the school year can vary between different schools and districts. It would be possible for students to miss less than eighteen days of school but more than ten percent of the school year.
A report produced by FutureEd brings to light another potential problem with the way chronic absenteeism is defined. Although most states outline what constitutes a chronically absent student, they fail to define "the expectations for how few chronically absent students a school should have." The lack of a realistic and consistent benchmark for schools to aim towards could make it difficult to accurately assess their progress.
One of the consequences of prioritizing attendance is that it could come at the cost of student participation in extracurricular activities that occasionally cut into school time. Ironically, an indicator aiming to improve school quality beyond academics could hamper the activities with the same intent. Without a uniform definition of what constitutes a 'justifiable' absence, using chronic absenteeism as an indicator could limit students' abilities to pursue their passions outside of school.
The manner of reporting absences also requires deeper consideration. According to FutureEd, "Some systems automatically record students as present unless they are reported absent, while others require teacher input before a student is considered present. If the default is set to 'present,' attendance rates could appear artificially high when teachers fail to submit regular reports." This potential to skew results is one of the reasons states should adopt multiple non-academic indicators to serve as checks on one another.
Contrary to concerns from The Hamilton Project that using multiple indicators would water down the attention directed to each one, most states seem to recognize that chronic absenteeism isn't an all-encompassing solution to improving SQSS. Connecticut's decision to include indicators for physical education and education in the arts implies that schools need to measure more than chronic absenteeism to make sure that students receive a well-rounded education. Other states have also included college and career-readiness as a fifth indicator to ensure that students achieve postsecondary success. In addition to chronic absenteeism, Illinois and several other approved state plans use "9th grade on track," an indicator to determine the academic requirements for ninth graders to graduate on time. Arkansas also uses community service and achievement in science and computer science as SQSS indicators.
Chronic absenteeism is an important indicator of school quality and student success, and research shows that state would do well to address it. However, there is more to school quality than whether students attend class and more to learning than being present. To that end, states seem to be using the SQSS indicator as an opportunity to innovate and collaborate to develop methods of assessing school quality and student success that go beyond traditional benchmarks. It is encouraging to see them move beyond what has been tried and tested to create promising practices of their own.
Topics: College and Career Readiness in OST, Alternative Education, Assessment, Accountability, Equity, College and Career Readiness and Success, Career Pathways, Every Student Succeeds Act (ESSA), Learning and Teaching Strategies, System Strategies and Approaches, Social and Emotional Learning, Policies & Legislation
ESSA and the Dirty A-Word
Jenna Tomasello discusses the challenges juvenile justice facilities face when it comes to education, ESSA and accountability.
A Seat at the Table: Questioning the Position of Special Education within Social-Emotional Learning
Logan Beyer explores the current and potential intersections between SEL and special education.
How Evidence-Based Strategies Can Help Struggling Schools
Guest bloggers Laurie Lee and Steve Fleischman share tools for using evidence to support struggling schools under ESSA.
Programs Versus Practices: What's the "What" in What Works?
Guest blogger Ruth Neild unpacks the issue of using research evidence under ESSA.


ENOUGH! Is the clarion call of our time. rEvolution in these times is an ACT of walking away from systems, practices, attitudes and structures that FAIL TO ACT in harmony, with integrity and in alignment with HEART…EARTH (same letters). Let's show up at our (most) local city government level at 12 noon LOCAL time on V-Day. Signs, shirts, presence, VOICE saying simply ENOUGH. Should there be police presence, walking to that police line, lowering signs and voices. Then in unison, from the HEART: "Will you join us?" Fall to silence, BEAMING A BREEZE OF PEACE, THROUGH AND FROM OUR HEARTS to and through these accidental "holders of the line" for 3 full minutes – in silence, with smiles, stares, whatever conveys for each and every participant her/is authentic/core invitation to JOIN US. Then in unison, again: "Will you join us?" Then turning on heels, A SYMBOL of WALKING AWAY – FINDING THE NEW WAY, NOT FIGHTING THE OLD WAY and IN CELEBRATION walking away from the police line/city government square. Declaring OUTLOUD: "Enough! The Parallel World of Peace, Justice, Freedom, Equality and More Than Enough IS HERE." Then DANCE.


At first glance you'd be forgiven for mistaking the Mini Oramics which Tom Richards has re-created for a vintage photocopier. It's not. It's a synth and sequencer and was designed by Daphne Oram in the 1960s, which was possibly inspired by the development of the Minimoog.
Mini-Oramics with James Bulley part 2 from Tom Richards on Vimeo.


text:
What states allow the insanity defense?
In his certiorari petition Kahler notes that courts in seven states recognize a constitutional right to the insanity defense: Nevada, California, Louisiana, Washington, Mississippi, Colorado and Minnesota.
Can a doctor deem a person incompetent?
In other words, it's up to courts, not doctors, to say whether someone is incompetent. This is governed by state law so different states have different criteria. But overall, if someone is found in court to be incompetent, they often will be assigned a guardian or conservator to manage decisions on their behalf.
What is the Ali standard?
The A.L.I. standard excludes those defendants whose mental illness or defect only manifests itself in criminal or antisocial conduct, thus addressing the conundrum of the serial killer whose only symptom of mental illness is the killing of his victims.
What is legally incompetent?
Lack of legal ability to do something, especially to testify or stand trial. Also known as "incompetency." May be caused by various types of disqualification, inability, or unfitness. Someone who is judged incompetent by means of a formal hearing may have a guardian appointed by the court.
Can a psychotic person be competent to stand trial?
A psychotic defendant may be incompetent to stand trial initially but may be restored to competency after treatment.
What is the most dangerous jail in America?
ADX Florence Facility
Is the Durham rule still used?
The Durham rule was abandoned in the case United States v. Brawner, 471 F. 2d 969 (1972). After the 1970s, U.S. jurisdictions have tended to not recognize this argument as it places emphasis on "mental disease or defect" and thus on testimony by psychiatrists and is argued to be somewhat ambiguous.
What are the four types of insanity defenses?
The four versions of the insanity defense are M'Naghten, irresistible impulse, substantial capacity, and Durham.
Can someone with mental illness go to jail?
800-950-NAMI. In a mental health crisis, people are more likely to encounter police than get medical help. As a result, 2 million people with mental illness are booked into jails each year. Nearly 15% of men and 30% of women booked into jails have a serious mental health condition.
Why is it important that a defendant be competent to stand trial?
The United States legal system has long recognized that criminal defendants must be competent to stand trial (CST) prior to proceeding with the legal process to allow for fairness for the accused and protect the integrity of the justice system.
What was the major change contained in the Insanity Defense Reform Act?
The Insanity Defense Reform Act of 1984 was signed into law by President Ronald Reagan on October 12, 1984, amending the United States federal laws governing defendants with mental diseases or defects to make it significantly more difficult to obtain a verdict of not guilty only by reason of insanity.
What happens if you are declared mentally incompetent?
If from the evidence presented the court is satisfied by clear and convincing evidence that the alleged incapacitated person lacks capacity, the court will declare that person as incapacitated. As such, the court will remove rights from the incapacitated person and delegate those rights to a guardian.
What happens if a defendant is found incompetent?
A defendant cannot be convicted of a crime if they are not mentally competent to stand trial. It does not prevent the police from making an arrest or the prosecution from filing charges, but the proceedings cannot go further until and unless the defendant is found to be competent.
What causes mental incompetence?
A lack of mental capacity could be due to: a stroke or brain injury. a mental health problem. dementia.
How do you get incompetent?
A defendant can be found incompetent to stand trial if he is unable to understand the nature and consequences of the proceedings against him and to assist properly in his defense. In such a case, he is involuntarily committed until his competency is restored.
What is institutionalized behavior?
The process by which beliefs, norms, social roles, values, or certain modes of behaviour are embedded in an organisation, a social system, or a society as a whole is called institutionalization. These concepts are said to be institutionalized when they are sanctioned and internalised within a group or a society.
How do you write two authors in a research paper?
Do celebrities worry about money?


Architectural Chain Single Fusee Skeleton Clock. Here is a great looking Skeleton Clock, with a very interesting Architectural Case, with a real fusee chain movement. It stands approximately 20 inches high. The case has several large spires on each side of the clock, and it has multiple upright frame posts. The eight day brass movement is driven with a fusee chain, and pendulum in the rear of the movement. It has a 4 inch skeleton dial with porcelain cartouche roman numerals. The 3" bell sets on top of the spired frame. Note the unusually shaped hammer which strikes the bell. It is a very nice example of the Architectural Skeleton Clock. Although not antique, this clock really appears to be antique, circa 1885. Note that the clock strikes every hour with what is called a passing bell strike. You can add this great looking chain fusee clock to your collection today. It has a very nice accompanying oval glass dome. Email us for more information.
The Shipping Charge for this item is $190.


text:
package com.sarahtolsma.divulge.module.events;

/**
 * Represents an event for web views.
 */
public class WebViewEvent extends Event
{
    /**
     * The data.
     */
    public String data;

    /**
     * The method.
     */
    public String method;

    /**
     * Initializes a new instance of the WebViewEvent class.
     */
    public WebViewEvent(String sourceName, String method, String data)
    {
        super(EventType.WebView, sourceName);

        this.data = data;
        this.method = method;
    }
}

redpajama_set_name: RedPajamaGithub


Home > Learning Center > Home Improvement > Why is My Toilet Draining Slowly?
Why is My Toilet Draining Slowly?
You're used to your toilet giving off that definitive roar when you flush it, but now there's only the slightest whimper as the water goes down the drain. Yep, you've got a problem, and you need to figure out why your toilet is draining slowly before the problem gets worse.
To understand why you should care if your toilet flushes quickly, you have to understand how a toilet works. When you flush your toilet, the flushing action triggers an influx of water from the tank into the toilet bowl before traveling down the main waste line. The speed with which this water travels actually creates the suction required for the actual flush.
And the slower this water moves, the more ineffective the flush — and the larger your problem becomes.
Obstruction in the pipes. When a toilet is slow to flush, the natural response is to reach for the plunger. In many cases, this is the right course of action. A firm seal with the plunger can often dislodge this obstruction, but if the problem persists, it may be something else.
Mineral deposits in the toilet tank. Is the tank filling completely with each flush? Over time mineral deposits will build up in your tank, and if the buildup is severe enough, the float can close earlier than it should. If this appears to be the case, simply clean the area to remove the buildup. You may also have to replace a couple of parts.This may include the flapper, as mineral deposit accumulation can hamper the seal your flapper provides. Fortunately, replacing your flapper isn't too expensive.
Problem with the flushing mechanism. Open the bowl to check the flapper — the rubber piece located on the bottom of the tank. If the flapper is not sealing tightly, or if the chain connected to the flapper is broken, it will affect your flush.
If your problem doesn't appear to be based on any of these possibilities, it's time to call an experienced plumber. A professional plumber can help troubleshoot your problem and get your toilet back to normal as quickly as possible.


text:
Q: Associations: One to Many Relationship, How to Return to the One from Many? I have a simple website where I show recipes from cookbooks.
Every cookbook has many recipes.
My question: how do I link the user back to the correct cookbook page from the recipe page?  How would I direct a user who is viewing a recipe with id 4 back to cookbook with id 2?
Cookbook Controller:
class CookbookController < ApplicationController
    def index
        @cookbooks = Cookbook.all
    end

    def show
    @cookbook = Cookbook.find(params[:id])
    @recipes = @cookbook.recipes
    end
end

Recipe Controller:
class RecipesController < ApplicationController
  def show
    @recipe = Recipe.find(params[:id])
  end
end

Cookbook Model:
class Cookbook < ActiveRecord::Base
  has_many :recipes
end

Recipe Model:
class Recipe < ActiveRecord::Base
  belongs_to :cookbook
end

Routes:
Rails.application.routes.draw do
  get '/' => redirect('/cookbooks')

  get '/cookbooks' => 'cookbooks#index'
  get '/cookbooks/:id' => 'cookbooks#show', as: :cookbook

  get '/recipe/:id' => 'recipes#show', as: :recipe
end

Up until now I have been using:
<%= link_to "Back", :back %>

but this isn't a permanent solution.
I followed the Rails Guide on Routing here and I have tried the following (and received the following errors):
<%= link_to "Back", cookbook_path(@cookbook) %>

No route matches {:action=>"show", :controller=>"cookbooks", :id=>nil} missing required keys: [:id]

<%= link_to "Back", cookbook_path(@cookbook.id) %>

undefined method `id' for nil:NilClass

And other solutions that either raised errors/exceptions or worked with the recipe id instead of the cookbook id.
I have also tried to allow for the Recipe Controller to inherit from the Cookbook Controller in order to get the id for the cookbook.

A: You were on the right track (no pun intended) when you attempted to use the Cookbook Controller with cookbook_path.
Each recipe stores the id of its respective cookbook with the one-to-many relationship you defined in both of your Models.
As such, we can utilize this simple link_to:
<%= link_to "Back", cookbook_path(@recipe.cookbook.id) %>

redpajama_set_name: RedPajamaStackExchange


The architectural office of Group X leader Antti Ahlava, helsinkizurich Office Ltd, has recently been awarded twice internationally.
The office received the Innovation and Excellence Award 2016 for Excellence in Urban Design, awarded by the international UK publisher LiveWire. The prize is given for the best championing their business fields and especially for impressive, international and innovative work in architecture.
On the other hand, helsinkizurich Office Ltd has been awarded with the first prize in the invited international architectural design competition for the Chäsimatt Quarter in Risch-Rotkreuz, Switzerland.


text:
PL4Tech - INFO 290|002 & Law 276.72|001
Privacy Law For Technologists
MW 10:30–12
South Hall 205
Professor Chris Hoofnagle
INFO 290 LEC 002 40455
LAW 276.72 LEC 001 45962
Law students: please note that Berkeley Law starts classes on Monday, August 21, but campus starts Wednesday the 23rd. Our first class will be on Wednesday the 23rd. We will make up the missed class.
Information privacy law profoundly shapes how internet-enabled services may work. Privacy Law for Technologists will translate the regulatory demands flowing from the growing field of privacy and security law to those who are creating interesting and transformative internet-enabled services. The course will meet twice a week, with the first session focusing on the formal requirements of the law, and the second on how technology might accommodate regulatory demands and goals. Topics include: Computer Fraud and Abuse Act (reverse engineering, scraping, computer attacks), unfair/deceptive trade practices, ECPA, children's privacy, big data and discrimination (FCRA, ECOA), DMCA, intermediary liability issues, ediscovery and data retention, the anti-marketing laws, and technical requirements flowing from the EU-US Privacy Shield
The required textbook for this class is my book (how opportunistic!): FTC Privacy Law and Policy (CUP 2016) But here is the good news: I negotiated a good price for it (about $37 in softcover), and there are several ways that you can get the content free. For instance, if you use the UCB VPN and go to Cambridge Books online, you can download a PDF of the whole book free.
This course is more demanding than it appears at first. Each week, you will be asked to learn substantive law, and then discuss how that law (or its policy goals) could be met with technology. This is a challenging exercise for both School of Information and School of Law students. Your participation in discussions (quality over quantity) is essential and is 30% of your grade. The remaining 70% comes from your final presentation.
Final presentation: you may work alone or in a group. Choose a service or a product of interest to you and prepare a presentation (no more than 10 minutes, and there will be a strict time limit) on how its privacy and/or security could be improved based on what you have learned in the course. You may work in a team for this presentation. Your presentation should identify the service or product's privacy/security implications, and discuss technological fixes, including the benefit and costs of the approach. Please identify your team and topic by October 2.
APM-015 Part II statement
This course will deal with material concerning current events and exploration of government actions and their possible consequences. Class discussion will feature such material.
BCLT Certificate
Law students: Hoofnagle's courses count toward's BCLT's certificate program.
Date Assignment
Introduction to the Course; Privacy
Daniel J. Solove, A Taxonomy of Privacy, 154(3) U. Penn. L. Rev. 477 (2006).
Paul N. Otto and Annie I. Antón, Addressing Legal Requirements in Requirements Engineering, 15th IEEE International Requirements Engineering Conference (RE 2007), Delhi, 2007, pp. 5-14.
Note, UCB subscribes to everything under the sun. If the link to the Otto/Anton paper does not work, be sure you have the UCB library proxy set up, or use the VPN. Either of these resources will give you subscribed access to pretty much anything. The VPN is probably easier to use--just download it, install it, and start it up. After that, every page you visit will get a UCB IP referrer, thus giving you access to materials.
Optional Event. The Troubled Future of Privacy ... and How to Stop It by Palantir Technologies' John Grant, Wozniak Lounge 430 Soda Hall, 6:00–7:30, dinner provided.
This week we will get into focus on a relatively-new movement in consumer protection: privacy by design. Generally attributed to former information and privacy commissioner of Ontario, Ann Cavoukian, privacy by design has increasing relevance in regulatory frameworks--the FTC has explicitly called. for companies to consider it.
Ann Cavoukian, 7 Foundational Principles of Privacy by Design (2012).
Sarah Spiekermann and Lorrie Faith Cranor, Engineering Privacy 35(1) IEEE Transactions on Software Engineering (Jan/Feb 2009)[IEEE link.].
Discussion: Privacy by Design
On an abstract level, privacy by design appears to be a useful approach to addressing technical choices. Today's discussion will focus on the mechanics of making privacy by design workable. We will consider the incentive conflicts in privacy by design, some case studies, and examples of privacy by design that you encounter in your role as consumer. For discussion, please:
Read Ira Rubinstein & Nathan Good, Privacy by Design: A Counterfactual Analysis of Google and Facebook Privacy Incidents, 28 Berkeley Technology Law Journal 1333 (2013). < This paper is co-authored by a School of Info PhD (Good) and won an award at the Privacy Law Scholars Conference.
Think about the products and services you use--find an example where privacy by design has been applied, or where you think it might be applied effectively. Come prepared to discuss your example in light of this week's readings. Post your example in the discussions area of bCourses.
W/r/t #2--and for future discussion assignments--feel free to work in a group to develop examples.
Mon Sep 4
Labor Day Holiday, No Class
Tues Sept 5
Optional Talk: Becoming a Technical Lawyer (or, Sorry, You Are Going to Have to Do Math After All) 12:45-1:45 Boalt Hall (probably room 105 or 110)
Description: In addition to criminal and civil code, lawyers inevitably need to understand computer code in order to function effectively in today's world. Technical architectures govern everything from determining what data exists to prove or disprove theories, when and how surveillance can be conducted, the range of policy options available to courts and legislatures, as well as raising novel legal questions that defy traditional solutions. John Grant, Director of Privacy and Civil Liberties Engineering at Palantir Technologies (J.D., Georgetown 2007), draws from his experience as a non-technical lawyer joining a highly technical startup to offer insights into what you need to know, why you need to know it, and how to build an effective relationship with the engineers who will be critical to your success.
Tue Sep 5
Optional Talk: Reigning in Online Abuses
Hany Farid, Sept 5, 2017 4pm, South Hall TBD
ABSTRACT: Online platforms today are being used in deplorably diverse ways: recruiting and radicalizing terrorists, buying and selling illegal weapons and underage prostitutes, cyberbullying and cyberstalking, revenge porn, theft of personal and financial data, propagating fake and hateful news, and much more. Technology companies have been and continue to be frustratingly slow in responding to these real threats with real consequences. I advocate for the development and deployment of new technologies that allow for the free flow of ideas while reigning in abuses. As a case study, I will describe one such technology—photoDNA—that is currently being used in the global fight against child exploitation. I will also describe the technological, legal, and policy obstacles that we faced prior to deployment and how lessons from this work can inform future efforts. I will also describe ongoing efforts in countering extremism on-line.
Wed Sep 6
Active Defense and "Hacking Back" Mini-Module
Class, the holiday breaks up our lecture/discussion schedule, so let's do a one-day module with both lecture and discussion. Jonathan Jaffe, PWC's Director of Cybersecurity will join us.
New amendments to federal law give more leeway for "active defense" measures. In this module, we will look at the new statutory language and attempt to envision what active defense might entail.
Please read a backgrounder on the Computer Fraud and Abuse Act:
Charles Doyle, Cybercrime: An Overview of the Federal Computer Fraud and Abuse Statute and Related Federal Criminal Laws , CRS Report, Oct. 2014, pages: summary, 1–2, 14–25.
And then portions of the Cybersecurity Act of 2015:
Cybersecurity Act of 2015 (this was enacted as part of a much larger omnibus spending bill), sections 101–104, 106.
Jonathan has specified two more readings:
Josephine Wolff, When Companies Get Hacked, Should They Be Allowed to Hack Back?, The Atlantic, July 14, 2017.
Dave Dittrich, Thoughts on the Active Cyber Defense Certainty Act 2.0, Medium, Jun. 15, 2017
Unfair and Deceptive Acts and Practices
This week we will study Unfair and Deceptive Acts and Practices (UDAP) law. UDAP law forms a baseline of regulation for technology in the US. In addition to the federal UDAP law, the Federal Trade Commission Act (FTC Act), states have their own versions of UDAP statutes, and some of these are broader than federal law.
Please read: Federal Trade Commission Privacy Law and Policy Chapter 5 (119–141).
Discussion: Unfair and Deceptive Acts and Practices
In preparation for discussion, please take these three steps:
Please read the following policy guides on modern advertising techniques
FTC Enforcement Policy Statement on Deceptively Formatted Advertisements (concerning "advertorial" or "native advertising").
Guides Concerning the Use of Endorsements and Testimonials in Advertising, 16 CFR 255.
Then, find some examples of advertising that is covered by either the policy statement or the guides (or covered by both) and post them here.
Finally, read about the business model of a native advertising network--there are several prominent ones, such as Outbrain and Taboola--or about a website that often hosts native content. Think about what is important to the different actors in the field.
Be prepared to discuss how you might implement policy or technological interventions to promote compliance with the various rules we learned about UDAP and the more specific policies set forth by the FTC in the policy statement and guides above. You could think of the problem from at least two ways--as a FTC lawyer or technologist, or as a company that is selling products that wants to avoid affiliate marketers and others from engaging in deception (e.g. in LeanSpa, the company was held liable for 3rd party affiliate marketers who created fake news sites).
FTC Privacy Part 1
Class, last week we discussed the basics of unfair and deceptive practices acts. This week and next we look at how the law of unfair and deceptive trade practices apply to online privacy issues. For the lecture, please read:
Federal Trade Commission Privacy Law and Policy, Chapter 6 (145–192). It is a lot of reading, but we'll use this same reading for this week and next.
Discussion: FTC Privacy Part 1
Let us start with privacy policies. For this discussion exercise, feel free to work in a group. Find a privacy policy from a website or service that you are interested in (try to select one that is not too long or intractable). Prior to class, place the text in to Microsoft Word or Google Docs, and highlight these elements in different colors:
1) Disclosures you think are "material" under the FTC Act.
2) Text that specifies affirmative obligations on the website/service (we shall do x).
3) Text that specifies restrictions on the website/service (we will not do y).
4) Text that gives the user some choice (opt in or opt out).
Post your policy or a link to it in the discussion board, and be prepared to discuss what you found and what puzzles/intrigues you about the privacy policy. We will discuss these four elements both from the lens of the requirements and prohibitions of the FTC Act, and from the perspective of what administrative and technical infrastructure must exist behind the scenes to implement these privacy policies.
For this week, please:
1) Review the reading from last week (Federal Trade Commission Privacy Law and Policy, Chapter 6).
2) Read the FTC report, Internet of Things: Privacy & Security in a Connected World (2015).
Discussion this week will focus on the internet of things (IoT). It will become clear that the IoT presents one of the most difficult regulatory challenges for privacy. Our goal will be to consider how the FTC might apply its tools to police the IoT sector, and how we might engineer IoT devices differently in order to protect consumers.
To prepare for the discussion, please choose a consumer product that is now sold as "connected." An example is door locks--these are bronze-age inventions that are now offered in "internet connected" formats. Give thought to the potential new benefits that come from internet connectivity for this product. What new functions will be enable? What knock-on effects will these functions create? What new societal tensions will internet connectivity introduce? How might we introduce privacy by design or other engineering principles to steer this technology toward FTC compliance?
Mon Oct 2
FTC Security & Security Breach Notification
For this lecture, please:
Read Federal Trade Commission Privacy Law and Policy, chapter 8 (216–235).
Read: California Office of Privacy Protection, Recommended Practices on Notice of Security Breach Involving Personal Information (2012).
Look at this page. on which one discloses security breaches to the California Attorney General.
Skim: PerkinsCoie, Security Breach Notification Chart (June 2016).
Make Up Session: Please attend Professor Edward Balleisen's talk, 12:45–2 in Boalt (Law School Room 130). To prepare please
Prepare a question for Professor Balleisen and post it on the discussion board.
Wed Oct 4
Discussion: Security Frameworks
For this discussion, we will divide into groups to analyze and present several different security standards. Note that the security standards we are visiting here are not law, exactly. They are often developed with the private sector and required by private contract or through procurement standards.
Group 1: Cover ISO 27000/27001/27002. These standards are not publicly available--they have to be licensed. However, Professor Georg Disterer has written a good overview of these standards. See, Georg Disterer, ISO/IEC 27000, 27001 and 27002 for Information Security Management, 4(2) Journal of Information Security (2003).
Group 2: Cover NIST 800-53 (Rev 4). This is a 460 page document. Suffice it to say that it would be a waste of time to read the whole thing. Instead, start with the NIST Summary, and then look at chapters 1, 2, and appendixes F, G, and J. In the process, be sure to note any controls that you find particularly useful or underexamined in the course so far.
Group 3: Cover PCI-DSS (Ver. 3.2) . PCI-DSS governs the acceptance of credit and debit cards. This is a long document as well. You might start by looking at the "quick" reference guide :) and the sample reporting form .
Group 4: NIST Cybersecurity Framework . You will see the NIST framework in practice because financial regulators and the SEC have urged companies to implement it. A good starting point for understanding the framework is the FAQ on the NIST website.
All groups: do some searching and try to determine who uses your group's standard and why. You'll find that many companies do state their security standard in product specification sheets and regulatory findings.
Group assignments: TBD
Discussion: Children's Privacy
Class, for our discussion, please spend about an hour looking at a specific COPPA-regulated service (remember--it can be a website, app or other internet "service.") Pay specific attention to the privacy policy (how it differs from the non-COPPA service you looked at weeks ago) and parental consent mechanisms. Overall, do you think the service meets the privacy and security goals of the COPPA? If you want a refresher on COPPA requirements, this guide from the FTC is very good.
We'll discuss the differences between COPPA and non-COPPA sites during our discussion, and then do a short, in-class exercise focused on monetizing COPPA regulated sites.
Makeup Session: Please attend Professor Josh Lauer's talk, 4:10–5:30 in South Hall 202.
To prepare, please:
Read From Rumor to Written Record: Credit Reporting and the Invention of Financial Identity in Nineteenth-Century America, Technology & Culture 49, no. 2 (2008): 301-324.
Prepare a question for Professor Lauer and post it on the discussion board.
The Stored Communications Act and Law Enforcement Agency (LEA) Requests
Please read Orin Kerr's A User's Guide to the Stored Communications Act, and a Legislator's Guide to Amending it, 72 George Washington Law Review 1208 (2004), pages 1208–1233.
Discussion: The Stored Communications Act and Law Enforcement Agency (LEA) Requests
Class, for this discussion, we are going to consider a series of different LEA requests for user information.
In order to prepare, could you:
1) Read the entire assignment, including the requests that the other groups are receiving. It's not a lot of reading--about 20 pages in total.
2) Give some thought to how you might respond to the request from the lens of your client/company? Is there anything special about your business model that would affect how you want to respond? What steps should you take to comply? What information should your company disclose in response to the request? What should it not provide?
In class, we'll divide into groups for 20-25 minutes, and then discuss with the whole class the steps and issues you think are important to responding.
Group 1: You work for the Internet Archive. Your Chief Security Officer (CSO) receives a call from the FBI, and Agent Jones says she is going to come in person to the Internet Archive office this afternoon with a request for information (nov2007_nsl_edited.pdf). Agent Jones appears, shows you this letter on FBI letterhead, allows you and the CSO to read it, but does not allow you to keep a copy.
Group 2: You work for a telecommunications carrier Sprint. Your company operates a law enforcement response office 24/7. This request appears in the fax machine (Sprint - Nextel Exigent Circumstances Form_edited.pdf) from Irvine PD. You do a quick Google search and turn up this guide for Cell Tracking Requests from Irvine's police department. (celltrackingpra_irvine4_irvineca.pdf).
Group 3: You are the publisher of a well-established libertarian magazine, Reason.com. You receive this grand jury subpoena (reason_gjs.pdf). Warning: this case involves threats and there is nasty language in it.
Feeling a bit at sea? That's totally normal! Companies receive these processes out of the blue, with no context, and often without their counsel present. We'll work through the issues together.
Wiretapping, Consumer Protection, and LEA Requests
California Penal Code §§ 630, 631, 632, 635, 637, and 637.7. (pdf version)
In the Matter of the Application of the UNITED STATES FOR AN ORDER AUTHORIZING THE ROVING INTERCEPTION OF ORAL COMMUNICATIONS, The Company, Appellant, v. UNITED STATES of America, Appellee, No. 02-15635, 349 F.3d 1132 (9th Cir. Nov. 18, 2003) (pdf version).
Discussion: Wiretapping, Consumer Protection, and LEA Requests
From the lecture it should become clear that many new consumer services "intercept" the human voice. There are obvious examples, such as in-home assistants (Amazon Echo, Google Home), devices that sometimes respond to human commands (such as Smart TVs), and perhaps some less obvious ones--consider that your phone may be "listening," or that you might use a "wearable" device that captures information in your interpersonal life.
There is almost no caselaw concerning these products and services--the closest we have are the Deep Packet Inspection cases, the Google Gmail Scanning Litigation, and the Google Street View Wifi Scanning cases.
For our discussion, we'll focus on what companies in this space are doing to comply with the federal Wiretap Act and state laws on interception of voice. To prepare
Please identify a product or service that captures the human voice and post it to the discussion page.
Try to determine how the company is dealing with the Wiretap Act issues I discussed in lecture. This might be apparent from the privacy policy, the terms of service, or aspects of the product's design
Give some thought to "secondary" parties that might be near the device. While you may have agreed to having your television capture your voice, visitors to your home presumably have not. What can the law or tech do about that problem?
Marketing Part 1
Please read FTC Privacy Law and Policy pages 236–240; 249–259.
Discussion: Marketing Part 1
To prepare for our discussion, please:
1) As you visit stores in person or on the web, take note of companies that wish to enroll you in text marketing. Here's an example from FEMA, and here's another from a company that recently litigated a TCPA case. Take a screenshot or copy the link and post it in the discussion area--remember that you might find these as you shop offline and if you can snap a picture of them, that's great.
2) I'd like to spend some time discussing "platform liability" for text messages. Please look at these services—can you tell what policies and procedures they have in place to deal with the problem that users might employ the services for illegal telemarketing? Be sure to look at the terms of service, privacy policy, and other disclosures surrounding enrollment.
https://groupme.com/en-US/ Oops! Groupme was recently bought by Microsoft. The old terms are here and the privacy policy here.
https://www.remind.com/
https://telefio.com
Mon Nov 6
Please read FTC Privacy Law & Policy 240–249; 259–267.
For the discussion, please:
1) Consider CAN-SPAM: The CAN-SPAM rules are under review this year. Given your experience with commercial email, consider what regulatory changes would you recommend to the FTC?
Are there technical or legal changes that would help the private sector or consumers better comply with the law, distinguish between commercial and non-commercial mail, enable filtering, and so on?
2) Find an example of software that potentially could be spyware. Upload a link to the discussion page. Look at the software's marketing, privacy policy, and related disclosures. Consider how it is using legal language and technology to avoid liability.
Financial Privacy
Please read Federal Trade Commission Privacy Law and Policy, Chapter 10 (268–305)
International Privacy
Class, for our last sessions, we will look at how the European Union is shaping privacy norms in the U.S. This is a quickly changing subject matter. For background, please read:
Federal Trade Commission Privacy Law and Policy, Chapter 11 (306–328).
Bird & Bird, Guide to the GDPR (May 2017).
Department of Commerce, Overview of the EU-U.S. Privacy Shield Framework, Feb. 29, 2016.
Thurs Nov 16
Optional Event: Professor Christine Borgman (UCLA Info Studies) will speak on Open Data, Trust, and Stewardship: Universities at the Privacy Frontier. Thursday, Nov. 16th from 3:30–5 at the Faculty Club. Register here.
Discussion: International Privacy
+MD Final Presentation on Blockchain Analysis
Class, assume that you work for Quantcast (https://www.quantcast.com/), focusing on the company's measurement product (https://www.quantcast.com/measure/ --check out the metrics on some websites of interest to you). Quantcast is among the most successful web measurement companies--it can figure out how many people visit a website and their basic demographics. It does this by encouraging website owners to place a beacon on their site that transmits data to Quantcast. Quantcast uses cookies to track these persistent and unique identifiers across sites. After becoming familiar with how Comcast Measure works, consider two problems that you face as the GDPR comes into effect in 2018:
1) Europeans who visit US-based websites, and demand access or challenge your processing of their data as "illegitimate."
2) Whether and how you can place Quantcast measure beacons on EU-based web services (which presumably will move European's data outside the EEA). Do you sign a standard contractual clause with the European web service, or try to transfer data under the new EU-US Privacy Shield?
No class--Thanksgiving break
KF & KH Alexa/Echo 27-Nov
AD Mint 27-Nov
VS & WT Uber 27-Nov
MG & JM Data Broker 27-Nov
JO & SC Venmo 27-Nov
ML & LN TBD 29-Nov
KB & KB Beacons/Ultrasonic Tracking 29-Nov
JC, BO, & KC Real Quantum 29-Nov
SS Google's AI cameras (Pixel and Clips). 29-Nov
SN OnStar 29-Nov
MR Spotify 27-Nov
The syllabus page shows a table-oriented view of the course schedule, and the basics of course grading. You can add any other comments, notes, or thoughts you have about the course structure, course policies or anything else.
To add some comments, click the "Edit" link at the top.
HTML Editor Rich Content Editor
Syllabus Description:
Update Syllabus
29 Previous month Next month Today Click to view event details
1 Previous month Next month Today Click to view event details
Course assignments are not weighted.


One of my favourite facts about this photograph is that I have no idea where it was taken. Tallinn is a city that rewards the inquisitive mind and it is with this spirit that my friend and I set out in the lingering light of dusk to explore a nearby forest (advice offered to us a few days earlier). Having heard that there was 'something interesting' hidden in the shaded expanse of green we needed no more convincing – our mission was set (we don't need many excuses to go for a bike ride in Tallinn anyway).
With the battery on our smartphones running low we ditched the maps and embraced the simple freedom afforded by two wheels and an empty time-schedule; gliding, winding and stuttering our way through the terrain of the forest. The stillness of the air and gentle rustling of the leaves overhead combined with setting sun to form the most perfect conditions for an evening ride. When the giant beard and wise eyes of Kalevipoeg emerged from behind the trees the peace and quiet was momentarily disturbed by my brief exclamation of "oh, that's cool".
Our mission was complete. I took this photo, cycled back home under the warmth of the street lights and to this day I can't remember where this clearing in the forest is or how we found it.
Funny you should mention that. I was saving my Soviet Statues post for another day but your challenge has inspired me to bring it forward to today!


It's hard to believe (because I baseline everything on the 90s), but the end of the 70s was almost 40 years ago. I've always looked at photos from that decade with fondness because although it had its problems, I'm not sure we can top its film photography, goofy humor, and short shorts on EVERYONE. I'm not sure why I was searching for photos with the term 70s picnic, but I was happy it led to my discovery of My 70s Tumblr. Dig in and remember what it feels like to get lost in a Tumblr instead of social media. That will be 40 years old before we know it too.
Want more? Yeah you do.


How do I create a new array each time there is... Learn more about array, empty matrix separated list MATLAB Learn more about array, empty matrix separated list MATLAB Toggle Main Navigation... The time management matrix will help you identify what you really spend your time on. It's a particularly useful tool if you want to know how to prioritize work, personal roles, goals and commitments.
The first number is the number of paragraphs to create. The second is the number of sentences in each paragraph. So if I type =Rand(20,30) into a blank document, I get 20 paragraphs of 3 sentences each.
of matrix A (3 x 3) and matrix B (4 x 3). Recall that the number of columns of the first matrix must be equal to Recall that the number of columns of the first matrix must be equal to the number of rows of the second matrix to produce a product matrix.


text:
Ali on the Run Show
Running Sports Fitness Endurance Sports Inspiration Women Ali Feller Entrepreneur Health and Well-Being Runners
By Ali Feller. Discovered by Player FM and our community — copyright is owned by the publisher, not Player FM, and audio is streamed directly from their servers. Hit the Subscribe button to track updates in Player FM, or paste the feed URL into other podcast apps.
Ali on the Run Show « »
184. Crohn's Disease and Motherhood with Natalie Hayden
"This illness is just a small part of me. It's not all of me. I'm still able to be a mom. And I haven't allowed my disease to rob me of that. It just gives me strength. It almost makes me feel like a badass some days! It's not always pretty, but for the most part, I'm doing what I want to do with my life despite my illness."
Natalie Hayden was diagnosed with Crohn's disease right after graduating college. She was on track to pursue her dream job as a television anchor, but her inflammatory bowel disease (IBD) diagnosis tried to derail that. After several hospitalizations and a series of bowel obstructions, Natalie underwent major surgery to remove 18 inches from her intestines. But despite the disease's valiant efforts to keep Natalie down, she has persevered. She went on to become a TV news anchor, just as she'd always dreamed, and she's a mother to two healthy children. Today, Natalie is a freelance, work-from-home mom who chronicles her life with Crohn's disease at Lights, Camera, Crohn's: An Unobstructed View. This is an honest conversation about what it looks like when you have a chronic illness and want to become a mom, and what concerns arose for both Natalie and me in our respective journeys.
Thank you to the American Gastroenterological Association's IBD Parenthood Project for sponsoring this episode of the Ali on the Run Show! If you or someone you know has inflammatory bowel disease, like Crohn's disease or ulcerative colitis, go to ibdparenthoodproject.org for support on your journey to and through parenthood.
What you'll get on this episode:
Natalie talks about her Crohn's diagnosis (4:30)
Natalie talks about moving away from home and pursuing her dream job — with Crohn's as her sidekick (11:00)
How having a chronic illness has affected Natalie's relationships and marriage (16:50)
Natalie talks about her history with bowel obstructions, and her bowel resection surgery (23:50)
Natalie talks about her decision to have children, and her concerns about how Crohn's may affect her ability to get pregnant, have a baby, and be a mom (37:20)
To breastfeed or not to breastfeed with a chronic illness? Natalie talks about trying to make the decision that was right for her and her family (45:20)
Follow Natalie:
Instagram @natalieannhayden
Twitter @nataliesparacio
Follow Ali:
Instagram @aliontherun1
Twitter @aliontherun1
Listen & Subscribe:
SUPPORT the Ali on the Run Show! If you're enjoying the show, please subscribe and leave a rating and review on Apple Podcasts. Spread the run love. And if you liked this episode, share it with your friends!
Similar to Ali on the Run Show
Tyngre Radio
I Tyngre Radio snackas det om styrketräning. Punkt. Värdar är Alex Danielsson och Andreas Guiance.