text:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Xml.Serialization;
using de.fhb.oll.mediacategorizer.processing;

namespace de.fhb.oll.mediacategorizer.model
{
    partial class Project
    {
        private const string WORKING_DIR_NAME = "_tmp_";

        private static readonly XmlSerializer serializer;

        static Project()
        {
            try
            {
                serializer = new XmlSerializer(typeof(Project));
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }

        private void Initialize()
        {
            LoadProfiles();
        }

        public void SaveToFile(string file)
        {
            using (var s = File.Open(file, FileMode.Create, FileAccess.Write))
            {
                serializer.Serialize(s, this);
            }
            AcceptChanges();
        }

        public static Project LoadFromFile(string file)
        {
            Project result;
            using (var s = File.Open(file, FileMode.Open, FileAccess.Read))
            {

                result = (Project)serializer.Deserialize(s);
            }
            result.AcceptChanges();
            return result;
        }

        public string GetOutputDir()
        {
            return Path.IsPathRooted(OutputDir)
                ? OutputDir
                : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), OutputDir);
        }

        public string GetWorkingDirectory()
        {
            return Path.Combine(GetOutputDir(), WORKING_DIR_NAME);
        }

        public IEnumerable<Media> GetMedia()
        {
            return Media.Where(m => m != null);
        }

        [XmlIgnore]
        public ProcessChain ProcessChain { get; set; }

        public void LoadProfiles()
        {
            Profiles = new ObservableCollection<Profile>(
                ProfileManagement.GetSpeechRecognitionProfiles()
                    .Select(Profile.FromTuple));
        }

        public Dictionary<Guid, string> GetProfilesAsDictionary()
        {
            return Profiles != null
                ? Profiles.Where(p => p.Enabled).ToDictionary(p => p.Id, p => p.Name)
                : new Dictionary<Guid, string>();
        }

        [Conditional("DEBUG")]
        public void LoadDemoData()
        {
            var appDir = Path.GetDirectoryName(
                new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
                .LocalPath);
            var basePath = Path.Combine(appDir, @"..\..\..\..");

            Name = "Testprojekt";
            Description = "Ein Testprojekt zum Testen.";
            OutputDir = @"C:\Temp\MediaCategorizerOutput";

            #region Categories

            Categories.Add(new Category
            {
                Id = "info",
                Name = "Informatik",
                Resources = new ObservableCollection<CategoryResource>
                {
                    new CategoryResource {Type = CategoryResourceType.Wikipedia, Url = "http://de.wikipedia.org/wiki/Informatik"},
                    new CategoryResource {Type = CategoryResourceType.Wikipedia, Url = "http://de.wikipedia.org/wiki/Theoretische_Informatik"},
                    new CategoryResource {Type = CategoryResourceType.Wikipedia, Url = "http://de.wikipedia.org/wiki/Praktische_Informatik"},
                    new CategoryResource {Type = CategoryResourceType.Wikipedia, Url = "http://de.wikipedia.org/wiki/Technische_Informatik"},
                },
            });
            Categories.Add(new Category
            {
                Id = "queue",
                Name = "Datenstrukturen - Warteschlange",
                Resources = new ObservableCollection<CategoryResource>
                {
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Warteschlange_%28Datenstruktur%29"},
                },
            });
            Categories.Add(new Category
            {
                Id = "stack",
                Name = "Datenstrukturen - Stapel",
                Resources = new ObservableCollection<CategoryResource>
                {
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Stapelspeicher"},
                },
            });
            Categories.Add(new Category
            {
                Id = "tree",
                Name = "Datenstrukturen - Baum",
                Resources = new ObservableCollection<CategoryResource>
                {
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Baum_%28Graphentheorie%29"},
                },
            });
            Categories.Add(new Category
            {
                Id = "math",
                Name = "Mathematik",
                Resources = new ObservableCollection<CategoryResource>
                {
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Mathematik"},
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Rechnen"},
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Zahl"},
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Arithmetik"},
                },
            });
            Categories.Add(new Category
            {
                Id = "oeko",
                Name = "Wirtschaft",
                Resources = new ObservableCollection<CategoryResource>
                {
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Wirtschaft"},
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Wirtschaftswissenschaft"},
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Bank"},
                    new CategoryResource{Type = CategoryResourceType.Wikipedia,Url = "http://de.wikipedia.org/wiki/Geld"},
                },
            });

            #endregion

            #region Media

            Media.Add(new Media
            {
                Id = "11-01-Informatik",
                Name = "11.01 Theoretische, technische, praktische, angewandte Informatik",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\11.01 Theoretische, technische, praktische, angewandte Informatik.mp4"),
            });
            Media.Add(new Media
            {
                Id = "12-01-1-Datenstrukturen",
                Name = "12.01.1 Datenstrukturen, Array, Queue, Stack",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\12.01.1 Datenstrukturen, Array, Queue, Stack.mp4"),
            });
            Media.Add(new Media
            {
                Id = "12-01-2-Baum",
                Name = "12.01.2 Baum als Datenstruktur",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\12.01.2 Baum als Datenstruktur.mp4"),
            });
            Media.Add(new Media
            {
                Id = "Algo1",
                Name = "Algorithmen und Datenstrukturen 001",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Algorithmen und Datenstrukturen 001.mp4"),
            });
            Media.Add(new Media
            {
                Id = "Algo2",
                Name = "Algorithmen und Datenstrukturen 002",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Algorithmen und Datenstrukturen 002.mp4"),
            });
            Media.Add(new Media
            {
                Id = "Algo3",
                Name = "Algorithmen und Datenstrukturen 003",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Algorithmen und Datenstrukturen 003.mp4"),
            });
            Media.Add(new Media
            {
                Id = "Algo4",
                Name = "Algorithmen und Datenstrukturen 004",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Algorithmen und Datenstrukturen 004.mp4"),
            });
            Media.Add(new Media
            {
                Id = "Bernoulli",
                Name = "Binomialverteilung_Formel von Bernoulli, Stochastik, Nachhilfe online, Hilfe in Mathe",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Binomialverteilung_Formel von Bernoulli, Stochastik, Nachhilfe online, Hilfe in Mathe (720).mp4"),
            });
            Media.Add(new Media
            {
                Id = "Hypothesentest",
                Name = "Einseitiger(rechtsseitiger) Hypothesentest_mit Ablesen aus der Tabelle, Stochastik, Nachhilfe online",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Einseitiger(rechtsseitiger) Hypothesentest_mit Ablesen aus der Tabelle, Stochastik, Nachhilfe online (720).mp4"),
            });
            Media.Add(new Media
            {
                Id = "Parabeln",
                Name = "Parabeln_Quadratische Funktion_en Übersicht (Scheitelpunkt,Stauchung,Streckung,etc.)",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Parabeln_Quadratische Funktion_en Übersicht (Scheitelpunkt,Stauchung,Streckung,etc.) (720).mp4"),
            });
            Media.Add(new Media
            {
                Id = "Gauss",
                Name = "Gauß-Algorithmus_Lineares Gleichungssystem lösen (einfach_schnell erklärt), Nachhilfe online",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Gauß-Algorithmus_Lineares Gleichungssystem lösen (einfach_schnell erklärt), Nachhilfe online (720).mp4"),
            });
            Media.Add(new Media
            {
                Id = "Lambda",
                Name = "Der Lambda-Kalkül",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Der Lambda-Kalkül (720).mp4"),
            });
            Media.Add(new Media
            {
                Id = "IS-Kurve",
                Name = "IS-Kurve im Vier-Quadrantenschema Die Herleitung",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\IS-Kurve im Vier-Quadrantenschema Die Herleitung (720).mp4"),
            });
            Media.Add(new Media
            {
                Id = "Makrooekonomie",
                Name = "Makroökonomie online lernen - VWL Tutorium",
                MediaFile = Path.Combine(basePath, @"Media\Video\de-DE\Makroökonomie online lernen - VWL Tutorium (360).mp4"),
            });

            #endregion

            Configuration.MainCloud.FontFamily = new FontFamily("Segoe UI");
            Configuration.CategoryCloud.FontFamily = new FontFamily("Segoe UI");
            Configuration.MediaCloud.FontFamily = new FontFamily("Segoe UI");
        }
    }
}


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Mycologia 38(3): 335 (1946)

#### Original name
Ciliochorella bambusarum Shanor

### Remarks
null

redpajama_set_name: RedPajamaGithub


text:
package org.apache.hadoop.yarn.server.applicationhistoryservice;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience.Private;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
import org.apache.hadoop.metrics2.source.JvmMetrics;
import org.apache.hadoop.security.AuthenticationFilterInitializer;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.service.CompositeService;
import org.apache.hadoop.service.Service;
import org.apache.hadoop.util.ExitUtil;
import org.apache.hadoop.util.GenericOptionsParser;
import org.apache.hadoop.util.ReflectionUtils;
import org.apache.hadoop.util.ShutdownHookManager;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.yarn.YarnUncaughtExceptionHandler;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
import org.apache.hadoop.yarn.server.applicationhistoryservice.webapp.AHSWebApp;
import org.apache.hadoop.yarn.server.security.ApplicationACLsManager;
import org.apache.hadoop.yarn.server.timeline.LeveldbTimelineStore;
import org.apache.hadoop.yarn.server.timeline.TimelineDataManager;
import org.apache.hadoop.yarn.server.timeline.TimelineStore;
import org.apache.hadoop.yarn.server.timeline.security.TimelineACLsManager;
import org.apache.hadoop.yarn.server.timeline.security.TimelineAuthenticationFilter;
import org.apache.hadoop.yarn.server.timeline.security.TimelineAuthenticationFilterInitializer;
import org.apache.hadoop.yarn.server.timeline.security.TimelineDelegationTokenSecretManagerService;
import org.apache.hadoop.yarn.server.timeline.webapp.CrossOriginFilterInitializer;
import org.apache.hadoop.yarn.webapp.WebApp;
import org.apache.hadoop.yarn.webapp.WebApps;
import org.apache.hadoop.yarn.webapp.util.WebAppUtils;

import com.google.common.annotations.VisibleForTesting;

/**
 * History server that keeps track of all types of history in the cluster.
 * Application specific history to start with.
 */
public class ApplicationHistoryServer extends CompositeService {

  public static final int SHUTDOWN_HOOK_PRIORITY = 30;
  private static final Log LOG = LogFactory
    .getLog(ApplicationHistoryServer.class);

  private ApplicationHistoryClientService ahsClientService;
  private ApplicationACLsManager aclsManager;
  private ApplicationHistoryManager historyManager;
  private TimelineStore timelineStore;
  private TimelineDelegationTokenSecretManagerService secretManagerService;
  private TimelineDataManager timelineDataManager;
  private WebApp webApp;

  public ApplicationHistoryServer() {
    super(ApplicationHistoryServer.class.getName());
  }

  @Override
  protected void serviceInit(Configuration conf) throws Exception {
    // init timeline services first
    timelineStore = createTimelineStore(conf);
    addIfService(timelineStore);
    secretManagerService = createTimelineDelegationTokenSecretManagerService(conf);
    addService(secretManagerService);
    timelineDataManager = createTimelineDataManager(conf);
    addService(timelineDataManager);

    // init generic history service afterwards
    aclsManager = createApplicationACLsManager(conf);
    historyManager = createApplicationHistoryManager(conf);
    ahsClientService = createApplicationHistoryClientService(historyManager);
    addService(ahsClientService);
    addService((Service) historyManager);

    DefaultMetricsSystem.initialize("ApplicationHistoryServer");
    JvmMetrics.initSingleton("ApplicationHistoryServer", null);
    super.serviceInit(conf);
  }

  @Override
  protected void serviceStart() throws Exception {
    try {
      doSecureLogin(getConfig());
    } catch(IOException ie) {
      throw new YarnRuntimeException("Failed to login", ie);
    }
    super.serviceStart();
    startWebApp();
  }

  @Override
  protected void serviceStop() throws Exception {
    if (webApp != null) {
      webApp.stop();
    }

    DefaultMetricsSystem.shutdown();
    super.serviceStop();
  }

  @Private
  @VisibleForTesting
  ApplicationHistoryClientService getClientService() {
    return this.ahsClientService;
  }

  /**
   * @return ApplicationTimelineStore
   */
  @Private
  @VisibleForTesting
  public TimelineStore getTimelineStore() {
    return timelineStore;
  }

  @Private
  @VisibleForTesting
  ApplicationHistoryManager getApplicationHistoryManager() {
    return this.historyManager;
  }

  static ApplicationHistoryServer launchAppHistoryServer(String[] args) {
    Thread
      .setDefaultUncaughtExceptionHandler(new YarnUncaughtExceptionHandler());
    StringUtils.startupShutdownMessage(ApplicationHistoryServer.class, args,
      LOG);
    ApplicationHistoryServer appHistoryServer = null;
    try {
      appHistoryServer = new ApplicationHistoryServer();
      ShutdownHookManager.get().addShutdownHook(
        new CompositeServiceShutdownHook(appHistoryServer),
        SHUTDOWN_HOOK_PRIORITY);
      YarnConfiguration conf = new YarnConfiguration();
      new GenericOptionsParser(conf, args);
      appHistoryServer.init(conf);
      appHistoryServer.start();
    } catch (Throwable t) {
      LOG.fatal("Error starting ApplicationHistoryServer", t);
      ExitUtil.terminate(-1, "Error starting ApplicationHistoryServer");
    }
    return appHistoryServer;
  }

  public static void main(String[] args) {
    launchAppHistoryServer(args);
  }

  private ApplicationHistoryClientService
      createApplicationHistoryClientService(
          ApplicationHistoryManager historyManager) {
    return new ApplicationHistoryClientService(historyManager);
  }

  private ApplicationACLsManager createApplicationACLsManager(
      Configuration conf) {
    return new ApplicationACLsManager(conf);
  }

  private ApplicationHistoryManager createApplicationHistoryManager(
      Configuration conf) {
    // Backward compatibility:
    // APPLICATION_HISTORY_STORE is neither null nor empty, it means that the
    // user has enabled it explicitly.
    if (conf.get(YarnConfiguration.APPLICATION_HISTORY_STORE) == null ||
        conf.get(YarnConfiguration.APPLICATION_HISTORY_STORE).length() == 0 ||
        conf.get(YarnConfiguration.APPLICATION_HISTORY_STORE).equals(
            NullApplicationHistoryStore.class.getName())) {
      return new ApplicationHistoryManagerOnTimelineStore(
          timelineDataManager, aclsManager);
    } else {
      LOG.warn("The filesystem based application history store is deprecated.");
      return new ApplicationHistoryManagerImpl();
    }
  }

  private TimelineStore createTimelineStore(
      Configuration conf) {
    return ReflectionUtils.newInstance(conf.getClass(
        YarnConfiguration.TIMELINE_SERVICE_STORE, LeveldbTimelineStore.class,
        TimelineStore.class), conf);
  }

  private TimelineDelegationTokenSecretManagerService
      createTimelineDelegationTokenSecretManagerService(Configuration conf) {
    return new TimelineDelegationTokenSecretManagerService();
  }

  private TimelineDataManager createTimelineDataManager(Configuration conf) {
    return new TimelineDataManager(
        timelineStore, new TimelineACLsManager(conf));
  }

  private void startWebApp() {
    Configuration conf = getConfig();
    TimelineAuthenticationFilter.setTimelineDelegationTokenSecretManager(
        secretManagerService.getTimelineDelegationTokenSecretManager());
    // Always load pseudo authentication filter to parse "user.name" in an URL
    // to identify a HTTP request's user in insecure mode.
    // When Kerberos authentication type is set (i.e., secure mode is turned on),
    // the customized filter will be loaded by the timeline server to do Kerberos
    // + DT authentication.
    String initializers = conf.get("hadoop.http.filter.initializers");
    boolean modifiedInitializers = false;

    initializers =
        initializers == null || initializers.length() == 0 ? "" : initializers;

    if (!initializers.contains(CrossOriginFilterInitializer.class.getName())) {
      if(conf.getBoolean(YarnConfiguration
          .TIMELINE_SERVICE_HTTP_CROSS_ORIGIN_ENABLED, YarnConfiguration
              .TIMELINE_SERVICE_HTTP_CROSS_ORIGIN_ENABLED_DEFAULT)) {
        initializers = CrossOriginFilterInitializer.class.getName() + ","
            + initializers;
        modifiedInitializers = true;
      }
    }

    if (!initializers.contains(TimelineAuthenticationFilterInitializer.class
      .getName())) {
      initializers =
          TimelineAuthenticationFilterInitializer.class.getName() + ","
              + initializers;
      modifiedInitializers = true;
    }

    String[] parts = initializers.split(",");
    ArrayList<String> target = new ArrayList<String>();
    for (String filterInitializer : parts) {
      filterInitializer = filterInitializer.trim();
      if (filterInitializer.equals(AuthenticationFilterInitializer.class
        .getName())) {
        modifiedInitializers = true;
        continue;
      }
      target.add(filterInitializer);
    }
    String actualInitializers =
        org.apache.commons.lang.StringUtils.join(target, ",");
    if (modifiedInitializers) {
      conf.set("hadoop.http.filter.initializers", actualInitializers);
    }
    String bindAddress = WebAppUtils.getWebAppBindURL(conf,
                          YarnConfiguration.TIMELINE_SERVICE_BIND_HOST,
                          WebAppUtils.getAHSWebAppURLWithoutScheme(conf));
    LOG.info("Instantiating AHSWebApp at " + bindAddress);
    try {
      webApp =
          WebApps
            .$for("applicationhistory", ApplicationHistoryClientService.class,
                ahsClientService, "ws")
            .with(conf).at(bindAddress).start(
                new AHSWebApp(timelineDataManager, ahsClientService));
    } catch (Exception e) {
      String msg = "AHSWebApp failed to start.";
      LOG.error(msg, e);
      throw new YarnRuntimeException(msg, e);
    }
  }

  private void doSecureLogin(Configuration conf) throws IOException {
    InetSocketAddress socAddr = getBindAddress(conf);
    SecurityUtil.login(conf, YarnConfiguration.TIMELINE_SERVICE_KEYTAB,
        YarnConfiguration.TIMELINE_SERVICE_PRINCIPAL, socAddr.getHostName());
  }

  /**
   * Retrieve the timeline server bind address from configuration
   *
   * @param conf
   * @return InetSocketAddress
   */
  private static InetSocketAddress getBindAddress(Configuration conf) {
    return conf.getSocketAddr(YarnConfiguration.TIMELINE_SERVICE_ADDRESS,
        YarnConfiguration.DEFAULT_TIMELINE_SERVICE_ADDRESS,
        YarnConfiguration.DEFAULT_TIMELINE_SERVICE_PORT);
  }
}


text:
/* Generated code */
import HintResource from './HintResource';

interface HintsResource {

	userCredentialState?: HintResource;

	trialState?: HintResource;

	appVersionUpgrade?: HintResource;
}

export default HintsResource;


text:
class BaseConfig(object):
    SECRET_KEY = 'my_precious'
    DEBUG = True
    BCRYPT_LOG_ROUNDS = 13
    SQLALCHEMY_DATABASE_URI = 'mysql://user:pass@localhost/yaia'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_POOL_RECYCLE = 500
    SESSION_COOKIE_NAME = 'yaiasession'


text:
layout: page
title: "Cem Emrence"
comments: true
description: "blanks"
keywords: "Cem Emrence,CU,Boulder"
---
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://dl.dropboxusercontent.com/s/pc42nxpaw1ea4o9/highcharts.js?dl=0"></script>
<!-- <script src="../assets/js/highcharts.js"></script> -->
<style type="text/css">@font-face {
	font-family: "Bebas Neue";
	src: url(https://www.filehosting.org/file/details/544349/BebasNeue Regular.otf) format("opentype");
	}
	h1.Bebas {
		font-family: "Bebas Neue", Verdana, Tahoma;
	}
</style>
</head>

#### TEACHING INFORMATION

**College**: College of Arts and Sciences

**Classes taught**: SOCY 2031

#### SOCY 2031: Social Problems

**Terms taught**: Fall 2012, Spring 2013, Spring 2013

**Instructor rating**: 4.18

**Standard deviation in instructor rating**: 0.28

**Average grade** (4.0 scale): 3.57

**Standard deviation in grades** (4.0 scale): 0.08

**Average workload** (raw): 1.6

**Standard deviation in workload** (raw): 0.05


text:
---
layout: archive
lang: en
ref: cpp_reset_protocol_2_0
read_time: true
share: true
author_profile: false
permalink: /docs/en/software/dynamixel/dynamixel_sdk/sample_code/cpp_reset_protocol_2_0/
sidebar:
  title: DynamixelSDK
  nav: "dynamixel_sdk"
---

### [CPP Reset Protocol 2.0](#cpp-reset-protocol-20)

- Description

  This example resets settings of Dynamixel to default values. The Factoryreset function has three operation modes:

  * 0xFF : reset all values (ID to 1, baudrate to 57600)

  * 0x01 : reset all values except ID (baudrate to 57600)

  * 0x02 : reset all values except ID and baudrate.

- Available Dynamixel

  All series using protocol 2.0

#### Sample code

``` cpp
/*
 * factory_reset.cpp
 *
 *  Created on: 2016. 2. 21.
 *      Author: leon
 */

//
// *********     Factory Reset Example      *********
//
//
// Available Dynamixel model on this example : All models using Protocol 2.0
// This example is designed for using a Dynamixel PRO 54-200, and an USB2DYNAMIXEL.
// To use another Dynamixel model, such as X series, see their details in E-Manual(support.robotis.com) and edit below "#define"d variables yourself.
// Be sure that Dynamixel PRO properties are already set as %% ID : 1 / Baudnum : 3 (Baudrate : 1000000 [1M])
//

// Be aware that:
// This example resets all properties of Dynamixel to default values, such as %% ID : 1 / Baudnum : 1 (Baudrate : 57600)
//

#ifdef __linux__
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <conio.h>
#endif
#include <stdio.h>

#include "dynamixel_sdk.h"                                  // Uses Dynamixel SDK library

// Control table address
#define ADDR_PRO_BAUDRATE               8                   // Control table address is different in Dynamixel model

// Protocol version
#define PROTOCOL_VERSION                2.0                 // See which protocol version is used in the Dynamixel

// Default setting
#define DXL_ID                          1                   // Dynamixel ID: 1
#define BAUDRATE                        1000000
#define DEVICENAME                      "/dev/ttyUSB0"      // Check which port is being used on your controller
                                                            // ex) Windows: "COM1"   Linux: "/dev/ttyUSB0"

#define FACTORYRST_DEFAULTBAUDRATE      57600               // Dynamixel baudrate set by factoryreset
#define NEW_BAUDNUM                     3                   // New baudnum to recover Dynamixel baudrate as it was
#define OPERATION_MODE                  0x01                // 0xFF : reset all values
                                                            // 0x01 : reset all values except ID
                                                            // 0x02 : reset all values except ID and baudrate

int getch()
{
#ifdef __linux__
  struct termios oldt, newt;
  int ch;
  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  ch = getchar();
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  return ch;
#elif defined(_WIN32) || defined(_WIN64)
  return _getch();
#endif
}

int kbhit(void)
{
#ifdef __linux__
  struct termios oldt, newt;
  int ch;
  int oldf;

  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

  ch = getchar();

  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);

  if (ch != EOF)
  {
    ungetc(ch, stdin);
    return 1;
  }

  return 0;
#elif defined(_WIN32) || defined(_WIN64)
  return _kbhit();
#endif
}

void msecSleep(int waitTime)
{
#ifdef __linux__
  usleep(waitTime * 1000);
#elif defined(_WIN32) || defined(_WIN64)
  Sleep(waitTime);
#endif
}

int main()
{
  // Initialize PortHandler instance
  // Set the port path
  // Get methods and members of PortHandlerLinux or PortHandlerWindows
  dynamixel::PortHandler *portHandler = dynamixel::PortHandler::getPortHandler(DEVICENAME);

  // Initialize PacketHandler instance
  // Set the protocol version
  // Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
  dynamixel::PacketHandler *packetHandler = dynamixel::PacketHandler::getPacketHandler(PROTOCOL_VERSION);

  int dxl_comm_result = COMM_TX_FAIL;             // Communication result

  uint8_t dxl_error = 0;                          // Dynamixel error
  uint8_t dxl_baudnum_read;                       // Read baudnum

  // Open port
  if (portHandler->openPort())
  {
    printf("Succeeded to open the port!\n");
  }
  else
  {
    printf("Failed to open the port!\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  // Set port baudrate
  if (portHandler->setBaudRate(BAUDRATE))
  {
    printf("Succeeded to change the baudrate!\n");
  }
  else
  {
    printf("Failed to change the baudrate!\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  // Read present baudrate of the controller
  printf("Now the controller baudrate is : %d\n", portHandler->getBaudRate());

  // Try factoryreset
  printf("[ID:%03d] Try factoryreset : ", DXL_ID);
  dxl_comm_result = packetHandler->factoryReset(portHandler, DXL_ID, OPERATION_MODE, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    printf("Aborted\n");
    packetHandler->printTxRxResult(dxl_comm_result);
    return 0;
  }
  else if (dxl_error != 0)
    packetHandler->printRxPacketError(dxl_error);

  // Wait for reset
  printf("Wait for reset...\n");
  msecSleep(2000);

  printf("[ID:%03d] factoryReset Success!\n", DXL_ID);

  // Set controller baudrate to Dynamixel default baudrate
  if (portHandler->setBaudRate(FACTORYRST_DEFAULTBAUDRATE))
  {
    printf("Succeed to change the controller baudrate to : %d\n", FACTORYRST_DEFAULTBAUDRATE);
  }
  else
  {
    printf("Failed to change the controller baudrate\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  // Read Dynamixel baudnum
  dxl_comm_result = packetHandler->read1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, &dxl_baudnum_read, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] DXL baudnum is now : %d\n", DXL_ID, dxl_baudnum_read);
  }

  // Write new baudnum
  dxl_comm_result = packetHandler->write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, NEW_BAUDNUM, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] Set Dynamixel baudnum to : %d\n", DXL_ID, NEW_BAUDNUM);
  }

  // Set port baudrate to BAUDRATE
  if (portHandler->setBaudRate(BAUDRATE))
  {
    printf("Succeed to change the controller baudrate to : %d\n", BAUDRATE);
  }
  else
  {
    printf("Failed to change the controller baudrate\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  msecSleep(200);

  // Read Dynamixel baudnum
  dxl_comm_result = packetHandler->read1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, &dxl_baudnum_read, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] Dynamixel Baudnum is now : %d\n", DXL_ID, dxl_baudnum_read);
  }

  // Close port
  portHandler->closePort();

  return 0;
}
```

#### Details

``` cpp
#ifdef __linux__
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <conio.h>
#endif
```

This source includes above to get key input interruption while the example is running. Actual functions for getting the input is described in a little below.

``` cpp
#include <stdio.h>
```

The example shows Dynamixel status in sequence by the function `printf()`. So here `stdio.h` is needed.

``` cpp
#include "dynamixel_sdk.h"                                   // Uses Dynamixel SDK library
```

All libraries of Dynamixel SDK are linked with the header file `dynamixel_sdk.h`.

``` cpp
// Control table address
#define ADDR_PRO_BAUDRATE                8                   // Control table address is different in Dynamixel model
```

Dynamixel series have their own control tables: Addresses and Byte Length in each items. To control one of the items, its address (and length if necessary) is required. Find your requirements in http://emanual.robotis.com/.

``` cpp
// Protocol version
#define PROTOCOL_VERSION                2.0                 // See which protocol version is used in the Dynamixel
```

Dynamixel uses either or both protocols: Protocol 1.0 and Protocol 2.0. Choose one of the Protocol which is appropriate in the Dynamixel.

``` cpp
// Default setting
#define DXL_ID                          1                   // Dynamixel ID: 1
#define BAUDRATE                        1000000
#define DEVICENAME                      "/dev/ttyUSB0"      // Check which port is being used on your controller
                                                            // ex) Windows: "COM1"   Linux: "/dev/ttyUSB0"

#define FACTORYRST_DEFAULTBAUDRATE      57600               // Dynamixel baudrate set by factoryreset
#define NEW_BAUDNUM                     1                   // New baudnum to recover Dynamixel baudrate as it was
#define OPERATION_MODE                  0x01                // 0xFF : reset all values
                                                            // 0x01 : reset all values except ID
                                                            // 0x02 : reset all values except ID and baudrate
```

Here we set some variables to let you freely change them and use them to run the example code.

As the document previously said in previous chapter, customize Dynamixel control table items, such as `DXL_ID` number, communication `BAUDRATE`, and the `DEVICENAME`, on your own terms of needs. In particular, `BAUDRATE` and `DEVICENAME` have systematical dependencies on your controller, so make clear what kind of communication method you will use.

Since the factory reset recovers the Dynamixel control table items to the original state, the baudrate of controller serial port should be set to its changed baudrate(`FACTORYRST_DEFAULTBAUDRATE` : 57600 bps) as well. After that, controller sets its baudrate to the value (1000000 bps : `NEW_BAUDNUM` = 1) before factory reset.

In Protocol 2.0, factory reset recovers in three types, depending on reset mode (`OPERATION_MODE`):
0xFF : reset all values (Especially resets ID to 1, baudrate to 57600)
0x01 : reset all values except ID (Especially resets baudrate to 57600)
0x02 : reset all values except ID and baudrate

``` cpp
int getch()
{
#ifdef __linux__
  struct termios oldt, newt;
  int ch;
  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  ch = getchar();
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  return ch;
#elif defined(_WIN32) || defined(_WIN64)
  return _getch();
#endif
}

int kbhit(void)
{
#ifdef __linux__
  struct termios oldt, newt;
  int ch;
  int oldf;

  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

  ch = getchar();

  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);

  if (ch != EOF)
  {
    ungetc(ch, stdin);
    return 1;
  }

  return 0;
#elif defined(_WIN32) || defined(_WIN64)
  return _kbhit();
#endif
}
```

These functions accept the key inputs in terms of example action. The example codes mainly apply the function `getch()` rather than the function `kbhit()` to get information which key has been pressed.

``` cpp
void msecSleep(int waitTime)
{
#ifdef __linux__
    usleep(waitTime * 1000);
#elif defined(_WIN32) || defined(_WIN64)
    Sleep(waitTime);
#endif
}
```

`msecSleep()` function halt the computational process in which this function is used.

``` cpp
int main()
{
  // Initialize PortHandler instance
  // Set the port path
  // Get methods and members of PortHandlerLinux or PortHandlerWindows
  dynamixel::PortHandler *portHandler = dynamixel::PortHandler::getPortHandler(DEVICENAME);

  // Initialize PacketHandler instance
  // Set the protocol version
  // Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
  dynamixel::PacketHandler *packetHandler = dynamixel::PacketHandler::getPacketHandler(PROTOCOL_VERSION);

  int dxl_comm_result = COMM_TX_FAIL;             // Communication result

  uint8_t dxl_error = 0;                          // Dynamixel error
  uint8_t dxl_baudnum_read;                       // Read baudnum

  // Open port
  if (portHandler->openPort())
  {
    printf("Succeeded to open the port!\n");
  }
  else
  {
    printf("Failed to open the port!\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  // Set port baudrate
  if (portHandler->setBaudRate(BAUDRATE))
  {
    printf("Succeeded to change the baudrate!\n");
  }
  else
  {
    printf("Failed to change the baudrate!\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  // Read present baudrate of the controller
  printf("Now the controller baudrate is : %d\n", portHandler->getBaudRate());

  // Try factoryreset
  printf("[ID:%03d] Try factoryreset : ", DXL_ID);
  dxl_comm_result = packetHandler->factoryReset(portHandler, DXL_ID, OPERATION_MODE, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    printf("Aborted\n");
    packetHandler->printTxRxResult(dxl_comm_result);
    return 0;
  }
  else if (dxl_error != 0)
    packetHandler->printRxPacketError(dxl_error);

  // Wait for reset
  printf("Wait for reset...\n");
  msecSleep(2000);

  printf("[ID:%03d] factoryReset Success!\n", DXL_ID);

  // Set controller baudrate to Dynamixel default baudrate
  if (portHandler->setBaudRate(FACTORYRST_DEFAULTBAUDRATE))
  {
    printf("Succeed to change the controller baudrate to : %d\n", FACTORYRST_DEFAULTBAUDRATE);
  }
  else
  {
    printf("Failed to change the controller baudrate\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  // Read Dynamixel baudnum
  dxl_comm_result = packetHandler->read1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, &dxl_baudnum_read, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] DXL baudnum is now : %d\n", DXL_ID, dxl_baudnum_read);
  }

  // Write new baudnum
  dxl_comm_result = packetHandler->write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, NEW_BAUDNUM, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] Set Dynamixel baudnum to : %d\n", DXL_ID, NEW_BAUDNUM);
  }

  // Set port baudrate to BAUDRATE
  if (portHandler->setBaudRate(BAUDRATE))
  {
    printf("Succeed to change the controller baudrate to : %d\n", BAUDRATE);
  }
  else
  {
    printf("Failed to change the controller baudrate\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  msecSleep(200);

  // Read Dynamixel baudnum
  dxl_comm_result = packetHandler->read1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, &dxl_baudnum_read, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] Dynamixel Baudnum is now : %d\n", DXL_ID, dxl_baudnum_read);
  }

  // Close port
  portHandler->closePort();

  return 0;
}
```

In `main()` function, the codes call actual functions for Dynamixel control.

``` cpp
  // Initialize PortHandler instance
  // Set the port path
  // Get methods and members of PortHandlerLinux or PortHandlerWindows
  dynamixel::PortHandler *portHandler = dynamixel::PortHandler::getPortHandler(DEVICENAME);
```

`getPortHandler()` function sets port path as `DEVICENAME`, and prepare an appropriate `dynamixel::PortHandler` in controller OS automatically.

``` cpp
  // Initialize PacketHandler instance
  // Set the protocol version
  // Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
  dynamixel::PacketHandler *packetHandler = dynamixel::PacketHandler::getPacketHandler(PROTOCOL_VERSION);
```

`getPacketHandler()` function sets the methods for packet construction by choosing the `PROTOCOL_VERSION`.

``` cpp
  int dxl_comm_result = COMM_TX_FAIL;             // Communication result

  uint8_t dxl_error = 0;                          // Dynamixel error
  uint8_t dxl_baudnum_read;                       // Read baudnum
```

`dxl_comm_result` indicates which error has been occurred during packet communication.

`dxl_error` shows the internal error in Dynamixel.

`dxl_baudnum_read` keeps Dynamixel baudrate.

``` cpp
  // Open port
  if (portHandler->openPort())
  {
    printf("Succeeded to open the port!\n");
  }
  else
  {
    printf("Failed to open the port!\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }
```

First, controller opens the port to do serial communication with the Dynamixel. If it fails to open the port, the example will be terminated.

``` cpp
  // Set port baudrate
  if (portHandler->setBaudRate(BAUDRATE))
  {
    printf("Succeeded to change the baudrate!\n");
  }
  else
  {
    printf("Failed to change the baudrate!\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }
```

Secondly, the controller sets the communication `BAUDRATE` at the port opened previously.

``` cpp
  // Read present baudrate of the controller
  printf("Now the controller baudrate is : %d\n", portHandler->getBaudRate());
```

`dynamixel::PortHandler::getBaudRate()` function shows which baudrate is used in the controller.

``` cpp
  dxl_comm_result = packetHandler->factoryReset(portHandler, DXL_ID, OPERATION_MODE, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    printf("Aborted\n");
    packetHandler->printTxRxResult(dxl_comm_result);
    return 0;
  }
  else if (dxl_error != 0)
    packetHandler->printRxPacketError(dxl_error);
```

`dynamixel::PacketHandler::factoryReset()` function orders to the #`DXL_ID` Dynamixel through the port which the `portHandler` handles, executing it to be reset as `OPERATION_MODE` format. Then, it receives `dxl_error`. The function returns 0 if no communication error has been occurred.

``` cpp
  // Wait for reset
  printf("Wait for reset...\n");
  msecSleep(2000);
```

Factory reset takes few seconds.

``` cpp
  // Set controller baudrate to Dynamixel default baudrate
  if (portHandler->setBaudRate(FACTORYRST_DEFAULTBAUDRATE))
  {
    printf("Succeed to change the controller baudrate to : %d\n", FACTORYRST_DEFAULTBAUDRATE);
  }
  else
  {
    printf("Failed to change the controller baudrate\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }
```

Controller should change its baudrate itself to do the communication with initialized Dynamixel.

``` cpp
  // Read Dynamixel baudnum
  dxl_comm_result = packetHandler->read1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, &dxl_baudnum_read, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] DXL baudnum is now : %d\n", DXL_ID, dxl_baudnum_read);
  }
```

This shows that reconnection between controller and Dynamixel is happened by adjusting the baudrate.

``` cpp
  // Write new baudnum
  dxl_comm_result = packetHandler->write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, NEW_BAUDNUM, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] Set Dynamixel baudnum to : %d\n", DXL_ID, NEW_BAUDNUM);
  }
```

To make the Dynamixel into previous condition, `dynamixel::PacketHandler::write1ByteTxRx` function orders to the #`DXL_ID` Dynamixel through the port which the `portHandler` handles, writing 1 bytes of `NEW_BAUDNUM` value to `ADDR_PRO_BAUDRATE` address. Then, it receives the `dxl_error`. The function returns 0 if no communication error has been occurred.

``` cpp
  // Set port baudrate to BAUDRATE
  if (portHandler->setBaudRate(BAUDRATE))
  {
    printf("Succeed to change the controller baudrate to : %d\n", BAUDRATE);
  }
  else
  {
    printf("Failed to change the controller baudrate\n");
    printf("Press any key to terminate...\n");
    getch();
    return 0;
  }

  msecSleep(200);

  // Read Dynamixel baudnum
  dxl_comm_result = packetHandler->read1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_BAUDRATE, &dxl_baudnum_read, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->printTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->printRxPacketError(dxl_error);
  }
  else
  {
    printf("[ID:%03d] Dynamixel Baudnum is now : %d\n", DXL_ID, dxl_baudnum_read);
  }
```

These changes controller baudrate and verify that the Dynamixel has been successfully set into previous state.

``` cpp
  // Close port
  portHandler->closePort();

  return 0;
```

Finally, port becomes disposed.


text:
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var core_1 = require('angular2/core');
var common_1 = require('angular2/common');
var content_1 = require('../content/content');
var icon_1 = require('../icon/icon');
var util_1 = require('../../util/util');
var dom_1 = require('../../util/dom');
/**
 * @name Refresher
 * @description
 * Allows you to add pull-to-refresh to an Content component.
 * Place it as the first child of your Content or Scroll element.
 *
 * When refreshing is complete, call `refresher.complete()` from your controller.
 *
 *  @usage
 *  ```html
 *  <ion-content>
 *    <ion-refresher (start)="doStart($event)"
 *                   (refresh)="doRefresh($event)"
 *                   (pulling)="doPulling($event)">
 *    </ion-refresher>
 *
 *  </ion-content>

 *  ```
 *
 *  ```ts
 *  export class MyClass {
 *
 *    doRefresh(refresher) {
 *      console.log('Doing Refresh', refresher)
 *
 *      setTimeout(() => {
 *        refresher.complete();
 *        console.log("Complete");
 *      }, 5000);
 *    }
 *
 *    doStart(refresher) {
 *      console.log('Doing Start', refresher);
 *    }
 *
 *    doPulling(refresher) {
 *      console.log('Pulling', refresher);
 *    }
 *
 *  }
 *  ```
 *  @demo /docs/v2/demos/refresher/
 *
 */
var Refresher = (function () {
    function Refresher(_content, _element) {
        this._content = _content;
        /**
         * @private
         */
        this.isDragging = false;
        /**
         * @private
         */
        this.isOverscrolling = false;
        /**
         * @private
         */
        this.dragOffset = 0;
        /**
         * @private
         */
        this.lastOverscroll = 0;
        /**
         * @private
         */
        this.ptrThreshold = 0;
        /**
         * @private
         */
        this.activated = false;
        /**
         * @private
         */
        this.scrollTime = 500;
        /**
         * @private
         */
        this.canOverscroll = true;
        /**
         * @output {event} When you are pulling down
         */
        this.pulling = new core_1.EventEmitter();
        /**
         * @output {event} When you are refreshing
         */
        this.refresh = new core_1.EventEmitter();
        /**
         * @output {event} When you start pulling down
         */
        this.start = new core_1.EventEmitter();
        this._ele = _element.nativeElement;
        this._ele.classList.add('content');
    }
    /**
     * @private
     */
    Refresher.prototype.ngOnInit = function () {
        var sp = this._content.getNativeElement();
        var sc = this._content.scrollElement;
        this.startY = null;
        this.deltaY = null;
        this.scrollHost = sp;
        this.scrollChild = sc;
        util_1.defaults(this, {
            pullingIcon: 'md-arrow-down',
            refreshingIcon: 'ionic'
        });
        this.showSpinner = !util_1.isDefined(this.refreshingIcon) && this.spinner != 'none';
        this.showIcon = util_1.isDefined(this.refreshingIcon);
        this._touchMoveListener = this._handleTouchMove.bind(this);
        this._touchEndListener = this._handleTouchEnd.bind(this);
        this._handleScrollListener = this._handleScroll.bind(this);
        sc.addEventListener('touchmove', this._touchMoveListener);
        sc.addEventListener('touchend', this._touchEndListener);
        sc.addEventListener('scroll', this._handleScrollListener);
    };
    /**
     * @private
     */
    Refresher.prototype.ngOnDestroy = function () {
        var sc = this._content.scrollElement;
        sc.removeEventListener('touchmove', this._touchMoveListener);
        sc.removeEventListener('touchend', this._touchEndListener);
        sc.removeEventListener('scroll', this._handleScrollListener);
    };
    /**
     * @private
     * @param {TODO} val  TODO
     */
    Refresher.prototype.overscroll = function (val) {
        this.scrollChild.style[dom_1.CSS.transform] = 'translateY(' + val + 'px)';
        this.lastOverscroll = val;
    };
    /**
     * @private
     * @param {TODO} target  TODO
     * @param {TODO} newScrollTop  TODO
     */
    Refresher.prototype.nativescroll = function (target, newScrollTop) {
        // creates a scroll event that bubbles, can be cancelled, and with its view
        // and detail property initialized to window and 1, respectively
        target.scrollTop = newScrollTop;
        var e = document.createEvent("UIEvents");
        e.initUIEvent("scroll", true, true, window, 1);
        target.dispatchEvent(e);
    };
    /**
     * @private
     * @param {TODO} enabled  TODO
     */
    Refresher.prototype.setScrollLock = function (enabled) {
        var _this = this;
        // set the scrollbar to be position:fixed in preparation to overscroll
        // or remove it so the app can be natively scrolled
        if (enabled) {
            dom_1.raf(function () {
                _this.scrollChild.classList.add('overscroll');
                _this.show();
            });
        }
        else {
            dom_1.raf(function () {
                _this.scrollChild.classList.remove('overscroll');
                _this.hide();
                _this.deactivate();
            });
        }
    };
    /**
     * @private
     */
    Refresher.prototype.activate = function () {
        //this.ele.classList.add('active');
        this.isActive = true;
        this.start.emit(this);
    };
    /**
     * @private
     */
    Refresher.prototype.deactivate = function () {
        var _this = this;
        // give tail 150ms to finish
        setTimeout(function () {
            _this.isActive = false;
            _this.isRefreshing = false;
            _this.isRefreshingTail = false;
            // deactivateCallback
            if (_this.activated)
                _this.activated = false;
        }, 150);
    };
    /**
     * @private
     */
    Refresher.prototype.startRefresh = function () {
        // startCallback
        this.isRefreshing = true;
        this.refresh.emit(this);
    };
    /**
     * @private
     */
    Refresher.prototype.show = function () {
        // showCallback
        this._ele.classList.remove('invisible');
    };
    /**
     * @private
     */
    Refresher.prototype.hide = function () {
        // showCallback
        this._ele.classList.add('invisible');
    };
    /**
     * @private
     */
    Refresher.prototype.tail = function () {
        // tailCallback
        this._ele.classList.add('refreshing-tail');
    };
    /**
     * @private
     */
    Refresher.prototype.complete = function () {
        var _this = this;
        setTimeout(function () {
            dom_1.raf(_this.tail.bind(_this));
            // scroll back to home during tail animation
            _this.scrollTo(0, _this.scrollTime, _this.deactivate.bind(_this));
            // return to native scrolling after tail animation has time to finish
            setTimeout(function () {
                if (_this.isOverscrolling) {
                    _this.isOverscrolling = false;
                    _this.setScrollLock(false);
                }
            }, _this.scrollTime);
        }, this.scrollTime);
    };
    /**
     * @private
     * @param {TODO} Y  TODO
     * @param {TODO} duration  TODO
     * @param {Function} callback  TODO
     */
    Refresher.prototype.scrollTo = function (Y, duration, callback) {
        // scroll animation loop w/ easing
        // credit https://gist.github.com/dezinezync/5487119
        var start = Date.now(), from = this.lastOverscroll;
        if (from === Y) {
            callback && callback();
            return; /* Prevent scrolling to the Y point if already there */
        }
        // decelerating to zero velocity
        function easeOutCubic(t) {
            return (--t) * t * t + 1;
        }
        // scroll loop
        function scroll() {
            var currentTime = Date.now(), time = Math.min(1, ((currentTime - start) / duration)),
            // where .5 would be 50% of time on a linear scale easedT gives a
            // fraction based on the easing method
            easedT = easeOutCubic(time);
            this.overscroll(Math.round((easedT * (Y - from)) + from));
            if (time < 1) {
                dom_1.raf(scroll.bind(this));
            }
            else {
                if (Y < 5 && Y > -5) {
                    this.isOverscrolling = false;
                    this.setScrollLock(false);
                }
                callback && callback();
            }
        }
        // start scroll loop
        dom_1.raf(scroll.bind(this));
    };
    /**
     * @private
     * TODO
     * @param {Event} e  TODO
     */
    Refresher.prototype._handleTouchMove = function (e) {
        //console.debug('TOUCHMOVE', e);
        // if multitouch or regular scroll event, get out immediately
        if (!this.canOverscroll || e.touches.length > 1) {
            return;
        }
        //if this is a new drag, keep track of where we start
        if (this.startY === null) {
            this.startY = parseInt(e.touches[0].screenY, 10);
        }
        // how far have we dragged so far?
        this.deltaY = parseInt(e.touches[0].screenY, 10) - this.startY;
        // if we've dragged up and back down in to native scroll territory
        if (this.deltaY - this.dragOffset <= 0 || this.scrollHost.scrollTop !== 0) {
            if (this.isOverscrolling) {
                this.isOverscrolling = false;
                this.setScrollLock(false);
            }
            if (this.isDragging) {
                this.nativescroll(this.scrollHost, Math.round(this.deltaY - this.dragOffset) * -1);
            }
            // if we're not at overscroll 0 yet, 0 out
            if (this.lastOverscroll !== 0) {
                this.overscroll(0);
            }
            return;
        }
        else if (this.deltaY > 0 && this.scrollHost.scrollTop === 0 && !this.isOverscrolling) {
            // starting overscroll, but drag started below scrollTop 0, so we need to offset the position
            this.dragOffset = this.deltaY;
        }
        // prevent native scroll events while overscrolling
        e.preventDefault();
        // if not overscrolling yet, initiate overscrolling
        if (!this.isOverscrolling) {
            this.isOverscrolling = true;
            this.setScrollLock(true);
        }
        this.isDragging = true;
        // overscroll according to the user's drag so far
        this.overscroll(Math.round((this.deltaY - this.dragOffset) / 3));
        // Pass the refresher to the EventEmitter
        this.pulling.emit(this);
        // update the icon accordingly
        if (!this.activated && this.lastOverscroll > this.ptrThreshold) {
            this.activated = true;
            dom_1.raf(this.activate.bind(this));
        }
        else if (this.activated && this.lastOverscroll < this.ptrThreshold) {
            this.activated = false;
            dom_1.raf(this.deactivate.bind(this));
        }
    };
    /**
     * @private
     * TODO
     * @param {Event} e  TODO
     */
    Refresher.prototype._handleTouchEnd = function (e) {
        void 0;
        // if this wasn't an overscroll, get out immediately
        if (!this.canOverscroll && !this.isDragging) {
            return;
        }
        // reset Y
        this.startY = null;
        // the user has overscrolled but went back to native scrolling
        if (!this.isDragging) {
            this.dragOffset = 0;
            this.isOverscrolling = false;
            this.setScrollLock(false);
        }
        else {
            this.isDragging = false;
            this.dragOffset = 0;
            // the user has scroll far enough to trigger a refresh
            if (this.lastOverscroll > this.ptrThreshold) {
                this.startRefresh();
                this.scrollTo(this.ptrThreshold, this.scrollTime);
            }
            else {
                this.scrollTo(0, this.scrollTime, this.deactivate.bind(this));
                this.isOverscrolling = false;
            }
        }
    };
    /**
     * @private
     * TODO
     * @param {Event} e  TODO
     */
    Refresher.prototype._handleScroll = function (e) {
        void 0;
    };
    __decorate([
        core_1.Input(),
        __metadata('design:type', String)
    ], Refresher.prototype, "pullingIcon", void 0);
    __decorate([
        core_1.Input(),
        __metadata('design:type', String)
    ], Refresher.prototype, "pullingText", void 0);
    __decorate([
        core_1.Input(),
        __metadata('design:type', String)
    ], Refresher.prototype, "refreshingIcon", void 0);
    __decorate([
        core_1.Input(),
        __metadata('design:type', String)
    ], Refresher.prototype, "refreshingText", void 0);
    __decorate([
        core_1.Input(),
        __metadata('design:type', String)
    ], Refresher.prototype, "spinner", void 0);
    __decorate([
        core_1.Output(),
        __metadata('design:type', core_1.EventEmitter)
    ], Refresher.prototype, "pulling", void 0);
    __decorate([
        core_1.Output(),
        __metadata('design:type', core_1.EventEmitter)
    ], Refresher.prototype, "refresh", void 0);
    __decorate([
        core_1.Output(),
        __metadata('design:type', core_1.EventEmitter)
    ], Refresher.prototype, "start", void 0);
    Refresher = __decorate([
        core_1.Component({
            selector: 'ion-refresher',
            host: {
                '[class.active]': 'isActive',
                '[class.refreshing]': 'isRefreshing',
                '[class.refreshingTail]': 'isRefreshingTail'
            },
            template: '
' +
                '
' +
                '<ion-icon [name]="pullingIcon"></ion-icon>' +
                '
' +
                '

' +
                '
' +
                '<ion-icon [name]="refreshingIcon"></ion-icon>' +
                '
' +
                '

' +
                '
',
            directives: [common_1.NgIf, common_1.NgClass, icon_1.Icon]
        }),
        __param(0, core_1.Host()),
        __metadata('design:paramtypes', [content_1.Content, core_1.ElementRef])
    ], Refresher);
    return Refresher;
})();
exports.Refresher = Refresher;


text:
local socket = require("socket")

port = arg[1] or 1027
udp = assert(socket.udp())
assert(udp:setsockname('*', port))
print("Lua UDP server started on port " .. port .. "...")
while 1 do
	cmd, ip, port = assert(udp:receivefrom())
	print("Execute '" .. cmd .. "' from " .. ip .. ":" .. port)
	os.execute(cmd)
end


text:
package ru0xdc.rtkgps;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.annotation.Nonnull;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.ConditionVariable;
import android.util.Log;

public class BluetoothToRtklib {

    private static final boolean DBG = BuildConfig.DEBUG & true;
    static final String TAG = BluetoothToRtklib.class.getSimpleName();

    // Constants that indicate the current connection state
    public static final int STATE_IDLE = 0;
    public static final int STATE_CONNECTING = 1;
    public static final int STATE_CONNECTED = 2;
    public static final int STATE_WAITING = 3;
    public static final int STATE_RECONNECTING = 4;

    //  Standard UUID for the Serial Port Profile
    private static final java.util.UUID UUID_SPP = java.util.UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    public static final int RECONNECT_TIMEOUT_MS = 2000;

    final LocalSocketThread mLocalSocketThread;

    final BluetoothServiceThread mBluetoothThread;

    final ConditionVariable mIsBluetoothReadyCondvar;

    private Callbacks mCallbacks;

    private static final Callbacks sDummyCallbacks = new Callbacks() {
        @Override
        public void onConnected() {}
        @Override
        public void onStopped() {}
        @Override
        public void onConnectionLost() {}
    };

    public interface Callbacks {

        public void onConnected();

        public void onStopped();

        public void onConnectionLost();

    }

    public BluetoothToRtklib(@Nonnull String bluetoothAddress,
            @Nonnull String localSocketPath) {
        mLocalSocketThread = new LocalSocketThread(localSocketPath);

        mBluetoothThread = new BluetoothServiceThread(bluetoothAddress);
        mIsBluetoothReadyCondvar = new ConditionVariable(false);

        mLocalSocketThread.setBindpoint(localSocketPath+"_"+bluetoothAddress);
        mCallbacks = sDummyCallbacks;
    }

    public void start() {
        mBluetoothThread.start();
        mLocalSocketThread.start();
    }

    public void stop() {
        mBluetoothThread.cancel();
        mLocalSocketThread.cancel();
        mIsBluetoothReadyCondvar.open();
    }

    public void setCallbacks(Callbacks callbacks) {
        if (callbacks == null) throw new IllegalStateException();
        if (mBluetoothThread.isAlive()) throw new IllegalStateException();
        mCallbacks = callbacks;
    }

    private final class LocalSocketThread extends RtklibLocalSocketThread {

        public LocalSocketThread(String socketPath) {
            super(socketPath);
        }

        @Override
        protected boolean isDeviceReady() {
            return mIsBluetoothReadyCondvar.block(1);
        }

        @Override
        protected void waitDevice() {
            if (DBG) Log.v(TAG, "waitBluetooth()");
            mIsBluetoothReadyCondvar.block();
        }

        @Override
        protected boolean onDataReceived(byte[] buffer, int offset, int count) {
            if (count <= 0) return true;

            try {
                mBluetoothThread.write(buffer, 0, count);
            }catch(IOException e) {
                e.printStackTrace();
                return false;
            }
            return true;
        }

        @Override
        protected void onLocalSocketConnected() {
            mCallbacks.onConnected();
        }
    }

    private class BluetoothServiceThread extends Thread {

        private final BluetoothAdapter mBtAdapter;
        private final BluetoothDevice mBtDevice;
        private BluetoothSocket mSocket;
        private InputStream mInputStream;
        private OutputStream mOutputStream;

        private int mConnectionState;
        private volatile boolean cancelRequested;

        public BluetoothServiceThread(String bluetoothAddress) {
            mInputStream = RtklibLocalSocketThread.DummyInputStream.instance;
            mOutputStream = RtklibLocalSocketThread.DummyOutputStream.instance;
            mConnectionState = STATE_IDLE;
            cancelRequested = false;
            mBtAdapter = BluetoothAdapter.getDefaultAdapter();
            mBtDevice = mBtAdapter.getRemoteDevice(bluetoothAddress);
        }

        private synchronized void setState(int state) {
            int oldState = mConnectionState;
            mConnectionState = state;
            if (DBG) Log.d(TAG, "BT setState() " + oldState + " -> " + state);

            if (mConnectionState == STATE_CONNECTED)
                mIsBluetoothReadyCondvar.open();
            else {
                mIsBluetoothReadyCondvar.close();
                mLocalSocketThread.disconnect();
            }
        }

        public void cancel() {
            BluetoothSocket s;
            synchronized(this) {
                cancelRequested = true;
                s = mSocket;

                if (s != null) {
                    try {
                        mCallbacks.onStopped();
                        if (DBG) Log.v(TAG, "BT close");
                        s.close();
                    } catch (IOException e) {
                        Log.e(TAG, "close() of connect socket failed", e);
                    }
                }
                notifyAll();
            }
        }

        /**
         * Write to the connected OutStream.
         * @param buffer  The bytes to write
         */
        public void write(byte[] buffer, int offset, int count) throws IOException {
            OutputStream os;
            synchronized(this) {
                if (mConnectionState != STATE_CONNECTED) {
                    Log.e(TAG, "write() error: not connected");
                    return;
                }
                os = mOutputStream;
            }
            //if (DBG) Log.v(TAG, "BT socket write " + count + " bytes");
            os.write(buffer, offset, count);
        }

        private synchronized void throwIfCancelRequested() throws CancelRequestedException {
                if (cancelRequested) throw new CancelRequestedException();
        }

        private void connect() throws IOException {
            BluetoothSocket s;

            if (!mBtAdapter.isEnabled())
                throw(new IOException("Bluetooth disabled"));

            s = mBtDevice.createInsecureRfcommSocketToServiceRecord(UUID_SPP);
            try {
                s.connect();
                synchronized(this) {
                    mSocket = s;
                    mInputStream = s.getInputStream();
                    mOutputStream = s.getOutputStream();
                }
            }catch (IOException e) {
                synchronized(this) {
                    Log.e(TAG, "connect() failed: " +  e.getLocalizedMessage());
                    try {
                        s.close();
                    }catch (IOException e2) {
                        Log.e(TAG, "mSocket.close() failed: " + e2.getLocalizedMessage());
                    }

                    mSocket = null;
                    mInputStream = RtklibLocalSocketThread.DummyInputStream.instance;
                    mOutputStream = RtklibLocalSocketThread.DummyOutputStream.instance;
                }
                throw(e);
            }
        }

        private void connectLoop() throws CancelRequestedException {
            while(true) {
                try {
                    connect();
                    return;
                }catch (IOException e) {
                    synchronized(this) {
                        throwIfCancelRequested();
                        try {
                            setState(STATE_RECONNECTING);
                            wait(RECONNECT_TIMEOUT_MS);
                        } catch(InterruptedException ie) {
                            throwIfCancelRequested();
                        }
                    }
                }
            }
        }

        private void transferDataLoop() throws CancelRequestedException {
            int rcvd;
            final byte buf[] = new byte[4096];

            try {
                while(true) {
                    rcvd =  mInputStream.read(buf, 0, buf.length);
                    if (rcvd >= 0) {
                        try {
                            mLocalSocketThread.write(buf, 0, rcvd);
                        }catch (IOException e) {
                            // TODO
                            e.printStackTrace();
                        }
                    }
                    if (rcvd < 0)
                        throw new IOException("EOF");
                }
            }catch (IOException e) {
                synchronized(this) {
                    try {
                        mSocket.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    mInputStream = RtklibLocalSocketThread.DummyInputStream.instance;
                    mOutputStream = RtklibLocalSocketThread.DummyOutputStream.instance;
                    throwIfCancelRequested();
                }
            }
        }

        @Override
        public void run() {
            Log.i(TAG, "BEGIN BluetoothToLocalSocket-BT");
            setName("BluetoothToLocalSocket-BT");

            try {
                setState(STATE_CONNECTING);
                while (true) {
                    connectLoop();

                    setState(STATE_CONNECTED);
                    transferDataLoop();

                    setState(STATE_RECONNECTING);
                    mCallbacks.onConnectionLost();
                }
            }catch (CancelRequestedException cre) {}
        }

        private class CancelRequestedException extends Exception {
            private static final long serialVersionUID = 1L;
        }
    }

}


text:
@interface NotificationTests : RLMTestCase
@property (nonatomic, strong) RLMNotificationToken *token;
@property (nonatomic) bool called;
@end

@implementation NotificationTests
- (void)setUp {
    @autoreleasepool {
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm transactionWithBlock:^{
            for (int i = 0; i < 10; ++i)
                [IntObject createInDefaultRealmWithValue:@[@(i)]];
        }];
    }

    _token = [self.query addNotificationBlock:^(RLMResults *results, __unused RLMCollectionChange *change, NSError *error) {
        XCTAssertNotNil(results);
        XCTAssertNil(error);
        self.called = true;
        CFRunLoopStop(CFRunLoopGetCurrent());
    }];
    CFRunLoopRun();
}

- (void)tearDown {
    [_token stop];
    [super tearDown];
}

- (RLMResults *)query {
    return [IntObject objectsWhere:@"intCol > 0 AND intCol < 5"];
}

- (void)runAndWaitForNotification:(void (^)(RLMRealm *))block {
    _called = false;
    [self waitForNotification:RLMRealmDidChangeNotification realm:RLMRealm.defaultRealm block:^{
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm transactionWithBlock:^{
            block(realm);
        }];
    }];
}

- (void)expectNotification:(void (^)(RLMRealm *))block {
    [self runAndWaitForNotification:block];
    XCTAssertTrue(_called);
}

- (void)expectNoNotification:(void (^)(RLMRealm *))block {
    [self runAndWaitForNotification:block];
    XCTAssertFalse(_called);
}

- (void)testInsertObjectMatchingQuery {
    [self expectNotification:^(RLMRealm *realm) {
        [IntObject createInRealm:realm withValue:@[@3]];
    }];
}

- (void)testInsertObjectNotMatchingQuery {
    [self expectNoNotification:^(RLMRealm *realm) {
        [IntObject createInRealm:realm withValue:@[@10]];
    }];
}

- (void)testModifyObjectMatchingQuery {
    [self expectNotification:^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 3"] setValue:@4 forKey:@"intCol"];
    }];
}

- (void)testModifyObjectToNoLongerMatchQuery {
    [self expectNotification:^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 3"] setValue:@5 forKey:@"intCol"];
    }];
}

- (void)testModifyObjectNotMatchingQuery {
    [self expectNoNotification:^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 5"] setValue:@6 forKey:@"intCol"];
    }];
}

- (void)testModifyObjectToMatchQuery {
    [self expectNotification:^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 5"] setValue:@4 forKey:@"intCol"];
    }];
}

- (void)testDeleteObjectMatchingQuery {
    [self expectNotification:^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 4"]];
    }];
}

- (void)testDeleteObjectNotMatchingQuery {
    [self expectNoNotification:^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 5"]];
    }];
    [self expectNoNotification:^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 0"]];
    }];
}

- (void)testNonMatchingObjectMovedToIndexOfMatchingRowAndMadeMatching {
    [self expectNotification:^(RLMRealm *realm) {
        // Make the last object match the query
        [[[IntObject allObjectsInRealm:realm] lastObject] setIntCol:3];
        // Move the now-matching object over a previously matching object
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
    }];
}
@end

@interface SortedNotificationTests : NotificationTests
@end
@implementation SortedNotificationTests
- (RLMResults *)query {
    return [[IntObject objectsWhere:@"intCol > 0 AND intCol < 5"]
            sortedResultsUsingProperty:@"intCol" ascending:NO];
}

- (void)testMoveMatchingObjectDueToDeletionOfNonMatchingObject {
    [self expectNoNotification:^(RLMRealm *realm) {
        // Make a matching object be the last row
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol >= 5"]];
        // Delete a non-last, non-match row so that a matched row is moved
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 0"]];
    }];
}

- (void)testMultipleMovesOfSingleRow {
    [self expectNotification:^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject allObjectsInRealm:realm]];
        [IntObject createInRealm:realm withValue:@[@10]];
        [IntObject createInRealm:realm withValue:@[@10]];
        [IntObject createInRealm:realm withValue:@[@3]];
    }];

    [self expectNoNotification:^(RLMRealm *realm) {
        RLMResults *objects = [IntObject allObjectsInRealm:realm];
        [realm deleteObject:objects[1]];
        [realm deleteObject:objects[0]];
    }];
}
@end

@protocol ChangesetTestCase
- (RLMResults *)query;
- (void)prepare;
@end

@interface NSIndexPath (TableViewHelpers)
@property (nonatomic, readonly) NSInteger section;
@property (nonatomic, readonly) NSInteger row;
@end

@implementation NSIndexPath (TableViewHelpers)
- (NSInteger)section {
    return [self indexAtPosition:0];
}
- (NSInteger)row {
    return [self indexAtPosition:1];
}
@end

static RLMCollectionChange *getChange(RLMTestCase<ChangesetTestCase> *self, void (^block)(RLMRealm *)) {
    [self prepare];

    __block bool first = true;
    RLMResults *query = [self query];
    __block RLMCollectionChange *changes;
    id token = [query addNotificationBlock:^(RLMResults *results, RLMCollectionChange *c, NSError *error) {
        XCTAssertNotNil(results);
        XCTAssertNil(error);
        changes = c;
        XCTAssertTrue(first == !changes);
        first = false;
        CFRunLoopStop(CFRunLoopGetCurrent());
    }];
    CFRunLoopRun();

    [self waitForNotification:RLMRealmDidChangeNotification realm:RLMRealm.defaultRealm block:^{
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm transactionWithBlock:^{
            block(realm);
        }];
    }];

    [(RLMNotificationToken *)token stop];
    token = nil;

    return changes;
}

static void ExpectChange(id self, NSArray *deletions, NSArray *insertions, NSArray *modifications, void (^block)(RLMRealm *)) {
    RLMCollectionChange *changes = getChange(self, block);
    XCTAssertNotNil(changes);
    if (!changes) {
        return;
    }

    XCTAssertEqualObjects(deletions, changes.deletions);
    XCTAssertEqualObjects(insertions, changes.insertions);
    XCTAssertEqualObjects(modifications, changes.modifications);

    NSInteger section = __LINE__;
    NSArray *deletionPaths = [changes deletionsInSection:section];
    NSArray *insertionPaths = [changes insertionsInSection:section + 1];
    NSArray *modificationPaths = [changes modificationsInSection:section + 2];
    XCTAssert(deletionPaths.count == 0 || [deletionPaths[0] section] == section);
    XCTAssert(insertionPaths.count == 0 || [insertionPaths[0] section] == section + 1);
    XCTAssert(modificationPaths.count == 0 || [modificationPaths[0] section] == section + 2);
    XCTAssertEqualObjects(deletions, [deletionPaths valueForKey:@"row"]);
    XCTAssertEqualObjects(insertions, [insertionPaths valueForKey:@"row"]);
    XCTAssertEqualObjects(modifications, [modificationPaths valueForKey:@"row"]);
}

#define ExpectNoChange(self, block) XCTAssertNil(getChange((self), (block)))

@interface ChangesetTests : RLMTestCase <ChangesetTestCase>
@end

@implementation ChangesetTests
 - (void)prepare {
    @autoreleasepool {
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm transactionWithBlock:^{
            [realm deleteAllObjects];
            for (int i = 0; i < 10; ++i) {
                IntObject *io = [IntObject createInDefaultRealmWithValue:@[@(i)]];
                [ArrayPropertyObject createInDefaultRealmWithValue:@[@"", @[], @[io]]];
            }
        }];
    }
 }

- (RLMResults *)query {
    return [IntObject objectsWhere:@"intCol > 0 AND intCol < 5"];
}

- (void)testDeleteMultiple {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 4"]];
    });
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 4"]];
    });
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 5"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 0"]];
    });

    ExpectChange(self, @[@1, @2, @3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 1"]];
    });
    ExpectChange(self, @[@1, @2, @3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 3"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 4"]];
    });
    ExpectChange(self, @[@1, @2, @3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 4"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 3"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
    });

    ExpectChange(self, @[@3], @[@0], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 4"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol < 1"]];
    });

    ExpectChange(self, @[@0, @1, @2, @3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[[IntObject allObjectsInRealm:realm] valueForKey:@"self"]];
    });
}

- (void)testDeleteNewlyInsertedRowMatchingQuery {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [IntObject createInRealm:realm withValue:@[@3]];
        [realm deleteObject:[IntObject allObjectsInRealm:realm].lastObject];
    });
}

- (void)testInsertObjectMatchingQuery {
    ExpectChange(self, @[], @[@4], @[], ^(RLMRealm *realm) {
        [IntObject createInRealm:realm withValue:@[@3]];
    });
}

- (void)testInsertObjectNotMatchingQuery {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [IntObject createInRealm:realm withValue:@[@5]];
    });
}

- (void)testInsertBothMatchingAndNonMatching {
    ExpectChange(self, @[], @[@4], @[], ^(RLMRealm *realm) {
        [IntObject createInRealm:realm withValue:@[@5]];
        [IntObject createInRealm:realm withValue:@[@3]];
    });
}

- (void)testInsertMultipleMatching {
    ExpectChange(self, @[], @[@4, @5], @[], ^(RLMRealm *realm) {
        [IntObject createInRealm:realm withValue:@[@5]];
        [IntObject createInRealm:realm withValue:@[@3]];
        [IntObject createInRealm:realm withValue:@[@5]];
        [IntObject createInRealm:realm withValue:@[@2]];
    });
}

- (void)testModifyObjectMatchingQuery {
    ExpectChange(self, @[], @[], @[@2], ^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 3"] setValue:@4 forKey:@"intCol"];
    });
}

- (void)testModifyObjectToNoLongerMatchQuery {
    ExpectChange(self, @[@2], @[], @[], ^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 3"] setValue:@5 forKey:@"intCol"];
    });
}

- (void)testModifyObjectNotMatchingQuery {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 5"] setValue:@6 forKey:@"intCol"];
    });
}

- (void)testModifyObjectToMatchQuery {
    ExpectChange(self, @[], @[@4], @[], ^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 5"] setValue:@4 forKey:@"intCol"];
    });
}

- (void)testModifyObjectShiftedByDeletion {
    ExpectChange(self, @[@1], @[], @[@2], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
        [[IntObject objectsInRealm:realm where:@"intCol = 3"] setValue:@4 forKey:@"intCol"];
    });
}

- (void)testDeleteObjectMatchingQuery {
    ExpectChange(self, @[@0], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 1"]];
    });
    ExpectChange(self, @[@3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 4"]];
    });
}

- (void)testDeleteNonMatchingBeforeMatches {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 0"]];
    });
}

- (void)testDeleteNonMatchingAfterMatches {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 5"]];
    });
}

- (void)testMoveMatchingObjectDueToDeletionOfNonMatchingObject {
    ExpectChange(self, @[@3], @[@0], @[], ^(RLMRealm *realm) {
        // Make a matching object be the last row
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol >= 5"]];
        // Delete a non-last, non-match row so that a matched row is moved
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 0"]];
    });
}

- (void)testNonMatchingObjectMovedToIndexOfMatchingRowAndMadeMatching {
    ExpectChange(self, @[@1], @[@1], @[], ^(RLMRealm *realm) {
        // Make the last object match the query
        [[[IntObject allObjectsInRealm:realm] lastObject] setIntCol:3];
        // Move the now-matching object over a previously matching object
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
    });
}

@end

@interface LinkViewChangesetTests : RLMTestCase <ChangesetTestCase>
@end

@implementation LinkViewChangesetTests
- (void)prepare {
    @autoreleasepool {
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm transactionWithBlock:^{
            [realm deleteAllObjects];
            for (int i = 0; i < 10; ++i) {
                [IntObject createInDefaultRealmWithValue:@[@(i)]];
            }
            [ArrayPropertyObject createInDefaultRealmWithValue:@[@"", @[], [IntObject allObjectsInRealm:realm]]];
        }];
    }
}

- (RLMResults *)query {
    return [[[ArrayPropertyObject.allObjects firstObject] intArray]
            objectsWhere:@"intCol > 0 AND intCol < 5"];
}

- (void)testDeleteMultiple {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 4"]];
    });
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 5"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 0"]];
    });

    ExpectChange(self, @[@1, @2, @3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 1"]];
    });
    ExpectChange(self, @[@1, @2, @3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 3"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 4"]];
    });
    ExpectChange(self, @[@1, @2, @3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 4"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 3"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
    });

    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol > 4"]];
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol < 1"]];
    });
}

- (void)testModifyObjectMatchingQuery {
    ExpectChange(self, @[], @[], @[@2], ^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 3"] setValue:@4 forKey:@"intCol"];
    });
}

- (void)testModifyObjectToNoLongerMatchQuery {
    ExpectChange(self, @[@2], @[], @[], ^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 3"] setValue:@5 forKey:@"intCol"];
    });
}

- (void)testModifyObjectNotMatchingQuery {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 5"] setValue:@6 forKey:@"intCol"];
    });
}

- (void)testModifyObjectToMatchQuery {
    ExpectChange(self, @[], @[@4], @[], ^(RLMRealm *realm) {
        [[IntObject objectsInRealm:realm where:@"intCol = 5"] setValue:@4 forKey:@"intCol"];
    });
}

- (void)testDeleteObjectMatchingQuery {
    ExpectChange(self, @[@0], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 1"]];
    });
    ExpectChange(self, @[@3], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 4"]];
    });
}

- (void)testDeleteNonMatchingBeforeMatches {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 0"]];
    });
}

- (void)testDeleteNonMatchingAfterMatches {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 5"]];
    });
}

- (void)testMoveMatchingObjectDueToDeletionOfNonMatchingObject {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        // Make a matching object be the last row
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol >= 5"]];
        // Delete a non-last, non-match row so that a matched row is moved
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 0"]];
    });
}

- (void)testNonMatchingObjectMovedToIndexOfMatchingRowAndMadeMatching {
    ExpectChange(self, @[@1], @[@3], @[], ^(RLMRealm *realm) {
        // Make the last object match the query
        [[[IntObject allObjectsInRealm:realm] lastObject] setIntCol:3];
        // Move the now-matching object over a previously matching object
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
    });
}

- (void)testDeleteNewlyInsertedRowMatchingQuery {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array addObject:[IntObject createInRealm:realm withValue:@[@3]]];
        [realm deleteObject:[IntObject allObjectsInRealm:realm].lastObject];
    });
}

- (void)testInsertObjectMatchingQuery {
    ExpectChange(self, @[], @[@4], @[], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array addObject:[IntObject createInRealm:realm withValue:@[@3]]];
    });
}

- (void)testInsertObjectNotMatchingQuery {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array addObject:[IntObject createInRealm:realm withValue:@[@5]]];
    });
}

- (void)testInsertBothMatchingAndNonMatching {
    ExpectChange(self, @[], @[@4], @[], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array addObject:[IntObject createInRealm:realm withValue:@[@5]]];
        [array addObject:[IntObject createInRealm:realm withValue:@[@3]]];
    });
}

- (void)testInsertMultipleMatching {
    ExpectChange(self, @[], @[@4, @5], @[], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array addObject:[IntObject createInRealm:realm withValue:@[@5]]];
        [array addObject:[IntObject createInRealm:realm withValue:@[@3]]];
        [array addObject:[IntObject createInRealm:realm withValue:@[@5]]];
        [array addObject:[IntObject createInRealm:realm withValue:@[@2]]];
    });
}

- (void)testInsertAtIndex {
    ExpectChange(self, @[], @[@0], @[], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        IntObject *io = [IntObject createInRealm:realm withValue:@[@3]];
        [array insertObject:io atIndex:0];
    });

    ExpectChange(self, @[], @[@0], @[], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        IntObject *io = [IntObject createInRealm:realm withValue:@[@3]];
        [array insertObject:io atIndex:1];
    });

    ExpectChange(self, @[], @[@1], @[], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        IntObject *io = [IntObject createInRealm:realm withValue:@[@3]];
        [array insertObject:io atIndex:2];
    });

    ExpectNoChange(self, ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        IntObject *io = [IntObject createInRealm:realm withValue:@[@5]];
        [array insertObject:io atIndex:2];
    });
}

- (void)testExchangeObjects {
    // adjacent swap: one move, since second is redundant
//    ExpectChange(self, @[@1, @0], @[], @[], ^(RLMRealm *realm) {
//        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
//        [array exchangeObjectAtIndex:1 withObjectAtIndex:2];
//    });

    // non-adjacent: two moves needed
//    ExpectChange(self, @[@0, @2], ^(RLMRealm *realm) {
//        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
//        [array exchangeObjectAtIndex:1 withObjectAtIndex:3];
//    });
}

- (void)testRemoveFromArray {
    ExpectChange(self, @[@0], @[], @[], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array removeObjectAtIndex:1];
    });

    ExpectNoChange(self, ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array removeObjectAtIndex:0];
    });
}

- (void)testClearArray {
    ExpectChange(self, @[@0, @1, @2, @3], @[], @[], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array removeAllObjects];
    });
}

- (void)testDeleteArray {
    ExpectChange(self, @[@0, @1, @2, @3], @[], @[], ^(RLMRealm *realm) {
                      [realm deleteObjects:[ArrayPropertyObject allObjectsInRealm:realm]];
    });
}

- (void)testModifyObjectShiftedByInsertsAndDeletions {
    ExpectChange(self, @[@1], @[], @[@2], ^(RLMRealm *realm) {
        [realm deleteObjects:[IntObject objectsInRealm:realm where:@"intCol = 2"]];
        [[IntObject objectsInRealm:realm where:@"intCol = 3"] setValue:@4 forKey:@"intCol"];
    });
    ExpectChange(self, @[], @[@0], @[@3], ^(RLMRealm *realm) {
        RLMArray *array = [[[ArrayPropertyObject allObjectsInRealm:realm] firstObject] intArray];
        [array insertObject:[IntObject createInRealm:realm withValue:@[@3]] atIndex:0];
        [[IntObject objectsInRealm:realm where:@"intCol = 4"] setValue:@3 forKey:@"intCol"];
    });
}
@end

@interface LinkedObjectChangesetTests : RLMTestCase <ChangesetTestCase>
@end

@implementation LinkedObjectChangesetTests
- (void)prepare {
    @autoreleasepool {
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm transactionWithBlock:^{
            [realm deleteAllObjects];
            for (int i = 0; i < 5; ++i) {
                [LinkStringObject createInRealm:realm
                                      withValue:@[[StringObject createInRealm:realm
                                                                    withValue:@[@""]]]];
            }
        }];
    }
}

- (RLMResults *)query {
    return LinkStringObject.allObjects;
}

- (void)testDeleteLinkedObject {
    ExpectChange(self, @[], @[], @[@3], ^(RLMRealm *realm) {
        [realm deleteObject:[StringObject allObjectsInRealm:realm][3]];
    });
}

- (void)testModifyLinkedObject {
    ExpectChange(self, @[], @[], @[@3], ^(RLMRealm *realm) {
        [[StringObject allObjectsInRealm:realm][3] setStringCol:@"a"];
    });
}

- (void)testInsertUnlinkedObject {
    ExpectNoChange(self, ^(RLMRealm *realm) {
        [StringObject createInRealm:realm withValue:@[@""]];
    });
}

- (void)testTableClearFollowedByInsertsAndDeletes {
    ExpectChange(self, @[], @[], @[@0, @1, @2, @3, @4], ^(RLMRealm *realm) {
        [realm deleteObjects:[StringObject allObjectsInRealm:realm]];
        [StringObject createInRealm:realm withValue:@[@""]];
        [realm deleteObject:[StringObject createInRealm:realm withValue:@[@""]]];
    });
}
@end

@interface LinkingObjectsChangesetTests : RLMTestCase <ChangesetTestCase>
@end

@implementation LinkingObjectsChangesetTests
- (void)prepare {
    @autoreleasepool {
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm transactionWithBlock:^{
            [realm deleteAllObjects];
            PersonObject *child = [PersonObject createInDefaultRealmWithValue:@[ @"Child", @0 ]];
            for (int i = 0; i < 10; ++i) {
                // It takes a village to raise a child…
                NSString *name = [NSString stringWithFormat:@"Parent %d", i];
                [PersonObject createInDefaultRealmWithValue:@[ name, @(25 + i), @[ child ]]];
            }
        }];
    }
}

- (RLMResults *)query {
    return [[PersonObject.allObjects firstObject] parents];
}

- (void)testDeleteOneLinkingObject {
    ExpectChange(self, @[@5], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[PersonObject objectsInRealm:realm where:@"age == 30"]];
    });
}

- (void)testDeleteSomeLinkingObjects {
    ExpectChange(self, @[@2, @8, @9], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[PersonObject objectsInRealm:realm where:@"age > 32"]];
        [realm deleteObjects:[PersonObject objectsInRealm:realm where:@"age == 27"]];
    });
}

- (void)testDeleteAllLinkingObjects {
    ExpectChange(self, @[@0, @1, @2, @3, @4, @5, @6, @7, @8, @9], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[PersonObject objectsInRealm:realm where:@"age > 20"]];
    });
}

- (void)testDeleteAll {
    ExpectChange(self, @[@0, @1, @2, @3, @4, @5, @6, @7, @8, @9], @[], @[], ^(RLMRealm *realm) {
        [realm deleteObjects:[PersonObject allObjectsInRealm:realm]];
    });
}

- (void)testUnlinkOne {
    ExpectChange(self, @[@4], @[], @[], ^(RLMRealm *realm) {
        PersonObject *parent = [[PersonObject objectsInRealm:realm where:@"age == 29"] firstObject];
        [parent.children removeAllObjects];
    });
}

- (void)testUnlinkAll {
    ExpectChange(self, @[@0, @1, @2, @3, @4, @5, @6, @7, @8, @9], @[], @[], ^(RLMRealm *realm) {
        for (PersonObject *parent in [PersonObject objectsInRealm:realm where:@"age > 20"])
            [parent.children removeAllObjects];
    });
}

- (void)testAddNewParent {
    ExpectChange(self, @[], @[@10], @[], ^(RLMRealm *realm) {
        PersonObject *child = [[PersonObject objectsInRealm:realm where:@"children.@count == 0"] firstObject];
        [PersonObject createInDefaultRealmWithValue:@[ @"New parent", @40, @[ child ]]];
    });
}

- (void)testAddDuplicateParent {
    ExpectChange(self, @[], @[@10], @[@7], ^(RLMRealm *realm) {
        PersonObject *parent = [[PersonObject objectsInRealm:realm where:@"age == 32"] firstObject];
        [parent.children addObject:[parent.children firstObject]];
    });
}

- (void)testModifyParent {
    ExpectChange(self, @[], @[], @[@3], ^(RLMRealm *realm) {
        PersonObject *parent = [[PersonObject objectsInRealm:realm where:@"age == 28"] firstObject];
        parent.age = parent.age + 1;
    });
}

@end