rapids/dev/datastreams/add-new-data-streams/index.html

2297 lines
83 KiB
HTML

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="icon" href="../../img/logo.png">
<meta name="generator" content="mkdocs-1.1.2, mkdocs-material-7.0.6+insiders-2.3.1">
<title>Add New Data Streams - RAPIDS</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.3a1236c2.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.de2705de.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,400i,700%7CRoboto+Mono&display=fallback">
<style>:root{--md-text-font-family:"Roboto";--md-code-font-family:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../stylesheets/extra.css">
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="blue" data-md-color-accent="blue">
<script>var palette=JSON.parse(localStorage.getItem("__palette"));if(null!==palette&&"object"==typeof palette.color)for(var key in palette.color)document.body.setAttribute("data-md-color-"+key,palette.color[key])</script>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#add-new-data-streams" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../.." title="RAPIDS" class="md-header__button md-logo" aria-label="RAPIDS" data-md-component="logo">
<img src="../../img/logo.png" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
RAPIDS
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Add New Data Streams
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="default" data-md-color-primary="blue" data-md-color-accent="blue" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_2" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5m0 8a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3z"/></svg>
</label>
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="blue" data-md-color-accent="blue" type="radio" name="__palette" id="__palette_2">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 10a2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2 2 2 0 0 1 2-2m10-3a5 5 0 0 1 5 5 5 5 0 0 1-5 5H7a5 5 0 0 1-5-5 5 5 0 0 1 5-5h10M7 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3h10a3 3 0 0 0 3-3 3 3 0 0 0-3-3H7z"/></svg>
</label>
</form>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" data-md-state="active" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/carissalow/rapids/" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M439.55 236.05L244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
</div>
<div class="md-source__repository">
carissalow/rapids
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="RAPIDS" class="md-nav__button md-logo" aria-label="RAPIDS" data-md-component="logo">
<img src="../../img/logo.png" alt="logo">
</a>
RAPIDS
</label>
<div class="md-nav__source">
<a href="https://github.com/carissalow/rapids/" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M439.55 236.05L244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
</div>
<div class="md-source__repository">
carissalow/rapids
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
Home
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2" type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2">
Setup
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Setup" data-md-level="1">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Setup
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../setup/overview/" class="md-nav__link">
Overview
</a>
</li>
<li class="md-nav__item">
<a href="../../workflow-examples/minimal/" class="md-nav__link">
Minimal Example
</a>
</li>
<li class="md-nav__item">
<a href="../../setup/installation/" class="md-nav__link">
Installation
</a>
</li>
<li class="md-nav__item">
<a href="../../setup/configuration/" class="md-nav__link">
Configuration
</a>
</li>
<li class="md-nav__item">
<a href="../../setup/execution/" class="md-nav__link">
Execution
</a>
</li>
<li class="md-nav__item">
<a href="../../citation/" class="md-nav__link">
Citation
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3" type="checkbox" id="__nav_3" checked>
<label class="md-nav__link" for="__nav_3">
Data Streams
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Data Streams" data-md-level="1">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Data Streams
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../data-streams-introduction/" class="md-nav__link">
Introduction
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_2" type="checkbox" id="__nav_3_2" >
<label class="md-nav__link" for="__nav_3_2">
Phone
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Phone" data-md-level="2">
<label class="md-nav__title" for="__nav_3_2">
<span class="md-nav__icon md-icon"></span>
Phone
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../aware-mysql/" class="md-nav__link">
aware_mysql
</a>
</li>
<li class="md-nav__item">
<a href="../aware-csv/" class="md-nav__link">
aware_csv
</a>
</li>
<li class="md-nav__item">
<a href="../aware-influxdb/" class="md-nav__link">
aware_influxdb (beta)
</a>
</li>
<li class="md-nav__item">
<a href="../mandatory-phone-format/" class="md-nav__link">
Mandatory Phone Format
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_3" type="checkbox" id="__nav_3_3" >
<label class="md-nav__link" for="__nav_3_3">
Fitbit
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Fitbit" data-md-level="2">
<label class="md-nav__title" for="__nav_3_3">
<span class="md-nav__icon md-icon"></span>
Fitbit
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../fitbitjson-mysql/" class="md-nav__link">
fitbitjson_mysql
</a>
</li>
<li class="md-nav__item">
<a href="../fitbitjson-csv/" class="md-nav__link">
fitbitjson_csv
</a>
</li>
<li class="md-nav__item">
<a href="../fitbitparsed-mysql/" class="md-nav__link">
fitbitparsed_mysql
</a>
</li>
<li class="md-nav__item">
<a href="../fitbitparsed-csv/" class="md-nav__link">
fitbitparsed_csv
</a>
</li>
<li class="md-nav__item">
<a href="../mandatory-fitbit-format/" class="md-nav__link">
Mandatory Fitbit Format
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_4" type="checkbox" id="__nav_3_4" >
<label class="md-nav__link" for="__nav_3_4">
Empatica
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Empatica" data-md-level="2">
<label class="md-nav__title" for="__nav_3_4">
<span class="md-nav__icon md-icon"></span>
Empatica
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../empatica-zip/" class="md-nav__link">
empatica_zip
</a>
</li>
<li class="md-nav__item">
<a href="../mandatory-empatica-format/" class="md-nav__link">
Mandatory Empatica Format
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
Add New Data Streams
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
Add New Data Streams
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#implement-a-container" class="md-nav__link">
Implement a Container
</a>
</li>
<li class="md-nav__item">
<a href="#implement-a-format" class="md-nav__link">
Implement a Format
</a>
<nav class="md-nav" aria-label="Implement a Format">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#name-mapping" class="md-nav__link">
Name mapping
</a>
</li>
<li class="md-nav__item">
<a href="#value-mapping" class="md-nav__link">
Value mapping
</a>
</li>
<li class="md-nav__item">
<a href="#complex-mapping" class="md-nav__link">
Complex mapping
</a>
</li>
<li class="md-nav__item">
<a href="#os-complex-mapping" class="md-nav__link">
OS complex mapping
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4" type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4">
Behavioral Features
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Behavioral Features" data-md-level="1">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Behavioral Features
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../features/feature-introduction/" class="md-nav__link">
Introduction
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_2" type="checkbox" id="__nav_4_2" >
<label class="md-nav__link" for="__nav_4_2">
Phone
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Phone" data-md-level="2">
<label class="md-nav__title" for="__nav_4_2">
<span class="md-nav__icon md-icon"></span>
Phone
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../features/phone-accelerometer/" class="md-nav__link">
Phone Accelerometer
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-activity-recognition/" class="md-nav__link">
Phone Activity Recognition
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-applications-crashes/" class="md-nav__link">
Phone Applications Crashes
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-applications-foreground/" class="md-nav__link">
Phone Applications Foreground
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-applications-notifications/" class="md-nav__link">
Phone Applications Notifications
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-battery/" class="md-nav__link">
Phone Battery
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-bluetooth/" class="md-nav__link">
Phone Bluetooth
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-calls/" class="md-nav__link">
Phone Calls
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-conversation/" class="md-nav__link">
Phone Conversation
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-data-yield/" class="md-nav__link">
Phone Data Yield
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-keyboard/" class="md-nav__link">
Phone Keyboard
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-light/" class="md-nav__link">
Phone Light
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-locations/" class="md-nav__link">
Phone Locations
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-log/" class="md-nav__link">
Phone Log
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-messages/" class="md-nav__link">
Phone Messages
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-screen/" class="md-nav__link">
Phone Screen
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-wifi-connected/" class="md-nav__link">
Phone WiFI Connected
</a>
</li>
<li class="md-nav__item">
<a href="../../features/phone-wifi-visible/" class="md-nav__link">
Phone WiFI Visible
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_3" type="checkbox" id="__nav_4_3" >
<label class="md-nav__link" for="__nav_4_3">
Fitbit
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Fitbit" data-md-level="2">
<label class="md-nav__title" for="__nav_4_3">
<span class="md-nav__icon md-icon"></span>
Fitbit
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../features/fitbit-data-yield/" class="md-nav__link">
Fitbit Data Yield
</a>
</li>
<li class="md-nav__item">
<a href="../../features/fitbit-heartrate-summary/" class="md-nav__link">
Fitbit Heart Rate Summary
</a>
</li>
<li class="md-nav__item">
<a href="../../features/fitbit-heartrate-intraday/" class="md-nav__link">
Fitbit Heart Rate Intraday
</a>
</li>
<li class="md-nav__item">
<a href="../../features/fitbit-sleep-summary/" class="md-nav__link">
Fitbit Sleep Summary
</a>
</li>
<li class="md-nav__item">
<a href="../../features/fitbit-sleep-intraday/" class="md-nav__link">
Fitbit Sleep Intraday
</a>
</li>
<li class="md-nav__item">
<a href="../../features/fitbit-steps-summary/" class="md-nav__link">
Fitbit Steps Summary
</a>
</li>
<li class="md-nav__item">
<a href="../../features/fitbit-steps-intraday/" class="md-nav__link">
Fitbit Steps Intraday
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4_4" type="checkbox" id="__nav_4_4" >
<label class="md-nav__link" for="__nav_4_4">
Empatica
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Empatica" data-md-level="2">
<label class="md-nav__title" for="__nav_4_4">
<span class="md-nav__icon md-icon"></span>
Empatica
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../features/empatica-accelerometer/" class="md-nav__link">
Empatica Accelerometer
</a>
</li>
<li class="md-nav__item">
<a href="../../features/empatica-heartrate/" class="md-nav__link">
Empatica Heart Rate
</a>
</li>
<li class="md-nav__item">
<a href="../../features/empatica-temperature/" class="md-nav__link">
Empatica Temperature
</a>
</li>
<li class="md-nav__item">
<a href="../../features/empatica-electrodermal-activity/" class="md-nav__link">
Empatica Electrodermal Activity
</a>
</li>
<li class="md-nav__item">
<a href="../../features/empatica-blood-volume-pulse/" class="md-nav__link">
Empatica Blood Volume Pulse
</a>
</li>
<li class="md-nav__item">
<a href="../../features/empatica-inter-beat-interval/" class="md-nav__link">
Empatica Inter Beat Interval
</a>
</li>
<li class="md-nav__item">
<a href="../../features/empatica-tags/" class="md-nav__link">
Empatica Tags
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../../features/add-new-features/" class="md-nav__link">
Add New Features
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5">
Visualizations
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Visualizations" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Visualizations
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../visualizations/data-quality-visualizations/" class="md-nav__link">
Data Quality
</a>
</li>
<li class="md-nav__item">
<a href="../../visualizations/feature-visualizations/" class="md-nav__link">
Features
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6">
Analysis Workflows
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Analysis Workflows" data-md-level="1">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Analysis Workflows
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../workflow-examples/analysis/" class="md-nav__link">
Complete Example
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_7" type="checkbox" id="__nav_7" >
<label class="md-nav__link" for="__nav_7">
Developers
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Developers" data-md-level="1">
<label class="md-nav__title" for="__nav_7">
<span class="md-nav__icon md-icon"></span>
Developers
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../developers/git-flow/" class="md-nav__link">
Git Flow
</a>
</li>
<li class="md-nav__item">
<a href="../../developers/remote-support/" class="md-nav__link">
Remote Support
</a>
</li>
<li class="md-nav__item">
<a href="../../developers/virtual-environments/" class="md-nav__link">
Virtual Environments
</a>
</li>
<li class="md-nav__item">
<a href="../../developers/documentation/" class="md-nav__link">
Documentation
</a>
</li>
<li class="md-nav__item">
<a href="../../developers/testing/" class="md-nav__link">
Testing
</a>
</li>
<li class="md-nav__item">
<a href="../../developers/test-cases/" class="md-nav__link">
Test cases
</a>
</li>
<li class="md-nav__item">
<a href="../../developers/validation-schema-config/" class="md-nav__link">
Validation schema of config.yaml
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_8" type="checkbox" id="__nav_8" >
<label class="md-nav__link" for="__nav_8">
Others
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Others" data-md-level="1">
<label class="md-nav__title" for="__nav_8">
<span class="md-nav__icon md-icon"></span>
Others
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../migrating-from-old-versions/" class="md-nav__link">
Migrating from an old version
</a>
</li>
<li class="md-nav__item">
<a href="../../code_of_conduct/" class="md-nav__link">
Code of Conduct
</a>
</li>
<li class="md-nav__item">
<a href="../../common-errors/" class="md-nav__link">
Common Errors
</a>
</li>
<li class="md-nav__item">
<a href="../../team/" class="md-nav__link">
Team
</a>
</li>
<li class="md-nav__item">
<a href="../../change-log/" class="md-nav__link">
Change Log
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#implement-a-container" class="md-nav__link">
Implement a Container
</a>
</li>
<li class="md-nav__item">
<a href="#implement-a-format" class="md-nav__link">
Implement a Format
</a>
<nav class="md-nav" aria-label="Implement a Format">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#name-mapping" class="md-nav__link">
Name mapping
</a>
</li>
<li class="md-nav__item">
<a href="#value-mapping" class="md-nav__link">
Value mapping
</a>
</li>
<li class="md-nav__item">
<a href="#complex-mapping" class="md-nav__link">
Complex mapping
</a>
</li>
<li class="md-nav__item">
<a href="#os-complex-mapping" class="md-nav__link">
OS complex mapping
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<a href="https://github.com/carissalow/rapids/edit/master/docs/datastreams/add-new-data-streams.md" title="Edit this page" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z"/></svg>
</a>
<h1 id="add-new-data-streams">Add New Data Streams<a class="headerlink" href="#add-new-data-streams" title="Permanent link">&para;</a></h1>
<p>A data stream is a set of sensor data collected using a specific type of <strong>device</strong> with a specific <strong>format</strong> and stored in a specific <strong>container</strong>. RAPIDS is agnostic to data streams&rsquo; formats and container; see the <a href="../data-streams-introduction">Data Streams Introduction</a> for a list of supported streams.</p>
<p><strong>A container</strong> is queried with an R or Python script that connects to the database, API or file where your stream&rsquo;s raw data is stored. </p>
<p><strong>A format</strong> is described using a <code>format.yaml</code> file that specifies how to map and mutate your stream&rsquo;s raw data to match the data and format RAPIDS needs.</p>
<p>The most common cases when you would want to implement a new data stream are:</p>
<ul>
<li>You collected data with a mobile sensing app RAPIDS does not support yet. For example, <a href="https://www.beiwe.org/">Beiwe</a> data stored in MySQL. You will need to define a new format file and a new container script.</li>
<li>You collected data with a mobile sensing app RAPIDS supports, but this data is stored in a container that RAPIDS can&rsquo;t connect to yet. For example, AWARE data stored in PostgreSQL. In this case, you can reuse the format file of the <code>aware_mysql</code> stream, but you will need to implement a new container script.</li>
</ul>
<div class="admonition hint">
<p class="admonition-title">Hint</p>
<p>Both the <code>container.[R|py]</code> and the <code>format.yaml</code> are stored in <code>./src/data/streams/[stream_name]</code> where <code>[stream_name]</code> can be <code>aware_mysql</code> for example.</p>
</div>
<h2 id="implement-a-container">Implement a Container<a class="headerlink" href="#implement-a-container" title="Permanent link">&para;</a></h2>
<p>The <code>container</code> script of a data stream can be implemented in R (strongly recommended) or python. This script must have two functions if you are implementing a stream for phone data or one function otherwise. The script can contain other auxiliary functions.</p>
<p>First of all, add any parameters your script might need in <code>config.yaml</code> under <code>(device)_DATA_STREAMS</code>. These parameters will be available in the <code>stream_parameters</code> argument of the one or two functions you implement. For example, if you are adding support for <code>Beiwe</code> data stored in <code>PostgreSQL</code> and your container needs a set of credentials to connect to a database, your new data stream configuration would be:</p>
<div class="highlight"><pre><span></span><code><span class="nt">PHONE_DATA_STREAMS</span><span class="p">:</span>
<span class="nt">USE</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">aware_python</span>
<span class="c1"># AVAILABLE:</span>
<span class="nt">aware_mysql</span><span class="p">:</span>
<span class="nt">DATABASE_GROUP</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">MY_GROUP</span>
<span class="hll"> <span class="nt">beiwe_postgresql</span><span class="p">:</span>
</span><span class="hll"> <span class="nt">DATABASE_GROUP</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">MY_GROUP</span> <span class="c1"># users define this group (user, password, host, etc.) in credentials.yaml</span>
</span></code></pre></div>
<p>Then implement one or both of the following functions:</p>
<div class="tabbed-set" data-tabs="1:2"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><label for="__tabbed_1_1">pull_data</label><div class="tabbed-content">
<p>This function returns the data columns for a specific sensor and participant. It has the following parameters:</p>
<table>
<thead>
<tr>
<th>Param</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>stream_parameters</td>
<td>Any parameters (keys/values) set by the user in any <code>[DEVICE_DATA_STREAMS][stream_name]</code> key of <code>config.yaml</code>. For example, <code>[DATABASE_GROUP]</code> inside <code>[FITBIT_DATA_STREAMS][fitbitjson_mysql]</code></td>
</tr>
<tr>
<td>sensor_container</td>
<td>The value set by the user in any <code>[DEVICE_SENSOR][CONTAINER]</code> key of <code>config.yaml</code>. It can be a table, file path, or whatever data source you want to support that contains the <strong>data from a single sensor for all participants</strong>. For example, <code>[PHONE_ACCELEROMETER][CONTAINER]</code></td>
</tr>
<tr>
<td>device</td>
<td>The device id that you need to get the data for (this is set by the user in the <a href="../../setup/configuration/#participant-files">participant files</a>). For example, in AWARE this device id is a uuid</td>
</tr>
<tr>
<td>columns</td>
<td>A list of the columns that you need to get from <code>sensor_container</code>. You specify these columns in your stream&rsquo;s <code>format.yaml</code></td>
</tr>
</tbody>
</table>
<div class="admonition example">
<p class="admonition-title">Example</p>
<p>This is the <code>pull_data</code> function we implemented for <code>aware_mysql</code>. Note that we can <code>message</code>, <code>warn</code> or <code>stop</code> the user during execution.</p>
<div class="highlight"><pre><span></span><code><span class="n">pull_data</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">stream_parameters</span><span class="p">,</span> <span class="n">device</span><span class="p">,</span> <span class="n">sensor_container</span><span class="p">,</span> <span class="n">columns</span><span class="p">){</span>
<span class="c1"># get_db_engine is an auxiliary function not shown here for brevity bu can be found in src/data/streams/aware_mysql/container.R</span>
<span class="n">dbEngine</span> <span class="o">&lt;-</span> <span class="nf">get_db_engine</span><span class="p">(</span><span class="n">stream_parameters</span><span class="o">$</span><span class="n">DATABASE_GROUP</span><span class="p">)</span>
<span class="n">query</span> <span class="o">&lt;-</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&quot;SELECT &quot;</span><span class="p">,</span> <span class="nf">paste</span><span class="p">(</span><span class="n">columns</span><span class="p">,</span> <span class="n">collapse</span> <span class="o">=</span> <span class="s">&quot;,&quot;</span><span class="p">),</span><span class="s">&quot; FROM &quot;</span><span class="p">,</span> <span class="n">sensor_container</span><span class="p">,</span> <span class="s">&quot; WHERE device_id = &#39;&quot;</span><span class="p">,</span> <span class="n">device</span><span class="p">,</span><span class="s">&quot;&#39;&quot;</span><span class="p">)</span>
<span class="c1"># Letting the user know what we are doing</span>
<span class="nf">message</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="s">&quot;Executing the following query to download data: &quot;</span><span class="p">,</span> <span class="n">query</span><span class="p">))</span>
<span class="n">sensor_data</span> <span class="o">&lt;-</span> <span class="nf">dbGetQuery</span><span class="p">(</span><span class="n">dbEngine</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>
<span class="nf">dbDisconnect</span><span class="p">(</span><span class="n">dbEngine</span><span class="p">)</span>
<span class="nf">if</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">sensor_data</span><span class="p">)</span> <span class="o">==</span> <span class="m">0</span><span class="p">)</span>
<span class="nf">warning</span><span class="p">(</span><span class="nf">paste</span><span class="p">(</span><span class="s">&quot;The device &#39;&quot;</span><span class="p">,</span> <span class="n">device</span><span class="p">,</span><span class="s">&quot;&#39; did not have data in &quot;</span><span class="p">,</span> <span class="n">sensor_container</span><span class="p">))</span>
<span class="nf">return</span><span class="p">(</span><span class="n">sensor_data</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div>
</div>
</div>
<input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><label for="__tabbed_1_2">infer_device_os</label><div class="tabbed-content">
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This function is only necessary for phone data streams. </p>
</div>
<p>RAPIDS allows users to use the keyword <code>infer</code> (previously <code>multiple</code>) to <a href="../../setup/configuration/#structure-of-participants-files">automatically infer</a> the mobile Operative System a phone was running. </p>
<p>If you have a way to infer the OS of a device id, implement this function. For example, for AWARE data we use the <code>aware_device</code> table.</p>
<p>If you don&rsquo;t have a way to infer the OS, call <code>stop("Error Message")</code> so other users know they can&rsquo;t use <code>infer</code> or the inference failed, and they have to assign the OS manually in the participant file.</p>
<p>This function returns the operative system (<code>android</code> or <code>ios</code>) for a specific phone device id. It has the following parameters:</p>
<table>
<thead>
<tr>
<th>Param</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>stream_parameters</td>
<td>Any parameters (keys/values) set by the user in any <code>[DEVICE_DATA_STREAMS][stream_name]</code> key of <code>config.yaml</code>. For example, <code>[DATABASE_GROUP]</code> inside <code>[FITBIT_DATA_STREAMS][fitbitjson_mysql]</code></td>
</tr>
<tr>
<td>device</td>
<td>The device id that you need to infer the OS for (this is set by the user in the <a href="../../setup/configuration/#participant-files">participant files</a>). For example, in AWARE this device id is a uuid</td>
</tr>
</tbody>
</table>
<div class="admonition example">
<p class="admonition-title">Example</p>
<p>This is the <code>infer_device_os</code> function we implemented for <code>aware_mysql</code>. Note that we can <code>message</code>, <code>warn</code> or <code>stop</code> the user during execution.</p>
<div class="highlight"><pre><span></span><code><span class="n">infer_device_os</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">stream_parameters</span><span class="p">,</span> <span class="n">device</span><span class="p">){</span>
<span class="c1"># get_db_engine is an auxiliary function not shown here for brevity bu can be found in src/data/streams/aware_mysql/container.R</span>
<span class="n">group</span> <span class="o">&lt;-</span> <span class="n">stream_parameters</span><span class="o">$</span><span class="n">DATABASE_GROUP</span>
<span class="n">dbEngine</span> <span class="o">&lt;-</span> <span class="nf">dbConnect</span><span class="p">(</span><span class="nf">MariaDB</span><span class="p">(),</span> <span class="n">default.file</span> <span class="o">=</span> <span class="s">&quot;./.env&quot;</span><span class="p">,</span> <span class="n">group</span> <span class="o">=</span> <span class="n">group</span><span class="p">)</span>
<span class="n">query</span> <span class="o">&lt;-</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&quot;SELECT device_id,brand FROM aware_device WHERE device_id = &#39;&quot;</span><span class="p">,</span> <span class="n">device</span><span class="p">,</span> <span class="s">&quot;&#39;&quot;</span><span class="p">)</span>
<span class="nf">message</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="s">&quot;Executing the following query to infer phone OS: &quot;</span><span class="p">,</span> <span class="n">query</span><span class="p">))</span>
<span class="n">os</span> <span class="o">&lt;-</span> <span class="nf">dbGetQuery</span><span class="p">(</span><span class="n">dbEngine</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>
<span class="nf">dbDisconnect</span><span class="p">(</span><span class="n">dbEngine</span><span class="p">)</span>
<span class="nf">if</span><span class="p">(</span><span class="nf">nrow</span><span class="p">(</span><span class="n">os</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">)</span>
<span class="nf">return</span><span class="p">(</span><span class="n">os</span> <span class="o">%&gt;%</span> <span class="nf">mutate</span><span class="p">(</span><span class="n">os</span> <span class="o">=</span> <span class="nf">ifelse</span><span class="p">(</span><span class="n">brand</span> <span class="o">==</span> <span class="s">&quot;iPhone&quot;</span><span class="p">,</span> <span class="s">&quot;ios&quot;</span><span class="p">,</span> <span class="s">&quot;android&quot;</span><span class="p">))</span> <span class="o">%&gt;%</span> <span class="nf">pull</span><span class="p">(</span><span class="n">os</span><span class="p">))</span>
<span class="n">else</span>
<span class="nf">stop</span><span class="p">(</span><span class="nf">paste</span><span class="p">(</span><span class="s">&quot;We cannot infer the OS of the following device id because it does not exist in the aware_device table:&quot;</span><span class="p">,</span> <span class="n">device</span><span class="p">))</span>
<span class="nf">return</span><span class="p">(</span><span class="n">os</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div>
</div>
</div>
</div>
<h2 id="implement-a-format">Implement a Format<a class="headerlink" href="#implement-a-format" title="Permanent link">&para;</a></h2>
<p>A format file <code>format.yaml</code> describes the mapping between your stream&rsquo;s raw data and the data that RAPIDS needs. This file has a section per sensor (e.g. <code>PHONE_ACCELEROMETER</code>), and each section has two attributes (keys):</p>
<ol>
<li>
<p><code>RAPIDS_COLUMN_MAPPINGS</code> are mappings between the columns RAPIDS needs and the columns your raw data already has. </p>
<ol>
<li>The reserved keyword <code>FLAG_TO_MUTATE</code> flags columns that RAPIDS requires but that are not initially present in your container (database, CSV file). These columns have to be created by your mutation scripts.</li>
</ol>
</li>
<li>
<p><code>MUTATION</code>. Sometimes your raw data needs to be transformed to match the format RAPIDS can handle (including creating columns marked as <code>FLAG_TO_MUTATE</code>)</p>
<ol>
<li>
<p><code>COLUMN_MAPPINGS</code> are mappings between the columns a mutation <code>SCRIPT</code> needs and the columns your raw data has.</p>
</li>
<li>
<p><code>SCRIPTS</code> are a collection of R or Python scripts that transform one or more raw data columns into the format RAPIDS needs.</p>
</li>
</ol>
</li>
</ol>
<div class="admonition hint">
<p class="admonition-title">Hint</p>
<p><code>[RAPIDS_COLUMN_MAPPINGS]</code> and <code>[MUTATE][COLUMN_MAPPINGS]</code> have a <code>key</code> (left-hand side string) and a <code>value</code> (right-hand side string). The <code>values</code> are the names used to pulled columns from a container (e.g., columns in a database table). All <code>values</code> are renamed to their <code>keys</code> in lower case. The renamed columns are sent to every mutation script within the <code>data</code> argument, and the final output is the input RAPIDS process further.</p>
<p>For example, let&rsquo;s assume we are implementing <code>beiwe_mysql</code> and defining the following format for <code>PHONE_FAKESENSOR</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nt">PHONE_FAKESENSOR</span><span class="p">:</span>
<span class="nt">ANDROID</span><span class="p">:</span>
<span class="nt">RAPIDS_COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">TIMESTAMP</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_timestamp</span>
<span class="nt">DEVICE_ID</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_deviceID</span>
<span class="nt">MAGNITUDE_SQUARED</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">FLAG_TO_MUTATE</span>
<span class="nt">MUTATE</span><span class="p">:</span>
<span class="nt">COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">MAGNITUDE</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_value</span>
<span class="nt">SCRIPTS</span><span class="p">:</span>
<span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">src/data/streams/mutations/phone/square_magnitude.py</span>
</code></pre></div>
<p>RAPIDS will:</p>
<ol>
<li>Download <code>beiwe_timestamp</code>, <code>beiwe_deviceID</code>, and <code>beiwe_value</code> from the container of <code>beiwe_mysql</code> (MySQL DB)</li>
<li>Rename these columns to <code>timestamp</code>, <code>device_id</code>, and <code>magnitude</code>, respectively.</li>
<li>Execute <code>square_magnitude.py</code> with a data frame as an argument containing the renamed columns. This script will square <code>magnitude</code> and rename it to <code>magnitude_squared</code></li>
<li>Verify the data frame returned by <code>square_magnitude.py</code> has the columns RAPIDS needs <code>timestamp</code>, <code>device_id</code>, and <code>magnitude_squared</code>.</li>
<li>Use this data frame as the input to be processed in the pipeline.</li>
</ol>
<p>Note that although <code>RAPIDS_COLUMN_MAPPINGS</code> and <code>[MUTATE][COLUMN_MAPPINGS]</code> keys are in capital letters for readability (e.g. <code>MAGNITUDE_SQUARED</code>), the names of the final columns you mutate in your scripts should be lower case.</p>
</div>
<p>Let&rsquo;s explain in more depth this column mapping with examples.</p>
<h3 id="name-mapping">Name mapping<a class="headerlink" href="#name-mapping" title="Permanent link">&para;</a></h3>
<p>The mapping for some sensors is straightforward. For example, accelerometer data most of the time has a timestamp, three axes (x,y,z), and a device id that produced it. AWARE and a different sensing app like Beiwe likely logged accelerometer data in the same way but with different column names. In this case, we only need to match Beiwe data columns to RAPIDS columns one-to-one:</p>
<div class="highlight"><pre><span></span><code><span class="nt">PHONE_ACCELEROMETER</span><span class="p">:</span>
<span class="nt">ANDROID</span><span class="p">:</span>
<span class="nt">RAPIDS_COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="hll"> <span class="nt">TIMESTAMP</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_timestamp</span>
</span><span class="hll"> <span class="nt">DEVICE_ID</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_deviceID</span>
</span><span class="hll"> <span class="nt">DOUBLE_VALUES_0</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_x</span>
</span><span class="hll"> <span class="nt">DOUBLE_VALUES_1</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_y</span>
</span><span class="hll"> <span class="nt">DOUBLE_VALUES_2</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_z</span>
</span> <span class="nt">MUTATE</span><span class="p">:</span>
<span class="nt">COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">SCRIPTS</span><span class="p">:</span> <span class="c1"># it&#39;s ok if this is empty</span>
</code></pre></div>
<h3 id="value-mapping">Value mapping<a class="headerlink" href="#value-mapping" title="Permanent link">&para;</a></h3>
<p>For some sensors, we need to map column names and values. For example, screen data has ON and OFF events; let&rsquo;s suppose Beiwe represents an ON event with the number <code>1,</code> but RAPIDS identifies ON events with the number <code>2</code>. In this case, we need to mutate the raw data coming from Beiwe and replace all <code>1</code>s with <code>2</code>s.</p>
<p>We do this by listing one or more R or Python scripts in <code>MUTATION_SCRIPTS</code> that will be executed in order. We usually store all mutation scripts under <code>src/data/streams/mutations/[device]/[platform]/</code> and they can be reused across data streams.</p>
<div class="highlight"><pre><span></span><code><span class="nt">PHONE_SCREEN</span><span class="p">:</span>
<span class="nt">ANDROID</span><span class="p">:</span>
<span class="nt">RAPIDS_COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">TIMESTAMP</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_timestamp</span>
<span class="nt">DEVICE_ID</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_deviceID</span>
<span class="nt">EVENT</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_event</span>
<span class=" -Error"> </span><span class="nt">MUTATE</span><span class="p">:</span>
<span class="nt">COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">SCRIPTS</span><span class="p">:</span>
<span class="hll"> <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">src/data/streams/mutations/phone/beiwe/beiwe_screen_map.py</span>
</span></code></pre></div>
<div class="admonition hint">
<p class="admonition-title">Hint</p>
<ul>
<li>A <code>MUTATION_SCRIPT</code> can also be used to clean/preprocess your data before extracting behavioral features.</li>
<li>A mutation script has to have a <code>main</code> function that receives two arguments, <code>data</code> and <code>stream_parameters</code>.</li>
<li>The <code>stream_parameters</code> argument contains the <code>config.yaml</code> key/values of your data stream (this is the same argument that your <code>container.[py|R]</code> script receives, see <a href="#implement-a-container">Implement a Container</a>). </li>
</ul>
<div class="tabbed-set" data-tabs="2:2"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><label for="__tabbed_2_1">python</label><div class="tabbed-content">
<p>Example of a python mutation script
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">stream_parameters</span><span class="p">):</span>
<span class="c1"># mutate data</span>
<span class="k">return</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</code></pre></div></p>
</div>
<input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><label for="__tabbed_2_2">R</label><div class="tabbed-content">
<p>Example of a R mutation script
<div class="highlight"><pre><span></span><code><span class="nf">source</span><span class="p">(</span><span class="s">&quot;renv/activate.R&quot;</span><span class="p">)</span> <span class="c1"># needed to use RAPIDS renv environment</span>
<span class="nf">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span>
<span class="n">main</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">stream_parameters</span><span class="p">){</span>
<span class="c1"># mutate data</span>
<span class="nf">return</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></p>
</div>
</div>
</div>
<h3 id="complex-mapping">Complex mapping<a class="headerlink" href="#complex-mapping" title="Permanent link">&para;</a></h3>
<p>Sometimes, your raw data doesn&rsquo;t even have the same columns RAPIDS expects for a sensor. For example, let&rsquo;s pretend Beiwe stores <code>PHONE_ACCELEROMETER</code> axis data in a single column called <code>acc_col</code> instead of three. You have to create a <code>MUTATION_SCRIPT</code> to split <code>acc_col</code> into three columns <code>x</code>, <code>y</code>, and <code>z</code>. </p>
<p>For this, you mark the three axes columns RAPIDS needs in <code>[RAPIDS_COLUMN_MAPPINGS]</code> with the word <code>FLAG_TO_MUTATE</code>, map <code>acc_col</code> in <code>[MUTATION][COLUMN_MAPPINGS]</code>, and list a Python script under <code>[MUTATION][SCRIPTS]</code> with the code to split <code>acc_col</code>. See an example below.</p>
<p>RAPIDS expects that every column mapped as <code>FLAG_TO_MUTATE</code> will be generated by your mutation script, so it won&rsquo;t try to retrieve them from your container (database, CSV file, etc.). </p>
<p>In our example, <code>acc_col</code> will be fetched from the stream&rsquo;s container and renamed to <code>JOINED_AXES</code> because <code>beiwe_split_acc.py</code> will split it into <code>double_values_0</code>, <code>double_values_1</code>, and <code>double_values_2</code>.</p>
<div class="highlight"><pre><span></span><code><span class="nt">PHONE_ACCELEROMETER</span><span class="p">:</span>
<span class="nt">ANDROID</span><span class="p">:</span>
<span class="nt">RAPIDS_COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">TIMESTAMP</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_timestamp</span>
<span class="nt">DEVICE_ID</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">beiwe_deviceID</span>
<span class="hll"> <span class="nt">DOUBLE_VALUES_0</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">FLAG_TO_MUTATE</span>
</span><span class="hll"> <span class="nt">DOUBLE_VALUES_1</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">FLAG_TO_MUTATE</span>
</span><span class="hll"> <span class="nt">DOUBLE_VALUES_2</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">FLAG_TO_MUTATE</span>
</span> <span class="nt">MUTATE</span><span class="p">:</span>
<span class="nt">COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="hll"> <span class="nt">JOINED_AXES</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">acc_col</span>
</span> <span class="nt">SCRIPTS</span><span class="p">:</span>
<span class="hll"> <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">src/data/streams/mutations/phone/beiwe/beiwe_split_acc.py</span>
</span></code></pre></div>
<p>This is a draft of <code>beiwe_split_acc.py</code> <code>MUTATION_SCRIPT</code>:
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">stream_parameters</span><span class="p">):</span>
<span class="c1"># data has the acc_col</span>
<span class="c1"># split acc_col into three columns: double_values_0, double_values_1, double_values_2 to match RAPIDS format</span>
<span class="c1"># remove acc_col since we don&#39;t need it anymore</span>
<span class="k">return</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
</code></pre></div></p>
<h3 id="os-complex-mapping">OS complex mapping<a class="headerlink" href="#os-complex-mapping" title="Permanent link">&para;</a></h3>
<p>There is a special case for a complex mapping scenario for smartphone data streams. The Android and iOS sensor APIs return data in different formats for certain sensors (like screen, activity recognition, battery, among others). </p>
<p>In case you didn&rsquo;t notice, the examples we have used so far are grouped under an <code>ANDROID</code> key, which means they will be applied to data collected by Android phones. Additionally, each sensor has an <code>IOS</code> key for a similar purpose. We use the complex mapping described above to transform iOS data into an Android format (it&rsquo;s always iOS to Android and any new phone data stream must do the same).</p>
<p>For example, this is the <code>format.yaml</code> key for <code>PHONE_ACTVITY_RECOGNITION</code>. Note that the <code>ANDROID</code> mapping is simple (one-to-one) but the <code>IOS</code> mapping is complex with three <code>FLAG_TO_MUTATE</code> columns, two <code>[MUTATE][COLUMN_MAPPINGS]</code> mappings, and one <code>[MUTATION][SCRIPT]</code>.</p>
<div class="highlight"><pre><span></span><code><span class="nt">PHONE_ACTIVITY_RECOGNITION</span><span class="p">:</span>
<span class="nt">ANDROID</span><span class="p">:</span>
<span class="nt">RAPIDS_COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">TIMESTAMP</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">timestamp</span>
<span class="nt">DEVICE_ID</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">device_id</span>
<span class="nt">ACTIVITY_TYPE</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">activity_type</span>
<span class="nt">ACTIVITY_NAME</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">activity_name</span>
<span class="nt">CONFIDENCE</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">confidence</span>
<span class="nt">MUTATION</span><span class="p">:</span>
<span class="nt">COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">SCRIPTS</span><span class="p">:</span>
<span class="nt">IOS</span><span class="p">:</span>
<span class="nt">RAPIDS_COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="nt">TIMESTAMP</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">timestamp</span>
<span class="nt">DEVICE_ID</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">device_id</span>
<span class="hll"> <span class="nt">ACTIVITY_TYPE</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">FLAG_TO_MUTATE</span>
</span><span class="hll"> <span class="nt">ACTIVITY_NAME</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">FLAG_TO_MUTATE</span>
</span><span class="hll"> <span class="nt">CONFIDENCE</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">FLAG_TO_MUTATE</span>
</span> <span class="nt">MUTATION</span><span class="p">:</span>
<span class="nt">COLUMN_MAPPINGS</span><span class="p">:</span>
<span class="hll"> <span class="nt">ACTIVITIES</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">activities</span>
</span><span class="hll"> <span class="nt">CONFIDENCE</span><span class="p">:</span> <span class="l l-Scalar l-Scalar-Plain">confidence</span>
</span> <span class="nt">SCRIPTS</span><span class="p">:</span>
<span class="hll"> <span class="p p-Indicator">-</span> <span class="s">&quot;src/data/streams/mutations/phone/aware/activity_recogniton_ios_unification.R&quot;</span>
</span></code></pre></div>
<details><summary>Example activity_recogniton_ios_unification.R</summary><p>In this <code>MUTATION_SCRIPT</code> we create <code>ACTIVITY_NAME</code> and <code>ACTIVITY_TYPE</code> based on <code>activities</code>, and map <code>confidence</code> iOS values to Android values.
<div class="highlight"><pre><span></span><code><span class="nf">source</span><span class="p">(</span><span class="s">&quot;renv/activate.R&quot;</span><span class="p">)</span>
<span class="nf">library</span><span class="p">(</span><span class="s">&quot;dplyr&quot;</span><span class="p">,</span> <span class="n">warn.conflicts</span> <span class="o">=</span> <span class="bp">F</span><span class="p">)</span>
<span class="nf">library</span><span class="p">(</span><span class="n">stringr</span><span class="p">)</span>
<span class="n">clean_ios_activity_column</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">ios_gar</span><span class="p">){</span>
<span class="n">ios_gar</span> <span class="o">&lt;-</span> <span class="n">ios_gar</span> <span class="o">%&gt;%</span>
<span class="nf">mutate</span><span class="p">(</span><span class="n">activities</span> <span class="o">=</span> <span class="nf">str_replace_all</span><span class="p">(</span><span class="n">activities</span><span class="p">,</span> <span class="n">pattern</span> <span class="o">=</span> <span class="s">&#39;(&quot;|\\[|\\])&#39;</span><span class="p">,</span> <span class="n">replacement</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="p">))</span>
<span class="n">existent_multiple_activities</span> <span class="o">&lt;-</span> <span class="n">ios_gar</span> <span class="o">%&gt;%</span>
<span class="nf">filter</span><span class="p">(</span><span class="nf">str_detect</span><span class="p">(</span><span class="n">activities</span><span class="p">,</span> <span class="s">&quot;,&quot;</span><span class="p">))</span> <span class="o">%&gt;%</span>
<span class="nf">group_by</span><span class="p">(</span><span class="n">activities</span><span class="p">)</span> <span class="o">%&gt;%</span>
<span class="nf">summarise</span><span class="p">(</span><span class="n">mutiple_activities</span> <span class="o">=</span> <span class="nf">unique</span><span class="p">(</span><span class="n">activities</span><span class="p">),</span> <span class="n">.groups</span> <span class="o">=</span> <span class="s">&quot;drop_last&quot;</span><span class="p">)</span> <span class="o">%&gt;%</span>
<span class="nf">pull</span><span class="p">(</span><span class="n">mutiple_activities</span><span class="p">)</span>
<span class="n">known_multiple_activities</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="s">&quot;stationary,automotive&quot;</span><span class="p">)</span>
<span class="n">unkown_multiple_actvities</span> <span class="o">&lt;-</span> <span class="nf">setdiff</span><span class="p">(</span><span class="n">existent_multiple_activities</span><span class="p">,</span> <span class="n">known_multiple_activities</span><span class="p">)</span>
<span class="nf">if</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">unkown_multiple_actvities</span><span class="p">)</span> <span class="o">&gt;</span> <span class="m">0</span><span class="p">){</span>
<span class="nf">stop</span><span class="p">(</span><span class="nf">paste0</span><span class="p">(</span><span class="s">&quot;There are unkwown combinations of ios activities, you need to implement the decision of the ones to keep: &quot;</span><span class="p">,</span> <span class="n">unkown_multiple_actvities</span><span class="p">))</span>
<span class="p">}</span>
<span class="n">ios_gar</span> <span class="o">&lt;-</span> <span class="n">ios_gar</span> <span class="o">%&gt;%</span>
<span class="nf">mutate</span><span class="p">(</span><span class="n">activities</span> <span class="o">=</span> <span class="nf">str_replace_all</span><span class="p">(</span><span class="n">activities</span><span class="p">,</span> <span class="n">pattern</span> <span class="o">=</span> <span class="s">&quot;stationary,automotive&quot;</span><span class="p">,</span> <span class="n">replacement</span> <span class="o">=</span> <span class="s">&quot;automotive&quot;</span><span class="p">))</span>
<span class="nf">return</span><span class="p">(</span><span class="n">ios_gar</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">unify_ios_activity_recognition</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">ios_gar</span><span class="p">){</span>
<span class="c1"># We only need to unify Google Activity Recognition data for iOS</span>
<span class="c1"># discard rows where activities column is blank</span>
<span class="n">ios_gar</span> <span class="o">&lt;-</span> <span class="n">ios_gar</span><span class="p">[</span><span class="o">-</span><span class="nf">which</span><span class="p">(</span><span class="n">ios_gar</span><span class="o">$</span><span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;&quot;</span><span class="p">),</span> <span class="p">]</span>
<span class="c1"># clean &quot;activities&quot; column of ios_gar</span>
<span class="n">ios_gar</span> <span class="o">&lt;-</span> <span class="nf">clean_ios_activity_column</span><span class="p">(</span><span class="n">ios_gar</span><span class="p">)</span>
<span class="c1"># make it compatible with android version: generate &quot;activity_name&quot; and &quot;activity_type&quot; columns</span>
<span class="n">ios_gar</span> <span class="o">&lt;-</span> <span class="n">ios_gar</span> <span class="o">%&gt;%</span>
<span class="nf">mutate</span><span class="p">(</span><span class="n">activity_name</span> <span class="o">=</span> <span class="nf">case_when</span><span class="p">(</span><span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;automotive&quot;</span> <span class="o">~</span> <span class="s">&quot;in_vehicle&quot;</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;cycling&quot;</span> <span class="o">~</span> <span class="s">&quot;on_bicycle&quot;</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;walking&quot;</span> <span class="o">~</span> <span class="s">&quot;walking&quot;</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;running&quot;</span> <span class="o">~</span> <span class="s">&quot;running&quot;</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;stationary&quot;</span> <span class="o">~</span> <span class="s">&quot;still&quot;</span><span class="p">),</span>
<span class="n">activity_type</span> <span class="o">=</span> <span class="nf">case_when</span><span class="p">(</span><span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;automotive&quot;</span> <span class="o">~</span> <span class="m">0</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;cycling&quot;</span> <span class="o">~</span> <span class="m">1</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;walking&quot;</span> <span class="o">~</span> <span class="m">7</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;running&quot;</span> <span class="o">~</span> <span class="m">8</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;stationary&quot;</span> <span class="o">~</span> <span class="m">3</span><span class="p">,</span>
<span class="n">activities</span> <span class="o">==</span> <span class="s">&quot;unknown&quot;</span> <span class="o">~</span> <span class="m">4</span><span class="p">),</span>
<span class="n">confidence</span> <span class="o">=</span> <span class="nf">case_when</span><span class="p">(</span><span class="n">confidence</span> <span class="o">==</span> <span class="m">0</span> <span class="o">~</span> <span class="m">0</span><span class="p">,</span>
<span class="n">confidence</span> <span class="o">==</span> <span class="m">1</span> <span class="o">~</span> <span class="m">50</span><span class="p">,</span>
<span class="n">confidence</span> <span class="o">==</span> <span class="m">2</span> <span class="o">~</span> <span class="m">100</span><span class="p">)</span>
<span class="p">)</span> <span class="o">%&gt;%</span>
<span class="nf">select</span><span class="p">(</span><span class="o">-</span><span class="n">activities</span><span class="p">)</span>
<span class="nf">return</span><span class="p">(</span><span class="n">ios_gar</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">main</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">stream_parameters</span><span class="p">){</span>
<span class="nf">return</span><span class="p">(</span><span class="nf">unify_ios_activity_recognition</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">stream_parameters</span><span class="p">))</span>
<span class="p">}</span>
</code></pre></div></p>
</details>
<!-- Add custom comment system integration here -->
<!-- Utterances integration -->
<h2 id="__comments">Comments</h2>
<script type="text/javascript">
var rapids_utterances_theme = false
document.onreadystatechange = function () {
if (document.readyState == "interactive") {
// wait for utterances to load and send it's first message.
addEventListener('message', event => {
if (event.origin !== 'https://utteranc.es' || rapids_utterances_theme == true) {
return;
}
rapids_utterances_theme = true
if(document.body.getAttribute("data-md-color-scheme") == "default")
document.querySelector("iframe.utterances-frame").contentWindow.postMessage({ type: "set-theme", theme: "github-light" },"https://utteranc.es/")
else
document.querySelector("iframe.utterances-frame").contentWindow.postMessage({ type: "set-theme", theme: "photon-dark" },"https://utteranc.es/")
});
document.getElementById('__palette_1').onclick = function(){
document.querySelector("iframe.utterances-frame").contentWindow.postMessage({ type: "set-theme", theme: "github-light" },"https://utteranc.es/")
}
document.getElementById('__palette_2').onclick = function(){
document.querySelector("iframe.utterances-frame").contentWindow.postMessage({ type: "set-theme", theme: "photon-dark" },"https://utteranc.es/")
}
}
}
</script>
<script src="https://utteranc.es/client.js"
repo="carissalow/rapids"
issue-term="pathname"
label="docs comments"
theme="github-light"
crossorigin="anonymous"
async>
</script>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer">
<a href="../mandatory-empatica-format/" class="md-footer__link md-footer__link--prev" rel="prev">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
</div>
<div class="md-footer__title">
<div class="md-ellipsis">
<span class="md-footer__direction">
Previous
</span>
Mandatory Empatica Format
</div>
</div>
</a>
<a href="../../features/feature-introduction/" class="md-footer__link md-footer__link--next" rel="next">
<div class="md-footer__title">
<div class="md-ellipsis">
<span class="md-footer__direction">
Next
</span>
Introduction
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Released under AGPL
</div>
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs Insiders
</a>
</div>
<div class="md-footer-social">
<a href="https://twitter.com/julio_ui" target="_blank" rel="noopener" title="twitter.com" class="md-footer-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": ["navigation.sections", "search.suggest", "search.highlight"], "translations": {"clipboard.copy": "Copy to clipboard", "clipboard.copied": "Copied to clipboard", "search.config.lang": "en", "search.config.pipeline": "trimmer, stopWordFilter", "search.config.separator": "[\\s\\-]+", "search.placeholder": "Search", "search.result.placeholder": "Type to start searching", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.term.missing": "Missing"}, "search": "../../assets/javascripts/workers/search.9849d06a.min.js", "version": {"method": "mike"}}</script>
<script src="../../assets/javascripts/bundle.7da13850.min.js"></script>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<script src="../../javascripts/extra.js"></script>
</body>
</html>