sketch slides

master
Oliver Kennedy 2024-05-01 13:22:02 -04:00
parent b901bb9499
commit e9e172c3ce
Signed by: okennedy
GPG Key ID: 3E5F9B3ABD3FDB60
3 changed files with 841 additions and 1 deletions

View File

@ -0,0 +1,431 @@
---
template: templates/cse4562_2021_slides.erb
title: Data Sketching
date: March 25, 2021
textbook: (readings only)
class_name: CSE 350
---
<section>
<section>
<ul>
<li><code>SELECT COUNT(DISTINCT A) FROM R</code></li>
<li><code>SELECT A, COUNT(*) FROM R GROUP BY A</code></li>
<li><code>SELECT A, COUNT(*) ... ORDER BY COUNT(*) DESC LIMIT 10</code></li>
</ul>
<p class="fragment" style="margin-top: 100px;">These are all "Holistic" aggregates ($O(|A|)$ memory). What happens when you run out of memory?</p>
</section>
<section>
<p><b>Sketching:</b> Hash function tricks used to <u>estimate</u> useful statistical properties.</p>
</section>
<section>
<dl>
<dt>Flajolet-Martin Sketches (HyperLogLog)</dt>
<dd>Estimating Count-Distinct</dd>
<dt>Count Sketches</dt>
<dd>Estimating Count-GroupBy</dd>
<dt>Count-Min Sketches</dt>
<dd>Estimating Count-GroupBy-TopK</dd>
</dl>
</section>
</section>
<section>
<section>
<h3>Count-Distinct</h3>
<div>
<span class="fragment" data-fragment-index="1">$3$</span>
<span class="fragment" data-fragment-index="2">$5$</span>
<span class="fragment" data-fragment-index="3">$4$</span>
<span class="fragment" data-fragment-index="4">$4$</span>
<span class="fragment" data-fragment-index="6">$2$</span>
<span class="fragment" data-fragment-index="6">$4$</span>
<span class="fragment" data-fragment-index="6">$3$</span>
<span class="fragment" data-fragment-index="6">$\ldots$</span>
</div>
<center>
<div style="border: 1px solid black; width: 200px; margin-top: 50px;" class="fragment" data-fragment-index="5">
<span>$3$</span>
<span>$5$</span>
<span>$4$</span>
<span class="fragment" data-fragment-index="6">$2$</span>
<span class="fragment" data-fragment-index="6">$\ldots$</span>
</div>
</center>
<p style="margin-top: 50px" class="fragment" data-fragment-index="5"><b>Challenge:</b> To avoid double counting, we need to track which values of $A$ we've seen. <span class="fragment" data-fragment-index="6">$O(|A|)$ memory required.</span></p>
</section>
<section>
<p>A brief digression</p>
</section>
<section>
<h3>The Coin Flip Game</h3>
Start with 0 points and flip a coin
<dl>
<div class="fragment">
<dt>Tails (🐕)</dt>
<dd>Get a point and flip again.</dd>
</div>
<div class="fragment">
<dt>Heads (👽)</dt>
<dd>Game over.</dd>
</div>
</dl>
</section>
<!--
[ 100d2 = 2 1 2 1 1 1 1 1 2 1 2 1 2 2 1 2 2 1 1 2 2 1 2 1 1 2 2 2 2 2 1 2 1 2 1 2 1 1 1 2 1 1 1 2 1 2 2 2 2 1 2 2 1 2 1 1 1 1 1 2 1 2 2 2 2 1 1 1 2 2 1 1 2 2 2 2 2 2 1 2 1 1 1 1 1 1 2 1 2 2 2 2 2 2 1 2 2 1 1 1 ] = 151
-->
<section>
<table>
<tr><th>Flips</th><th>Score</th></tr>
<tr><td align="left">
<span class="fragment">(👽)</span>
</td><td class="fragment">0</td></tr>
<tr><td align="left">
<span class="fragment">(🐕)</span>
<span class="fragment">(👽)</span>
</td><td class="fragment">1</td></tr>
<tr><td align="left">
<span class="fragment">(🐕)</span>
<span class="fragment">(🐕)</span>
<span class="fragment">(🐕)</span>
<span class="fragment">(🐕)</span>
<span class="fragment">(🐕)</span>
<span class="fragment">(👽)</span>
</td><td class="fragment">5</td></tr>
</table>
</section>
<section>
<table>
<tr><th>Flips</th><th>Score</th><th>Probability</th>
<th class="fragment" data-fragment-index="1">E[# Games]</th>
</tr>
<tr><td>(👽)</td><td>0</td><td>0.5</td>
<td class="fragment" data-fragment-index="1">2</td>
</tr>
<tr><td>(🐕)(👽)</td><td>1</td><td>0.25</td>
<td class="fragment" data-fragment-index="1">4</td>
</tr>
<tr><td>(🐕)(🐕)(👽)</td><td>2</td><td>0.125</td>
<td class="fragment" data-fragment-index="1">8</td>
</tr>
<tr class="fragment"><td>(🐕)$\times N$ &nbsp;&nbsp;(👽)</td><td>$N$</td><td>$\frac{1}{2^{N+1}}$</td>
<td>$2^{N+1}$</td>
</tr>
</table>
<p class="fragment" style="margin-top: 50px;">If I told you that in a series of games, my best score was $N$, you might expect that I played $2^{N+1}$ games.</p>
<p class="fragment" style="margin-top: 50px;">To do that, I only need to track my top score!</p>
</section>
<section>
<p><b>Idea:</b> Simulate coin flips with a hash function</p>
<p class="fragment" style="margin-top: 50px;">... take the index of the lowest-order nonzero bit</p>
</section>
<section>
<table>
<tr><th>Object</th><th>Hash Bits</th><th>Score</th></tr>
<tr class="fragment"><td>$O_1$</td><td>0101101<u>1</u></td><td>0</td></tr>
<tr class="fragment"><td>$O_2$</td><td>0011011<u>1</u></td><td>0</td></tr>
<tr class="fragment"><td>$O_3$</td><td>0011<u>1</u>000</td><td>3</td></tr>
<tr class="fragment"><td>$O_4$</td><td>100100<u>1</u>0</td><td>1</td></tr>
<tr class="fragment"><td>$O_3$</td><td>0011<u>1</u>000</td><td>3</td></tr>
<tr class="fragment"><td></td><td></td><td style="border-top: 1px solid black">3</td></tr>
</table>
<p class="fragment"><b>Estimate: </b> $2^{3+1} = 16$</p>
<p class="fragment">Duplicates can't raise the top score!</p>
</section>
<section>
<p><b>Problem: </b> Noisy estimate!</p>
<p class="fragment"><b>Idea 1:</b> Instead of your top score, track the lowest score you have not gotten yet ($R$).</p>
</section>
<section>
<table>
<tr><th>Object</th><th>Hash Bits</th><th>Score</th></tr>
<tr><td>$O_1$</td><td>0101101<u>1</u></td><td>0</td></tr>
<tr><td>$O_2$</td><td>0011011<u>1</u></td><td>0</td></tr>
<tr><td>$O_3$</td><td>0011<u>1</u>000</td><td>3</td></tr>
<tr><td>$O_4$</td><td>100100<u>1</u>0</td><td>1</td></tr>
<tr><td>$O_3$</td><td>0011<u>1</u>000</td><td>3</td></tr>
<tr class="fragment"><td></td><td></td><td style="border-top: 1px solid black">{0, 1, 3}<div class="fragment">$R = 2$</div></td></tr>
</table>
<p class="fragment"><b>Estimate: </b> $\frac{2^R}{\phi} = \frac{2^{2}}{0.77351} \approx 5.2$</p>
</section>
<section>
<p><b>Idea 2:</b> Compute several estimates in parallel and average estimates.</p>
</section>
<section>
<h3>Flajolet-Martin Sketches</h3>
<h4>($\approx$ HyperLogLog)</h4>
<ol>
<li>For each record...
<ol>
<li>Hash each record</li>
<li>Find the index of the lowest-order non-zero bit</li>
<li>Add the index of the bit to a set</li>
</ol></li>
<li>Find $R$, the lowest index <b>not</b> in the set</li>
<li>Estimate Count-Distinct as $\frac{2^R}{\phi}$ ($\phi \approx 0.77351$)</li>
<li>Repeat (in parallel) as needed</li>
</ol>
</section>
</section>
<section>
<section>
<h3>Group-By Count</h3>
<p style="margin-top: 100px;"><b>Problem: </b> Need a counter for each individual A</p>
</section>
<section>
<p><b>Idea:</b> Keep only one counter!</p>
</section>
<section>
<img src="../../cse-562/2021fa/graphics/Clipart/facepalm.jpg"/>
<p class="fragment">No... seriously</p>
</section>
<section>
$$\delta(O_i) = \begin{cases} \textbf{if } h(O_i) = 0 \mod 2 & \textbf{then } -1 \\ \textbf{if } h(O_i) = 1 \mod 2 & \textbf{then } +1\end{cases}$$
</section>
<section>
$$\sum_i \delta(O_i)$$
</section>
<section>
<table>
<tr><th>Object</th><th>$\delta(O_i)$</th><th>Running Count</th></tr>
<tr class="fragment"><td>$O_3$</td><td>-1</td><td>-1</td></tr>
<tr class="fragment"><td>$O_1$</td><td>+1</td><td>0</td></tr>
<tr class="fragment"><td>$O_4$</td><td>-1</td><td>-1</td></tr>
<tr class="fragment"><td>$O_2$</td><td>+1</td><td>0</td></tr>
<tr class="fragment"><td>$O_4$</td><td>-1</td><td>-1</td></tr>
<tr class="fragment"><td>$O_1$</td><td>+1</td><td>0</td></tr>
<tr class="fragment"><td>$O_3$</td><td>-1</td><td>-1</td></tr>
<tr class="fragment"><td>$O_3$</td><td>-1</td><td>-2</td></tr>
<tr class="fragment"><td>$O_1$</td><td>+1</td><td>-1</td></tr>
</table>
</section>
<section>
<table>
<tr><td align="left">$Total =$</td></tr>
<tr class="fragment"><td align="middle">$\texttt{COUNT_OF}(O_i) \cdot \delta(O_i)$</td></tr>
<tr class="fragment"><td align="right">$+ \sum_{j \neq i}\texttt{COUNT_OF}(O_j) \cdot \delta(O_j)$</td></tr>
</table>
<table style="margin-top: 60px">
<tr class="fragment"><td align="left">$E[\sum_{j}\texttt{COUNT_OF}(O_j) \cdot \delta(O_j)]$=</td></tr>
<tr class="fragment"><td align="middle">$\frac{1}{2}\sum \texttt{COUNT_OF}(O_j)$</td></tr>
<tr class="fragment"><td align="right">$ - \frac{1}{2}\sum \texttt{COUNT_OF}(O_j)$</td></tr>
</table>
<p style="margin-top: 60px;" class="fragment">
$$Total \approx \texttt{COUNT_OF}(O_i) \cdot \delta(O_i) + 0$$
</p>
</section>
<section>
<p>Running total was $-1$</p>
<table>
<tr><th>Object</th><th>$\delta(O_i)$</th><th>Estimate</th></tr>
<tr class="fragment"><td>$O_1$</td><td>+1</td><td>-1</td></tr>
<tr class="fragment"><td>$O_2$</td><td>+1</td><td>-1</td></tr>
<tr class="fragment"><td>$O_3$</td><td>-1</td><td>+1</td></tr>
<tr class="fragment"><td>$O_4$</td><td>-1</td><td>+1</td></tr>
</table>
<p class="fragment">Not... so... great</p>
</section>
<section>
<p><b>Problem 1:</b> All of the objects use the same counter (no way to differentiate an estimate for $O_1$ from $O_2$).</p>
<p><b>Problem 2:</b> The estimate is <b>really</b> noisy</p>
</section>
<section>
<p><b>Idea 1:</b> Multiple Buckets ($h(x)$ picks a bucket)</p>
<p><b>Idea 2:</b> Multiple Trials ($h \rightarrow h_1, h_2, \ldots$; $\delta \rightarrow \delta_1, \delta_2, \ldots$)</p>
</section>
<%
prng = Random.new(2019)
num_trials = 2
num_buckets = 2
num_objects = 4
all_fns = (0...num_objects).map {
(0...num_trials).map {
[ prng.rand(2)*2-1,
prng.rand(num_buckets)
] } }
%>
<section>
<table>
<tr><th>Object</th>
<% (1..num_trials).each do |i| %>
<th>$h_<%=i%>(O_i)$</th>
<th>$\delta_<%=i%>(O_i)$</th>
<% end %></tr>
<% all_fns.each.with_index do |o_fns, i| %>
<tr><td>$O_<%=i+1%>$</td>
<% o_fns.each do |d, h| %>
<td>Bucket <%=h+1%></td>
<td><%=d%></td>
<% end %></tr>
<% end %>
</table>
</section>
<% m = (0...num_trials).map { [0]*num_buckets } %>
<% log = [] %>
<% [ 2, 1, 4, 1, 2, 1 ].each do |i| %>
<% o_fns = all_fns[i-1]; %>
<section>
<p>Objects Seen: $<%= log.map { |l| "O_#{l}" }.join(",") %>$</p>
<table>
<tr><th></th><th>Bucket 1</th><th>Bucket 2</th></tr>
<% m.each.with_index do |buckets, trial| %>
<tr><td style="font-weight: bold;">Trial <%=trial%></td>
<% buckets.each do |cnt| %><td><%= cnt %></td><% end %>
</tr>
<% end %>
</table>
<table>
<tr><th>Object</th>
<% (0...num_trials).each do |i| %><th>Trial <%=i+1%></th><% end %>
<th>Estimate</th><th>Real</th></tr>
<% (0...num_objects).each do |o| %>
<tr><td>$O_<%=o+1%>$</td>
<% est = 0; (0...num_trials).each do |i| %>
<% delta, bucket = all_fns[o][i]; est += m[i][bucket] * delta %>
<td><%= m[i][bucket] * delta %></td>
<% end %>
<td><%= est.to_f/num_trials %></td>
<td><%= log.select { |x| x == o+1 }.count %></td>
</tr>
<% end %>
</table>
<%
log.push(i)
o_fns.each.with_index do |d_h, trial|
d, h = d_h
m[trial][h] += d
end
%>
</section>
<% end %>
<section>
<p>In practice, use <i>Median</i> and not <i>Mode</i> to combine trials</p>
</section>
</section>
<section>
<section>
<h3>Top-K Group-By Count</h3>
<p style="margin-top: 100px;"><b>Problem:</b> "Heavy Hitters" overwhelm smaller counts</p>
</section>
<section>
<p><b>Idea: </b> Give up. Drop $\delta$.</p>
</section>
<section>
<h3>Count-Min Sketch</h3>
</section>
<% m = (0...num_trials).map { [0]*num_buckets } %>
<% counts = [ 10, 32, 1002, 500 ] %>
<%
counts.each.with_index do |cnt, o|
o_fns = all_fns[o]
(0...num_trials).each do |i|
d, h = o_fns[i]
m[i][h] += cnt
end
end
%>
<section>
<table>
<tr><th>Object</th>
<th>Appearances</th>
<% (1..num_trials).each do |i| %>
<th>$h_<%=i%>(O_i)$</th>
<% end %></tr>
<% all_fns.each.with_index do |o_fns, i| %>
<tr><td>$O_<%=i+1%>$</td>
<td><%= counts[i] %></td>
<% o_fns.each do |d, h| %>
<td>Bucket <%=h+1%></td>
<% end %></tr>
<% end %>
</table>
<table>
<tr><th></th><% (1..num_buckets).each { |b| %><th>Bucket <%=b%></th><% } %></tr>
<% m.each.with_index do |buckets, trial| %>
<tr><td style="font-weight: bold;">Trial <%=trial%></td>
<% buckets.each do |cnt| %><td><%= cnt %></td><% end %>
</tr>
<% end %>
</table>
</section>
<section>
<table>
<tr><th></th><% (1..num_buckets).each { |b| %><th>Bucket <%=b%></th><% } %></tr>
<% m.each.with_index do |buckets, trial| %>
<tr><td style="font-weight: bold;">Trial <%=trial%></td>
<% buckets.each do |cnt| %><td><%= cnt %></td><% end %>
</tr>
<% end %>
</table>
<table>
<tr><th>Object</th>
<th>Appearances</th>
<% (1..num_trials).each do |i| %>
<th>Estimate <%=i%></th>
<% end %>
<th>Min</th>
</tr>
<% all_fns.each.with_index do |o_fns, o| %>
<tr><td>$O_<%=o+1%>$</td>
<td><%= counts[o] %></td>
<% (0...num_trials).each do |i| %>
<td><%=m[i][o_fns[i][1]]%></td>
<% end %>
<td><%=(0...num_trials).map { |i| m[i][o_fns[i][1]]}.min%></td>
</tr>
<% end %>
</table>
</section>
</section>

View File

@ -0,0 +1,409 @@
@font-face {
font-family: 'News Cycle';
font-style: normal;
font-weight: 400;
src: local('News Cycle'), local('NewsCycle'), url(../../../slide/reveal.js-3.7.0/fonts/9Xe8dq6pQDsPyVH2D3tMQsDdSZkkecOE1hvV7ZHvhyU.ttf) format('truetype');
}
@font-face {
font-family: 'News Cycle';
font-style: normal;
font-weight: 700;
src: local('News Cycle Bold'), local('NewsCycle-Bold'), url(../../../slide/reveal.js-3.7.0/fonts/G28Ny31cr5orMqEQy6ljt8BaWKZ57bY3RXgXH6dOjZ0.ttf) format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'), url(../../../slide/reveal.js-3.7.0/fonts/1EqTbJWOZQBfhZ0e3RL9uvesZW2xOQ-xsNqO47m55DA.ttf) format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 700;
src: local('Lato Bold'), local('Lato-Bold'), url(../../../slide/reveal.js-3.7.0/fonts/MZ1aViPqjfvZwVD_tzjjkwLUuEpTyoUstqEm5AMlJo4.ttf) format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 400;
src: local('Lato Italic'), local('Lato-Italic'), url(../../../slide/reveal.js-3.7.0/fonts/61V2bQZoWB5DkWAUJStypevvDin1pK8aKteLpeZ5c0A.ttf) format('truetype');
}
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 700;
src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url(../../../slide/reveal.js-3.7.0/fonts/HkF_qI1x_noxlxhrhMQYECZ2oysoEQEeKwjgmXLRnTc.ttf) format('truetype');
}
/**@import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
**/
/**
* A simple theme for reveal.js presentations, similar
* to the default theme. The accent color is darkblue.
*
* This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed.
* reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
*
* with edits (C) 2017-2021 Oliver Kennedy.
*/
/*********************************************
* GLOBAL STYLES
*********************************************/
body {
background: #fff;
background-color: #fff; }
.reveal {
font-family: 'Lato', sans-serif;
font-size: 36px;
font-weight: normal;
color: #000; }
::selection {
color: #fff;
background: rgba(0, 0, 0, 0.99);
text-shadow: none; }
.reveal .slides > section, .reveal .slides > section > section {
line-height: 1.3;
font-weight: inherit; }
/*********************************************
* STATIC HEADER/FOOTER
*********************************************/
.reveal .header {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
height: 25px;
text-align: center;
padding-left: 15px;
padding-right: 15px;
padding-bottom: 10px;
padding-top: 15px;
background-color: #041a9b;
color: white;
font-size: 0.5em;
z-index: 100;
}
.reveal .footer {
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
height: 40px;
text-align: center;
padding-left: 15px;
padding-right: 15px;
padding-bottom: 10px;
padding-top: 20px;
background-color: #041a9b;
color: white;
font-size: 0.5em;
z-index: 100;
}
/*********************************************
* HEADERS
*********************************************/
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {
margin: 0 0 20px 0;
color: #000;
font-family: 'News Cycle', Impact, sans-serif;
font-weight: normal;
line-height: 1.2;
letter-spacing: normal;
text-transform: none;
text-shadow: none;
word-wrap: break-word; }
.reveal h1 {
font-size: 3.77em; }
.reveal h2 {
font-size: 2.11em; }
.reveal h3 {
font-size: 1.55em; }
.reveal h4 {
font-size: 1em; }
.reveal h1 {
text-shadow: none; }
/*********************************************
* OTHER
*********************************************/
.reveal p {
margin: 20px 0;
line-height: 1.3; }
.reveal imagecredits {
font-size: 12pt;
position: absolute;
right: -10px;
bottom: -10px;
text-align: right;
}
.reveal citation {
font-size: 12pt;
position: absolute;
right: -10px;
bottom: -10px;
text-align: right;
}
.reveal tt {
font-family: courier;
font-weight: bold;
}
/* Ensure certain elements are never larger than the slide itself */
.reveal img, .reveal video, .reveal iframe {
max-width: 95%;
max-height: 95%; }
.reveal strong, .reveal b {
font-weight: bold; }
.reveal em {
font-style: italic; }
.reveal ol, .reveal dl, .reveal ul {
display: inline-block;
text-align: left;
margin: 0 0 0 1em; }
.reveal ol {
list-style-type: decimal; }
.reveal ul {
list-style-type: disc; }
.reveal ul > li {
margin-top: 20px; }
.reveal ul.tight > li {
margin-top: 10px; }
.reveal ol > li {
margin-top: 20px; }
.reveal ol.tight > li {
margin-top: 0px; }
.reveal ul ul {
list-style-type: square; }
.reveal ul ul ul {
list-style-type: circle; }
.reveal ul ul, .reveal ul ol, .reveal ol ol, .reveal ol ul {
display: block;
margin-left: 40px; }
.reveal dt {
margin-top: 20px;
margin-bottom: 0px;
font-weight: bold; }
.reveal dd {
margin-top: 0px;
margin-left: 40px; }
.reveal q, .reveal blockquote {
quotes: none; }
.reveal blockquote {
display: block;
position: relative;
width: 70%;
margin: 20px auto;
padding: 5px;
font-style: italic;
background: rgba(255, 255, 255, 0.05);
box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); }
.reveal blockquote p:first-child, .reveal blockquote p:last-child {
display: inline-block; }
.reveal q {
font-style: italic; }
.reveal pre {
display: block;
position: relative;
width: 90%;
margin: 20px auto;
text-align: left;
font-size: 0.55em;
font-family: monospace;
line-height: 1.2em;
word-wrap: break-word;
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); }
.reveal code {
font-family: monospace;
}
.reveal pre code {
display: block;
padding: 5px;
overflow: auto;
max-height: 400px;
word-wrap: normal;
background: #3F3F3F;
color: #DCDCDC; }
.reveal table {
margin: auto;
border-collapse: collapse;
border-spacing: 0; }
.reveal table th {
font-weight: bold;
border-bottom: 1px solid; }
.reveal table th, .reveal table td {
text-align: center;
padding: 0.2em 0.5em 0.2em 0.5em;}
.reveal table th[align="left"], .reveal table td[align="left"] {
text-align: left; }
.reveal table th[align="right"], .reveal table td[align="right"] {
text-align: right; }
.reveal table tr:last-child td {
border-bottom: none; }
.reveal sup {
vertical-align: super; }
.reveal sub {
vertical-align: sub; }
.reveal small {
display: inline-block;
font-size: 0.6em;
line-height: 1.2em;
vertical-align: top; }
.reveal small * {
vertical-align: top; }
/*********************************************
* LINKS
*********************************************/
.reveal a {
color: #00008B;
text-decoration: none;
-webkit-transition: color 0.15s ease;
-moz-transition: color 0.15s ease;
transition: color 0.15s ease; }
.reveal a:hover {
color: #0000f1;
text-shadow: none;
border: none; }
.reveal .roll span:after {
color: #fff;
background: #00003f; }
/*********************************************
* IMAGES
*********************************************/
.reveal section img {
margin: 15px 0px;
background: rgba(255, 255, 255, 0.12);
}
.reveal section img.bordered
{
border: 4px solid #000;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
}
.reveal a img {
-webkit-transition: all 0.15s linear;
-moz-transition: all 0.15s linear;
transition: all 0.15s linear; }
.reveal a:hover img {
background: rgba(255, 255, 255, 0.2);
border-color: #00008B;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); }
/*********************************************
* NAVIGATION CONTROLS
*********************************************/
.reveal .controls div.navigate-left, .reveal .controls div.navigate-left.enabled {
border-right-color: #00008B; }
.reveal .controls div.navigate-right, .reveal .controls div.navigate-right.enabled {
border-left-color: #00008B; }
.reveal .controls div.navigate-up, .reveal .controls div.navigate-up.enabled {
border-bottom-color: #00008B; }
.reveal .controls div.navigate-down, .reveal .controls div.navigate-down.enabled {
border-top-color: #00008B; }
.reveal .controls div.navigate-left.enabled:hover {
border-right-color: #0000f1; }
.reveal .controls div.navigate-right.enabled:hover {
border-left-color: #0000f1; }
.reveal .controls div.navigate-up.enabled:hover {
border-bottom-color: #0000f1; }
.reveal .controls div.navigate-down.enabled:hover {
border-top-color: #0000f1; }
/*********************************************
* PROGRESS BAR
*********************************************/
.reveal .progress {
background: rgba(0, 0, 0, 0.2); }
.reveal .progress span {
background: #00008B;
-webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
-moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }
/*********************************************
* SLIDE NUMBER
*********************************************/
.reveal .slide-number {
color: #00008B; }
/*********************************************
* CUSTOM HIGHLIGHTS
*********************************************/
.reveal .slides section .fragment.highlight-grey,
.reveal .slides section .fragment.highlight-current-grey {
opacity: 1;
visibility: inherit; }
.reveal .slides section .fragment.highlight-grey.visible {
color: lightgrey; }
.reveal .slides section .fragment.highlight-current-grey.current-fragment {
color: lightgrey; }
/*********************************************
* CUSTOM TAGS
*********************************************/
attribution {
width: 100%;
text-align: right;
font-size: 40%;
display: block;
}

View File

@ -1,7 +1,7 @@
<!doctype html>
<%
class_name = "CSE-4/562 Spring 2021"
class_name = "CSE-4/562 Spring 2021" unless defined? class_name
%>
<html lang="en">