Environment Setup

Notebook Setup

In [111]:
from IPython.core.display import display, HTML
display(HTML("<style>.container { width:75% !important; margin-left:350px; }</style>"))

Most Common Libraries

In [2]:
import numpy as np
import pandas as pd
import datetime as dt

import matplotlib
import matplotlib.pyplot as plt

#from plydata import define, query, select, group_by, summarize, arrange, head, rename
#import plotnine
#from plotnine import *

numpy

  • large multi-dimensional array and matrices
  • High level mathematical funcitons to operate on them
  • Efficient array computation, modeled after matlab
  • Support vectorized array math functions (built on C, hence faster than python for loop and list)

scipy

  • Collection of mathematical algorithms and convenience functions built on the numpy extension
  • Built uponi numpy

Pandas

  • Data manipulation and analysis
  • Offer data structures and operations for manipulating numerical tables and time series
  • Good for analyzing tabular data
  • Use for exploratory data analysis, data pre-processing, statistics and visualization
  • Built upon numpy

scikit-learn

  • Machine learning functions
  • Built on top of scipy

matplotlib

  • Data Visualization

Magic Functions

  • IPython has a set of predefined ‘magic functions’ that you can call with a command line style syntax
  • There are two types of magics:
    • Line Magic : prefix with %
      Work much like OS command-line calls: they get as an argument the rest of the line, where arguments are passed without parentheses or quotes. Lines magics can return results and can be used in the right hand side of an assignment
    • Cell Magic : prefix with %%
      They are functions that get as an argument not only the rest of the line, but also the lines below it in a separate argument.

List of Magic

In [82]:
%lsmagic
Out[82]:
Available line magics:
%alias  %alias_magic  %autocall  %automagic  %autosave  %bookmark  %cd  %clear  %cls  %colors  %config  %connect_info  %copy  %ddir  %debug  %dhist  %dirs  %doctest_mode  %echo  %ed  %edit  %env  %gui  %hist  %history  %killbgscripts  %ldir  %less  %load  %load_ext  %loadpy  %logoff  %logon  %logstart  %logstate  %logstop  %ls  %lsmagic  %macro  %magic  %matplotlib  %mkdir  %more  %notebook  %page  %pastebin  %pdb  %pdef  %pdoc  %pfile  %pinfo  %pinfo2  %popd  %pprint  %precision  %profile  %prun  %psearch  %psource  %pushd  %pwd  %pycat  %pylab  %qtconsole  %quickref  %recall  %rehashx  %reload_ext  %ren  %rep  %rerun  %reset  %reset_selective  %rmdir  %run  %save  %sc  %set_env  %store  %sx  %system  %tb  %time  %timeit  %unalias  %unload_ext  %who  %who_ls  %whos  %xdel  %xmode

Available cell magics:
%%!  %%HTML  %%SVG  %%bash  %%capture  %%cmd  %%debug  %%file  %%html  %%javascript  %%js  %%latex  %%markdown  %%perl  %%prun  %%pypy  %%python  %%python2  %%python3  %%ruby  %%script  %%sh  %%svg  %%sx  %%system  %%time  %%timeit  %%writefile

Automagic is ON, % prefix IS NOT needed for line magics.

Line Magic

Execute magic on each line

%timeit

  • Run the line for default 7 times (use -r to specify)
  • Each run has default 100,000,000 loops (use -n to specify)
In [83]:
%timeit -r 2 -n 100 3+1000/0.25*100
36.4 ns ± 0 ns per loop (mean ± std. dev. of 2 runs, 100 loops each)

%matplotlib

Output graph inline to frontend (Jupyter Notebook). Therefore is stored in the Notebook document

In [84]:
%matplotlib inline

%who

  • Analyse variables of global scope
  • Specify optional type to filter the variables
In [85]:
a = 1
type(a)
Out[85]:
int
In [86]:
%who int
a	 
In [87]:
%who
HTML	 NamespaceMagics	 a	 aes	 annotate	 arrange	 arrow	 as_labeller	 coord_cartesian	 
coord_equal	 coord_fixed	 coord_flip	 coord_trans	 define	 display	 dt	 element_blank	 element_line	 
element_rect	 element_text	 expand_limits	 facet_grid	 facet_null	 facet_wrap	 geom_abline	 geom_area	 geom_bar	 
geom_bin2d	 geom_blank	 geom_boxplot	 geom_col	 geom_count	 geom_crossbar	 geom_density	 geom_dotplot	 geom_errorbar	 
geom_errorbarh	 geom_freqpoly	 geom_histogram	 geom_hline	 geom_jitter	 geom_label	 geom_line	 geom_linerange	 geom_path	 
geom_point	 geom_pointrange	 geom_polygon	 geom_qq	 geom_quantile	 geom_rect	 geom_ribbon	 geom_rug	 geom_segment	 
geom_smooth	 geom_spoke	 geom_step	 geom_text	 geom_tile	 geom_violin	 geom_vline	 get_ipython	 getsizeof	 
ggplot	 ggsave	 ggtitle	 group_by	 guide_colorbar	 guide_colourbar	 guide_legend	 guides	 head	 
json	 label_both	 label_context	 label_value	 labeller	 labs	 lims	 matplotlib	 np	 
pd	 plotnine	 plt	 position_dodge	 position_fill	 position_identity	 position_jitter	 position_jitterdodge	 position_nudge	 
position_stack	 qplot	 query	 rename	 scale_alpha	 scale_alpha_continuous	 scale_alpha_datetime	 scale_alpha_discrete	 scale_alpha_identity	 
scale_alpha_manual	 scale_color_brewer	 scale_color_cmap	 scale_color_continuous	 scale_color_datetime	 scale_color_desaturate	 scale_color_discrete	 scale_color_distiller	 scale_color_gradient	 
scale_color_gradient2	 scale_color_gradientn	 scale_color_gray	 scale_color_grey	 scale_color_hue	 scale_color_identity	 scale_color_manual	 scale_colour_brewer	 scale_colour_cmap	 
scale_colour_continuous	 scale_colour_datetime	 scale_colour_desaturate	 scale_colour_discrete	 scale_colour_distiller	 scale_colour_gradient	 scale_colour_gradient2	 scale_colour_gradientn	 scale_colour_gray	 
scale_colour_grey	 scale_colour_hue	 scale_colour_identity	 scale_colour_manual	 scale_fill_brewer	 scale_fill_cmap	 scale_fill_continuous	 scale_fill_datetime	 scale_fill_desaturate	 
scale_fill_discrete	 scale_fill_distiller	 scale_fill_gradient	 scale_fill_gradient2	 scale_fill_gradientn	 scale_fill_gray	 scale_fill_grey	 scale_fill_hue	 scale_fill_identity	 
scale_fill_manual	 scale_linetype	 scale_linetype_continuous	 scale_linetype_discrete	 scale_linetype_identity	 scale_linetype_manual	 scale_shape	 scale_shape_continuous	 scale_shape_discrete	 
scale_shape_identity	 scale_shape_manual	 scale_size	 scale_size_area	 scale_size_continuous	 scale_size_datetime	 scale_size_discrete	 scale_size_identity	 scale_size_manual	 
scale_size_radius	 scale_stroke	 scale_stroke_continuous	 scale_stroke_discrete	 scale_x_continuous	 scale_x_date	 scale_x_datetime	 scale_x_discrete	 scale_x_log10	 
scale_x_reverse	 scale_x_sqrt	 scale_x_timedelta	 scale_y_continuous	 scale_y_date	 scale_y_datetime	 scale_y_discrete	 scale_y_log10	 scale_y_reverse	 
scale_y_sqrt	 scale_y_timedelta	 select	 stat_bin	 stat_bin2d	 stat_bin_2d	 stat_bindot	 stat_boxplot	 stat_count	 
stat_density	 stat_ecdf	 stat_function	 stat_identity	 stat_qq	 stat_quantile	 stat_smooth	 stat_sum	 stat_summary	 
stat_summary_bin	 stat_unique	 stat_ydensity	 summarize	 theme	 theme_538	 theme_bw	 theme_classic	 theme_dark	 
theme_get	 theme_gray	 theme_grey	 theme_light	 theme_linedraw	 theme_matplotlib	 theme_minimal	 theme_seaborn	 theme_set	 
theme_update	 theme_void	 theme_xkcd	 time	 var_dic_list	 watermark	 xlab	 xlim	 ylab	 
ylim	 

Cell Magic

Execute magic on the entire cell

%%timeit

  • Run the line for default 7 times (use -r to specify)
  • Each run has default 100,000,000 loops (use -n to specify)
In [88]:
%%timeit -r 1 -n 10
import time
for _ in range(100):
    time.sleep(0.01)# sleep for 0.01 seconds
1.25 s ± 0 ns per loop (mean ± std. dev. of 1 run, 10 loops each)

Package Management

Conda

Conda Environment

In [89]:
!conda info
     active environment : base
    active env location : C:\ProgramData\Anaconda3
            shell level : 1
       user config file : C:\Users\YKS-NIC\.condarc
 populated config files : C:\Users\YKS-NIC\.condarc
          conda version : 4.5.4
    conda-build version : 3.10.7
         python version : 3.6.5.final.0
       base environment : C:\ProgramData\Anaconda3  (read only)
           channel URLs : https://repo.anaconda.com/pkgs/main/win-64
                          https://repo.anaconda.com/pkgs/main/noarch
                          https://repo.anaconda.com/pkgs/free/win-64
                          https://repo.anaconda.com/pkgs/free/noarch
                          https://repo.anaconda.com/pkgs/r/win-64
                          https://repo.anaconda.com/pkgs/r/noarch
                          https://repo.anaconda.com/pkgs/pro/win-64
                          https://repo.anaconda.com/pkgs/pro/noarch
                          https://repo.anaconda.com/pkgs/msys2/win-64
                          https://repo.anaconda.com/pkgs/msys2/noarch
          package cache : C:\ProgramData\Anaconda3\pkgs
                          C:\Users\YKS-NIC\AppData\Local\conda\conda\pkgs
       envs directories : C:\Users\YKS-NIC\AppData\Local\conda\conda\envs
                          C:\ProgramData\Anaconda3\envs
                          C:\Users\YKS-NIC\.conda\envs
               platform : win-64
             user-agent : conda/4.5.4 requests/2.18.4 CPython/3.6.5 Windows/10 Windows/10.0.17134
          administrator : False
             netrc file : None
           offline mode : False

Package Version

In [90]:
!conda list
# packages in environment at C:\ProgramData\Anaconda3:
#
# Name                    Version                   Build  Channel
_ipyw_jlab_nb_ext_conf    0.1.0            py36he6757f0_0  
alabaster                 0.7.10           py36hcd07829_0  
anaconda                  custom           py36h363777c_0  
anaconda-client           1.6.14                   py36_0  
anaconda-navigator        1.8.7                    py36_0  
anaconda-project          0.8.2            py36hfad2e28_0  
asn1crypto                0.22.0           py36h8e79faa_1  
astroid                   1.5.3            py36h9d85297_0  
astropy                   2.0.2            py36h06391c4_4  
babel                     2.5.0            py36h35444c1_0  
backcall                  0.1.0                    py36_0  
backports                 1.0              py36h81696a8_1  
backports.shutil_get_terminal_size 1.0.0            py36h79ab834_2  
beautifulsoup4            4.6.0            py36hd4cc5e8_1  
bitarray                  0.8.1            py36h6af124b_0  
bkcharts                  0.2              py36h7e685f7_0  
blaze                     0.11.3           py36h8a29ca5_0  
bleach                    2.0.0            py36h0a7e3d6_0  
bokeh                     0.12.16                  py36_0  
boto                      2.48.0           py36h1a776d2_1  
bottleneck                1.2.1            py36hd119dfa_0  
bzip2                     1.0.6                    vc14_1  [vc14]  conda-forge
ca-certificates           2018.03.07                    0  
cachecontrol              0.12.3           py36hfe50d7b_0  
certifi                   2018.4.16                py36_0  
cffi                      1.10.0           py36hae3d1b5_1  
chardet                   3.0.4            py36h420ce6e_1  
click                     6.7              py36hec8c647_0  
cloudpickle               0.4.0            py36h639d8dc_0  
clyent                    1.2.2            py36hb10d595_1  
colorama                  0.3.9            py36h029ae33_0  
comtypes                  1.1.2            py36heb9b3d1_0  
conda                     4.5.4                    py36_0  
conda-build               3.10.7                   py36_0  
conda-env                 2.6.0                h36134e3_1  
conda-verify              2.0.0            py36h065de53_0  
console_shortcut          0.1.1                h6bb2dd7_3  
contextlib2               0.5.5            py36he5d52c0_0  
cryptography              2.0.3            py36h123decb_1  
curl                      7.55.1           vc14hdaba4a4_3  [vc14]
cycler                    0.10.0           py36h009560c_0  
cython                    0.26.1           py36h18049ac_0  
cytoolz                   0.8.2            py36h547e66e_0  
dask                      0.15.3           py36h396fcb9_0  
dask-core                 0.15.3           py36hd651449_0  
datashape                 0.5.4            py36h5770b85_0  
decorator                 4.1.2            py36he63a57b_0  
distlib                   0.2.5            py36h51371be_0  
distributed               1.19.1           py36h8504682_0  
docutils                  0.14             py36h6012d8f_0  
entrypoints               0.2.3            py36hfd66bb0_2  
et_xmlfile                1.0.1            py36h3d2d736_0  
fastcache                 1.0.2            py36hffdae1b_0  
filelock                  2.0.12           py36hd7ddd41_0  
flask                     0.12.2           py36h98b5e8f_0  
flask-cors                3.0.3            py36h8a3855d_0  
freetype                  2.8.1                    vc14_0  [vc14]  conda-forge
get_terminal_size         1.0.0                h38e98db_0  
gevent                    1.2.2            py36h342a76c_0  
glob2                     0.5              py36h11cc1bd_1  
greenlet                  0.4.12           py36ha00ad21_0  
h5py                      2.7.0            py36hfbe0a52_1  
hdf5                      1.10.1           vc14hb361328_0  [vc14]
heapdict                  1.0.0            py36h21fa5f4_0  
html5lib                  0.999999999      py36ha09b1f3_0  
icc_rt                    2017.0.4             h97af966_0  
icu                       58.2                     vc14_0  [vc14]  conda-forge
idna                      2.6              py36h148d497_1  
imageio                   2.2.0            py36had6c2d2_0  
imagesize                 0.7.1            py36he29f638_0  
intel-openmp              2018.0.0             hcd89f80_7  
ipykernel                 4.6.1            py36hbb77b34_0  
ipython                   6.4.0                    py36_0  
ipython_genutils          0.2.0            py36h3c5d0ee_0  
ipywidgets                7.2.1                    py36_0  
isort                     4.2.15           py36h6198cc5_0  
itsdangerous              0.24             py36hb6c5a24_1  
jdcal                     1.3              py36h64a5255_0  
jedi                      0.10.2           py36hed927a0_0  
jinja2                    2.9.6            py36h10aa3a0_1  
jpeg                      9b                       vc14_2  [vc14]  conda-forge
jsonschema                2.6.0            py36h7636477_0  
jupyter                   1.0.0            py36h422fd7e_2  
jupyter_client            5.2.2                    py36_0  
jupyter_console           5.2.0            py36h6d89b47_1  
jupyter_contrib_core      0.3.3                    py36_1    conda-forge
jupyter_contrib_nbextensions 0.3.3                    py36_0    conda-forge
jupyter_core              4.4.0            py36h56e9d50_0  
jupyter_highlight_selected_word 0.1.0                    py36_0    conda-forge
jupyter_latex_envs        1.3.8.2                  py36_1    conda-forge
jupyter_nbextensions_configurator 0.4.0                    py36_0    conda-forge
jupyterlab                0.32.1                   py36_0  
jupyterlab_launcher       0.10.2                   py36_0  
lazy-object-proxy         1.3.1            py36hd1c21d2_0  
libiconv                  1.14                     vc14_4  [vc14]  conda-forge
libpng                    1.6.34                   vc14_0  [vc14]  conda-forge
libsodium                 1.0.16               h9d3ae62_0  
libssh2                   1.8.0            vc14hcf584a9_2  [vc14]
libtiff                   4.0.9                    vc14_0  [vc14]  conda-forge
libxml2                   2.9.5                    vc14_1  [vc14]  conda-forge
libxslt                   1.1.32                   vc14_0  [vc14]  conda-forge
llvmlite                  0.20.0                   py36_0  
locket                    0.2.0            py36hfed976d_1  
lockfile                  0.12.2           py36h0468280_0  
lxml                      4.1.0            py36h0dcd83c_0  
lzo                       2.10             vc14h0a64fa6_1  [vc14]
m2w64-gcc-libgfortran     5.3.0                         6  
m2w64-gcc-libs            5.3.0                         7  
m2w64-gcc-libs-core       5.3.0                         7  
m2w64-gmp                 6.1.0                         2  
m2w64-libwinpthread-git   5.0.0.4634.697f757               2  
markupsafe                1.0              py36h0e26971_1  
matplotlib                2.1.0            py36h11b4b9c_0  
mccabe                    0.6.1            py36hb41005a_1  
menuinst                  1.4.10           py36h42196fb_0  
mistune                   0.7.4            py36h4874169_0  
mizani                    0.4.4                      py_0    conda-forge
mkl                       2018.0.0             h36b65af_4  
mkl-service               1.1.2            py36h57e144c_4  
mpmath                    0.19             py36he326802_2  
msgpack-python            0.4.8            py36h58b1e9d_0  
msys2-conda-epoch         20160418                      1  
multipledispatch          0.4.9            py36he44c36e_0  
navigator-updater         0.1.0            py36h8a7b86b_0  
nbconvert                 5.3.1            py36h8dc0fde_0  
nbformat                  4.4.0            py36h3a5bc1b_0  
nbmerge                   0.0.4                     <pip>
networkx                  2.0              py36hff991e3_0  
nltk                      3.2.4            py36hd0e0a39_0  
nose                      1.3.7            py36h1c3779e_2  
notebook                  5.5.0                    py36_0  
numba                     0.35.0             np113py36_10  
numexpr                   2.6.2            py36h7ca04dc_1  
numpy                     1.13.3           py36ha320f96_0  
numpydoc                  0.7.0            py36ha25429e_0  
odo                       0.5.1            py36h7560279_0  
olefile                   0.44             py36h0a7bdd2_0  
openpyxl                  2.4.8            py36hf3b77f6_1  
openssl                   1.0.2o               h8ea7d77_0  
packaging                 16.8             py36ha0986f6_1  
palettable                3.1.0                      py_0    conda-forge
pandas                    0.22.0           py36h6538335_0  
pandoc                    1.19.2.1             hb2460c7_1  
pandocfilters             1.4.2            py36h3ef6317_1  
partd                     0.3.8            py36hc8e763b_0  
path.py                   10.3.1           py36h3dd8b46_0  
pathlib2                  2.3.0            py36h7bfb78b_0  
patsy                     0.4.1            py36h42cefec_0  
pep8                      1.7.0            py36h0f3d67a_0  
pickleshare               0.7.4            py36h9de030f_0  
pillow                    4.2.1            py36hdb25ab2_0  
pip                       9.0.1            py36hadba87b_3  
pkginfo                   1.4.1            py36hb0f9cfa_1  
plotnine                  0.3.0                      py_0    conda-forge
ply                       3.10             py36h1211beb_0  
plydata                   0.3.2                     <pip>
progress                  1.3              py36hbeca8d3_0  
prompt_toolkit            1.0.15           py36h60b8f86_0  
psutil                    5.4.0            py36h4e662fb_0  
py                        1.4.34           py36ha4aca3a_1  
pycodestyle               2.3.1            py36h7cc55cd_0  
pycosat                   0.6.3            py36h413d8a4_0  
pycparser                 2.18             py36hd053e01_1  
pycrypto                  2.6.1            py36he68e6e2_1  
pycurl                    7.43.0           py36h086bf4c_3  
pyflakes                  1.6.0            py36h0b975d6_0  
pygments                  2.2.0            py36hb010967_0  
pylint                    1.7.4            py36ha4e6ded_0  
pyodbc                    4.0.17           py36h0006bc2_0  
pyopenssl                 17.2.0           py36h15ca2fc_0  
pyparsing                 2.2.0            py36h785a196_1  
pyqt                      5.6.0            py36hb5ed885_5  
pysocks                   1.6.7            py36h698d350_1  
pytables                  3.4.2            py36h71138e3_2  
pytest                    3.2.1            py36h753b05e_1  
python                    3.6.5                h0c2934d_0  
python-dateutil           2.6.1            py36h509ddcb_1  
pytz                      2017.2           py36h05d413f_1  
pywavelets                0.5.2            py36hc649158_0  
pywin32                   221              py36h9c10281_0  
pywinpty                  0.5.3                    py36_0  
pyyaml                    3.12             py36h1d1928f_1  
pyzmq                     17.0.0           py36hfa6e2cd_1  
qt                        5.6.2                    vc14_1  [vc14]  conda-forge
qtawesome                 0.4.4            py36h5aa48f6_0  
qtconsole                 4.3.1            py36h99a29a9_0  
qtpy                      1.4.2                    py36_0  
requests                  2.18.4           py36h4371aae_1  
rope                      0.10.5           py36hcaf5641_0  
ruamel_yaml               0.11.14          py36h9b16331_2  
scikit-image              0.13.0           py36h6dffa3f_1  
scikit-learn              0.19.1           py36h53aea1b_0  
scipy                     1.0.0            py36h1260518_0  
seaborn                   0.8.0            py36h62cb67c_0  
send2trash                1.4.2                    py36_0  
setuptools                36.5.0           py36h65f9e6e_0  
simplegeneric             0.8.1            py36heab741f_0  
singledispatch            3.4.0.3          py36h17d0c80_0  
sip                       4.18.1           py36h9c25514_2  
six                       1.11.0           py36h4db2310_1  
snowballstemmer           1.2.1            py36h763602f_0  
sortedcollections         0.5.3            py36hbefa0ab_0  
sortedcontainers          1.5.7            py36ha90ac20_0  
sphinx                    1.6.3            py36h9bb690b_0  
sphinxcontrib             1.0              py36hbbac3d2_1  
sphinxcontrib-websupport  1.0.1            py36hb5e5916_1  
spyder                    3.2.7                    py36_0  
spyder-notebook           0.1.1                    py36_0    spyder-ide
sqlalchemy                1.1.13           py36h5948d12_0  
sqlite                    3.20.1                   vc14_2  [vc14]  conda-forge
statsmodels               0.8.0            py36h6189b4c_0  
sympy                     1.1.1            py36h96708e0_0  
tblib                     1.3.2            py36h30f5020_0  
terminado                 0.8.1                    py36_1  
testpath                  0.3.1            py36h2698cfe_0  
tk                        8.6.7                    vc14_0  [vc14]  conda-forge
toolz                     0.8.2            py36he152a52_0  
tornado                   4.5.2            py36h57f6048_0  
traitlets                 4.3.2            py36h096827d_0  
typing                    3.6.2            py36hb035bda_0  
unicodecsv                0.14.1           py36h6450c06_0  
urllib3                   1.22             py36h276f60a_0  
vc                        14                   h2379b0c_2  
vs2015_runtime            14.0.25123           hd4c4e62_2  
wcwidth                   0.1.7            py36h3d5aa90_0  
webencodings              0.5.1            py36h67c50ae_1  
werkzeug                  0.12.2           py36h866a736_0  
wheel                     0.29.0           py36h6ce6cde_1  
widgetsnbextension        3.2.1                    py36_0  
win_inet_pton             1.0.1            py36he67d7fd_1  
win_unicode_console       0.5              py36hcdbd4b5_0  
wincertstore              0.2              py36h7fe50ca_0  
winpty                    0.4.3                         4  
wrapt                     1.10.11          py36he5f5981_0  
xlrd                      1.1.0            py36h1cb58dc_1  
xlsxwriter                1.0.2            py36hf723b7d_0  
xlwings                   0.11.4           py36hd3cf94d_0  
xlwt                      1.3.0            py36h1a4751e_0  
yaml                      0.1.7                    vc14_0  [vc14]  conda-forge
zeromq                    4.2.5                hc6251cf_0  
zict                      0.1.3            py36h2d8e73e_0  
zlib                      1.2.11                   vc14_0  [vc14]  conda-forge

Package Installation

Conda is recommended distribution.

To install from official conda channel:

conda install <package_name>  # always install latest
conda install <package_name=version_number>

To install from conda-forge community channel:

conda install -c conda-forge <package_name>
conda install -c conda-forge <package_name=version_number>
# conda official channel
conda install numpy
conda install scipy
conda install pandas
conda install matpotlib
conda install scikit-learn
conda install seaborn
conda install pip

# conda-forge community channel
conda install -c conda-forge plotnine

PIP

Use pip if the package is not available in conda.

Package Version

In [91]:
!pip list
alabaster (0.7.10)
anaconda-client (1.6.14)
anaconda-navigator (1.8.7)
anaconda-project (0.8.2)
asn1crypto (0.22.0)
astroid (1.5.3)
astropy (2.0.2)
babel (2.5.0)
backcall (0.1.0)
backports.shutil-get-terminal-size (1.0.0)
beautifulsoup4 (4.6.0)
bitarray (0.8.1)
bkcharts (0.2)
blaze (0.11.3)
bleach (2.0.0)
bokeh (0.12.16)
boto (2.48.0)
Bottleneck (1.2.1)
CacheControl (0.12.3)
certifi (2018.4.16)
cffi (1.10.0)
chardet (3.0.4)
click (6.7)
cloudpickle (0.4.0)
clyent (1.2.2)
colorama (0.3.9)
comtypes (1.1.2)
conda (4.5.4)
conda-build (3.10.7)
conda-verify (2.0.0)
contextlib2 (0.5.5)
cryptography (2.0.3)
cycler (0.10.0)
Cython (0.26.1)
cytoolz (0.8.2)
dask (0.15.3)
datashape (0.5.4)
decorator (4.1.2)
distlib (0.2.5)
distributed (1.19.1)
docutils (0.14)
entrypoints (0.2.3)
et-xmlfile (1.0.1)
fastcache (1.0.2)
filelock (2.0.12)
Flask (0.12.2)
Flask-Cors (3.0.3)
gevent (1.2.2)
glob2 (0.5)
greenlet (0.4.12)
h5py (2.7.0)
heapdict (1.0.0)
html5lib (0.999999999)
idna (2.6)
imageio (2.2.0)
imagesize (0.7.1)
ipykernel (4.6.1)
ipython (6.4.0)
ipython-genutils (0.2.0)
ipywidgets (7.2.1)
isort (4.2.15)
itsdangerous (0.24)
jdcal (1.3)
jedi (0.10.2)
Jinja2 (2.9.6)
jsonschema (2.6.0)
jupyter-client (5.2.2)
jupyter-console (5.2.0)
jupyter-contrib-core (0.3.3)
jupyter-contrib-nbextensions (0.3.3)
jupyter-core (4.4.0)
jupyter-highlight-selected-word (0.1.0)
jupyter-latex-envs (1.3.8.2)
jupyter-nbextensions-configurator (0.4.0)
jupyterlab (0.32.1)
jupyterlab-launcher (0.10.2)
lazy-object-proxy (1.3.1)
llvmlite (0.20.0)
locket (0.2.0)
lockfile (0.12.2)
lxml (4.1.0)
MarkupSafe (1.0)
matplotlib (2.1.0)
mccabe (0.6.1)
menuinst (1.4.10)
mistune (0.7.4)
mizani (0.4.4)
mpmath (0.19)
msgpack-python (0.4.8)
multipledispatch (0.4.9)
navigator-updater (0.1.0)
nbconvert (5.3.1)
nbformat (4.4.0)
nbmerge (0.0.4)
networkx (2.0)
nltk (3.2.4)
nose (1.3.7)
notebook (5.5.0)
numba (0.35.0+10.g143f70e)
numexpr (2.6.2)
numpy (1.13.3)
numpydoc (0.7.0)
odo (0.5.1)
olefile (0.44)
openpyxl (2.4.8)
packaging (16.8)
palettable (3.1.0)
pandas (0.22.0)
pandocfilters (1.4.2)
partd (0.3.8)
path.py (10.3.1)
pathlib2 (2.3.0)
patsy (0.4.1)
pep8 (1.7.0)
pickleshare (0.7.4)
Pillow (4.2.1)
pip (9.0.1)
pkginfo (1.4.1)
plotnine (0.3.0)
ply (3.10)
plydata (0.3.2)
progress (1.3)
prompt-toolkit (1.0.15)
psutil (5.4.0)
py (1.4.34)
pycodestyle (2.3.1)
pycosat (0.6.3)
pycparser (2.18)
pycrypto (2.6.1)
pycurl (7.43.0)
pyflakes (1.6.0)
Pygments (2.2.0)
pylint (1.7.4)
pyodbc (4.0.17)
pyOpenSSL (17.2.0)
pyparsing (2.2.0)
PySocks (1.6.7)
pytest (3.2.1)
python-dateutil (2.6.1)
pytz (2017.2)
PyWavelets (0.5.2)
pywin32 (221)
pywinpty (0.5.3)
PyYAML (3.12)
pyzmq (17.0.0)
QtAwesome (0.4.4)
qtconsole (4.3.1)
QtPy (1.4.2)
requests (2.18.4)
rope (0.10.5)
ruamel-yaml (0.11.14)
scikit-image (0.13.0)
scikit-learn (0.19.1)
scipy (1.0.0)
seaborn (0.8)
Send2Trash (1.4.2)
setuptools (36.5.0.post20170921)
simplegeneric (0.8.1)
singledispatch (3.4.0.3)
six (1.11.0)
snowballstemmer (1.2.1)
sortedcollections (0.5.3)
sortedcontainers (1.5.7)
Sphinx (1.6.3)
sphinxcontrib-websupport (1.0.1)
spyder (3.2.7)
spyder-notebook (0.1.1)
SQLAlchemy (1.1.13)
statsmodels (0.8.0)
sympy (1.1.1)
tables (3.4.2)
tblib (1.3.2)
terminado (0.8.1)
testpath (0.3.1)
toolz (0.8.2)
tornado (4.5.2)
traitlets (4.3.2)
typing (3.6.2)
unicodecsv (0.14.1)
urllib3 (1.22)
wcwidth (0.1.7)
webencodings (0.5.1)
Werkzeug (0.12.2)
wheel (0.29.0)
widgetsnbextension (3.2.1)
win-inet-pton (1.0.1)
win-unicode-console (0.5)
wincertstore (0.2)
wrapt (1.10.11)
xlrd (1.1.0)
XlsxWriter (1.0.2)
xlwings (0.11.4)
xlwt (1.3.0)
zict (0.1.3)
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
You are using pip version 9.0.1, however version 10.0.1 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

Package Installation

pip install <package_name>

pip install plydata

Python Fundamental

Variable and Values

  • Every varibales in python are objects
  • Every variable assginment is reference based, that is, each object value is the reference to memory block of data
In [92]:
# a,b refer to the same memory location
a = 123
b = a  
print ('Data of a =',a,'\nData of b =',b)
print ('ID of a = ', id(a))
print ('ID of b = ',id(b))
Data of a = 123 
Data of b = 123
ID of a =  1990753152
ID of b =  1990753152

Changing data value (using assignment) actually changed the reference value

In [93]:
a = 123
b = a
a = 456  # reassignemnt changed a memory reference
         # b memory reference not changed
print ('Data of a =',a,'\nData of b =',b)
print ('ID of a = ', id(a))
print ('ID of b = ',id(b))
Data of a = 456 
Data of b = 123
ID of a =  1761565045776
ID of b =  1990753152

Assignment

Multiple Assignment

In [94]:
x = y = 3
print (x,y)
3 3

Augmented Assignment

In [95]:
x = 1
y = x + 1
y += 1
print (y)
3

Unpacking Assingment

In [96]:
x,y = 1,3
print (x,y)
1 3

Built-in Data Types

Numbers

Integer

In [97]:
n = 123
type (n)
Out[97]:
int

Float

In [98]:
f = 123.4
type (f)
Out[98]:
float

Number Operators

Division always return float

In [99]:
print(4/2)  # return int
type(4/2)
2.0
Out[99]:
float

Integer Division return truncated int or float

In [100]:
print (8//3)    # return int
print (8//3.2)  # return float
2
2.0

Remainder return either float or integer

In [101]:
print (8%3)    # return int
print (8%3.2)  # return float
2
1.5999999999999996

Power return int or float

In [102]:
print (2**3)    # return int
print (2.1**3)  # return float
print (2**3.1)  # return float
8
9.261000000000001
8.574187700290345

String

A List of Characters

String is an object class 'str'. It is an ordered collection of letters, an array of object type str

Load Library

In [204]:
import string

Constructor

Classical Method

class str(object='')

In [279]:
my_string = str()        ## empty string

class str(object=b'', encoding='utf-8', errors='strict')

In [280]:
my_string = str('abc')

Shortcut Method

In [199]:
my_string = 'abc'
<class 'str'>
3

Multiline Method

In [278]:
my_string = '''
This is me.
Yong Keh Soon
'''
print(my_string)
my_string
This is me.
Yong Keh Soon

Out[278]:
'\nThis is me.\nYong Keh Soon\n'
In [295]:
my_string = '''
This is me.
Yong Keh Soon
'''
print(my_string)
my_string
This is me.
Yong Keh Soon

Out[295]:
'\nThis is me.\nYong Keh Soon\n'
In [12]:
s='abcde'
print( type(s) )
print( s[0], s[1], s[2] )
print( len(s) )
print(type(s[1]))
<class 'str'>
a b c
5
<class 'str'>

Immutability

  • String is immuatable. Changing its content will result in error
  • Changing the variable completley change the reference (for new object)
In [1]:
s = 'abcde'
print ('s : ', id(s))
s = 'efgh'
print ('s : ', id(s))
s :  1786613484712
s :  1786613484544
In [104]:
## s[1] = 'z' # error

Class Constants

Letters

In [206]:
print( string.ascii_letters )
print( string.ascii_lowercase )
print( string.ascii_uppercase )
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Digits

In [210]:
string.digits
Out[210]:
'0123456789'

White Spaces

In [209]:
string.whitespace
Out[209]:
' \t\n\r\x0b\x0c'

Instance Methods

Substitution : format()

By Positional

In [226]:
'{} + {} + {}'.format('a', 'b', 'c')  # auto sequence
Out[226]:
'a + b + c'
In [232]:
 '{0} + {1} = {2}'.format('aa', 'bb', 'cc') # manual sequence
Out[232]:
'aa + bb = cc'
In [231]:
 '{2} + {1} = {2}'.format('a', 'b', 'c') # manual sequence
Out[231]:
'c + b = c'

By Name

In [237]:
'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W') ## constant
Out[237]:
'Coordinates: 37.24N, -115.81W'
In [236]:
coord = {'latitude': '37.24N', 'longitude': '-115.81W'} ## dictionary key/value
'Coordinates: {latitude}, {longitude}'.format(**coord)
Out[236]:
'Coordinates: 37.24N, -115.81W'

Formatting Number
Float

In [243]:
'{:+f}; {:+f}'.format(3.14, -3.14)  # show it always
Out[243]:
'+3.140000; -3.140000'
In [244]:
'{: f}; {: f}'.format(3.14, -3.14)  # show a space for positive numbers
Out[244]:
' 3.140000; -3.140000'
In [273]:
'Correct answers: {:.2f}'.format(55676.345345)
Out[273]:
'Correct answers: 55676.35'

Integer, Percentage

In [274]:
'{:,}  {:,.2%}'.format(1234567890, 55676.345345)
Out[274]:
'1,234,567,890  5,567,634.53%'

Alignment

In [281]:
'{:<30}'.format('left aligned')
Out[281]:
'left aligned                  '
In [282]:
'{:>30}'.format('right aligned')
Out[282]:
'                 right aligned'
In [284]:
'{:^30}'.format('centered')  # use '*' as a fill char
Out[284]:
'           centered           '
In [285]:
'{:*^30}'.format('centered')  # use '*' as a fill char
Out[285]:
'***********centered***********'

Substitution : f-string

In [268]:
my_name = 'Yong Keh Soon'
salary = 11123.346
f'Hello, {my_name}, your salary is {salary:,.2f} !'
Out[268]:
'Hello, Yong Keh Soon, your salary is 11,123.35 !'

Conversion: upper() lower()

In [34]:
'myEXEel.xls'.upper()
Out[34]:
'MYEXEEL.XLS'
In [35]:
'myEXEel.xls'.lower()
Out[35]:
'myexeel.xls'

find() pattern position

string.find() return position of first occurance. -1 if not found
In [302]:
s='I love karaoke, I know you love it oo'
print (s.find('lov'))
print (s.find('kemuning'))
2
-1

strip() off blank spaces

In [109]:
filename = '  myexce l.   xls   '
filename.strip()
Out[109]:
'myexce l.   xls'

List Related: split()

Splitting delimeter is specified. Observe the empty spaces were conserved in result array

In [108]:
animals = 'a1,a2 ,a3, a4'
animals.split(',')
Out[108]:
['a1', 'a2 ', 'a3', ' a4']

List Related: join()

In [300]:
'-'.join(['1', '2', '3', '4'])
Out[300]:
'1-2-3-4'

Operator

% Old Style Substitution

In [292]:
name = 'Yong'
'Hey %s, how are you !' % name
Out[292]:
'Hey Yong, how are you !'
In [294]:
name = 'Yong'
errno = 123
'Hey %s, there is a %d error!' % (name, errno)
Out[294]:
'Hey Yong, there is a 123 error!'

+ Concatenation

In [296]:
'this is ' + 'awesome'
Out[296]:
'this is awesome'

in matching

For single string, partial match

In [29]:
print( 'abc' in '123abcdefg' )
True

For list of strings, exact match. Workaround for partial match in list of strings, convert list to single string

In [31]:
print( 'abc' in ['123','abcdefg'] )
print( 'abc' in ['abcdefg','123'] )
print( 'abc' in ['123','abc','def'] )
print( 'abc' in str(['123','abcdefg']) )
False
False
True
True

Comparitor

In [39]:
a='abc'
b='abc'
print(a==b)
print(a!=b)
True
False

Iterations

string[start:end:step]  # default step:1, start:0, end:last

If step is negative, end value must be lower than start value

In [105]:
s = 'abcdefghijk'
print (s[0])      # first later
print (s[:3])     # first 3 letters
print (s[2:8:2])  # stepping
print (s[-1])     # last letter
print (s[-3:])    # last three letters
print (s[::-1])   # reverse everything
print (s[8:2:-1])
a
abc
ceg
k
ijk
kjihgfedcba
ihgfed

Boolean

In [36]:
b = False

if (b):
    print ('It is true')
else:
    print ('It is fake')
    
It is fake

What is Considered False ?

Everything below are false, anything else are true

In [113]:
print (bool(0))      # zero
print (bool(None))   # none
print (bool(''))     # empty string
print (bool([]))     # empty list
print (bool(()))     # empty tupple
print (bool(False))  # False
print (bool(2-2))    # expression that return any value above
False
False
False
False
False
False
False

and operator

  • and can return different data types
  • If evaluated result is True, the last True Value is returned (because python need to evaluate up to the last value)
  • If evaluated result is False, the first False Value will be returned (because python return it immediately when detecting False value)
In [114]:
print (123 and 2 and 1)
print (123 and () and 2)
1
()

not operator

In [115]:
not (True or False)
Out[115]:
False

or operator

  • or can return different data type
  • If evaluated result is True, first True Value will be returned (right hand side value need not be evaluated)
  • If evaluated result is False, last Fasle Value will be returned (need to evalute all items before concluding False)
In [116]:
print (1 or 2)
print (0 or 1 or 1)
print (0 or () or [])
1
1
[]

None

None is Object

  • None is a Python object NonType
  • Any operation to None object will result in error
  • For array data with None elements, verification is required to check through iteration to determine if the item is not None. It is very computaionaly heavy
In [96]:
type(None)
Out[96]:
NoneType
In [117]:
t = np.array([1,2,3,4,5])
t.dtype  #  its an integer
Out[117]:
dtype('int32')
In [118]:
t = np.array([1, 2, 3, None, 4, 5])
t.dtype  # it's an object
Out[118]:
dtype('O')

Comparing None

Not Prefered Method

In [101]:
null_variable = None
print( null_variable == None )
True

Prefered

In [106]:
print( null_variable is None )
print( null_variable is not None )
True
False

Built-In Data Structure

Tuple

Tuple is an immutable list. Any attempt to change/update tuple will return error. It can contain different types of object.

Benefits of tuple against List are:

  • Faster than list
  • Protects your data against accidental change
  • Can be used as key in dictionaries, list can't

Assignment

(item1, item2, item3)

This is a formal syntax for defining tuple, items inside ( ) notation

In [119]:
t = (1,2,3,'o','apple')
t
Out[119]:
(1, 2, 3, 'o', 'apple')
In [120]:
type(t)
Out[120]:
tuple

item1, item2, item3

  • Without ( ) notation, it is also considered as tuple
  • However, some functions may not consider this method
In [121]:
1,2,3,'o','apple'
Out[121]:
(1, 2, 3, 'o', 'apple')

Accessing

In [122]:
print (t[1])
print (type(t[1]))
2
<class 'int'>
In [123]:
print (t[1:3])
type ([t[1:3]])
(2, 3)
Out[123]:
list

Duplicating Tuple

In [154]:
original = (1,2,3,4,5)
copy_test = original
print(original)
print(copy_test)
(1, 2, 3, 4, 5)
(1, 2, 3, 4, 5)
In [155]:
print('Original ID: ', id(original))
print('Copy ID:     ', id(copy_test))
Original ID:  1786618835280
Copy ID:      1786618835280

List

  • List is a collection of ordered items, where the items can be different data types
  • You can pack list of items by placing them into []
  • List is mutable

Creating List

List is An Object

In [135]:
test = [1,2,34,5]
type(test)
Out[135]:
list

Empty List

In [124]:
empty = []      # literal assignment method
empty = list()  # constructor method
print (empty)
type(empty)
[]
Out[124]:
list

Literal Assignment Method

  • Multiple data types is allowed in a list
In [125]:
mylist = [123,'abc',456]

Creating List using Constructor Method

  • Note that list(string) will split the string into letters
In [127]:
list('hello')
Out[127]:
['h', 'e', 'l', 'l', 'o']

Creating List using split() method

  • Split base on spaces (by default) to create a list item
In [128]:
'a bunch of words'.split()
Out[128]:
['a', 'bunch', 'of', 'words']
  • Split can also break into items base on specified delimter
In [129]:
'a1,a2,a3, a4'.split(',')
Out[129]:
['a1', 'a2', 'a3', ' a4']

Accessing Items

Access specific index number

In [45]:
food = ['bread', 'noodle', 'rice', 'biscuit','jelly','cake']
print (food[2])  # 3rd item
print (food[-1]) # last item
rice
cake

Access range of indexes

In [46]:
print (food[:4])     # first 3 items
print (food[-3:])    # last 3 items
print (food[1:5])    # item 1 to 4
print (food[5:2:-1]) # item 3 to 5, reverse order
print (food[::-1])   # reverse order
['bread', 'noodle', 'rice', 'biscuit']
['biscuit', 'jelly', 'cake']
['noodle', 'rice', 'biscuit', 'jelly']
['cake', 'jelly', 'biscuit']
['cake', 'jelly', 'biscuit', 'rice', 'noodle', 'bread']

Remove Item(s)

Removal of non-existance item will result in error

Search and remove first occurance of an item

In [116]:
food = list(['bread', 'noodle', 'rice', 'biscuit','jelly','cake','noodle'])
food.remove('noodle')
print (food)
['bread', 'rice', 'biscuit', 'jelly', 'cake', 'noodle']

Remove last item

In [117]:
food.pop()
print (food)
['bread', 'rice', 'biscuit', 'jelly', 'cake']

Remove item at specific position

In [118]:
food.pop(1)  # counter start from 0
print(food)
['bread', 'biscuit', 'jelly', 'cake']
In [119]:
food.remove('jelly')
print(food)
['bread', 'biscuit', 'cake']

Appending Item (s)

Append One Item

In [136]:
food.append('jelly')
print (food)
['bread', 'biscuit', 'jelly', 'cake', 'jelly']

Append Multiple Items extend() will expand the list/tupple argument and append as multiple items

In [137]:
food.extend(['nand','puff'])
print (food)
['bread', 'biscuit', 'jelly', 'cake', 'jelly', 'nand', 'puff']

Concateneting Multiple Lists

Concatenating Lists Although you can use '+' operator, however '-' operator is not supported

In [138]:
['dog','cat','horse'] + ['elephant','tiger'] + ['sheep']
Out[138]:
['dog', 'cat', 'horse', 'elephant', 'tiger', 'sheep']

Other Methods

Reversing the order of the items

In [139]:
food.reverse()
food
Out[139]:
['puff', 'nand', 'jelly', 'cake', 'jelly', 'biscuit', 'bread']

Locating the Index Number of An Item

In [140]:
food.index('biscuit')
Out[140]:
5

Count occurance

In [120]:
test = ['a','a','a','b','c']
test.count('a')
Out[120]:
3

Sorting The Order of Items

In [141]:
food.sort()
print (food)
['biscuit', 'bread', 'cake', 'jelly', 'jelly', 'nand', 'puff']

List is Mutable

The reference list variable won't change after adding/removing its item

In [142]:
food = ['cake','jelly','roti','noodle']
print ('food : ',id(food))
food += ['salad','chicken']
print ('food : ',id(food))
food :  1761565257672
food :  1761565257672
In [143]:
x = [1,2,3]
y = [x,'abc']
print (y)
x[2] = 'k'
print (y)
[[1, 2, 3], 'abc']
[[1, 2, 'k'], 'abc']

A function is actually an object, which reference never change, hence mutable

In [57]:
def spam (elem, some_list=['a','b']):
    some_list.append(elem)
    return some_list

print (spam(1,['x']))
print (spam(2)) ## second parameter is not passed
print (spam(3)) ##  notice the default was remembered
['x', 1]
['a', 'b', 2]
['a', 'b', 2, 3]

Duplicate or Reference

Use = : It just copy the refernce. IDs are similar

In [164]:
original = [1,2,3,4,5]
copy_test = original
print('Original ID: ', id(original))
print('Copy ID:     ', id(copy_test))                          
Original ID:  1786620135432
Copy ID:      1786620135432
In [171]:
original[0]=999   ## change original
print(original)
print(copy_test)  ## copy affected
[999, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

Duplicate A List Object with copy(). Resulting IDs are different

In [167]:
original = [1,2,3,4,5]
copy_test = original.copy()
print(original)
print(copy_test)
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
In [168]:
print('Original ID: ', id(original))
print('Copy ID:     ', id(copy_test))
Original ID:  1786620112776
Copy ID:      1786619865544
In [170]:
original[0] = 999  ## change original
print(original)    
print(copy_test)   ## copy not affected
[999, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

Passing To Function As Reference

In [149]:
def func(x):
    print (x)
    print('ID in Function:      ', id(x))
    x.append(6)    ## modify the refrence
    
my_list = [1,2,3,4,5]
print('ID outside Function: ', id(my_list))

func(my_list)  ## call the function, pass the reference
print(my_list) ## content was altered
ID outside Function:  1786619973128
[1, 2, 3, 4, 5]
ID in Function:       1786619973128
[1, 2, 3, 4, 5, 6]

List Is Iterable

For Loop

In [50]:
s = ['abc','abcd','bcde','bcdee','cdefg']
for x in s:
    if 'abc' in x:
        print (x)
abc
abcd
In [59]:
new_list = []
old_list = ['abc','abcd','bcde','bcdee','cdefg']
for x in old_list:
    if 'abc' in x:
        new_list.append(x)
        
print( new_list )
['abc', 'abcd']
In [62]:
new_list = [x for x in old_list if 'abc' in x]
print( new_list)
['abc', 'abcd']

Conversion

Convert mutable list to immutable tuple with tuple()

In [173]:
original_tuple = tuple(original)
print( id(original) )
print(id(original_tuple))
1786620112776
1786618835280

Built-In Functions Applicable To List

Number of Elements

In [122]:
len(food)
Out[122]:
3

Max Value

In [128]:
test = [1,2,3,5,5,3,2,1]
m = max(test)
test.index(m)  ## only first occurance is found
Out[128]:
3

Dictionaries

Dictionary is a list of index-value items.

Creating dict

Creating dict with literals

Simple Dictionary

In [76]:
animal_counts = { 'cats' : 2, 'dogs' : 5, 'horses':4}
print (animal_counts)
print( type(animal_counts) )
{'cats': 2, 'dogs': 5, 'horses': 4}
<class 'dict'>

Dictionary with list

In [69]:
animal_names = {'cats':   ['Walter','Ra'],
                'dogs':   ['Jim','Roy','John','Lucky','Row'],
                'horses': ['Sax','Jack','Ann','Jeep']
               }
animal_names
Out[69]:
{'cats': ['Walter', 'Ra'],
 'dogs': ['Jim', 'Roy', 'John', 'Lucky', 'Row'],
 'horses': ['Sax', 'Jack', 'Ann', 'Jeep']}

Creating dict with variables

In [83]:
cat_names = ['Walter','Ra','Jim']
dog_names = ['Jim','Roy','John','Lucky','Row']
horse_names= ['Sax','Jack','Ann','Jeep']
animal_names = {'cats': cat_names, 'dogs': dog_names, 'horses': horse_names}
animal_names
Out[83]:
{'cats': ['Walter', 'Ra', 'Jim'],
 'dogs': ['Jim', 'Roy', 'John', 'Lucky', 'Row'],
 'horses': ['Sax', 'Jack', 'Ann', 'Jeep']}

Accessing dict

Find out the list of keys using keys()

In [74]:
print (animal_names.keys())
print (sorted(animal_names.keys()))
dict_keys(['cats', 'dogs', 'horses'])
['cats', 'dogs', 'horses']

Find out the list of values using values()

In [77]:
print (animal_names.values())
print (sorted(animal_names.values()))
dict_values([['Walter', 'Ra'], ['Jim', 'Roy', 'John', 'Lucky', 'Row'], ['Sax', 'Jack', 'Ann', 'Jeep']])
[['Jim', 'Roy', 'John', 'Lucky', 'Row'], ['Sax', 'Jack', 'Ann', 'Jeep'], ['Walter', 'Ra']]

Refer a dictionary item using index

In [78]:
animal_names['dogs']
Out[78]:
['Jim', 'Roy', 'John', 'Lucky', 'Row']

Accessing non-existance key natively will return Error

In [151]:
##animal_count['cow']

Accessing non-existance key with get() will return None

In [152]:
print (animal_counts.get('cow'))
None

Dict are Mutable

Use [key] notation to update the content of element. However, if the key is non-existance, this will return error.

In [90]:
animal_names['dogs'] = ['Ali','Abu','Bakar']
animal_names
Out[90]:
{'cats': ['Walter', 'Ra', 'Jim'],
 'dogs': ['Ali', 'Abu', 'Bakar'],
 'horses': ['Sax', 'Jack', 'Ann', 'Jeep']}

Use clear() to erase all elements

In [ ]:
animal_names.clear()

Sets

Set is unordered collection of unique items

In [153]:
myset = {'a','b','c','d','a','b','e','f','g'}
print (myset) # notice no repetition values
{'g', 'd', 'f', 'c', 'a', 'b', 'e'}

Membership Test

In [154]:
print ('a' in myset)      # is member ?
print ('f' not in myset)  # is not member ?
True
False

Subset Test

Subset Test : <=
Proper Subset Test : <

In [155]:
mysubset = {'d','g'}
mysubset <= myset
Out[155]:
True

Proper Subset test that the master set contain at least one element which is not in the subset

In [156]:
mysubset = {'b','a','d','c','e','f','g'}
print ('Is Subset : ', mysubset <= myset)
print ('Is Proper Subet : ', mysubset < myset)
Is Subset :  True
Is Proper Subet :  False

Union using '|'

In [157]:
{'a','b','c'} | {'e','f'}
Out[157]:
{'a', 'b', 'c', 'e', 'f'}

Intersection using '&'

Any elments that exist in both left and right set

In [158]:
{'a','b','c','d'} & {'c','d','e','f'}
Out[158]:
{'c', 'd'}

Difference using '-'

Anything in left that is not in right

In [159]:
{'a','b','c','d'} - {'c','d','e','f'}
Out[159]:
{'a', 'b'}

range

range(X) generates sequence of integer object

range (lower_bound, upper_bound, step_size)  
# lower bound is optional, default = 0
# upper bound is not included in result
# step is optional, default = 1

Use list() to convert in order to view actual sequence of data

In [160]:
r = range(10)     # default lower bound =0, step =1
print (type (r))
print (r)
print (list(r))
<class 'range'>
range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

More Examples

In [161]:
print (list(range(2,8)))    # step not specified, default 1
print ('Odds Number : ' , list(range(1,10,2))) # generate odds number
[2, 3, 4, 5, 6, 7]
Odds Number :  [1, 3, 5, 7, 9]

Control and Loops

If Statement

Multiline If.. Statements

In [162]:
price = 102
if price <100:
    print ('buy')
elif price < 110:
    print ('hold')
elif price < 120:
    print ('think about it')
else:
    print ('sell')
print('end of programming')
hold
end of programming

Single Line If .. Statement

In [4]:
price = 70
if price<80: print('buy')
buy
In [5]:
price = 85
'buy' if (price<80) else 'dont buy'
Out[5]:
'dont buy'

For Loops

Loop thorugh 'range'

In [163]:
for i in range (1,10,2):
    print ('Odds Number : ',i) 
Odds Number :  1
Odds Number :  3
Odds Number :  5
Odds Number :  7
Odds Number :  9

Loop through 'list'

Standard For Loop

In [164]:
letters = ['a','b','c','d']
for e in letters:
    print ('Letter : ',e)
Letter :  a
Letter :  b
Letter :  c
Letter :  d

List Comprehension

Iterate through existing list, and build new list based on condition
new_list = [expression(i) for i in old_list]

In [47]:
s = ['abc','abcd','bcde','bcdee','cdefg']
[x.upper() for x in s]
Out[47]:
['ABC', 'ABCD', 'BCDE', 'BCDEE', 'CDEFG']

Extend list comprehension can be extended with if condition**
new_list = [expression(i) for i in old_list if filter(i)]

In [53]:
old_list    = ['abc','abcd','bcde','bcdee','cdefg']
matching = [ x.upper() for x in old_list if 'bcd' in x ]
print( matching )
['ABCD', 'BCDE', 'BCDEE']

Loop Through 'Dictionary'

Looping through dict will picup key

In [165]:
d = {"x": 1, "y": 2}
for key in d:
    print (key, d[key])
x 1
y 2

Generators

  • Generator is lazy, produce items only if asked for, hence more memory efficient
  • Generator is function with 'yield' instead of 'return'
  • Generator contains one or more yields statement
  • When called, it returns an object (iterator) but does not start execution immediately
  • Methods like iter() and next() are implemented automatically. So we can iterate through the items using next()
  • Once the function yields, the function is paused and the control is transferred to the caller
  • Local variables and their states are remembered between successive calls
  • Finally, when the function terminates, StopIteration is raised automatically on further calls

Basic Generator Function

Below example give clear understanding of how generator works

In [166]:
def my_gen():
    n = 1
    print('This is printed first')
    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n
In [167]:
a = my_gen()
type(a)
Out[167]:
generator
In [168]:
next(a)
This is printed first
Out[168]:
1
In [169]:
next(a)
This is printed second
Out[169]:
2
In [170]:
next(a)
This is printed at last
Out[170]:
3
In [171]:
next(a)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-171-15841f3f11d4> in <module>()
----> 1 next(a)

StopIteration: 

Useful Generator Fuction

Generator is only useful when it uses for-loop

  • for-loop within generator
  • for-loop to iterate through a generator
In [ ]:
def rev_str(my_str):
    length = len(my_str)
    for i in range(length - 1,-1,-1):
        yield my_str[i]
In [ ]:
for c in rev_str("hello"):
     print(c)

Generator Expression

Use () to create an annonymous generator function

In [ ]:
my_list = [1, 3, 6, 10]
a = (x**2 for x in my_list)
In [ ]:
next(a)
In [ ]:
next(a)
In [ ]:
sum(a) # sum the power of 6,10

Compare to Iterator Class

In [ ]:
class PowTwo:
    def __init__(self, max = 0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n > self.max:
            raise StopIteration

        result = 2 ** self.n
        self.n += 1
        return result

Obviously, Generator is more concise and cleaner

In [ ]:
def PowTwoGen(max = 0):
    n = 0
    while n < max:
        yield 2 ** n
        n += 1

Library and Functions

Library are group of functions

Package Source

Conda

  • Package manager for any language
  • Install binaries

PIP

  • Package manager python only
  • Compile from source
  • Stands for Pip Installs Packages
  • Python's officially-sanctioned package manager, and is most commonly used to install packages published on the Python Package Index (PyPI)
  • Both pip and PyPI are governed and supported by the Python Packaging Authority (PyPA).

Importing Library

There are two methods to import library functions:

Standalone Namespace

- import <libName>                        # access function through: libName.functionName
- import <libName> as <shortName>         # access function through: shortName.functionName

Global Namespace

- from   <libName> import *               # all functions available at global namespace
- from   <libName> import <functionName>  # access function through: functionName    
- from   <libName> import <functionName> as <shortFunctionName>  # access function through shortFunctionName

Import Entire Library

Import Into Standalone Namespace

In [ ]:
import math
math.sqrt(9)

Use as for aliasing library name. This is useful if you have conflicting library name

In [ ]:
import math as m
m.sqrt(9)

Import Into Global Name Space

All functions in the library accessible through global namespace

from <libName> import *

Import Specific Function

In [ ]:
from math import sqrt
print (sqrt(9))

Use as for aliasing function name

In [ ]:
from math import sqrt as sq
print (sq(9))

Machine Learning Packages

alt text

Define Function

Function Arguments

By default, arguments are assigned to function left to right

In [215]:
def myfun(x,y):
    print ('x:',x)
    print ('y:',y)
    
myfun(5,8)
x: 5
y: 8

However, you can also specify the argument assigment during function call

In [216]:
myfun (y=8,x=5)
x: 5
y: 8

Function can have default argement value

In [110]:
def myfun(x=1,y=1):  # default argument value is 1
    print ('x:',x)
    print ('y:',y)
    
myfun(5)  # pass only one argument
x: 5
y: 1

List Within Function

Consider a function is an object, its variable (some_list) is immutable and hence its reference won't change, even data changes

In [ ]:
def spam (elem, some_list=[]):
    some_list.append(elem)
    return some_list

print (spam(1))
print (spam(2))
print (spam(3))

Return Statement

In [ ]:
def bigger(x,y):
    if (x>y):
        return x
    else:
        return y
    
print (bigger(5,8))

No Return Statement

if no return statement, python return None

In [120]:
def dummy():
    print ('This is a dummy function, return no value')

dummy()
This is a dummy function, return no value

Return Multiple Value

Multiple value is returned as tuple. Use multiple assignment to assign to multiple variable

In [ ]:
def minmax(x,y,z):
    return min(x,y,z), max(x,y,z)

a,b = minmax(7,8,9)     # multiple assignment
c   = minmax(7,8,9)     # tuple

print (a,b)
print (c)    

Passing Function as Argument

You can pass a function name as an argument to a function

In [121]:
def myfun(x,y,f):
    f(x,y)

myfun('hello',54,print)
hello 54

Arguments

args is a tuple

Example 1

Error example, too many parameters passed over to function

In [197]:
def myfun(x,y):
    print (x)
    print (y)
    print (z)
    
myfun(1,2,3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-197-baa9bece46e7> in <module>()
      4     print (z)
      5 
----> 6 myfun(1,2,3)

TypeError: myfun() takes 2 positional arguments but 3 were given

Example 2

First argument goes to x, remaining goes to args as tuple

In [109]:
def myfun(x,*args):
    print (x)
    print (args)     #tuple
    
myfun(1,2,3,4,5,'abc')
1
(2, 3, 4, 5, 'abc')

Example 3

First argument goes to x, second argument goest to y, remaining goes to args

In [185]:
def myfun(x,y,*args):
    print (x)
    print (y)
    print (args)     #tuple
    
myfun(1,2,3)
1
2
(3,)

Example 4

In [198]:
def myfun(x,*args, y=9):
    print (x)
    print (y)
    print (args)     #tuple
    
myfun(1,2,3,4,5)
1
9
(2, 3, 4, 5)

Example 5

All goes to args

In [188]:
def myfun(*args):
    print (args)     #tuple
    
myfun(1,2,3,4,5)
(1, 2, 3, 4, 5)

Example 6 Empty args

In [200]:
def myfun(x,y,*args):
    print (x)
    print (y)
    print (args)
    
myfun(1,2)
1
2
()

keyword arguments

kwargs is a dictionary

Example 1

In [211]:
def foo(**kwargs):
    print(kwargs)
    
foo(a=1,b=2,c=3)
{'a': 1, 'b': 2, 'c': 3}

Example 2

In [202]:
def foo(x,**kwargs):
    print(x)
    print(kwargs)
    
foo(9,a=1,b=2,c=3)
9
{'a': 1, 'b': 2, 'c': 3}
In [204]:
foo(9) #empty dictionary
9
{}

Example 3

In [217]:
def foo(a,b,c,d=1):
    print(a)
    print(b)
    print(c)
    print(d)
    
foo(**{"a":2,"b":3,"c":4})
2
3
4
1

Mixing *args, **kwargs

Always put args before kwargs

Example 1

In [210]:
def foo(x,y=1,**kwargs):
    print (x)
    print (y)
    print (kwargs)
    
foo(1,2,c=3,d=4)
1
2
{'c': 3, 'd': 4}

Example 2

In [212]:
def foo(x,y=2,*args,**kwargs):
    print (x)
    print (y)
    print (args)
    print (kwargs)
    
foo(1,2,3,4,5,c=6,d=7)
1
2
(3, 4, 5)
{'c': 6, 'd': 7}

Object Oriented Programming

Defining Class

  • Every function within a class must have at least one parameter - self, accept it
  • Use init as the constructor function. init is optional
In [ ]:
class Person:
    wallet = 0  # 
    def __init__(self, myname,money=0):   # constructor
        self.name = myname
        self.wallet=money
    def say_hi(self):
        print('Hello, my name is : ', self.name)
    def say_bye(self):
        print('Goodbye', Person.ID)
    def take(self,amount):
        self.wallet+=amount
    def balance(self):
        print('Wallet Balance:',self.wallet)

Object Class Assignment

In [ ]:
#p = Person() ## this will fail, as the constructor expect a parameter
p1 = Person('Yong')  
p2 = Person('Gan',200)

Calling Method

In [ ]:
p1.say_hi()
p1.balance()
In [ ]:
p2.say_hi()
p2.balance()

Getting Property

In [ ]:
p1.wallet
In [ ]:
p2.wallet

Setting Property

In [ ]:
p1.wallet = 900
p1.wallet

Decorator

Definition

  • Decorator is a function that accept callable as the only argument
  • The main purpose of decarator is to enhance the program of the decorated function
  • It returns a callable

Examples

Example 1 - Plain decorator function

  • Many times, it is useful to register a function elsewhere - for example, registering a task in a task runner, or a functin with signal handler
  • register is a decarator, it accept decorated as the only argument
  • foo() and bar() are the decorated function of register
In [8]:
registry = []

def register(decorated):
    registry.append(decorated)
    return decorated

@register
def foo():
    return 3

@register
def bar():
    return 5
In [4]:
registry
Out[4]:
[<function __main__.foo>, <function __main__.bar>]
In [11]:
registry[0]()
Out[11]:
3
In [12]:
registry[1]()
Out[12]:
5

Example 2 - Decorator with Class

  • Extending the use case above
  • register is the decarator, it has only one argument
In [103]:
class Registry(object):
    def __init__(self):
        self._functions = []
    def register(self,decorated):
        self._functions.append(decorated)
        return decorated
    def run_all(self,*args,**kwargs):
        return_values = []
        for func in self._functions:
            return_values.append(func(*args,**kwargs))
        return return_values

The decorator will decorate two functions, for both object a and b

In [104]:
a = Registry()
b = Registry()

@a.register
def foo(x=3):
    return x

@b.register
def bar(x=5):
    return x

@a.register
@b.register
def bax(x=7):
    return x

Observe the result

In [108]:
print (a._functions)
print (b._functions)
[<function foo at 0x000002AB7B6C6BF8>, <function bax at 0x000002AB7B6C80D0>]
[<function bar at 0x000002AB7B6C6C80>, <function bax at 0x000002AB7B6C80D0>]
In [105]:
print (a.run_all())
print (b.run_all())
[3, 7]
[5, 7]
In [ ]:
 
In [106]:
print ( a.run_all(x=9) )
print ( b.run_all(x=9) )
[9, 9]
[9, 9]

datetime Standard Library

This is a built-in library by Python. There is no need to install this library.

ISO8601

https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators

Date Time

UTC: "2007-04-05T14:30Z" #notice Z GMT+8: "2007-04-05T12:30+08:00 #notice +08:00 GMT+8: "2007-04-05T12:30+0800 #notice +0800 GMT+8: "2007-04-05T12:30+08 #notice +08

Date

2019-02-04 #notice no timezone available

Module Import

In [176]:
from datetime import date     # module for date object
from datetime import time     # module for time object
from datetime import datetime # module for datetime object
from datetime import timedelta

Class

datetime library contain three class of objects:

  • date (year,month,day)
  • time (hour,minute,second)
  • datetime (year,month,day,hour,minute,second)
  • timedelta: duration between two datetime or date object

date

Constructor

In [177]:
print( date(2000,1,1) )
print( date(year=2000,month=1,day=1) )
print( type(date(year=2000,month=1,day=1)))
2000-01-01
2000-01-01
<class 'datetime.date'>

Class Method

today

This is local date (not UTC)

In [39]:
date.today()
Out[39]:
datetime.date(2019, 2, 5)
In [40]:
print( date.today() )
2019-02-05

Convert From ISO fromisoformat

strptime is not available for date conversion. It is only for datetime conversion

In [13]:
date.fromisoformat('2011-11-11')
Out[13]:
datetime.date(2011, 11, 11)

To convert non-iso format date string to date object, convert to datetime first, then to date

Instance Method

replace()

  • Replace year/month/day with specified parameter, non specified params will remain unchange.
  • Example below change only month. You can change year or day in combination
In [9]:
print( date.today() )
print( date.today().replace(month=8) )
2019-02-05
2019-08-05

weekday(), isoweekday()

For weekday(), Zero being Monday
For isoweekday(), Zero being Sunday

In [106]:
print( date.today().weekday() )
print( date.today().isoweekday() )
1
2
In [61]:
weekdays = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
wd = date.today().weekday()
print( date.today(), "is day", wd ,"which is", weekdays[wd] )
2019-02-05 is day 1 which is Tue

Formating with isoformat()

isoformat() return ISO 8601 String (YYYY-MM-DD)

In [12]:
date.today().isoformat() # return string
Out[12]:
'2019-02-05'

Formating with strftime

For complete directive, see below:
https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior

In [17]:
date.today().strftime("%m/%d")
Out[17]:
'02/05'

isocalendar()

isocalendar return a 3-tuple, (ISO year, ISO week number, ISO weekday).

In [179]:
date.today().isocalendar() ## return tuple 
Out[179]:
(2019, 23, 1)

Attributes

In [105]:
print( date.today().year )
print( date.today().month )
print( date.today().day )
2019
2
5

datetime

Constructor

In [185]:
print( datetime(2000,1,1,0,0,0))
print( datetime(year=2000,month=1,day=1,hour=23,minute=15,second=55))
print(type(datetime(2000,1,1,0,0,0)))
2000-01-01 00:00:00
2000-01-01 23:15:55
<class 'datetime.datetime'>

Class Method

now and today

Both now() and today() return current local datetime

In [65]:
datetime.now()
Out[65]:
datetime.datetime(2019, 2, 5, 0, 58, 6, 627911)
In [66]:
datetime.today()
Out[66]:
datetime.datetime(2019, 2, 5, 0, 58, 9, 154960)

utcnow

In [112]:
datetime.utcnow()
Out[112]:
datetime.datetime(2019, 2, 4, 17, 55, 59, 797875)

combine() date and time

Apply datetime.combine() module method on both date and time object to get datetime

In [187]:
now = datetime.now()
datetime.combine(now.date(), now.time())
Out[187]:
datetime.datetime(2019, 6, 3, 23, 1, 30, 179182)

Convert from String strptime()

Use strptime to convert string into datetime object

%I : 12-hour
%H : 24-hour
%M : Minute
%p : AM/PM
%y : 18
%Y : 2018
%b : Mar
%m : month (1 to 12)
%d : day
In [117]:
datetime.strptime('2011-02-25','%Y-%m-%d')
Out[117]:
datetime.datetime(2011, 2, 25, 0, 0)
In [81]:
datetime.strptime('9-01-18','%d-%m-%y')
Out[81]:
datetime.datetime(2018, 1, 9, 0, 0)
In [78]:
datetime.strptime('09-Mar-2018','%d-%b-%Y')
Out[78]:
datetime.datetime(2018, 3, 9, 0, 0)
In [79]:
datetime.strptime('2/5/2018 4:49 PM', '%m/%d/%Y %I:%M %p')
Out[79]:
datetime.datetime(2018, 2, 5, 16, 49)

Convert from ISO fromisoformat

  • fromisoformat() is intend to be reverse of isoformat()
  • It actually not ISO compliance: when Z or +8 is included at the nd of the string, error occur
In [9]:
s = datetime.now().isoformat()
datetime.fromisoformat("2019-02-05T10:22:33")
Out[9]:
datetime.datetime(2019, 2, 5, 10, 22, 33)

Instance Method

weekday

In [24]:
datetime.now().weekday()
Out[24]:
1

replace

In [25]:
datetime.now().replace(year=1999)
Out[25]:
datetime.datetime(1999, 2, 5, 9, 42, 34, 38400)

convert to .time()

In [34]:
datetime.now().time()
Out[34]:
datetime.time(9, 52, 47, 719398)

Convert to .date()

In [44]:
datetime.now().date()
Out[44]:
datetime.date(2019, 2, 5)

Convert to String

str

In [17]:
str( datetime.now() )
Out[17]:
'2019-02-05 15:10:11.093005'

Use strftime()

In [22]:
datetime.now().strftime('%d-%b-%Y')
Out[22]:
'05-Feb-2019'
In [24]:
datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ')  ## ISO 8601 UTC
Out[24]:
'2019-02-05T07:13:54.691364Z'

Use isoformat()

In [53]:
datetime.utcnow().isoformat()
Out[53]:
'2019-02-05T02:29:11.607484'

Attributes

In [22]:
print( datetime.now().year )
print( datetime.now().month )
print( datetime.now().day )
print( datetime.now().hour )
print( datetime.now().minute )
2019
2
5
9
41

time

Constructor

In [124]:
print( time(2) )    #default single arugement, hour
print( time(2,15) ) #default two arguments, hour, minute
print( time(hour=2,minute=15,second=30) )
02:00:00
02:15:00
02:15:30

Class Method

now()

There is unfortunately no single function to extract the current time. Use time() function of an datetime object

In [33]:
datetime.now().time()
Out[33]:
datetime.time(9, 52, 3, 374617)

Attributes

In [36]:
print( datetime.now().time().hour )
print( datetime.now().time().minute )
print( datetime.now().time().second )
9
54
16

timedelta

  • years argument is not supported
  • Apply timedelta on datetime object
  • timedelta cannot be applied on time object , because timedelta potentially go beyond single day (24H)
In [188]:
delt = timedelta(days=365,minutes=33,seconds=15)
In [189]:
now = datetime.now()
print ('delt+now : ', now+delt)
delt+now :  2020-06-02 23:39:00.392096

Getting External Data

Webscraping using request & BeautifulSoup4

Use webscraping technique only if API is not available

Library

In [190]:
import requests
from bs4 import BeautifulSoup
In [191]:
url = "https://www.epicurious.com/search/tofu%20chill"
res = requests.get(url)
if (res.status_code == 200):
    soup = BeautifulSoup(res.content,'lxml')
    print (soup.prettify())
else:
    print('Failure')
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8"/>
  <meta content="app-id=312101965" name="apple-itunes-app"/>
  <title>
   Search | Epicurious.com
  </title>
  <link href="//assets.adobedtm.com" rel="dns-prefetch"/>
  <link href="https://www.google-analytics.com" rel="dns-prefetch"/>
  <link href="//tpc.googlesyndication.com" rel="dns-prefetch"/>
  <link href="//static.parsely.com" rel="dns-prefetch"/>
  <link href="//condenast.demdex.net" rel="dns-prefetch"/>
  <link href="//capture.condenastdigital.com" rel="dns-prefetch"/>
  <link href="//pixel.condenastdigital.com" rel="dns-prefetch"/>
  <link href="//use.typekit.net" rel="dns-prefetch"/>
  <link href="//fonts.typekit.net" rel="dns-prefetch"/>
  <link href="//p.typekit.net" rel="dns-prefetch"/>
  <link href="//assets.epicurious.com" rel="dns-prefetch"/>
  <link href="//ad.doubleclick.net" rel="dns-prefetch"/>
  <link href="//pagead2.googlesyndication.com" rel="dns-prefetch"/>
  <link href="//z.moatads.com" rel="dns-prefetch"/>
  <meta content="en_US" itemprop="inLanguage" property="og:locale"/>
  <meta content="IE=edge" http-equiv="x-ua-compatible"/>
  <meta content="no-cache" http-equiv="cache-control"/>
  <meta content="no-cache" http-equiv="pragma"/>
  <meta content="Search | Epicurious.com" itemprop="name"/>
  <meta content="https://www.epicurious.com/static/img/misc/epicurious-social-logo.png" itemprop="logo"/>
  <meta content="Easily search and browse more than 37,000 recipes, articles, galleries, menus, and videos from Epicurious.com, Bon Appétit, and other partners." name="description"/>
  <meta content="Epicurious" itemprop="author"/>
  <link href="https://www.epicurious.com/search/tofu%20chill" rel="canonical"/>
  <meta content="Copyright (c) 2019 Conde Nast" name="copyright"/>
  <meta content="9c2002da922784afad64b638161c75f7" name="p:domain_verify"/>
  <meta content="Search | Epicurious.com" property="og:title"/>
  <meta content="website" property="og:type"/>
  <meta content="https://www.epicurious.com/search/tofu%20chill" property="og:url"/>
  <meta content="Easily search and browse more than 37,000 recipes, articles, galleries, menus, and videos from Epicurious.com, Bon Appétit, and other partners." property="og:description"/>
  <meta content="https://www.epicurious.com/static/img/misc/epicurious-social-logo.png" property="og:image"/>
  <meta content="Epicurious" property="og:site_name"/>
  <meta content="1636080783276430" property="fb:app_id"/>
  <meta content="722582662" property="fb:admins"/>
  <meta content="774348857" property="fb:admins"/>
  <meta content="596666898" property="fb:admins"/>
  <meta content="837402" property="fb:admins"/>
  <meta content="685417657" property="fb:admins"/>
  <meta content="22500087" property="fb:admins"/>
  <meta content="1107036618" property="fb:admins"/>
  <meta content="1045857449" property="fb:admins"/>
  <meta content="14601235" property="fb:admins"/>
  <link href="https://plus.google.com/106968200752753566855" rel="publisher"/>
  <link href="/static/img/favicon.png" rel="icon" type="image/png"/>
  <meta content="#f93f23" name="theme-color"/>
  <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
  <!-- metadataTags end -->
  <script>
   var EPI = EPI || {
        barCnsCrtPage: false,
        onCompleteActions: []
    };

    document.onreadystatechange = function () {
        if (document.readyState === 'complete') {
            EPI.onCompleteActions.forEach(function (callback) {
                if (typeof callback === 'function') {
                    callback();
                }
            });

            if (window.location.search.substr(1).indexOf('ui-regression-test=true') >= 0) {
                console.log('ui-regression-test-ready');
            }
        }
    };

    <!-- https://github.com/filamentgroup/loadJS -->
    !function(a){var b=function(b,c){"use strict";var d=a.document.getElementsByTagName("script")[0],e=a.document.createElement("script");return e.src=b,e.async=!0,d.parentNode.insertBefore(e,d),c&&"function"==typeof c&&(e.onload=c),e};"undefined"!=typeof module?module.exports=b:a.loadJS=b}("undefined"!=typeof global?global:this);    // loadCSS
    (function(h){var d=function(d,e,n){function k(a){if(b.body)return a();setTimeout(function(){k(a)})}function f(){a.addEventListener&&a.removeEventListener("load",f);a.media=n||"all"}var b=h.document,a=b.createElement("link"),c;if(e)c=e;else{var l=(b.body||b.getElementsByTagName("head")[0]).childNodes;c=l[l.length-1]}var m=b.styleSheets;a.rel="stylesheet";a.href=d;a.media="only x";k(function(){c.parentNode.insertBefore(a,e?c:c.nextSibling)});var g=function(b){for(var c=a.href,d=m.length;d--;)if(m[d].href===
    c)return b();setTimeout(function(){g(b)})};a.addEventListener&&a.addEventListener("load",f);a.onloadcssdefined=g;g(f);return a};"undefined"!==typeof exports?exports.loadCSS=d:h.loadCSS=d})("undefined"!==typeof global?global:this);
    
    (function(a){if(a.loadCSS){var b=loadCSS.relpreload={};b.support=function(){try{return a.document.createElement("link").relList.supports("preload")}catch(b){return!1}};b.poly=function(){for(var b=a.document.getElementsByTagName("link"),d=0;d<b.length;d++){var c=b[d];"preload"===c.rel&&"style"===c.getAttribute("as")&&(a.loadCSS(c.href,c),c.rel=null)}};if(!b.support()){b.poly();var e=a.setInterval(b.poly,300);a.addEventListener&&a.addEventListener("load",function(){a.clearInterval(e)});a.attachEvent&&
    a.attachEvent("onload",function(){a.clearInterval(e)})}}})(this);
  </script>
  <link as="style" href="https://use.typekit.net/zpl6zji.css" onload="this.rel='stylesheet'" rel="preload" type="text/css"/>
  <style>
   @font-face{src:url("/static/fonts/renner/renner-thin.woff2") format("woff2"),url("/static/fonts/renner/renner-thin.woff") format("woff");font-family:'Renner';font-weight:100;font-style:normal}@font-face{src:url("/static/fonts/renner/renner-thinitalic.woff2") format("woff2"),url("/static/fonts/renner/renner-thinitalic.woff") format("woff");font-family:'Renner';font-weight:100;font-style:italic}@font-face{src:url("/static/fonts/renner/renner-light.woff2") format("woff2"),url("/static/fonts/renner/renner-light.woff") format("woff");font-family:'Renner';font-weight:200;font-style:normal}@font-face{src:url("/static/fonts/renner/renner-lightitalic.woff2") format("woff2"),url("/static/fonts/renner/renner-lightitalic.woff") format("woff");font-family:'Renner';font-weight:200;font-style:italic}@font-face{src:url("/static/fonts/renner/renner-book.woff2") format("woff2"),url("/static/fonts/renner/renner-book.woff") format("woff");font-family:'Renner';font-weight:300;font-style:normal}@font-face{src:url("/static/fonts/renner/renner-bookitalic.woff2") format("woff2"),url("/static/fonts/renner/renner-bookitalic.woff") format("woff");font-family:'Renner';font-weight:300;font-style:italic}@font-face{src:url("/static/fonts/renner/renner-medium.woff2") format("woff2"),url("/static/fonts/renner/renner-medium.woff") format("woff");font-family:'Renner';font-weight:500;font-style:normal}@font-face{src:url("/static/fonts/renner/renner-mediumitalic.woff2") format("woff2"),url("/static/fonts/renner/renner-mediumitalic.woff") format("woff");font-family:'Renner';font-weight:500;font-style:italic}@font-face{src:url("/static/fonts/renner/renner-bold.woff2") format("woff2"),url("/static/fonts/renner/renner-bold.woff") format("woff");font-family:'Renner';font-weight:bold;font-style:normal}@font-face{src:url("/static/fonts/renner/renner-boldtalic.woff2") format("woff2"),url("/static/fonts/renner/renner-boldtalic.woff") format("woff");font-family:'Renner';font-weight:bold;font-style:italic}@font-face{src:url("/static/fonts/renner/renner-black.woff2") format("woff2"),url("/static/fonts/renner/renner-black.woff") format("woff");font-family:'Renner';font-weight:800;font-style:normal}@font-face{src:url("/static/fonts/renner/renner-blackitalic.woff2") format("woff2"),url("/static/fonts/renner/renner-blackitalic.woff") format("woff");font-family:'Renner';font-weight:800;font-style:italic}@font-face{src:url("/static/fonts/source-serif-pro/source-serif-pro-regular.woff2") format("woff2"),url("/static/fonts/source-serif-pro/source-serif-pro-regular.woff") format("woff");font-family:'Source Serif Pro';font-weight:normal;font-style:normal}@font-face{src:url("/static/fonts/source-serif-pro/source-serif-pro-semibold.woff2") format("woff2"),url("/static/fonts/source-serif-pro/source-serif-pro-semibold.woff") format("woff");font-family:'Source Serif Pro';font-weight:600;font-style:normal}@font-face{src:url("/static/fonts/source-serif-pro/source-serif-pro-bold.woff2") format("woff2"),url("/static/fonts/source-serif-pro/source-serif-pro-bold.woff") format("woff");font-family:'Source Serif Pro';font-weight:bold;font-style:normal}header[role="banner"]{font-family:"Renner",sans-serif;font-weight:bold}[class$="-flash-message"]{font-family:"Source Serif Pro",serif;font-style:italic;font-weight:normal}.icon-share{background-image:url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%22-64%20741%20128%20102%22%3E%3Cpath%20d%3D%22M37%20813.7v19.5h-88.7v-63.4h19.6l13.6-11.8H-64v87H49.4v-43.2zm-11.7-19.8s-54.7-14.2-69.4%2034.6c0%200-5.3-69.9%2069.4-69.9V741L64%20775.8l-38.7%2036v-17.9z%22%2F%3E%3C%2Fsvg%3E");background-repeat:no-repeat}footer[role="contentinfo"] .corporate-info .conde-nast-brands .nav-title:after{background-repeat:no-repeat;background-size:contain;height:1em;width:.7em}footer[role="contentinfo"] .corporate-info .conde-nast-brands .nav-title:after{content:"";display:inline-block;position:relative;top:1px;vertical-align:baseline}footer[role="contentinfo"] .corporate-info .conde-nast-brands .nav-title:after{background-position:100% 0%;margin-left:.5rem}footer[role="contentinfo"] .corporate-info .conde-nast-brands .nav-title:after{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNzAgMTAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik03MCA1MC44NTlMMCAwbDIxLjU4IDUwLjg1OUwwIDEwMHoiIGZpbGw9IiNDQ0MiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==")}footer[role="contentinfo"] .corporate-info>.section-title,.homepage-content-channel-link,.lightreg-dialog fieldset legend,header[role="banner"] .epicurious-logo,footer[role="contentinfo"] .epicurious-links .epi-social-links .nav-title,.main-navigation .facebook-social-channel-link,.branding .facebook-social-channel-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .facebook-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .feed-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .googleplus-link,header[role="banner"] .show-main-navigation:hover,header[role="banner"] .show-main-navigation,header[role="banner"] .show-search-button:hover,.search-dialog-form [type="submit"]:hover,header[role="banner"] .show-search-button,.search-dialog-form [type="submit"],.user-status[data-user-type="anonymous"] .recipebox-status:hover,.user-status[data-user-type="anonymous"] .recipebox-status,.user-status[data-user-type="authenticated"] .recipebox-status,.main-navigation .instagram-social-channel-link,.branding .instagram-social-channel-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .instagram-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .pinterest-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .tumblr-link,.main-navigation .twitter-social-channel-link,.branding .twitter-social-channel-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .twitter-link,.search-dialog-form [type="reset"]:hover,[class$="-form"] .close-button,.search-dialog-form [type="reset"],.dismiss-main-navigation:hover,[class$="-comment-form"] .close-button,.dismiss-main-navigation,footer[role="contentinfo"] .epicurious-links .epi-social-links .youtube-link{background-color:transparent;background-position:50% 50%;background-repeat:no-repeat;background-size:contain}footer[role="contentinfo"] .corporate-info>.section-title{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjUwIDM2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xOC41IDMzLjRjLTEuMyAxLjMtMy4zIDIuMS01LjIgMi4yLTYuMyAwLTcuNy01LjQtNy43LTEyLjdzMS4zLTEyLjcgNy42LTEyLjdjMiAwIDMuOC45IDUuMSAyLjJsMy40IDZoLjJ2LTguM2gtLjJsLTMuMyAxLjdjLTEtLjgtMi44LTIuMS01LjMtMi4xQzcuMSA5LjcgMCAxNC41IDAgMjIuOVM3IDM2IDEzLjMgMzZjMi40IDAgNC41LTEuMyA1LjQtMi4xbDMuNCAxLjdoLjJWMjdoLS4ybC0zLjYgNi40ek0zOC45IDkuN0MzMyA5LjcgMjYgMTQuOSAyNiAyMi45UzMzIDM2IDM4LjkgMzZzMTIuOC01LjEgMTIuOC0xMy4xLTctMTMuMi0xMi44LTEzLjJ6bTAgMjUuOGMtNiAwLTcuMy01LTcuMy0xMi42czEuNC0xMi43IDcuMy0xMi43YzYgMCA3LjMgNS4xIDcuMyAxMi43cy0xLjQgMTIuNi03LjMgMTIuNnpNNzIuMyAxMC42aDMuMnYxNi4xaC0uMUw2NC4yIDEwLjJoLTkuN3YuNGgzLjJ2MjQuNWgtMy4ydi40aDYuOXYtLjRoLTMuMlYxMC42aC4xTDc1LjggMzZoLjJWMTAuNmgzLjJ2LS40aC02Ljl6TTkyLjggMTAuMkg4MnYuNGgzLjF2MjQuNUg4MnYuNGgxMC45YzUuNCAwIDE0LjctMi40IDE0LjctMTIuOHMtOS4zLTEyLjUtMTQuOC0xMi41em0tLjEgMjQuOUg5MFYxMC42aDIuN2M2LjQgMCA5LjMgNC42IDkuMyAxMi4zLjEgNy43LTIuOSAxMi4yLTkuMyAxMi4yek0xMjcuNyAzNS4xaC05LjN2LTEzaDQuN2MxLjUgMS4zIDMuMyA0LjkgMy4zIDQuOWguMlYxNi44aC0uMnMtMS44IDMuNy0zLjMgNC45aC00LjdWMTAuNmg4LjNjMi40IDEuNiA0LjUgNi40IDQuNSA2LjRoLjJ2LTYuOGgtMjEuMXYuNGgzLjF2MjQuNWgtMy4xdi40aDIxLjhWMjdoLS4ycy0yLjEgNS43LTQuMiA4LjF6TTEyNy4zIDQuOGwtLjctMS43LjYtMy0uMi0uMS03LjcgNi42di4yek0xNzcuNCAxMC4yaC03di40aDMuM3YxNi4xaC0uMWwtMTEuMy0xNi41aC05LjZ2LjRoMy4ydjI0LjVoLTMuMnYuNGg2Ljl2LS40aC0zLjJWMTAuNmguMUwxNzQgMzZoLjJWMTAuNmgzLjJ6TTE5MC42IDkuM2gtLjJsLTEwLjYgMjUuOGgtMi45di40aDYuNnYtLjRoLTMuMWw0LTkuN2g4bDQuMiA5LjdoLTMuMnYuNGgxMS41di0uNEgyMDJMMTkwLjYgOS4zem0tNi4xIDE1LjhsMy43LTkuMSAzLjkgOS4xaC03LjZ6TTIxOSAyMC43bC00LjgtMS43Yy0yLjQtLjgtNC40LTIuMS00LjQtNC41IDAtMi44IDIuMS00LjMgNS4zLTQuMyAyIDAgMy4zLjYgNC40IDEuN2wzLjUgNS45aC4ydi04aC0uMmwtMy4zIDEuN2MtLjgtLjctMi4yLTEuNy00LjYtMS43LTQuNyAwLTcuNyAzLjEtNy44IDcuNiAwIDMuNiAyLjQgNS40IDUuMiA2LjVsNC45IDEuOGMyLjYgMSA0LjQgMi4xIDQuNCA0LjggMCAyLjUtMS42IDUuMS01LjkgNS4xLTIgMC00LjMtLjktNS42LTIuMmwtMy43LTYuNWgtLjJsLjIgOC44aC4ybDMuNC0xLjhjMSAuOSAzLjQgMi4yIDUuOCAyLjIgNS4zIDAgOC44LTMuOSA4LjgtOC4yLjEtNC4zLTIuOC02LjItNS44LTcuMnpNMjI3LjMgMTAuMnY3LjloLjJzMi4zLTUgNC40LTcuNWg0LjN2MjQuNWgtMy44di40SDI0NXYtLjRoLTMuOFYxMC42aDQuM2MyLjEgMi40IDQuNCA3LjUgNC40IDcuNWguMnYtNy45aC0yMi44eiIgZmlsbD0iI2ExYTFhMSIvPjwvc3ZnPg==")}.homepage-content-channel-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjU2IDI1NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxjaXJjbGUgZmlsbD0iI0ZGRiIgY3g9IjEyOCIgY3k9IjEyOCIgcj0iMTE5Ii8+PHBhdGggZD0iTTY4LjQgOTVjLTYuNiAwLTExLjQgMTcuOC05IDM0LjJsMTguNi01YzAtMTUuOC0yLjgtMjkuMi05LjYtMjkuMnptNzMuOSA1LjNjLTIuOSAwLTUuMi45LTcuMSAyLjRWMTUzYzEuMiAxLjcgMy4yIDMgNi4yIDMgNy40IDAgMTMuMi03LjkgMTMuMi0yOSAwLTE0LjItMi42LTI2LjctMTIuMy0yNi43ek0xMjggMEM1Ny4zIDAgMCA1Ny4zIDAgMTI4YzAgNzAuNiA1Ny4zIDEyOCAxMjggMTI4czEyOC01Ny4zIDEyOC0xMjhTMTk4LjcgMCAxMjggMHptNzMuNiA1Ny45YzcuMSAwIDEyLjkgNS40IDEyLjkgMTEuOSAwIDYuNy01LjggMTEuOS0xMi45IDExLjktNy4xLjEtMTIuOS01LjItMTIuOS0xMS45czUuOC0xMS45IDEyLjktMTEuOXpNMTAyLjQgMTI0bC00MS43IDExLjhjLjkgNC43IDMuNSA5LjEgNy4xIDEyLjEgMy4xIDIuMSA2LjggMy41IDEwLjcgMy41IDEyLjUgMCAyMC43LTEwLjkgMjAuNy0xMC45bDEuOC42YzAgLjEtLjEuMy0uMS40aC4xYy0xLjEgNS43LTkuNCAyNi4xLTM0LjEgMjYuMS05LjYgMC0xNy4zLTMuMS0yMy4yLTguMi05LTcuMy0xNC0xOC45LTE0LTMxLjQgMC0yMS4xIDE0LjMtMzkuNCAzOC41LTM5LjQgMTguOSAwIDMzLjUgMTQuNiAzNC4yIDM1di40em00Ny40IDQzLjNjLTUuNiAwLTEwLjgtMS44LTE0LjUtNC45djM2LjNoLTI2LjZsLjEtMTA4LjdoMjUuOWwuNiA3YzQuNC01LjIgMTAuNi04LjUgMTcuOS04LjUgMTguNyAwIDI3LjcgMTguMyAyNy43IDM5LjQgMCAyMi44LTEzLjQgMzkuNC0zMS4xIDM5LjR6bTY1LjItMS44aC0yNi43bC4xLTc1LjNIMjE1djc1LjN6IiBmaWxsPSIjRjkzRjIzIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L2c+PC9zdmc+")}.lightreg-dialog fieldset legend,header[role="banner"] .epicurious-logo{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNjEyIDEyOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwLjYgODguOWMtMi44IDAtNC41LTEuMS01LjUtMi44VjQwLjhjMS43LTEuMyAzLjgtMi4yIDYuMy0yLjIgOC43IDAgMTEuMSAxMS4yIDExLjEgMjQuMS0uMSAxOS4xLTUuNCAyNi4yLTExLjkgMjYuMnptMTAuNS02MC43Yy02LjYgMC0xMi4xIDMtMTYuMSA3LjZsLS41LTYuM0g3MS4ybC0uMSA5Ny45aDI0Vjk0LjdjMy4zIDIuOCA4IDQuNCAxMyA0LjQgMTYgMCAyOC0xNSAyOC0zNS41IDAtMTktOC4xLTM1LjQtMjUtMzUuNHptMjY2LjIgMS41aDIzLjl2NjcuOGgtMjMuOVYyOS43ek0zNzEgNDIuM2MwIDcuOS00LjUgMTMuMy0xMS44IDEzLjMtNy4yIDAtMTEtNS4yLTExLTEwLjIgMC0xLjcuNi01IDIuMy03LjUtMy0xLjYtMTEuNCAxLjgtMTQuNCAxMS42djQ4aC0yMy45VjI5LjdoMjMuNUwzMzYgNDFjNC4zLTguMSAxMC44LTEyLjggMTguOS0xMi44IDEwLjUgMCAxNi4xIDYuNiAxNi4xIDE0LjF6bS05Mi4yLTEyLjZoMjMuOXY2Ny44aC0yMy45di0xNWMtMi40IDYuNi04LjIgMTYuNi0yMC41IDE2LjYtMTIuOCAwLTE5LTEwLjEtMTktMjAuOVYzOS41YzAtNS4xLTEuNC03LjYtMy4zLTguNXYtMS4zaDI3LjJ2NDEuNmMwIDEwLjMgNC42IDExIDcuMyAxMSAzLjggMCA2LjYtMy4zIDguMy04VjI5Ljd6TTYxMiA3NS41YzAgMTMuNy0xMi4yIDIzLjQtMjkuNyAyMy40LTkuMiAwLTE4LTQuNi0yMy00LjYtMy42IDAtNC41IDEtNC41IDFsLS44LTE4LjhoMi4xYzkuNiAxMi43IDE2LjIgMTguMyAyNi4xIDE4LjMgNi40IDAgMTEuOC0zLjIgMTEuOC04LjcgMC01LjktNS4zLTcuMy0xMy05LjItMjAuNy01LjMtMjYuNS0xNC4zLTI2LjUtMjYuNCAwLTEzLjQgMTEuNy0yMi41IDI2LjMtMjIuNSA1IDAgOS43IDEgMTMuMyAyLjIgMi4yLjcgOC42IDMuNSAxMi45IDMuMnYxOC4yaC0yQzU5Ni45IDM5LjggNTg5LjkgMzIgNTgxIDMyYy01LjYgMC04LjggMy41LTguOCA4IDAgNS41IDUuMiA3IDE0LjUgOS43IDE2LjggNS4yIDI1LjMgMTEuNyAyNS4zIDI1Ljh6bS04OS4zLTQ1LjhoMjMuOXY2Ny44aC0yMy45di0xNWMtMi40IDYuNi04LjIgMTYuNi0yMC41IDE2LjYtMTIuOCAwLTE5LTEwLjEtMTktMjAuOVYzOS41YzAtNS4xLTEuNC03LjYtMy4zLTguNXYtMS4zaDI3LjJ2NDEuNmMwIDEwLjMgNC42IDExIDcuMyAxMSAzLjggMCA2LjYtMy4zIDguMy04VjI5Ljd6bS04MC43IDY1Yy02LjkgMC05LjQtOS40LTkuNC0zMS4yIDAtMjEuOCAyLjUtMzEuMiA5LjQtMzEuMnM5LjQgOS40IDkuNCAzMS4yYzAgMjEuOC0yLjYgMzEuMi05LjQgMzEuMnptMC02Ni41Yy0yMS42IDAtMzQuMSAxNS44LTM0LjEgMzUuMyAwIDE5LjUgMTIuNSAzNS4zIDM0LjEgMzUuM3MzNC0xNS44IDM0LTM1LjNjMC0xOS41LTEyLjUtMzUuMy0zNC0zNS4zem0tMjk5LjEgMS41aDIzLjl2NjcuOGgtMjMuOVYyOS43em04OSA0NS4zbDEuNS41Yy0xLjcgOS0xMCAyMy41LTI4LjcgMjMuNS0yMS4xIDAtMzEuMi0xNi40LTMxLjItMzUuNCAwLTIwLjQgMTMuNC0zNS41IDMzLjQtMzUuNSAxNC44IDAgMjMuOSA3LjkgMjMuOSAxNi40IDAgNS4yLTMuOSA5LjQtOS43IDkuNC00LjIgMC04LjUtMy45LTguNS04LjcgMC00LjkgMy03LjYgNi41LTguMi0xLjItMi4yLTMuMy0zLjktNy4xLTMuOS02LjUgMC0xMy45IDguMS0xMy45IDI3LjYgMCAxMi44IDYuMiAyNC4xIDE4LjkgMjQuMSAxMC4yIDAgMTQuOS05LjggMTQuOS05Ljh6bTE0NS42LTYzLjdjMC02IDUuMi0xMC44IDExLjctMTAuOCA2LjQgMCAxMS43IDQuOCAxMS43IDEwLjggMCA2LTUuMiAxMC44LTExLjcgMTAuOC02LjUgMC0xMS43LTQuOC0xMS43LTEwLjh6bS0yMzQuNCAwYzAtNiA1LjItMTAuOCAxMS43LTEwLjggNi40IDAgMTEuNyA0LjggMTEuNyAxMC44IDAgNi01LjIgMTAuOC0xMS43IDEwLjgtNi41IDAtMTEuNy00LjgtMTEuNy0xMC44ek0yNi44IDY0LjhDMjQuNyA1MC4xIDI4LjkgMzQgMzQuOSAzNGM2LjEgMCA4LjYgMTIuMSA4LjcgMjYuMmwtMTYuOCA0LjZ6bTcuOC0zNi41QzEyLjkgMjguMyAwIDQ0LjggMCA2My43IDAgNzUgNC41IDg1LjQgMTIuNiA5MmM1LjMgNC42IDEyLjMgNy40IDIwLjkgNy40IDIyLjIgMCAyOS43LTE4LjMgMzAuNy0yMy41aC0uMWMwLS4xIDAtLjIuMS0uM2wtMS41LS41cy03LjQgOS44LTE4LjYgOS44Yy0zLjUgMC02LjgtMS4yLTkuNi0zLjItMy4zLTIuNy01LjYtNi43LTYuNC0xMC45TDY1LjUgNjB2LS4zYy0uOC0xOC4zLTEzLjgtMzEuNC0zMC45LTMxLjR6IiBmaWxsPSIjRUY0MjI5Ii8+PC9zdmc+")}footer[role="contentinfo"] .epicurious-links .epi-social-links .nav-title{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNjEyIDEyOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwLjYgODguOWMtMi44IDAtNC41LTEuMS01LjUtMi44VjQwLjhjMS43LTEuMyAzLjgtMi4yIDYuMy0yLjIgOC43IDAgMTEuMSAxMS4yIDExLjEgMjQuMS0uMSAxOS4xLTUuNCAyNi4yLTExLjkgMjYuMnptMTAuNS02MC43Yy02LjYgMC0xMi4xIDMtMTYuMSA3LjZsLS41LTYuM0g3MS4ybC0uMSA5Ny45aDI0Vjk0LjdjMy4zIDIuOCA4IDQuNCAxMyA0LjQgMTYgMCAyOC0xNSAyOC0zNS41IDAtMTktOC4xLTM1LjQtMjUtMzUuNHptMjY2LjIgMS41aDIzLjl2NjcuOGgtMjMuOVYyOS43ek0zNzEgNDIuM2MwIDcuOS00LjUgMTMuMy0xMS44IDEzLjMtNy4yIDAtMTEtNS4yLTExLTEwLjIgMC0xLjcuNi01IDIuMy03LjUtMy0xLjYtMTEuNCAxLjgtMTQuNCAxMS42djQ4aC0yMy45VjI5LjdoMjMuNUwzMzYgNDFjNC4zLTguMSAxMC44LTEyLjggMTguOS0xMi44IDEwLjUgMCAxNi4xIDYuNiAxNi4xIDE0LjF6bS05Mi4yLTEyLjZoMjMuOXY2Ny44aC0yMy45di0xNWMtMi40IDYuNi04LjIgMTYuNi0yMC41IDE2LjYtMTIuOCAwLTE5LTEwLjEtMTktMjAuOVYzOS41YzAtNS4xLTEuNC03LjYtMy4zLTguNXYtMS4zaDI3LjJ2NDEuNmMwIDEwLjMgNC42IDExIDcuMyAxMSAzLjggMCA2LjYtMy4zIDguMy04VjI5Ljd6TTYxMiA3NS41YzAgMTMuNy0xMi4yIDIzLjQtMjkuNyAyMy40LTkuMiAwLTE4LTQuNi0yMy00LjYtMy42IDAtNC41IDEtNC41IDFsLS44LTE4LjhoMi4xYzkuNiAxMi43IDE2LjIgMTguMyAyNi4xIDE4LjMgNi40IDAgMTEuOC0zLjIgMTEuOC04LjcgMC01LjktNS4zLTcuMy0xMy05LjItMjAuNy01LjMtMjYuNS0xNC4zLTI2LjUtMjYuNCAwLTEzLjQgMTEuNy0yMi41IDI2LjMtMjIuNSA1IDAgOS43IDEgMTMuMyAyLjIgMi4yLjcgOC42IDMuNSAxMi45IDMuMnYxOC4yaC0yQzU5Ni45IDM5LjggNTg5LjkgMzIgNTgxIDMyYy01LjYgMC04LjggMy41LTguOCA4IDAgNS41IDUuMiA3IDE0LjUgOS43IDE2LjggNS4yIDI1LjMgMTEuNyAyNS4zIDI1Ljh6bS04OS4zLTQ1LjhoMjMuOXY2Ny44aC0yMy45di0xNWMtMi40IDYuNi04LjIgMTYuNi0yMC41IDE2LjYtMTIuOCAwLTE5LTEwLjEtMTktMjAuOVYzOS41YzAtNS4xLTEuNC03LjYtMy4zLTguNXYtMS4zaDI3LjJ2NDEuNmMwIDEwLjMgNC42IDExIDcuMyAxMSAzLjggMCA2LjYtMy4zIDguMy04VjI5Ljd6bS04MC43IDY1Yy02LjkgMC05LjQtOS40LTkuNC0zMS4yIDAtMjEuOCAyLjUtMzEuMiA5LjQtMzEuMnM5LjQgOS40IDkuNCAzMS4yYzAgMjEuOC0yLjYgMzEuMi05LjQgMzEuMnptMC02Ni41Yy0yMS42IDAtMzQuMSAxNS44LTM0LjEgMzUuMyAwIDE5LjUgMTIuNSAzNS4zIDM0LjEgMzUuM3MzNC0xNS44IDM0LTM1LjNjMC0xOS41LTEyLjUtMzUuMy0zNC0zNS4zem0tMjk5LjEgMS41aDIzLjl2NjcuOGgtMjMuOVYyOS43em04OSA0NS4zbDEuNS41Yy0xLjcgOS0xMCAyMy41LTI4LjcgMjMuNS0yMS4xIDAtMzEuMi0xNi40LTMxLjItMzUuNCAwLTIwLjQgMTMuNC0zNS41IDMzLjQtMzUuNSAxNC44IDAgMjMuOSA3LjkgMjMuOSAxNi40IDAgNS4yLTMuOSA5LjQtOS43IDkuNC00LjIgMC04LjUtMy45LTguNS04LjcgMC00LjkgMy03LjYgNi41LTguMi0xLjItMi4yLTMuMy0zLjktNy4xLTMuOS02LjUgMC0xMy45IDguMS0xMy45IDI3LjYgMCAxMi44IDYuMiAyNC4xIDE4LjkgMjQuMSAxMC4yIDAgMTQuOS05LjggMTQuOS05Ljh6bTE0NS42LTYzLjdjMC02IDUuMi0xMC44IDExLjctMTAuOCA2LjQgMCAxMS43IDQuOCAxMS43IDEwLjggMCA2LTUuMiAxMC44LTExLjcgMTAuOC02LjUgMC0xMS43LTQuOC0xMS43LTEwLjh6bS0yMzQuNCAwYzAtNiA1LjItMTAuOCAxMS43LTEwLjggNi40IDAgMTEuNyA0LjggMTEuNyAxMC44IDAgNi01LjIgMTAuOC0xMS43IDEwLjgtNi41IDAtMTEuNy00LjgtMTEuNy0xMC44ek0yNi44IDY0LjhDMjQuNyA1MC4xIDI4LjkgMzQgMzQuOSAzNGM2LjEgMCA4LjYgMTIuMSA4LjcgMjYuMmwtMTYuOCA0LjZ6bTcuOC0zNi41QzEyLjkgMjguMyAwIDQ0LjggMCA2My43IDAgNzUgNC41IDg1LjQgMTIuNiA5MmM1LjMgNC42IDEyLjMgNy40IDIwLjkgNy40IDIyLjIgMCAyOS43LTE4LjMgMzAuNy0yMy41aC0uMWMwLS4xIDAtLjIuMS0uM2wtMS41LS41cy03LjQgOS44LTE4LjYgOS44Yy0zLjUgMC02LjgtMS4yLTkuNi0zLjItMy4zLTIuNy01LjYtNi43LTYuNC0xMC45TDY1LjUgNjB2LS4zYy0uOC0xOC4zLTEzLjgtMzEuNC0zMC45LTMxLjR6IiBmaWxsPSIjRkZGRkZGIi8+PC9zdmc+")}.main-navigation .facebook-social-channel-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTM4IDI1NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCAxMzcuMDIyaDM5LjE5M1YyNTZoNDkuMDExVjEzNy4wMjJoNDkuMDEyVjg4LjA5SDg4LjIwNFY2My4yN2MwLTguMjkyIDUuMjU3LTE1LjA1NSA5Ljc5Ni0xNS4wNTVoMzkuMjE2VjBIOThDNjUuNTU3LS4wMTIgMzkuMTkzIDI4LjYwNyAzOS4xOTMgNjMuOTc2Vjg4LjA5SDB2NDguOTMyeiIgZmlsbC1ydWxlPSJub256ZXJvIiBmaWxsPSIjRjkzRjIzIi8+PC9zdmc+")}.branding .facebook-social-channel-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDIgNDIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAyMS4wM0MwIDkuNDM3IDkuMzkyIDAgMjEgMGMxMS42MDcgMCAyMSA5LjQzOCAyMSAyMS4wM0M0MiAzMi42MiAzMi42MDcgNDIgMjEgNDIgOS4zOTIgNDIgMCAzMi42MiAwIDIxLjAzeiIgZmlsbC1ydWxlPSJub256ZXJvIiBmaWxsPSIjRjkzRjIzIi8+PHBhdGggZD0iTTE1LjU1NCAyMS43NDdoMy4xMXY5LjQ0aDMuODl2LTkuNDRoMy44OXYtMy44ODRoLTMuODl2LTEuOTdjMC0uNjU3LjQxOC0xLjE5NC43OC0xLjE5NGgzLjExdi0zLjgyNmgtMy4xMWMtMi41NzYgMC00LjY3IDIuMjctNC42NyA1LjA3OHYxLjkxM2gtMy4xMXYzLjg4M3oiIGZpbGw9IiNGRkYiLz48L2c+PC9zdmc+")}footer[role="contentinfo"] .epicurious-links .epi-social-links .facebook-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii02NCA3MjggMTI4IDEyOCI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTS02NCA3OTJjMC0zNS4yIDI4LjUtNjQgNjQtNjRzNjQgMjguOCA2NCA2NC0yOC41IDY0LTY0IDY0LTY0LTI4LjYtNjQtNjR6bTQ3LjMgMi4xaDkuNHYyOC44SDQuNXYtMjguOGgxMS44di0xMS44SDQuNXYtNi4xYzAtMi4xIDEuMi0zLjYgMi40LTMuNmg5LjR2LTExLjVINi45Yy03LjkgMC0xNC4zIDctMTQuMyAxNS41djUuOGgtOS40bC4xIDExLjd6Ij48L3BhdGg+PC9zdmc+")}footer[role="contentinfo"] .epicurious-links .epi-social-links .feed-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii05NiA2NTMgMTI4IDEyOCI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTS0zMiA2NTNjLTM1LjMgMC02NCAyOC43LTY0IDY0czI4LjcgNjQgNjQgNjQgNjQtMjguNyA2NC02NC0yOC43LTY0LTY0LTY0em0tMjQgOTZjLTQuNCAwLTgtMy42LTgtOHMzLjYtOCA4LTggOCAzLjYgOCA4LTMuNiA4LTggOHptMjIgMGMwLTE2LjUtMTMuNS0zMC0zMC0zMHYtMTJjMjMuMiAwIDQyIDE4LjggNDIgNDJoLTEyem0yNCAwYzAtMTQuNC01LjYtMjgtMTUuOC0zOC4yQy0zNiA3MDAuNi00OS42IDY5NS02NCA2OTV2LTEyYzE3LjYgMCAzNC4yIDYuOSA0Ni43IDE5LjNDLTQuOSA3MTQuOCAyIDczMS40IDIgNzQ5aC0xMnoiPjwvcGF0aD48L3N2Zz4=")}footer[role="contentinfo"] .epicurious-links .epi-social-links .googleplus-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTI4IDEyOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTI4IDY0LjAwMmMuMyAzNS4yLTI4LjUgNjQtNjQgNjRzLTY0LTI4LjgtNjQtNjRjMC0zNS41IDI4LjUtNjMuNyA2NC02NCAzNC45LS4zIDYzLjcgMjguNSA2NCA2NHptLTY5LjUtMTQuNmMwLTUuOC0uNi04LjgtNC45LTEwLjkgMC0xLjUgNy45LS42IDcuOS0zaC0xN3MtMTcuMy4zLTE3LjMgMTQuOWMwIDE0LjkgMTQuOSAxMyAxNC45IDEzdjMuOWMwIDEuNSAyLjEuOSAyLjQgMy45LTEuMiAwLTIwLjktLjYtMjAuOSAxMi40IDAgMTMuMyAxNy42IDEyLjQgMTcuNiAxMi40czIwLjMgMS4yIDIwLjMtMTUuNWMwLTkuNy0xMS41LTEzLTExLjUtMTdzOC41LTUgOC41LTE0LjF6bS0yNy45IDM0Yy0uMy01LjIgNS4yLTkuNyAxMi4xLTEwLjMgNy0uMyAxMyAzLjMgMTMuNiA4LjUuMyA1LjItNS4yIDkuNy0xMi4xIDEwLTcuMi45LTEzLjMtMy0xMy42LTguMnptOS40LTQ0LjljNC4yLTEuMiA4LjggMi40IDEwLjYgOC41IDEuNSA1LjgtLjYgMTEuNS00LjkgMTIuNC00LjIgMS4yLTguOC0yLjctMTAuNi04LjUtMS40LTUuNy43LTExLjIgNC45LTEyLjR6bTM3LjMgMjIuMnYtMTEuMkg3NHYxMS4ySDYzLjF2My4zSDc0djExLjJoMy4zdi0xMS4yaDEwLjl2LTMuM0g3Ny4zem0yMS45LTkuMXYyNy45aDUuMnYtMzkuMWgtMy45Yy0uNiAzLTEuOCA0LjktMy4zIDUuOC0xLjUuNi0zLjkgMS41LTcuNiAxLjh2My42aDkuNnoiIGZpbGwtcnVsZT0ibm9uemVybyIgZmlsbD0iI0ZGRiIvPjwvc3ZnPg==")}header[role="banner"] .show-main-navigation:hover{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjUgMTgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iIzMzMyIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwaDI1djJIMHpNMCA4aDI1djJIMHpNMCAxNmgyNXYySDB6Ii8+PC9nPjwvc3ZnPg==")}header[role="banner"] .show-main-navigation{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjUgMTgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI0ExQTFBMSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwaDI1djJIMHpNMCA4aDI1djJIMHpNMCAxNmgyNXYySDB6Ii8+PC9nPjwvc3ZnPg==")}header[role="banner"] .show-search-button:hover,.search-dialog-form [type="submit"]:hover{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDIgNDIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTQwLjgxIDM1LjMybC05Ljk4Ni05Ljk4NWExNi4yNiAxNi4yNiAwIDAgMCAyLjM3My04LjQ4NUMzMy4xOTcgNy44MjIgMjUuMzc0IDAgMTYuMzQ1IDAgNy4zMiAwIDAgNy4zMiAwIDE2LjM0N2MwIDkuMDI4IDcuODIyIDE2Ljg1IDE2Ljg1IDE2Ljg1IDMgMCA1LjgxMi0uODE0IDguMjMtMi4yMjZsMTAuMDM3IDEwLjA0YTIuNTE0IDIuNTE0IDAgMCAwIDMuNTU3IDBsMi40OS0yLjQ5Yy45ODMtLjk4Mi42MjctMi4yMi0uMzU1LTMuMnpNNS4wMyAxNi4zNDZjMC02LjI1IDUuMDY3LTExLjMxNyAxMS4zMTUtMTEuMzE3IDYuMjUgMCAxMS44MiA1LjU3IDExLjgyIDExLjgyUzIzLjEgMjguMTY3IDE2Ljg1IDI4LjE2N2MtNi4yNSAwLTExLjgyLTUuNTctMTEuODItMTEuODJ6IiBmaWxsPSIjMzMzIi8+PC9zdmc+")}header[role="banner"] .show-search-button,.search-dialog-form [type="submit"]{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDIgNDIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTQwLjgxIDM1LjMybC05Ljk4Ni05Ljk4NWExNi4yNiAxNi4yNiAwIDAgMCAyLjM3My04LjQ4NUMzMy4xOTcgNy44MjIgMjUuMzc0IDAgMTYuMzQ1IDAgNy4zMiAwIDAgNy4zMiAwIDE2LjM0N2MwIDkuMDI4IDcuODIyIDE2Ljg1IDE2Ljg1IDE2Ljg1IDMgMCA1LjgxMi0uODE0IDguMjMtMi4yMjZsMTAuMDM3IDEwLjA0YTIuNTE0IDIuNTE0IDAgMCAwIDMuNTU3IDBsMi40OS0yLjQ5Yy45ODMtLjk4Mi42MjctMi4yMi0uMzU1LTMuMnpNNS4wMyAxNi4zNDZjMC02LjI1IDUuMDY3LTExLjMxNyAxMS4zMTUtMTEuMzE3IDYuMjUgMCAxMS44MiA1LjU3IDExLjgyIDExLjgyUzIzLjEgMjguMTY3IDE2Ljg1IDI4LjE2N2MtNi4yNSAwLTExLjgyLTUuNTctMTEuODItMTEuODJ6IiBmaWxsPSIjYTFhMWExIi8+PC9zdmc+")}.user-status[data-user-type="anonymous"] .recipebox-status:hover{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDIgNDIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxwYXRoIGQ9Ik0zNS44MjQgMS4xNThDMzAuNDc0LTEuNzM0IDIzLjQ3Ni45ODggMjEgNy4yMjYgMTguNTI0Ljk4NyAxMS41MjYtMS43MzcgNi4xNzYgMS4xNTkuNDc3IDQuMjUtMi4yNDggMTIuMTM4IDIuMjUzIDIxLjQ0MyA1LjQ0OSAyOC4wNjcgMTEuMTE1IDMzLjA1NiAyMSA0Mi4wMDFjOS44ODUtOC45NDUgMTUuNTUxLTEzLjkzOSAxOC43NDctMjAuNTU5IDQuNTAxLTkuMzA0IDEuNzc2LTE3LjE5NC0zLjkyMy0yMC4yODR6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIGZpbGw9Im5vbmUiPjx1c2UgZmlsbD0iIzMzMyIgZmlsbC1ydWxlPSJldmVub2RkIiB4bGluazpocmVmPSIjYSIvPjxwYXRoIHN0cm9rZT0iMzMzIiBkPSJNMjEgNDEuMzI2Yy05LjczMy04LjgxLTEyLjA3OC0xMS4wNzUtMTQuODcxLTE0LjY1OS0xLjQxLTEuODA3LTIuNTI1LTMuNTc1LTMuNDI2LTUuNDQxQy0xLjM5OCAxMi43NDYuNDcyIDQuODIgNi40MTQgMS41OTljNS4xMy0yLjc3NyAxMS43NzUtLjEgMTQuMTIxIDUuODExTDIxIDguNTgxbC40NjUtMS4xN2MyLjM0NS01LjkxIDguOTktOC41ODcgMTQuMTIxLTUuODEzIDUuOTQyIDMuMjIyIDcuODEyIDExLjE0OCAzLjcxIDE5LjYyNi0uODk4IDEuODYxLTIuMDEgMy42MjQtMy40MTMgNS40MjctMi43OTYgMy41OS01LjE2NCA1Ljg3OC0xNC44ODMgMTQuNjc1eiIvPjwvZz48L3N2Zz4=")}.user-status[data-user-type="anonymous"] .recipebox-status{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDIgNDIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxwYXRoIGQ9Ik0zNS44MjQgMS4xNThDMzAuNDc0LTEuNzM0IDIzLjQ3Ni45ODggMjEgNy4yMjYgMTguNTI0Ljk4NyAxMS41MjYtMS43MzcgNi4xNzYgMS4xNTkuNDc3IDQuMjUtMi4yNDggMTIuMTM4IDIuMjUzIDIxLjQ0MyA1LjQ0OSAyOC4wNjcgMTEuMTE1IDMzLjA1NiAyMSA0Mi4wMDFjOS44ODUtOC45NDUgMTUuNTUxLTEzLjkzOSAxOC43NDctMjAuNTU5IDQuNTAxLTkuMzA0IDEuNzc2LTE3LjE5NC0zLjkyMy0yMC4yODR6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIGZpbGw9Im5vbmUiPjx1c2UgZmlsbD0iI2ExYTFhMSIgZmlsbC1ydWxlPSJldmVub2RkIiB4bGluazpocmVmPSIjYSIvPjxwYXRoIHN0cm9rZT0iI2ExYTFhMSIgZD0iTTIxIDQxLjMyNmMtOS43MzMtOC44MS0xMi4wNzgtMTEuMDc1LTE0Ljg3MS0xNC42NTktMS40MS0xLjgwNy0yLjUyNS0zLjU3NS0zLjQyNi01LjQ0MUMtMS4zOTggMTIuNzQ2LjQ3MiA0LjgyIDYuNDE0IDEuNTk5YzUuMTMtMi43NzcgMTEuNzc1LS4xIDE0LjEyMSA1LjgxMUwyMSA4LjU4MWwuNDY1LTEuMTdjMi4zNDUtNS45MSA4Ljk5LTguNTg3IDE0LjEyMS01LjgxMyA1Ljk0MiAzLjIyMiA3LjgxMiAxMS4xNDggMy43MSAxOS42MjYtLjg5OCAxLjg2MS0yLjAxIDMuNjI0LTMuNDEzIDUuNDI3LTIuNzk2IDMuNTktNS4xNjQgNS44NzgtMTQuODgzIDE0LjY3NXoiLz48L2c+PC9zdmc+")}.user-status[data-user-type="authenticated"] .recipebox-status{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDIgNDIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxwYXRoIGQ9Ik0zNS44MjQgMS4xNThDMzAuNDc0LTEuNzM0IDIzLjQ3Ni45ODggMjEgNy4yMjYgMTguNTI0Ljk4NyAxMS41MjYtMS43MzcgNi4xNzYgMS4xNTkuNDc3IDQuMjUtMi4yNDggMTIuMTM4IDIuMjUzIDIxLjQ0MyA1LjQ0OSAyOC4wNjcgMTEuMTE1IDMzLjA1NiAyMSA0Mi4wMDFjOS44ODUtOC45NDUgMTUuNTUxLTEzLjkzOSAxOC43NDctMjAuNTU5IDQuNTAxLTkuMzA0IDEuNzc2LTE3LjE5NC0zLjkyMy0yMC4yODR6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIGZpbGw9Im5vbmUiPjx1c2UgZmlsbD0iI0Y5M0YyMyIgZmlsbC1ydWxlPSJldmVub2RkIiB4bGluazpocmVmPSIjYSIvPjxwYXRoIHN0cm9rZT0iI0Y5M0YyMyIgZD0iTTIxIDQxLjMyNmMtOS43MzMtOC44MS0xMi4wNzgtMTEuMDc1LTE0Ljg3MS0xNC42NTktMS40MS0xLjgwNy0yLjUyNS0zLjU3NS0zLjQyNi01LjQ0MUMtMS4zOTggMTIuNzQ2LjQ3MiA0LjgyIDYuNDE0IDEuNTk5YzUuMTMtMi43NzcgMTEuNzc1LS4xIDE0LjEyMSA1LjgxMUwyMSA4LjU4MWwuNDY1LTEuMTdjMi4zNDUtNS45MSA4Ljk5LTguNTg3IDE0LjEyMS01LjgxMyA1Ljk0MiAzLjIyMiA3LjgxMiAxMS4xNDggMy43MSAxOS42MjYtLjg5OCAxLjg2MS0yLjAxIDMuNjI0LTMuNDEzIDUuNDI3LTIuNzk2IDMuNTktNS4xNjQgNS44NzgtMTQuODgzIDE0LjY3NXoiLz48L2c+PC9zdmc+")}.main-navigation .instagram-social-channel-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjU2IDI1NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRjkzRjIzIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0xMjguMzQ5Ljg0N2MtMzQuNjMgMC0zOC45NzQuMTQ3LTUyLjU4My43NjgtMTMuNTY2LjYxLTIyLjgzIDIuNzY1LTMwLjkyOSA1LjkyYTYyLjQxNSA2Mi40MTUgMCAwIDAtMjIuNiAxNC43MDIgNjIuNDE1IDYyLjQxNSAwIDAgMC0xNC43MDIgMjIuNjFjLTMuMTU1IDguMDg4LTUuMzEgMTcuMzUzLTUuOTEgMzAuOTJDLjk4NCA4OS4zNzQuODQ3IDkzLjcxNy44NDcgMTI4LjM0OGMwIDM0LjYzLjE0NyAzOC45NzQuNzY4IDUyLjU4Mi42MSAxMy41NjcgMi43NjUgMjIuODMyIDUuOTIgMzAuOTMgMy4yNiA4LjM5MSA3LjYxNCAxNS41MTEgMTQuNzAyIDIyLjZhNjIuNDE1IDYyLjQxNSAwIDAgMCAyMi42IDE0LjcwMWM4LjA5OCAzLjE1NSAxNy4zNzQgNS4zMTEgMzAuOTQgNS45MjEgMTMuNTk4LjYzMSAxNy45NDEuNzY4IDUyLjU3Mi43NjggMzQuNjMgMCAzOC45NzQtLjE0NyA1Mi41ODItLjc2OCAxMy41NjctLjYxIDIyLjgzMi0yLjc2NiAzMC45My01LjkyYTYyLjQxNSA2Mi40MTUgMCAwIDAgMjIuNi0xNC43MDMgNjIuNDE1IDYyLjQxNSAwIDAgMCAxNC43MDEtMjIuNmMzLjE1NS04LjA5NyA1LjMxMS0xNy4zNzMgNS45MjEtMzAuOTQuNjMxLTEzLjU5Ny43NjgtMTcuOTQuNzY4LTUyLjU3MSAwLTM0LjYzLS4xNDctMzguOTc0LS43NjgtNTIuNTgzLS42MS0xMy41NjYtMi43NjYtMjIuODMtNS45Mi0zMC45MjlhNjIuNDE1IDYyLjQxNSAwIDAgMC0xNC43MDMtMjIuNiA2Mi40MTUgNjIuNDE1IDAgMCAwLTIyLjYtMTQuNzAyYy04LjA5Ny0zLjE1NS0xNy4zNjItNS4zMS0zMC45MjktNS45MUMxNjcuMzIzLjk4NCAxNjIuOTguODQ3IDEyOC4zNS44NDdtMCAyMi45NjhjMzQuMDQyIDAgMzguMDcuMTI2IDUxLjUzLjc0NyAxMi40Mi41NjggMTkuMTcyIDIuNjUgMjMuNjYzIDQuMzk2IDUuOTUyIDIuMzEzIDEwLjIgNS4wNjggMTQuNjcgOS41MjcgNC40NiA0LjQ3IDcuMjE1IDguNzE5IDkuNTI4IDE0LjY2IDEuNzQ2IDQuNTAyIDMuODI4IDExLjI1MyA0LjM5NiAyMy42NzMuNjIgMTMuNDYxLjczNiAxNy40NzguNzM2IDUxLjUzIDAgMzQuMDQzLS4xMTUgMzguMDctLjczNiA1MS41MzItLjU2OCAxMi40Mi0yLjY1IDE5LjE3MS00LjM5NiAyMy42NjItMi4zMTMgNS45NTItNS4wNjkgMTAuMi05LjUyOCAxNC42N2EzOS40NjggMzkuNDY4IDAgMCAxLTE0LjY2IDkuNTI4Yy00LjUgMS43NDYtMTEuMjUyIDMuODI4LTIzLjY3MiA0LjM5Ni0xMy40NS42Mi0xNy40NzkuNzM2LTUxLjUzMS43MzYtMzQuMDUzIDAtMzguMDgtLjExNS01MS41My0uNzM2LTEyLjQyLS41NjgtMTkuMTcyLTIuNjUtMjMuNjYzLTQuMzk2YTM5LjQ2OCAzOS40NjggMCAwIDEtMTQuNjctOS41MjggMzkuNDY4IDM5LjQ2OCAwIDAgMS05LjUyOC0xNC42NmMtMS43NDYtNC41LTMuODI4LTExLjI1Mi00LjM5Ni0yMy42NzItLjYyLTEzLjQ2MS0uNzM3LTE3LjQ5LS43MzctNTEuNTMxIDAtMzQuMDUzLjExNi0zOC4wNy43MzctNTEuNTMuNTY4LTEyLjQyIDIuNjUtMTkuMTcyIDQuMzk2LTIzLjY2MyAyLjMxMy01Ljk1MiA1LjA2OC0xMC4yMDEgOS41MjctMTQuNjdhMzkuNDY4IDM5LjQ2OCAwIDAgMSAxNC42NzEtOS41MThjNC41MDEtMS43NDYgMTEuMjUzLTMuODI4IDIzLjY3My00LjM5NiAxMy40Ni0uNjIgMTcuNDg5LS43MzYgNTEuNTMtLjczNiIvPjxwYXRoIGQ9Ik0xMjQuNTE0IDE2NS43MzJhNDEuMjI5IDQxLjIyOSAwIDEgMSAwLTgyLjQ0N2MyMi41MTQuMzU0IDQwLjU4IDE4LjcwNiA0MC41OCA0MS4yMjQgMCAyMi41MTctMTguMDY2IDQwLjg3LTQwLjU4IDQxLjIyM20wLTEwNC43MjVhNjMuNTE2IDYzLjUxNiAwIDEgMCAwIDEyNy4wMjNjMzQuNzYyLS40NCA2Mi43MTEtMjguNzQ2IDYyLjcxMS02My41MTFzLTI3Ljk0OS02My4wNzEtNjIuNzExLTYzLjUxMiIvPjwvZz48L3N2Zz4=")}.branding .instagram-social-channel-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjUgMjUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbC1ydWxlPSJub256ZXJvIiBmaWxsPSJub25lIj48cGF0aCBkPSJNMjUgMTIuNUMyNSAxOS40MDQgMTkuNDA0IDI1IDEyLjUgMjUgNS41OTcgMjUgMCAxOS40MDQgMCAxMi41UzUuNTk2IDAgMTIuNSAwQzE5LjQwMyAwIDI1IDUuNTk2IDI1IDEyLjUiIGZpbGw9IiNGOTNGMjMiLz48ZyBmaWxsPSIjRkZGIj48cGF0aCBkPSJNMTIuNTk2IDUuNzY0Yy0xLjc2IDAtMS45OC4wMDgtMi42NzEuMDQtLjY5LjAzNC0xLjE2MS4xNDctMS41NzMuMzE0LS40MzUuMTctLjgyOC40MzYtMS4xNDguNzc3YTMuMzIgMy4zMiAwIDAgMC0uNzQ3IDEuMTkzYy0uMTYuNDI4LS4yNy45MTgtLjMwMSAxLjYzNS0uMDMyLjcxOC0uMDQuOTQ4LS4wNCAyLjc3NyAwIDEuODMuMDA4IDIuMDU5LjA0IDIuNzc3LjAzMS43MTcuMTQgMS4yMDcuMzAxIDEuNjM1LjE2Ni40NDMuMzg3LjgxOS43NDcgMS4xOTMuMzYuMzc1LjcyMi42MDUgMS4xNDguNzc3LjQxMi4xNjcuODgzLjI4IDEuNTczLjMxMy42OS4wMzMuOTEyLjA0IDIuNjcxLjA0IDEuNzYgMCAxLjk4LS4wMDcgMi42NzItLjA0LjY5LS4wMzIgMS4xNi0uMTQ2IDEuNTcyLS4zMTMuNDM1LS4xNy44MjgtLjQzNiAxLjE0OC0uNzc3LjM2LS4zNzQuNTgyLS43NS43NDctMS4xOTMuMTYtLjQyOC4yNy0uOTE4LjMwMi0xLjYzNS4wMzEtLjcxOC4wMzgtLjk0OC4wMzgtMi43NzcgMC0xLjgzLS4wMDctMi4wNTktLjAzOC0yLjc3Ny0uMDMyLS43MTctLjE0MS0xLjIwNy0uMzAyLTEuNjM1YTMuMzEzIDMuMzEzIDAgMCAwLS43NDctMS4xOTMgMy4xNjIgMy4xNjIgMCAwIDAtMS4xNDgtLjc3N2MtLjQxMi0uMTY3LS44ODMtLjI4LTEuNTcyLS4zMTMtLjY5MS0uMDMzLS45MTItLjA0LTIuNjcyLS4wNG0wIDEuMjEzYzEuNzMgMCAxLjkzNS4wMDcgMi42MTkuMDQuNjMxLjAyOS45NzQuMTQgMS4yMDMuMjMxYTIgMiAwIDAgMSAuNzQ0LjUwNGMuMjI3LjIzNi4zNjcuNDYuNDg1Ljc3NC4wODkuMjM4LjE5NS41OTQuMjIzIDEuMjUxLjAzMi43MS4wMzguOTIzLjAzOCAyLjcyMiAwIDEuNzk4LS4wMDYgMi4wMTEtLjAzOCAyLjcyMi0uMDI4LjY1Ny0uMTM0IDEuMDEzLS4yMjMgMS4yNS0uMTAzLjI5LS4yNjguNTU2LS40ODUuNzc1YTIgMiAwIDAgMS0uNzQ0LjUwNGMtLjIyOS4wOTItLjU3Mi4yMDItMS4yMDMuMjMyLS42ODQuMDMyLS44ODguMDM5LTIuNjE5LjAzOS0xLjczIDAtMS45MzUtLjAwNy0yLjYxOC0uMDQtLjYzMi0uMDI5LS45NzUtLjE0LTEuMjAzLS4yMzFhMiAyIDAgMCAxLS43NDUtLjUwNCAyLjA5NSAyLjA5NSAwIDAgMS0uNDg0LS43NzRjLS4wOS0uMjM4LS4xOTUtLjU5NC0uMjI0LTEuMjUxLS4wMzEtLjcxLS4wMzgtLjkyNC0uMDM4LTIuNzIyIDAtMS43OTkuMDA3LTIuMDExLjAzOC0yLjcyMi4wMjktLjY1Ny4xMzUtMS4wMTMuMjI0LTEuMjUuMTE3LS4zMTUuMjU3LS41NC40ODQtLjc3NWEyIDIgMCAwIDEgLjc0NS0uNTA0Yy4yMjgtLjA5Mi41NzEtLjIwMiAxLjIwMy0uMjMyLjY4My0uMDMyLjg4OC0uMDM5IDIuNjE4LS4wMzkiLz48cGF0aCBkPSJNMTIuNTk2IDE0Ljc0NWMtMS4xOTIgMC0yLjE2LTEuMDA1LTIuMTYtMi4yNDUgMC0xLjI0Ljk2OC0yLjI0NSAyLjE2LTIuMjQ1IDEuMTkzIDAgMi4xNiAxLjAwNSAyLjE2IDIuMjQ1IDAgMS4yNC0uOTY3IDIuMjQ1LTIuMTYgMi4yNDVtMC01LjcwNGMtMS44MzcgMC0zLjMyNyAxLjU0OS0zLjMyNyAzLjQ1OSAwIDEuOTEgMS40OSAzLjQ1OSAzLjMyNyAzLjQ1OSAxLjgzOCAwIDMuMzI3LTEuNTQ5IDMuMzI3LTMuNDU5IDAtMS45MS0xLjQ5LTMuNDU5LTMuMzI3LTMuNDU5bTQuMjM2LS4xMzdjMCAuNDQ3LS4zNDguODA5LS43NzcuODA5LS40MyAwLS43NzgtLjM2Mi0uNzc4LS44MDkgMC0uNDQ2LjM0OC0uODA4Ljc3OC0uODA4LjQzIDAgLjc3Ny4zNjIuNzc3LjgwOCIvPjwvZz48L2c+PC9zdmc+")}footer[role="contentinfo"] .epicurious-links .epi-social-links .instagram-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii02NCA3MjggMTI4IDEyOCI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTExLjIgNzc4LjR2LTYuOGMwLTEuMyAxLTIuMyAyLjMtMi4zaDYuOGMxLjMgMCAyLjMgMS4xIDIuMyAyLjN2Ni44YzAgMS4zLTEgMi4zLTIuMyAyLjNoLTYuOGMtMS4zIDAtMi4zLTEuMS0yLjMtMi4zek02NCA3OTJjMCAzNS4zLTI4LjcgNjQtNjQgNjRzLTY0LTI4LjctNjQtNjQgMjguNy02NCA2NC02NCA2NCAyOC43IDY0IDY0em0tMzQuNi0yMi43YzAtMy44LTMtNi44LTYuOC02LjhoLTQ1LjNjLTMuOCAwLTYuOCAzLTYuOCA2Ljh2NDUuM2MwIDMuOCAzIDYuOCA2LjggNi44aDQ1LjNjMy43IDAgNi44LTMuMSA2LjgtNi44di00NS4zek0tLjEgODAzLjJjNi4yIDAgMTEuMy01LjEgMTEuMy0xMS4zLjEtNi4yLTUtMTEuMy0xMS4zLTExLjNzLTExLjMgNS4xLTExLjMgMTEuM2MwIDYuMyA1LjEgMTEuMyAxMS4zIDExLjN6bTE3LjYtMTUuOGMuNCAxLjQuNiAzIC42IDQuNSAwIDEwLTguMSAxOC4xLTE4LjEgMTguMXMtMTguMS04LjEtMTguMS0xOC4xYzAtMS42LjItMy4xLjYtNC41aC01LjF2MjQuOWMwIDEuMiAxIDIuMyAyLjMgMi4zaDQwLjhjMS4zIDAgMi4zLTEgMi4zLTIuM3YtMjQuOWgtNS4zeiI+PC9wYXRoPjwvc3ZnPg==")}footer[role="contentinfo"] .epicurious-links .epi-social-links .pinterest-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii02NCA3MjggMTI4IDEyOCI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTTY0IDc5MmMwIDM1LjUtMjguNSA2NC02NCA2NHMtNjQtMjguNS02NC02NCAyOC41LTY0IDY0LTY0YzM1LjIgMCA2NCAyOC41IDY0IDY0em0tMzcuMy0xM2MtMS4yLTEwLTEwLjMtMTguOC0yMS4yLTIwLTE3LTIuMS0zMi4yIDguNS0zMi41IDI0LjkgMCA3LjkgMi40IDEyLjcgOS40IDE1LjUgNC45LTQuOS0uOS03LjYtMS41LTEzLTEuNS0xNCAxNC45LTI3LjMgMjkuNC0xOC41IDEwLjMgNi4xIDguNSAzMS44LTMuOSAzNC4zLTIuNC4zLTUuOC0uMy02LjctMS41LTYuMS01LjggNC45LTE1LjIgMS4yLTIzLjQtMy03LTExLjUtMS41LTEyLjQgNC45LS42IDMuMyAxLjIgNi40IDEuMiA5LjQgMCA2LjctNC4yIDE2LjEtNS4yIDIyLjctLjYgMi43LS45IDguMi0uMyAxMC45aC0uMyA0LjVjMy01LjIgNS4yLTEzLjMgNi43LTIwLjMgMS4yLS42IDEuNSAxLjIgMi4xIDEuOCA1LjggNC4yIDE2LjEgMS44IDIwLjYtMi4xIDcuMS01LjMgOS44LTE2LjggOC45LTI1LjZ6Ij48L3BhdGg+PC9zdmc+")}footer[role="contentinfo"] .epicurious-links .epi-social-links .tumblr-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii02NCA3MjggMTI4IDEyOCI+PHBhdGggZmlsbD0iI2ZmZmZmZiIgZD0iTS42IDcyOGM4LjggMCAxNyAxLjggMjQuNiA1LjIgNy42IDMuNCAxNC4zIDcuOSAyMCAxMy43IDUuOCA1LjggMTAuMyAxMi41IDEzLjYgMjAuNCAzLjMgNy42IDUuMiAxNS44IDUuMiAyNC43IDAgOC44LTEuOCAxNy40LTUuMiAyNS0zLjMgNy45LTcuOSAxNC42LTEzLjYgMjAuNC01LjggNS44LTEyLjcgMTAuNC0yMC4zIDEzLjdDMTcgODU0LjUgOC44IDg1NiAwIDg1NnMtMTcuMy0xLjUtMjQuOS00LjljLTcuOS0zLTE0LjktNy42LTIwLjYtMTMuNHMtMTAuMy0xMi44LTEzLjYtMjAuNGMtMy4zLTcuOS00LjktMTYuMi00LjktMjVzMS41LTE3LjEgNC45LTI0LjdjMy4zLTcuNiA3LjktMTQuNiAxMy42LTIwLjRzMTIuNC0xMC40IDIwLjMtMTMuN2M3LjYtMy43IDE1LjgtNS41IDI0LjYtNS41SC42em0tMTYuNyA1OS43aDd2MThjMCAyLjQuMyA0LjMuNiA1LjIuMyAxLjIgMS4yIDIuMSAyLjQgMy40IDEuNSAxLjIgMyAyLjEgNC41IDIuNC45LjMgMS44LjMgMi40LjYuNi4zIDEuOC4zIDMgLjMgMi4xIDAgMy45LS4zIDUuOC0uNiAxLjgtLjYgMy45LTEuMiA1LjgtMi4xVjgwN2MtMi40IDEuNS00LjkgMi40LTcuNiAyLjQtMS44IDAtMy0uMy0zLjktLjktLjktLjYtMS41LTEuMi0yLjEtMi4xLS4zLS42LS4zLTIuNC0uMy01LjV2LTEzLjFoMTEuOHYtOS4xSDEuNVY3NjdoLTdjLS4zIDIuNy0uOSA0LjktMS44IDYuNC0uOSAxLjgtMi4xIDMuNC0zLjMgNC4zLS42LjYtMS41IDEuMi0yLjcgMS41LS45LjYtMi4xLjktMyAxLjJsLjIgNy4zeiI+PC9wYXRoPjwvc3ZnPg==")}.main-navigation .twitter-social-channel-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzE0IDI1NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzE0IDMwLjc5M2ExNDMuMzc3IDE0My4zNzcgMCAwIDEtMTguMTAyIDUuODgxYy02LjA1MyAxLjUwNi0xMi4zODcgMi44NTctMTkuMDAzIDQuMDY3IDYuNjE2LTQuMjIxIDEyLjM1OS05LjM0MyAxNy4yMDEtMTUuMzggNC44MjgtNi4wMzYgOC43NDEtMTIuNjY0IDExLjc2OC0xOS44OTZhMTg2OS4zNyAxODY5LjM3IDAgMCAxLTIwLjM2OSA5LjA0NyA4OS45MzEgODkuOTMxIDAgMCAxLTIyLjE1NiA2LjMzMiA1NS4zNiA1NS4zNiAwIDAgMC0xOS45MTgtMTUuMzhBNjEuOTEzIDYxLjkxMyAwIDAgMCAyMTcuMTgzLjAwNmMtMTcuNDk3IDAtMzIuNTg2IDYuMzMyLTQ1LjI1NSAxOS4wMS0xMi42NjkgMTIuNjUtMTkuMDAzIDI4LjA0NC0xOS4wMDMgNDYuMTExIDAgMy42My41OTEgOC40NyAxLjgxNiAxNC40OTMtMjcuMTQtMS4yMS01Mi4wNC03LjgyMy03NC42Ni0xOS44OTZhMTkwLjc5IDE5MC43OSAwIDAgMS01OC4zNjEtNDcuOTQgNjguNjE4IDY4LjYxOCAwIDAgMC04LjE1IDMyLjU0NmMwIDI0LjEzMiA5LjM2IDQxLjkzMiAyOC4wNTQgNTMuMzcyLTEwLjg1MyAwLTIwLjUxLTIuMzkyLTI4Ljk1NS03LjI0N3YuOTE1YzAgMTUuNjg5IDQuODI4IDI5LjQwOCAxNC40ODQgNDEuMTcyIDkuNjI4IDExLjczNSAyMS43MDYgMTkuMTM2IDM2LjE5IDIyLjE2MWE1NS45MDIgNTUuOTAyIDAgMCAxLTcuNjg1IDEuMzM3Yy0zLjE1Ni4zMzYtNi4zMjguNDktOS41MDIuNDY1LTIuNDIgMC02LjAzOS0uNTc3LTEwLjg2Ny0xLjgwMiAzLjYxOCAxMi42NSAxMC44NjcgMjMuMjE4IDIxLjcyIDMxLjY2IDEwLjg1MyA4LjQ0MyAyMy41MjIgMTIuOTYgMzguMDA2IDEzLjU2NS0yMi45MyAxOC4wOTUtNDkuNDY0IDI3LjE0My03OS42MyAyNy4xNDNIMGExNzkuODI4IDE3OS44MjggMCAwIDAgNDYuMTU2IDIxLjI0N0M2My4wMiAyNTMuNDUzIDgwLjUzMSAyNTYgOTguNjMzIDI1NmMyOS41NiAwIDU1Ljc5OC01LjU3MiA3OC43MjgtMTYuNzE2IDIyLjkzLTExLjE1OSA0Mi4wODktMjUuNDY5IDU3LjQ2LTQyLjk4N2ExODIuMDY1IDE4Mi4wNjUgMCAwIDAgMzQuODUzLTU4Ljc5YzcuODEyLTIxLjY5NyAxMS43NTMtNDMuNDIzIDExLjc1My02NS4xMlY2NC4yNGExMjkuOTEgMTI5LjkxIDAgMCAwIDE4LjEwMy0xNS44M2M1LjQxOS01LjcyNyAxMC4yNDctMTEuNjA5IDE0LjQ3LTE3LjYzMSIgZmlsbD0iI0Y5M0YyMyIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+")}.branding .twitter-social-channel-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTI4IDEyOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0xMjggNjRjMCAzNS41LTI4LjUgNjQtNjQgNjQtMzUuMiAwLTY0LTI4LjgtNjQtNjRDMCAyOC41IDI4LjggMCA2NCAwYzM1LjUgMCA2NCAyOC41IDY0IDY0eiIgZmlsbC1ydWxlPSJub256ZXJvIiBmaWxsPSIjRjkzRjIzIi8+PHBhdGggZD0iTTkxLjMgNDcuNmMyLjctMS41IDQuNS00LjIgNS44LTctMi40IDEuMi01LjUgMi40LTguNSAzLTIuMS0yLjQtNS41LTQuMi05LjQtNC4yLTcgMC0xMyA1LjgtMTMgMTMgMCAuOS4zIDIuMS4zIDMtMTAuOS0uNi0yMC4zLTUuOC0yNi43LTEzLjYtMS4yIDIuMS0xLjUgNC4yLTEuNSA2LjcgMCA0LjUgMi4xIDguNSA1LjggMTAuNi0yLjEgMC00LjItLjYtNS44LTEuNXYuM2MwIDYuMSA0LjIgMTEuNSAxMC4zIDEyLjctLjkuMy0yLjEuMy0zLjMuMy0uNiAwLTEuNS0uMy0yLjEtLjMgMS41IDUuMiA2LjEgOC44IDEyLjEgOS4xLTQuMiAzLjMtMTAgNS41LTE2LjEgNS41aC0zQzQyIDg4LjggNDguNiA5MSA1NS45IDkxYzI0IDAgMzYuNy0xOS43IDM2LjctMzd2LTEuNWMyLjQtMS44IDQuOS00LjIgNi43LTYuNy0zLjEuNi01LjMgMS41LTggMS44eiIgZmlsbD0iI0ZGRiIvPjwvZz48L3N2Zz4=")}footer[role="contentinfo"] .epicurious-links .epi-social-links .twitter-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTI4IDEyOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTI4IDY0YzAgMzUuNS0yOC41IDY0LTY0IDY0LTM1LjIgMC02NC0yOC44LTY0LTY0QzAgMjguNSAyOC44IDAgNjQgMGMzNS41IDAgNjQgMjguNSA2NCA2NHpNOTEuMyA0Ny42YzIuNy0xLjUgNC41LTQuMiA1LjgtNy0yLjQgMS4yLTUuNSAyLjQtOC41IDMtMi4xLTIuNC01LjUtNC4yLTkuNC00LjItNyAwLTEzIDUuOC0xMyAxMyAwIC45LjMgMi4xLjMgMy0xMC45LS42LTIwLjMtNS44LTI2LjctMTMuNi0xLjIgMi4xLTEuNSA0LjItMS41IDYuNyAwIDQuNSAyLjEgOC41IDUuOCAxMC42LTIuMSAwLTQuMi0uNi01LjgtMS41di4zYzAgNi4xIDQuMiAxMS41IDEwLjMgMTIuNy0uOS4zLTIuMS4zLTMuMy4zLS42IDAtMS41LS4zLTIuMS0uMyAxLjUgNS4yIDYuMSA4LjggMTIuMSA5LjEtNC4yIDMuMy0xMCA1LjUtMTYuMSA1LjVoLTNDNDIgODguOCA0OC42IDkxIDU1LjkgOTFjMjQgMCAzNi43LTE5LjcgMzYuNy0zN3YtMS41YzIuNC0xLjggNC45LTQuMiA2LjctNi43LTMuMS42LTUuMyAxLjUtOCAxLjh6IiBmaWxsLXJ1bGU9Im5vbnplcm8iIGZpbGw9IiNGRkYiLz48L3N2Zz4=")}.search-dialog-form [type="reset"]:hover{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjUgMjUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iIzMzMyI+PHBhdGggZD0iTTIyLjI0NCAwTDI1IDIuNzU2IDIuNzU2IDI1IDAgMjIuMjQ0IDIyLjI0NCAweiIvPjxwYXRoIGQ9Ik0yLjc1NSAwTDI1IDIyLjI0NSAyMi4yNDMgMjUgMCAyLjc1NSAyLjc1NSAweiIvPjwvZz48L3N2Zz4=")}[class$="-form"] .close-button,.search-dialog-form [type="reset"],.dismiss-main-navigation:hover,[class$="-comment-form"] .close-button{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjUgMjUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI0ExQTFBMSI+PHBhdGggZD0iTTIyLjI0NCAwTDI1IDIuNzU2IDIuNzU2IDI1IDAgMjIuMjQ0IDIyLjI0NCAweiIvPjxwYXRoIGQ9Ik0yLjc1NSAwTDI1IDIyLjI0NSAyMi4yNDMgMjUgMCAyLjc1NSAyLjc1NSAweiIvPjwvZz48L3N2Zz4=")}.dismiss-main-navigation{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjUgMjUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI0NDQyI+PHBhdGggZD0iTTIyLjI0NCAwTDI1IDIuNzU2IDIuNzU2IDI1IDAgMjIuMjQ0IDIyLjI0NCAweiIvPjxwYXRoIGQ9Ik0yLjc1NSAwTDI1IDIyLjI0NSAyMi4yNDMgMjUgMCAyLjc1NSAyLjc1NSAweiIvPjwvZz48L3N2Zz4=")}footer[role="contentinfo"] .epicurious-links .epi-social-links .youtube-link{background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTI4IDEyOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNjQuMDkzIDEyOGMtOC44NjUgMC0xNy4xOC0xLjY2OS0yNC45NDktNS4wMDctNy43NjgtMy4zMzgtMTQuNTY2LTcuODktMjAuMzkzLTEzLjY1NUMxMi45MjUgMTAzLjU3NSA4LjM0IDk2LjgwNSA1LjAwNCA4OS4wNCAxLjY2NiA4MS4yNjUgMCA3Mi45NSAwIDY0LjA5YzAtOC44NjEgMS42NjYtMTcuMTc2IDUuMDA0LTI0Ljk0NCAzLjMzOC03Ljc2OSA3LjkyLTE0LjU2NiAxMy43NDctMjAuMzkzIDUuODI3LTUuODI2IDEyLjYyNS0xMC40MDggMjAuMzkzLTEzLjc0NkM0Ni45MTQgMS42NjkgNTUuMjI4IDAgNjQuMDkzIDBjOC44NTggMCAxNy4xNzMgMS42NjkgMjQuOTQ1IDUuMDA3IDcuNzY4IDMuMzQxIDE0LjUzMyA3LjkyIDIwLjI5OSAxMy43NDYgNS43NjMgNS44MjcgMTAuMzE1IDEyLjYyNCAxMy42NTYgMjAuMzkzQzEyNi4zMyA0Ni45MTQgMTI4IDU1LjIyOSAxMjggNjQuMDljMCA4Ljg2LTEuNjcyIDE3LjE3NS01LjAwNyAyNC45NDYtMy4zNDEgNy43NjktNy44OTMgMTQuNTM2LTEzLjY1NiAyMC4yOTktNS43NjYgNS43NjUtMTIuNTM0IDEwLjMxNy0yMC4zIDEzLjY1NS03Ljc3MSAzLjM0MS0xNi4wODYgNS4wMS0yNC45NDQgNS4wMXpNMzcuNTA2IDcxLjM3NWg0LjU1MnYyMi4yMTNoNC4xODhWNzEuMzc1aDQuNTUydi0zLjY0NEgzNy41MDZ2My42NDR6bTQuMTg4LTM3LjUxbDUuNjQ0IDE3LjI5N3YxMS4yODloNC45MTZWNTAuNjE5bDUuNjQ4LTE2Ljc1NGgtNC45MTZsLTMuMDk5IDExLjQ3MWgtLjE3OWwtMy4yNzctMTEuNDdoLTQuNzM3em0yMS42NyA0MC42MDNoLTMuODIzdjE0LjU2OGMtLjQ5LjQ4Ni0uODUuNzktMS4wOTMuOTA4LS4zNjQuMjQ2LS43MjguMzY3LTEuMDkyLjM2Ny0uNDg2IDAtLjc5Mi0uMDYtLjkxLS4xODUgMC0uMTE4LS4wMzEtLjI3My0uMDkyLS40NTVhMS45MTkgMS45MTkgMCAwIDEtLjA4OC0uNjM1Vjc0LjQ2OEg1Mi40NFY5MC40OWMwIDEuMDkyLjI0MyAxLjk0Mi43MjkgMi41NDkuMzY0LjQ4NiAxLjAzMS43MjggMi4wMDMuNzI4LjcyOCAwIDEuNDU2LS4xODIgMi4xODUtLjU0OS44NDYtLjM2MSAxLjU3OC0uOTY4IDIuMTg4LTEuODJ2Mi4xODdoMy44MjNWNzQuNDY4aC0uMDAzem0tNS4xMDEtMTcuMjk0YzAgMS43MDIuNTUgMy4wOTUgMS42MzkgNC4xODRDNjAuOTk0IDYyLjQ1MSA2Mi41MTIgNjMgNjQuNDU0IDYzYzEuOTQyIDAgMy40NjItLjU1IDQuNTUyLTEuNjQyIDEuMDkyLS44NDYgMS42MzgtMi4yNDIgMS42MzgtNC4xODRWNDYuMjQ2YzAtMS41NzgtLjU0Ni0yLjg0OS0xLjYzOC0zLjgyNi0xLjA5LTEuMDktMi41NS0xLjYzNi00LjM2Ny0xLjYzNi0xLjgyNCAwLTMuMzk5LjQ4Ni00LjczNyAxLjQ1Ny0xLjA5IDEuMDktMS42NCAyLjQyNy0xLjY0IDQuMDAydjEwLjkzem0xNS4yOTUgMTcuMTA5Yy0uODUgMC0xLjQ1NC4xMjQtMS44MjEuMzY3LS43MjguNDg1LTEuMjc1LjkxLTEuNjM5IDEuMjc0di04LjE5M2gtMy44MjR2MjUuODU3aDMuODI0di0xLjQ1NmMuMzY0LjM2LjkxLjc4OSAxLjYzOSAxLjI3NC43MjguMjQzIDEuMzkzLjM2NCAyLjAwMy4zNjQgMS4wOTIgMCAxLjk0Mi0uMzY0IDIuNTQ5LTEuMDkyLjYwNy0uODQ3LjkxLTEuODc4LjkxLTMuMDk1di0xMC41NmMwLTEuNDU3LS4zMDMtMi42NjgtLjkxLTMuNjM5LS43MjgtLjczMS0xLjYzOS0xLjEwMS0yLjczMS0xLjEwMXptLjU0OS0xNS4yOTJjMCAxLjA5LjI0IDIuMDAzLjcyOCAyLjczMi40ODMuNzI1IDEuMjc1IDEuMDg5IDIuMzY0IDEuMDg5LjYwNyAwIDEuMzk2LS4yNDMgMi4zNjctLjcyOC40ODMtLjI0My45NDEtLjUxNiAxLjM2Ni0uODIuNDI1LS4zMDMuODItLjY5OCAxLjE4NC0xLjE4NnYyLjM2N2g0LjM3di0yMS4xMmgtNC4zN3YxNi4wMjJhMy42NCAzLjY0IDAgMCAxLTEuMjc1IDEuMDkyYy0uNjA3LjM2MS0xLjAzMi41NDYtMS4yNzUuNTQ2LS4zNjQgMC0uNjctLjExOC0uOTEtLjM2NC0uMTI0LS4xMjEtLjE4NS0uNDgyLS4xODUtMS4wOTJWNDEuMzI0aC00LjM2N3YxNy42NjdoLjAwM3ptMTYuMzg0IDIwLjU3NWMwLTEuNTc4LS40ODUtMi45NzEtMS40NTMtNC4xODUtLjk3MS0uOTcxLTIuMzEtMS40NTctNC4wMDYtMS40NTctMS43MDMgMC0zLjA5NS41NDctNC4xODggMS42NC0xLjA5MiAxLjA5Mi0xLjYzOSAyLjQyNy0xLjYzOSA0LjAwMnY4LjU1N2MwIDEuNzAyLjQ4MyAzLjE1OSAxLjQ1NyA0LjM2NyAxLjA5IDEuMDk1IDIuNDI1IDEuNjQxIDQuMDAzIDEuNjQxIDEuOTQyIDAgMy4zOTktLjQ4NSA0LjM3LTEuNDU2Ljk2OC0xLjIxIDEuNDUzLTIuNzMxIDEuNDUzLTQuNTUydi0uOTFoLTQuMDAydi45MWMwIDEuMjE0LS4xMjUgMS45NDUtLjM2NSAyLjE4OC0uMjQ1LjI0My0uNjcuMzYxLTEuMjc0LjM2MS0uNzI5IDAtMS4xNTYtLjE4Mi0xLjI3NS0uNTQ2LS4yNDYtLjI0My0uMzY0LS45MS0uMzY0LTIuMDAzdi0zLjYzOGg3LjI4di00LjkyaC4wMDN6bS0yNi4wMzctMjAuMjFjLS42MDcgMC0xLjA5LS4xODItMS40NTQtLjU0Ny0uMjQ2LS40ODItLjM2NC0uOTEtLjM2NC0xLjI3NFY0Ni4wNjdjMC0uNDg1LjE4Mi0uODQ2LjU0Ni0xLjA5Mi4xMjItLjM2NC41NS0uNTUgMS4yNzUtLjU1LjQ4NSAwIC45MTMuMTg2IDEuMjc3LjU1LjM2MS4yNDYuNTQ3LjYwNy41NDcgMS4wOTJ2MTEuNDY4YzAgLjQ4NS0uMTg2LjkxMy0uNTQ3IDEuMjc0LS4zNjcuMzY1LS43OTUuNTQ3LTEuMjguNTQ3em01LjY0NCAxOC41NzRjLjExOS0uMTIxLjI0My0uMjEyLjM2NC0uMjczYTEuNTggMS41OCAwIDAgMCAuMzY1LS4yNzZjLjI0IDAgLjM5MS0uMDI3LjQ1Mi0uMDkxLjA2My0uMDYuMjEtLjA4OC40NTUtLjA4OC40ODIgMCAuODQ3LjE4MiAxLjA5Mi41NDYuMjQuMjQzLjM2NS43MjguMzY1IDEuNDU3djkuODMxYzAgLjcyNi0uMDY0IDEuMTU0LS4xODYgMS4yNzUtLjM2NC4zNjEtLjcyOC41NDYtMS4wOTIuNTQ2LS4yNDMgMC0uMzk1LS4wMy0uNDUyLS4wOS0uMDY0LS4wNjItLjIxMy0uMDkyLS40NTUtLjA5Mi0uMjQzLS4xMTgtLjU0Ny0uMzYxLS45MS0uNzI4Vjc3LjkzaC4wMDJ6bTEzLjQ3Ny0uMTg1Yy4yNC0uMjQzLjY2NS0uMzY0IDEuMjc1LS4zNjQuNjA0IDAgMS4wMjkuMTIxIDEuMjc0LjM2NC4yNC40ODUuMzY1IDEuMDkuMzY1IDEuODJ2MS44MjRIODMuMjF2LTEuODIzYzAtLjk3MS4xMTgtMS41NzguMzY0LTEuODIxeiIgZmlsbD0iI0ZGRiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+")}footer[role="contentinfo"] .corporate-info>.section-title,.lightreg-dialog fieldset legend,header[role="banner"] .epicurious-logo,footer[role="contentinfo"] .epicurious-links .epi-social-links .nav-title,.main-navigation .facebook-social-channel-link,.branding .facebook-social-channel-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .facebook-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .feed-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .googleplus-link,header[role="banner"] .show-main-navigation,header[role="banner"] .show-search-button,.search-dialog-form [type="submit"],.user-status[data-user-type="anonymous"] .recipebox-status:hover,.user-status[data-user-type="anonymous"] .recipebox-status,.user-status[data-user-type="authenticated"] .recipebox-status,.main-navigation .instagram-social-channel-link,.branding .instagram-social-channel-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .instagram-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .pinterest-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .tumblr-link,.main-navigation .twitter-social-channel-link,.branding .twitter-social-channel-link,footer[role="contentinfo"] .epicurious-links .epi-social-links .twitter-link,[class$="-form"] .close-button,.search-dialog-form [type="reset"],.dismiss-main-navigation:hover,[class$="-comment-form"] .close-button,.dismiss-main-navigation,footer[role="contentinfo"] .epicurious-links .epi-social-links .youtube-link{border:none;direction:ltr;display:inline-block;overflow:hidden;padding:0;text-align:left;text-indent:-9999px}footer[role="contentinfo"] .corporate-info>.section-title>a,.lightreg-dialog fieldset legend>a,header[role="banner"] .epicurious-logo>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .nav-title>a,.main-navigation .facebook-social-channel-link>a,.branding .facebook-social-channel-link>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .facebook-link>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .feed-link>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .googleplus-link>a,header[role="banner"] .show-main-navigation>a,header[role="banner"] .show-search-button>a,.search-dialog-form [type="submit"]>a,.user-status[data-user-type="anonymous"] .recipebox-status:hover>a,.user-status[data-user-type="anonymous"] .recipebox-status>a,.user-status[data-user-type="authenticated"] .recipebox-status>a,.main-navigation .instagram-social-channel-link>a,.branding .instagram-social-channel-link>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .instagram-link>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .pinterest-link>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .tumblr-link>a,.main-navigation .twitter-social-channel-link>a,.branding .twitter-social-channel-link>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .twitter-link>a,[class$="-form"] .close-button>a,.search-dialog-form [type="reset"]>a,.dismiss-main-navigation:hover>a,[class$="-comment-form"] .close-button>a,.dismiss-main-navigation>a,footer[role="contentinfo"] .epicurious-links .epi-social-links .youtube-link>a{display:block;height:100%;width:100%}html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline}html{line-height:1}ol,ul{list-style:none}table{border-collapse:collapse;border-spacing:0}caption,th,td{text-align:left;font-weight:normal;vertical-align:middle}q,blockquote{quotes:none}q:before,q:after,blockquote:before,blockquote:after{content:"";content:none}a img{border:none}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}html{box-sizing:border-box;font-size:16px;line-height:1.625em}*,*:before,*:after{box-sizing:inherit}* html{font-size:100%}body{background:#fff;font-family:"Source Serif Pro",serif;font-weight:400;position:relative;color:#333;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media only screen and (max-width: 640px){body{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;width:100%;min-width:0}}html,body{height:100%}h1,h2,h3,h4,h5,h6{line-height:1.15538em;padding:0.273em 0;text-rendering:optimizeLegibility}p{font-family:"Source Serif Pro",serif;font-weight:400;font-size:1rem;margin-bottom:6px;line-height:.75em}[class$="-flash-message"]{border:1px solid #eee;font-size:1rem;line-height:1.25;margin:1rem 0;padding:1rem}.confirm-flash-message{border-color:#83b838;color:#83b838}.error-flash-message{border-color:#f93f23;color:#f93f23}ol{list-style:decimal}img{max-width:100%;height:auto}.apply-social{line-height:0}.social-img picture,.apply-social picture{display:inline-block;line-height:0;position:relative}strong{font-weight:700;line-height:inherit}em{font-style:italic;line-height:inherit}hr{border:1px solid #ccc;clear:both;margin:1rem 0 1.125rem;height:0}.btn,.skiplink{display:inline-block;width:auto;-webkit-appearance:none;text-align:center}.btn>a,.btn input,.btn button,.skiplink>a,.skiplink input,.skiplink button{display:block;height:100%}.btn input,.btn button,.skiplink input,.skiplink button{background:none;border:none;width:100%;font-size:100%;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}html{-webkit-overflow-scrolling:touch}a{color:#333;line-height:normal;text-decoration:none}a:hover,a:active{text-decoration:underline}button{border:none}button:focus{outline:0}button:hover{cursor:pointer}fieldset{border:none;margin:0;padding:0}.field .input{position:relative;padding:0 .625rem;background:#fff;border:1px solid #d8d8d8}img.photo,.photo-wrap img{max-width:none}img{-webkit-transition:opacity .7s;-moz-transition:opacity .7s;-o-transition:opacity .7s;transition:opacity .7s}img.pending{opacity:0}img.loaded{opacity:1}.component-lazy img{opacity:0}.component-lazy.img-loaded img,.component-lazy.img-error img{opacity:1}input{border-radius:0;-webkit-appearance:none}input:focus{outline:0}ul,li{margin:0;padding:0}.flag-inappropriate-content-button{font-family:"Renner",sans-serif;font-style:normal;font-weight:bold;color:#a1a1a1;font-size:.75rem;line-height:0rem;background-color:#fff;border:1px solid #a1a1a1;display:block;margin:0 auto;padding:1.4375rem 0 1.375rem;text-transform:uppercase;width:15rem}.flag-inappropriate-content-button:hover{border-color:#333;color:#333}.flagged.flag-inappropriate-content-button,.flagged.flag-inappropriate-content-button:hover{border-color:#f93f23;color:#f93f23;cursor:default}[class$="-form"]{background-color:#fff;display:block;margin:0 auto;padding:2rem 0;width:100%;z-index:1}[class$="-form"] ::selection{background-color:transparent}[class$="-form"] a{color:inherit}[class$="-form"] fieldset,[class$="-form"] label,[class$="-form"] p{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#333;font-size:.875rem;line-height:1.25rem}[class$="-form"] fieldset,[class$="-form"] p{border:none;margin:0;padding:.5rem 2rem}[class$="-form"] p{padding:0}[class$="-form"] legend{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#333;font-size:1.875rem;line-height:1.875rem;margin:0 auto;padding:.5rem 0 .75rem}[class$="-form"] label{cursor:default;display:none}[class$="-form"] .description,[class$="-form"] .warning{margin:1rem 0}[class$="-form"] .warning{color:#f93f23}[class$="-form"] input[type="checkbox"],[class$="-form"] input[type="checkbox"]:focus{border:1px solid #ccc;border-radius:0;height:.75rem;width:.75rem}[class$="-form"] input[type="checkbox"]:checked,[class$="-form"] input[type="checkbox"]:focus:checked{background-color:#f93f23}[class$="-form"] input[type="checkbox"]:hover,[class$="-form"] input[type="checkbox"]:focus:hover{border-color:#333}[class$="-form"] input[type="email"],[class$="-form"] input[type="password"],[class$="-form"] input[type="text"],[class$="-form"] textarea{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#333;font-size:.875rem;line-height:.875rem;border:1px solid #ccc;display:block;margin:1rem 0;padding:1rem .5rem;width:100%}[class$="-form"] input[type="email"].error,[class$="-form"] input[type="email"]:invalid,[class$="-form"] input[type="password"].error,[class$="-form"] input[type="password"]:invalid,[class$="-form"] input[type="text"].error,[class$="-form"] input[type="text"]:invalid,[class$="-form"] textarea.error,[class$="-form"] textarea:invalid{border-color:#f93f23}[class$="-form"] input[type="email"]:focus,[class$="-form"] input[type="password"]:focus,[class$="-form"] input[type="text"]:focus,[class$="-form"] textarea:focus{border-color:#999;outline:none}[class$="-form"] input[type="email"]::selection,[class$="-form"] input[type="password"]::selection,[class$="-form"] input[type="text"]::selection,[class$="-form"] textarea::selection{background-color:#ccc}[class$="-form"] textarea{overflow-y:auto;resize:none}[class$="-form"] .close-button{background-color:transparent;background-repeat:no-repeat;background-position:50% 50%;background-size:.9375rem,.9375rem;border:none;direction:ltr;display:inline-block;height:.9375rem;overflow:hidden;padding:0;text-indent:-9999px;width:.9375rem;position:absolute;right:13px;top:11px}[class$="-form"] .close-button>a{display:block;height:100%;width:100%}[class$="-form"] .cancel-button,[class$="-form"] .save-button,[class$="-form"] .submit-button{font-family:"Renner",sans-serif;font-style:normal;font-weight:bold;color:#fff;font-size:.875rem;line-height:0rem;background-color:#333;border:1px solid #333;display:inline-block;margin:36px auto;padding:22px 0 21px;text-transform:uppercase;width:100%}[class$="-form"] .cancel-button:focus,[class$="-form"] .cancel-button:hover,[class$="-form"] .save-button:focus,[class$="-form"] .save-button:hover,[class$="-form"] .submit-button:focus,[class$="-form"] .submit-button:hover{background-color:#292929}[class$="-form"] .cancel-button{background-color:#fff;border-color:#f93f23;color:#f93f23}[class$="-form"] .cancel-button:focus,[class$="-form"] .cancel-button:hover{background-color:#f93f23;color:#fff}[class$="-modal-dialog"] [class$="-form"]{background-color:#fff;display:block;margin:0 auto;padding:25px 0 0;width:90%}@media only screen and (min-width: 768px){[class$="-form"] .close-button{right:15px;top:15px}[class$="-form"] .submit-button{width:158px}}.contact-us-comment-form,.flag-inappropriate-content-comment-form{border:1px solid #ccc}[class$="-login-form"],[class$="-registration-form"],[class$="-reset-password-form"],[class$="-update-password-form"]{text-align:center}[class$="-login-form"] .fine-print,[class$="-registration-form"] .fine-print,[class$="-reset-password-form"] .fine-print,[class$="-update-password-form"] .fine-print{color:#9B9B9B;font-size:.625rem;text-align:center}[class$="-login-form"] .fine-print a,[class$="-registration-form"] .fine-print a,[class$="-reset-password-form"] .fine-print a,[class$="-update-password-form"] .fine-print a{text-decoration:underline}[class$="-login-form"] .goto-counterpart a,[class$="-registration-form"] .goto-counterpart a,[class$="-reset-password-form"] .goto-counterpart a,[class$="-update-password-form"] .goto-counterpart a{text-decoration:underline}[class$="-login-form"] .forgot-password-link{display:block;margin:1rem 0;text-align:right;text-decoration:underline;text-transform:capitalize}.piano-ad-blocker-registration-form .close-button{display:none}.piano-engaged-user-registration-form .close-button{font-family:"Renner",sans-serif;font-style:normal;font-weight:bold;color:#ccc;font-size:.625rem;line-height:0rem;background:none;background-color:#e5e5e5;bottom:1rem;height:auto;margin-right:-50px;padding:15px 0 14px;right:50%;text-indent:0;top:initial;width:100px}.piano-engaged-user-registration-form .close-button:hover{color:#333}.piano-ad-blocker-modal-dialog,.piano-login-modal-dialog,.piano-reset-password-modal-dialog{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#333;font-size:.875rem;line-height:1.25rem;padding:2rem 0 0;text-align:center}.piano-ad-blocker-modal-dialog .dialog-title,.piano-login-modal-dialog .dialog-title,.piano-reset-password-modal-dialog .dialog-title{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#f93f23;font-size:1.875rem;line-height:1.875rem;margin:0 auto;padding:8px 0 12px;width:40%}.piano-ad-blocker-modal-dialog .description,.piano-ad-blocker-modal-dialog .your-ad-blocker,.piano-login-modal-dialog .description,.piano-login-modal-dialog .your-ad-blocker,.piano-reset-password-modal-dialog .description,.piano-reset-password-modal-dialog .your-ad-blocker{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#333;font-size:.875rem;line-height:1.25rem;display:block;margin:0 auto;padding:0 2rem}.piano-ad-blocker-modal-dialog .your-ad-blocker .what,.piano-login-modal-dialog .your-ad-blocker .what,.piano-reset-password-modal-dialog .your-ad-blocker .what{background-color:#ccc;display:block;margin:1rem 0;padding:1rem}.piano-ad-blocker-modal-dialog .your-ad-blocker .how,.piano-login-modal-dialog .your-ad-blocker .how,.piano-reset-password-modal-dialog .your-ad-blocker .how{display:block;text-decoration:underline}@media only screen and (min-width: 768px){.piano-ad-blocker-modal-dialog,.piano-login-modal-dialog,.piano-reset-password-modal-dialog{height:96%;top:2%}.piano-ad-blocker-modal-dialog .description,.piano-ad-blocker-modal-dialog .your-ad-blocker,.piano-login-modal-dialog .description,.piano-login-modal-dialog .your-ad-blocker,.piano-reset-password-modal-dialog .description,.piano-reset-password-modal-dialog .your-ad-blocker{padding:0 6rem}}.ReactModalPortal>div{opacity:0;transition:opacity 0.25s}.ReactModalPortal>div.ReactModal__Overlay--after-open{opacity:1}body[data-overlay="modal"],body.ReactModal__Body--open{height:100%;overflow:hidden;padding-right:15px}body[data-overlay="modal"] .content-wrapper,body[data-overlay="modal"] .page-wrap,body.ReactModal__Body--open .content-wrapper,body.ReactModal__Body--open .page-wrap{display:block;filter:blur(5px);-moz-filter:blur(5px);-ms-filter:blur(5px);-o-filter:blur(5px);-webkit-filter:blur(5px)}[class$="-modal-dialog-wrapper"],[class$="-modal-confirmation-wrapper"]{background:rgba(0,0,0,0.7);display:block;height:100%;left:0;position:fixed;top:0;width:100%;z-index:9999999}[class$="-modal-confirmation-wrapper"]{background:none}[class$="-modal-confirmation-wrapper"] .recipbox-modal-confirmation{display:flex;justify-content:center;align-items:center}[class$="-modal-confirmation-wrapper"] .recipbox-modal-confirmation p{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#f93f23;font-size:.875rem;line-height:1.125rem;margin:0}[class$="-modal-dialog"],[class$="-modal-confirmation"]{background-color:#ffffff;display:block;height:90%;left:50%;margin-left:-45%;outline:none;position:fixed;top:5%;width:90%;z-index:999999}[class$="-modal-confirmation"]{height:auto;margin-left:-30%;padding:1.1875rem;text-align:center;top:30%;width:14.5rem}@media only screen and (min-width: 768px){[class$="-modal-dialog"],[class$="-modal-confirmation"]{border:1px solid #ccc;height:80%;left:50%;margin-left:-300px;top:10%;width:600px}[class$="-modal-confirmation-wrapper"] .recipbox-modal-confirmation p{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#f93f23;font-size:1.0625rem;line-height:1.375rem}[class$="-modal-confirmation"]{height:auto;left:50%;margin-left:-10%;padding:1.875rem;top:50%;width:24.875rem}.error-modal-dialog{height:auto}}.content-wrapper{margin:0 auto}.content-wrapper .main-content{-webkit-transition:-webkit-transform .3s linear;-moz-transition:-moz-transform .3s linear;-o-transition:-o-transform .3s linear;transition:transform .3s linear}.content-and-rail{*zoom:1}.content-and-rail:before,.content-and-rail:after{content:"";display:table}.content-and-rail:after{clear:both}.fullwidth{width:100%}.hide{display:none}.show{display:block}.locked{position:fixed}.modal.show{visibility:visible;opacity:1}.ad-container{line-height:0}.embed-video{*zoom:1;clear:both;position:relative}.embed-video:before,.embed-video:after{content:"";display:table}.embed-video:after{clear:both}.embed-video .video-container{position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden}.embed-video .video-container iframe,.embed-video .video-container object,.embed-video .video-container embed{position:absolute;top:0;left:0;width:100%;height:100%}.embed-social{*zoom:1;clear:both;position:relative}.embed-social:before,.embed-social:after{content:"";display:table}.embed-social:after{clear:both}.embed-social .embed-facebook{margin-bottom:20px;position:relative;padding-top:0;padding-bottom:0}.embed-social .embed-facebook iframe,.embed-social .embed-facebook object,.embed-social .embed-facebook embed{position:absolute;top:0;left:0;width:100%;height:100%}.embed-social .embed-instagram{margin-bottom:20px;position:relative;padding-top:30px;padding-bottom:113%}.embed-social .embed-instagram blockquote{margin-left:0;margin-right:0;width:100%}.embed-social .embed-instagram blockquote:before{content:""}@media only screen and (max-width: 640px){.embed-social .embed-instagram{padding-bottom:122%}}.embed-social .embed-instagram iframe,.embed-social .embed-instagram object,.embed-social .embed-instagram embed{position:absolute;top:0;left:0;width:100%;height:100%}.embed-social .embed-twitter{position:relative;padding-top:0px;padding-bottom:0px;text-align:-webkit-center}.embed-social .embed-twitter iframe,.embed-social .embed-twitter object,.embed-social .embed-twitter embed{position:absolute;top:0;left:0;width:100%;height:100%}.cnid-loader{position:fixed;top:45%;left:50%;margin-left:-8px;margin-top:-8px;background-color:#000;width:50px;height:50px;border-radius:10px;opacity:.8;z-index:1101}.cnid-loader img{position:absolute;top:16%;left:16%}.cnid-ios-scroll{-webkit-overflow-scrolling:touch;overflow-y:auto}div.social-img{display:inline-block;position:relative;line-height:0}.social-buttons{position:absolute;z-index:10;bottom:.625rem;right:.625rem;*zoom:1}.social-buttons:before,.social-buttons:after{content:"";display:table}.social-buttons:after{clear:both}.social-buttons div{float:left}.social-buttons div.facebook{margin-right:.375rem}.social-buttons div.social{display:block;line-height:0;height:1.75rem;width:1.75rem}.browsehappy{text-align:center;font-weight:normal;font-size:16px;font-family:"Renner",sans-serif;background-color:#f1f2f2;position:fixed;height:26px;bottom:-14px;z-index:99999;width:100%}[class^="icon-"]{background-position:50% 50%;background-repeat:no-repeat;background-size:100% 100%;cursor:pointer;display:block;direction:ltr;overflow:hidden;padding:0;text-indent:-9999px}[class^="icon-"] a{display:block;height:100%;width:100%}.icon-epicurious{height:63px;margin:0 auto;overflow:initial;position:relative;width:304px}.print-controls{display:none}.content-container{width:100%;max-width:1024px;min-width:320px;margin:0 auto;padding-left:10px;padding-right:10px;*zoom:1}.content-container:before,.content-container:after{content:"";display:table}.content-container:after{clear:both}.content-container>*:first-child{margin-left:0}@media only screen and (max-width: 640px){.content-container{width:auto;min-width:0;margin-left:0;margin-right:0}}.rail-promo img{width:300px;min-height:300px}.main.has-rail{margin-left:1.953125%;float:left;min-height:1px;position:relative;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:68.1396484375%;margin-left:0}@media only screen and (max-width: 640px){.main.has-rail{float:left;margin-left:0;width:100%}}.main.no-rail{padding:0;margin:0}.main.no-rail:before,.main.no-rail:after{content:"";display:table}.main.no-rail:after{clear:both}@media only screen and (min-width: 1024px){.mobile{display:none}body>.content-wrapper>div.main{margin-top:1.25rem}}.rail{margin-left:1.953125%;float:left;min-height:1px;position:relative;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:29.9072265625%;position:static}@media only screen and (max-width: 640px){.rail{float:left;margin-left:0;width:100%}}.rail div.video{margin:0;padding:0}.video-container,.cne-interlude-player-container{width:100%}.video-container.sticky,.cne-interlude-player-container.sticky{position:fixed;width:18.75rem;z-index:15}.weather{width:300px;height:400px;background-color:#ccc}.rail div{margin-bottom:20px}.epi-sticky.stuck{position:fixed;margin-left:0;transform:translateZ(0);-webkit-transform:translateZ(0);z-index:9}.byline,.byline-divider,.pub-date{font:normal bold .6326875rem "Renner",sans-serif;color:#f93f23;text-transform:uppercase;letter-spacing:1px}.byline.sponsored,.byline-divider.sponsored,.pub-date.sponsored{color:#f93f23;display:inline-block;border:1px solid #f93f23;padding:.375rem .75rem}.byline.mobile,.byline-divider.mobile,.pub-date.mobile{display:none}.pub-date,.byline-divider{color:#a4a4a4}.sponsor-logo{display:block;margin-bottom:.5rem}h3.tag,.sponsor-logo{text-transform:uppercase;margin:0 0 1.375rem 0;padding:0}h3.tag a,.sponsor-logo a{color:#a1a1a1;font:normal 20.169px "Renner",sans-serif}.sponsor-logo{margin:0;padding:0 0 0.5rem}.fullwidth .section-header{max-width:62.75rem !important}.section-header{width:100%;max-width:1024px;min-width:320px;margin:0 auto;padding-left:10px;padding-right:10px;*zoom:1;text-align:center;overflow:hidden;max-width:62.75rem !important;margin:0 auto;padding:0}.section-header:before,.section-header:after{content:"";display:table}.section-header:after{clear:both}.section-header>*:first-child{margin-left:0}@media only screen and (max-width: 640px){.section-header{width:auto;min-width:0;margin-left:0;margin-right:0}}.section-header h2{display:inline-block;position:relative}.section-header h2:before{content:"";position:absolute;border-top:2px solid #ccc;width:25rem;height:2px;display:block;left:-25.375rem;top:54%}.section-header h2:after{content:"";position:absolute;border-top:2px solid #ccc;width:25rem;height:2px;display:block;right:-25.375rem;top:54%}.top5 h2{color:#333;font:bold 2.375rem/3.125rem "Source Serif Pro",serif;text-transform:none}@media only screen and (min-width: 641px) and (max-width: 1023px){.mobile{display:none}.nav.mobile{display:block}.content-container{padding:0 1.625rem}.rail{float:none;margin:0;padding:0;text-align:center;width:100%}.content-block{padding:0}.tablet-ads1{*zoom:1;margin:0 0 1.75rem;text-align:center}.tablet-ads1:before,.tablet-ads1:after{content:"";display:table}.tablet-ads1:after{clear:both}.tablet-ads1 .ad,.tablet-ads1 .weather,.tablet-ads1 .cook-it{max-width:18.75rem}.tablet-ads1 .ad{margin-left:auto;margin-right:auto}.tablet-ads2{text-align:center}.section-header{overflow:hidden}.section-header h2:before{width:104%;left:-106%}.section-header h2:after{width:104%;right:-106%}.fullwidth .section-header{margin:0 3.25%;width:93.5%}}@media only screen and (max-width: 640px){body{overflow-x:hidden}body.modal-open{overflow:hidden}.content-container{padding:0}.rail{float:none;margin:0;padding:0 .625rem}.rail div{margin-left:auto;margin-right:auto;text-align:center}.content-block{padding:0 1rem}h3.tag a{font:normal 18.369px "Renner",sans-serif}.section-header h2:before,.section-header h2:after{display:none}.top5 h2{font-size:1.625rem;line-height:2rem}.progression{*zoom:1}.progression:before,.progression:after{content:"";display:table}.progression:after{clear:both}.progression.mobile{display:inline-block}.progression li{text-indent:-9999px;float:left;margin:0 .75rem 0 0;background:url("/static/img/mobile-sprite.png") 0 0 no-repeat;height:7px;width:7px}.progression li:last-child{margin-right:0}.progression li.on{background:url("/static/img/mobile-sprite.png") 0 -7px no-repeat}.byline.sponsored{padding:.375rem .75rem;width:85%;text-align:center;margin-bottom:.25rem}.ad.ad-footer{display:block;position:fixed;bottom:0;margin-bottom:0;width:100%;background-color:#f1f2f2;text-align:center;padding:.375rem 0;z-index:9999}body.parallax-loaded .ad.ad-footer{position:relative}}.lightreg-overlay{background-color:rgba(0,0,0,0.8);bottom:0;top:0;left:0;position:fixed;right:0;z-index:9999999}.lightreg-dialog{background-color:#ffffff;background-clip:padding-box;font:normal .75rem "Renner",sans-serif;height:80%;left:0;margin-left:0;outline:none;position:fixed;top:10%;width:100%}.lightreg-dialog a{color:#333;font-size:.75rem;text-decoration:none;letter-spacing:1px}.lightreg-dialog form{padding-top:2.25rem}.lightreg-dialog fieldset{margin:0 auto;padding:0;width:18.4375rem}.lightreg-dialog fieldset legend{display:block;height:3.625rem;margin:0 auto .5rem;width:17.5rem}.lightreg-dialog input:focus,.lightreg-dialog button:focus{outline:0}.lightreg-dialog input::-webkit-input-placeholder{color:#ccc;font-weight:normal;text-transform:uppercase}.lightreg-dialog input:-moz-placeholder{color:#ccc;font-weight:normal;text-transform:uppercase}.lightreg-dialog input::-moz-placeholder{color:#ccc;font-weight:normal;text-transform:uppercase}.lightreg-dialog input:-ms-input-placeholder{color:#ccc;font-weight:normal;text-transform:uppercase}.lightreg-dialog input[type=text],.lightreg-dialog input[type=email],.lightreg-dialog input[type=password]{border:1px solid #ccc;border-radius:0;color:#ccc;display:block;font:normal 1rem/1.125rem "Renner",sans-serif;letter-spacing:1px;height:2.8125rem;margin:0 0 .9375rem;padding:0 0 0 .75rem;width:100%;-webkit-appearance:none}.lightreg-dialog input[type=password]{margin-bottom:.875rem}.lightreg-dialog input[type=text].error,.lightreg-dialog input[type=email].error,.lightreg-dialog input[type=password].error,.lightreg-dialog input:focus:invalid:focus,.lightreg-dialog textarea:focus:invalid:focus,.lightreg-dialog select:focus:invalid:focus{color:#f93f23;border:2px solid #f93f23}.lightreg-dialog textarea:focus,.lightreg-dialog input[type="text"]:focus,.lightreg-dialog input[type="password"]:focus,.lightreg-dialog input[type="datetime"]:focus,.lightreg-dialog input[type="datetime-local"]:focus,.lightreg-dialog input[type="date"]:focus,.lightreg-dialog input[type="month"]:focus,.lightreg-dialog input[type="time"]:focus,.lightreg-dialog input[type="week"]:focus,.lightreg-dialog input[type="number"]:focus,.lightreg-dialog input[type="email"]:focus,.lightreg-dialog input[type="url"]:focus,.lightreg-dialog input[type="search"]:focus,.lightreg-dialog input[type="tel"]:focus,.lightreg-dialog input[type="color"]:focus,.lightreg-dialog .uneditable-input:focus{border-color:#ccc}.lightreg-dialog .error-message{color:#f93f23;text-align:left;position:relative;top:-.75rem}.lightreg-dialog button.submit-button{font:normal 12.274px "Renner",sans-serif;letter-spacing:1px;background:#333;border:0;border-radius:.25rem;color:#fff;cursor:pointer;display:block;font-size:.75rem;height:2.8125rem;margin:1.875rem 0 .8125rem;padding:.375rem .75rem;touch-action:manipulation;user-select:none;width:100%}.lightreg-dialog button.submit-button:hover,.lightreg-dialog button.submit-button:focus,.lightreg-dialog button.submit-button:active,.lightreg-dialog button.submit-button.active,.lightreg-dialog button.submit-button.disabled,.lightreg-dialog button.submit-button[disabled]{background-color:#333;color:#fff}.lightreg-dialog .description{font-family:"Renner",sans-serif;font-size:.75rem;line-height:1rem;margin:0 0 1.25rem}.lightreg-dialog .forgot-password-link{margin:.8125rem 0 0}.lightreg-dialog .goto-counterpart{font-size:.75rem;letter-spacing:1px;text-align:center}.lightreg-dialog .fine-print{margin-top:.5625rem}.lightreg-dialog .fine-print,.lightreg-dialog .fine-print a{color:#9B9B9B;font-size:.6875rem;line-height:normal;letter-spacing:1px;padding:0;text-align:center}.lightreg-dialog .loading-message{margin:1.5rem 0 0}.lightreg-dialog p.success-message,.lightreg-dialog p.description,.lightreg-dialog p.fine-print{font-family:"Renner",sans-serif}.lightreg-dialog .base-registration-form .fine-print{margin-top:1.5625rem}.lightreg-dialog .base-reset-password-form .success-message,.lightreg-dialog .base-update-password-form .success-message{font-size:1rem;margin-bottom:1.875rem}@media only screen and (min-width: 1024px){.lightreg-dialog{border:1px solid rgba(0,0,0,0.3);left:50%;margin-left:-18.75rem;width:37.5rem}}.loading-message-wrapper{background-color:rgba(255,255,255,0.7);height:100%;left:0;position:absolute;top:0;width:100%;z-index:1}.loading-message-wrapper:hover{cursor:wait}body[data-overlay="modal"] .loading-message-wrapper{background-color:rgba(0,0,0,0.7);position:fixed;z-index:9999}@keyframes loading-spin{100%{transform:rotate(360deg);-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);-o-transform:rotate(360deg)}}@-webkit-keyframes loading-spin{100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes loading-spin{100%{-moz-transform:rotate(360deg)}}@-ms-keyframes loading-spin{100%{-ms-transform:rotate(360deg)}}@-o-keyframes loading-spin{100%{-o-transform:rotate(360deg)}}.loading-message{animation:loading-spin 0.7s infinite linear;border-bottom:7px solid rgba(161,161,161,0.2);border-left:7px solid rgba(161,161,161,0.2);border-radius:100%;border-right:7px solid rgba(161,161,161,0.2);border-top:7px solid #f93f23;direction:ltr;display:block;height:3rem;left:50%;margin:-1.5rem 0 0 -1.5rem;overflow:hidden;position:absolute;text-indent:-9999px;top:50%;width:3rem;-webkit-animation:loading-spin 0.7s infinite linear;-moz-animation:loading-spin 0.7s infinite linear;-ms-animation:loading-spin 0.7s infinite linear;-o-animation:loading-spin 0.7s infinite linear}.loading-message:hover{cursor:wait}.site-header-wrap{display:block;height:3.75rem}header[role="banner"]{font:bold .8125rem/normal "Renner",sans-serif;background-color:#fff;box-shadow:0 1px 3px 0 rgba(0,0,0,0.1);font-size:1rem;height:3.75rem;left:0;top:0;transition:top .5s;width:100%;z-index:20}header[role="banner"] ::selection{background-color:transparent}header[role="banner"] a{color:inherit}header[role="banner"] fieldset,header[role="banner"] form,header[role="banner"] legend{margin:0;padding:0}header[role="banner"] .nav-title,header[role="banner"] .section-title{display:none}header[role="banner"] .show-main-navigation{height:1.125rem;left:1.125rem;position:absolute;top:1.375rem;width:1.5625rem}header[role="banner"] .epicurious-logo{height:1.8125rem;left:3.75rem;position:absolute;top:1rem;width:8.625rem}header[role="banner"] .epicurious-logo a{display:block}header[role="banner"] .show-search-button{height:1.625rem;outline:none;position:absolute;right:1.125rem;top:1.0625rem;width:1.625rem}body[data-bannerad-type="leaderboard"][data-bannerad-flow="fixed"][data-siteheader-flow="fixed"][data-bannerad-display="hidden"] header[role="banner"]{top:0}body[data-bannerad-type="leaderboard"][data-bannerad-flow="fixed"][data-siteheader-flow="fixed"][data-bannerad-display="visible"] header[role="banner"]{top:7.125rem}body[data-overlay="modal"] header[role="banner"],body.ReactModal__Body--open header[role="banner"]{left:-8px}body[data-siteheader-flow="fixed"] header[role="banner"]{position:fixed}body[data-siteheader-flow="scroll"] header[role="banner"]{position:relative}@media only screen and (min-width: 768px){header[role="banner"] .show-main-navigation{left:1.5rem}header[role="banner"] .epicurious-logo{left:50%;transform:translateX(-50%)}header[role="banner"] .epicurious-logo:hover{height:1.9375rem;top:.9375rem;width:8.75rem}header[role="banner"] .show-search-button{right:1.25rem;top:1rem}}@media only screen and (min-width: 1024px){header[role="banner"] .show-main-navigation{left:1.3125rem}header[role="banner"] .show-search-button{background-position:100% 50%;background-size:1.3125rem;color:#a1a1a1;font-size:.8125rem;height:0;line-height:0;letter-spacing:1px;padding:.6875rem 1.625rem .625rem 0;right:1.4375rem;text-indent:0;top:1.3125rem;width:auto}header[role="banner"] .show-search-button:hover{background-position:100% 50%;color:#333;text-decoration:none}}input:-webkit-autofill,select:-webkit-autofill,textarea:-webkit-autofill{background-color:inherit;background-image:inherit;color:inherit}.global-search-modal-dialog-wrapper{background:rgba(255,255,255,0.9)}.global-search-modal-dialog{background-color:transparent;border:none;height:100%;margin-left:-50%;top:0;width:100%}.global-search-modal-dialog .search-dialog-form{background-color:transparent;margin:0 .9375rem;padding:0;width:calc(100% - 30px)}.search-dialog-form{border-bottom:1px solid #ccc;position:relative}.search-dialog-form fieldset{padding:0}.search-dialog-form input[type="text"]{font:bold 1rem/1 "Renner",sans-serif;background-color:transparent;border:0;margin:2.25rem 0 .8125rem 1.3125rem;padding:0;width:calc(100% - 20px)}.search-dialog-form input[type="text"]:focus{color:#333}.search-dialog-form input[type="text"]::placeholder{color:#ccc}.search-dialog-form input[type="text"].error{color:#f30}.search-dialog-form [type="submit"]{height:1rem;left:0;position:absolute;top:2.25rem;width:1rem}.search-dialog-form [type="submit"]:hover{cursor:pointer}.search-dialog-form [type="reset"]{background-size:.9375rem .9375rem;height:1.4375rem;position:absolute;right:0;top:.9375rem;width:1.4375rem}.search-dialog-form [type="reset"]:hover{background-size:.9375rem .9375rem}@media only screen and (min-width: 768px){.global-search-modal-dialog .search-dialog-form{margin:0 auto;width:40rem}.search-dialog-form input[type="text"]{font-size:2.6875rem;margin:11.5rem 0 2.125rem 2.875rem;width:calc(100% - 46px)}.search-dialog-form [type="submit"]{height:2rem;left:0;top:12.125rem;width:2rem}.search-dialog-form [type="reset"]{height:1.625rem;top:5.875rem;width:1.625rem}}@media only screen and (min-width: 1024px){.global-search-modal-dialog .search-dialog-form{width:51.875rem}.search-dialog-form [type="reset"]{height:2rem;top:5.875rem;width:2rem}}.site-pushdown-ad-wrap{display:none}body[data-bannerad-type="crown"] .site-header-ad-wrap{display:none}body[data-bannerad-type="crown"] .site-header-ad-wrap.loaded{display:block}body[data-bannerad-type="mobile-banner"],body[data-bannerad-type="mobile-leaderboard"]{padding-bottom:4.625rem}body[data-bannerad-type="mobile-banner"] .site-header-ad-wrap>div,body[data-bannerad-type="mobile-banner"].homepage .site-pushdown-ad-wrap>div,body[data-bannerad-type="mobile-leaderboard"] .site-header-ad-wrap>div,body[data-bannerad-type="mobile-leaderboard"].homepage .site-pushdown-ad-wrap>div{background-color:#f1f2f2;bottom:0;height:3.875rem;overflow:hidden;position:fixed;padding:.375rem 0;text-align:center;width:100%;z-index:20}body[data-bannerad-type="leaderboard"] .site-header-ad-wrap,body[data-bannerad-type="leaderboard"].homepage .site-pushdown-ad-wrap{padding:0}body[data-bannerad-type="leaderboard"] .site-header-ad-wrap>div,body[data-bannerad-type="leaderboard"].homepage .site-pushdown-ad-wrap>div{height:7.125rem;overflow:hidden;padding:.75rem 0;transition:top .5s;width:100%;z-index:20}body[data-bannerad-type="leaderboard"][data-bannerad-flow="fixed"] .site-header-ad-wrap,body[data-bannerad-type="leaderboard"][data-bannerad-flow="fixed"].homepage .site-pushdown-ad-wrap{height:7.125rem}body[data-bannerad-type="leaderboard"][data-bannerad-flow="fixed"] .site-header-ad-wrap>div,body[data-bannerad-type="leaderboard"][data-bannerad-flow="fixed"].homepage .site-pushdown-ad-wrap>div{background-color:#f1f2f2;position:fixed}body[data-bannerad-type="leaderboard"][data-bannerad-display="hidden"] .site-header-ad-wrap>div,body[data-bannerad-type="leaderboard"][data-bannerad-display="hidden"].homepage .site-pushdown-ad-wrap>div{top:-7.125rem}body[data-bannerad-type="leaderboard"][data-bannerad-display="visible"] .site-header-ad-wrap>div,body[data-bannerad-type="leaderboard"][data-bannerad-display="visible"].homepage .site-pushdown-ad-wrap>div{top:0}@media only screen and (min-width: 768px){.site-header-ad-wrap{background-color:#f1f2f2;text-align:center;width:100%}.site-header-ad-wrap>div{display:block;left:0;margin:0 auto;top:0}body[data-bannerad-type="pushdown"] .site-pushdown-ad-wrap{margin-top:1.875rem;margin-bottom:1.875rem}body[data-bannerad-type="other"][data-bannerad-display="visible"] .site-header-ad-wrap{margin-top:4.8125rem}body[data-bannerad-type="other"][data-bannerad-display="visible"] [id^='adUnitContainer']{margin-top:4.8125rem !important}}@media screen, print{.printable .site-header-ad-wrap{display:none}}.main-navigation{font-family:"Renner",sans-serif;font-style:normal;font-weight:bold;color:#333;font-size:.875rem;line-height:1em;background-color:#333;color:#fff;height:100%;left:-16.6875rem;letter-spacing:0.1px;line-height:3.125rem;padding-top:1.625rem;position:fixed;top:0;text-align:center;transition:transform 0.3s linear;width:16.6875rem;z-index:22}.main-navigation .logout-user-action{border:1px solid #f93f23;color:#f93f23;padding:.5rem 2rem}.main-navigation[aria-expanded="true"]{-webkit-transform:translateX(16.6875rem);-moz-transform:translateX(16.6875rem);-ms-transform:translateX(16.6875rem);-o-transform:translateX(16.6875rem);transform:translateX(16.6875rem);overflow-y:auto}.dismiss-main-navigation{height:1.0625rem;left:1.625rem;position:absolute;top:1.375rem;width:1.0625rem}@media only screen and (min-width: 768px){.main-navigation{left:-20.125rem;padding-top:2.8125rem;width:20.125rem}.main-navigation[aria-expanded="true"]{-webkit-transform:translateX(20.125rem);-moz-transform:translateX(20.125rem);-ms-transform:translateX(20.125rem);-o-transform:translateX(20.125rem);transform:translateX(20.125rem)}}@media screen, print{.printable .main-navigation{display:none}}.content-channel-links{text-transform:uppercase}[class$="-content-channel-link"]{color:#fff;display:block;margin:1.875rem 0}[class$="-content-channel-link"] a{display:block;letter-spacing:1px}[class$="-content-channel-link"] a:hover{color:#f93f23;text-decoration:none}.homepage-content-channel-link{background-color:transparent;background-repeat:no-repeat;background-position:50% 50%;background-size:cover;border:none;direction:ltr;display:inline-block;height:3.4375rem;overflow:hidden;padding:0;text-indent:-9999px;width:3.4375rem;border:1px solid #f93f23;border-radius:100%;display:block;margin:0 auto 2.1875rem}.homepage-content-channel-link>a{display:block;height:100%;width:100%}.curated-content-channel-link{color:#83b838}body.recipes-menus .recipes-menus-content-channel-link,body.expert-advice .expert-advice-content-channel-link,body.ingredients .ingredients-content-channel-link,body.holidays-events .holidays-events-content-channel-link,body.community .community-content-channel-link,body.video .video-content-channel-link{color:#f93f23}@media only screen and (min-width: 768px){.homepage-content-channel-link{height:5.625rem;width:5.625rem}}.main-navigation .social-channel-links .section-title{display:block;font-size:.8125rem;letter-spacing:1px;padding:1.25rem 0 .5rem}.main-navigation .facebook-social-channel-link{width:.8125rem}.main-navigation .twitter-social-channel-link{width:1.875rem}.main-navigation .instagram-social-channel-link{width:1.5625rem}.main-navigation [class$="-social-channel-link"]{height:1.5625rem;margin:0 .75rem}.branding .social-channel-links{display:none}@media only screen and (min-width: 1024px){.branding .social-channel-links{display:block;position:absolute;right:7.5rem;top:1rem}.branding .social-channel-links .section-title{color:#a1a1a1;display:inline-block;font-size:.8125rem;letter-spacing:1px;height:1em;line-height:1;overflow:hidden;padding:0;vertical-align:middle;width:50px}.branding .social-channel-links ul{display:inline-block;line-height:0;vertical-align:middle}.branding [class$="-social-channel-link"]{height:1.5625rem;margin:0 .375rem;width:1.5625rem}}header[role="banner"] .user-actions{background-color:inherit;font-size:12px;height:auto;padding:0}header[role="banner"] .user-actions [class$="-user-action"]{color:#333}header[role="banner"] .user-actions[data-user-type="anonymous"] [class$="-user-action"]{display:none;position:absolute}header[role="banner"] .user-actions[data-user-type="authenticated"]{left:6.25rem;line-height:1em;position:absolute;top:2.1875rem;white-space:nowrap}header[role="banner"] .user-actions[data-user-type="authenticated"] .user-action-list{border-bottom:1px solid #e5e5e5;display:none;padding-top:16px}header[role="banner"] .user-actions[data-user-type="authenticated"] .user-action-list [class$="-user-action"]{background-color:#fff;border:1px solid #e5e5e5;border-bottom:none;transition:background-color .5s}header[role="banner"] .user-actions[data-user-type="authenticated"] .user-action-list [class$="-user-action"]:hover{background-color:#f93f23;color:#fff}header[role="banner"] .user-actions[data-user-type="authenticated"] .user-action-list [class$="-user-action"] a{display:block;padding:15px}header[role="banner"] .user-actions[data-user-type="authenticated"][data-show-user-actions="true"] .user-action-list{display:block}.user-status{display:block;position:absolute;right:3.8125rem}.user-status .loading-message-wrapper{height:2rem;left:10px;opacity:.25;top:6px;width:2rem}.user-status .loading-message-wrapper .loading-message{height:2rem;width:2rem}.user-status .recipebox-status{display:block;outline:none}.user-status[data-user-type="anonymous"]{top:1.25rem}.user-status[data-user-type="anonymous"] .recipebox-status{height:1.3125rem;width:1.3125rem}.user-status[data-user-type="anonymous"] .login-register-actions{color:#a1a1a1;display:none;font-size:.8125rem;letter-spacing:1px;line-height:1;vertical-align:top}.user-status[data-user-type="anonymous"] .login-register-actions a:hover{color:#333;text-decoration:none}.user-status[data-user-type="anonymous"] .login-register-actions [title="Log-in"]:after{color:#a1a1a1;content:"/"}.user-status[data-user-type="authenticated"]{outline:none;top:.9375rem}.user-status[data-user-type="authenticated"] .recipebox-status{height:1.75rem;width:1.75rem}.user-status[data-user-type="authenticated"] .recipebox-size{font-family:"Renner",sans-serif;font-style:normal;font-weight:bold;color:#f93f23;font-size:.625rem;line-height:.625rem;background-color:#fff;border:solid 1px #a1a1a1;border-radius:100%;bottom:.5rem;display:block;height:1.25rem;overflow:hidden;padding:.25rem 0;position:absolute;right:-.625rem;text-align:center;width:1.25rem}.user-status[data-user-type="authenticated"] .user-greeting{color:#f93f23;display:none}.user-status[data-user-type="authenticated"]:hover .recipebox-size,.user-status[data-user-type="authenticated"]:hover .user-greeting{text-decoration:underline}.main-navigation .user-status[data-user-type="anonymous"]{margin-top:1.125rem;position:static}.main-navigation .user-status[data-user-type="anonymous"] .recipebox-status{display:none}.main-navigation .user-status[data-user-type="anonymous"] .login-register-actions{border:solid 1px #979797;color:#979797;display:inline-block;margin:0 auto;padding:.5rem 2rem}.main-navigation .user-status[data-user-type="anonymous"] .login-register-actions a:hover{color:#f93f23}.main-navigation .user-status[data-user-type="authenticated"]{display:none}@media only screen and (min-width: 768px){.user-status[data-user-type="anonymous"]{top:1.0625rem}.user-status[data-user-type="anonymous"] .recipebox-status{height:1.5rem;width:1.5rem}.user-status[data-user-type="authenticated"]{right:4.3125rem}}@media only screen and (min-width: 1024px){.user-status{left:4.1875rem;right:initial;z-index:21}.user-status[data-user-type="anonymous"]{top:1.3125rem}.user-status[data-user-type="anonymous"] .recipebox-status{height:1.3125rem;width:1.3125rem}.user-status[data-user-type="anonymous"] .login-register-actions{display:inline-block;margin:4px 0 0 12px}.user-status[data-user-type="authenticated"]{right:initial}.user-status[data-user-type="authenticated"] .user-greeting{display:inline-block;font-size:.8125rem;font-weight:normal;left:2.8125rem;letter-spacing:0.1px;position:absolute;top:.375rem;white-space:nowrap}}@media screen, print{.printable header[role="banner"]{width:auto}.printable header[role="banner"] .show-main-nvaigation,.printable header[role="banner"] .user-status,.printable header[role="banner"] .search-dialog{display:none}}[class$="-comment-form"]{left:50%;margin-left:-45%;padding:25px 0 0;position:absolute;top:0}[class$="-comment-form"] .title{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#333;font-size:1.875rem;line-height:1.875rem;padding:0 16px}[class$="-comment-form"] .description,[class$="-comment-form"] .warning{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#333;font-size:.875rem;line-height:1.25rem;margin:12px 0;padding:0 16px}[class$="-comment-form"] .warning{color:#f93f23}[class$="-comment-form"] .actions,[class$="-comment-form"] .fields{border:none;margin:0;padding:0 16px}[class$="-comment-form"] .comment,[class$="-comment-form"] .email,[class$="-comment-form"] .name{font-family:"Renner",sans-serif;font-style:normal;font-weight:normal;color:#333;font-size:.875rem;line-height:.875rem;display:block;width:100%;border:1px solid #ccc;margin:.5rem 0;padding:.5rem}[class$="-comment-form"] .comment.error,[class$="-comment-form"] .comment:invalid,[class$="-comment-form"] .email.error,[class$="-comment-form"] .email:invalid,[class$="-comment-form"] .name.error,[class$="-comment-form"] .name:invalid{border-color:#f93f23}[class$="-comment-form"] .comment:focus,[class$="-comment-form"] .email:focus,[class$="-comment-form"] .name:focus{border-color:#999;outline:none}[class$="-comment-form"] .comment{overflow-y:auto;resize:none}[class$="-comment-form"] .close-button{background-color:transparent;background-repeat:no-repeat;background-position:50% 50%;background-size:.9375rem,.9375rem;border:none;direction:ltr;display:inline-block;height:.9375rem;overflow:hidden;padding:0;text-indent:-9999px;width:.9375rem;position:absolute;right:13px;top:11px}[class$="-comment-form"] .close-button>a{display:block;height:100%;width:100%}[class$="-comment-form"] .submit-button{font-family:"Renner",sans-serif;font-style:normal;font-weight:bold;color:#fff;font-size:.875rem;line-height:0rem;background-color:#333;display:block;margin:36px auto;padding:23px 0 22px;width:100%}@media only screen and (min-width: 768px){[class$="-comment-form"]{margin-left:-189px;padding:30px 0 0;width:378px}[class$="-comment-form"] .title,[class$="-comment-form"] .description,[class$="-comment-form"] .warning{padding:0 30px}[class$="-comment-form"] .fields,[class$="-comment-form"] .actions{padding:0 30px}[class$="-comment-form"] .name,[class$="-comment-form"] .email,[class$="-comment-form"] .comment{margin:8px 0}[class$="-comment-form"] .close-button{right:15px;top:15px}[class$="-comment-form"] .submit-button{width:158px}}footer[role="contentinfo"]{-webkit-transition:-webkit-transform .3s linear;-moz-transition:-moz-transform .3s linear;-o-transition:-o-transform .3s linear;transition:transform .3s linear;background-color:#f93f23}footer[role="contentinfo"] ::selection{background-color:transparent}footer[role="contentinfo"] ul,footer[role="contentinfo"] li{display:inline;margin:0;padding:0}footer[role="contentinfo"] .epicurious-links,footer[role="contentinfo"] .corporate-info{display:block;margin:0 auto;padding:52px 16px;width:100%}footer[role="contentinfo"] .epicurious-links [class$="-link"]{font:bold .75rem/1.0625rem "Renner",sans-serif;color:#fff;letter-spacing:1px;padding:5px 0}footer[role="contentinfo"] .epicurious-links>.section-title{display:none}footer[role="contentinfo"] .epicurious-links .epi-social-links .nav-title{background-position:0 0;height:1.875rem;margin-bottom:1.25rem;vertical-align:top;width:100%}footer[role="contentinfo"] .epicurious-links .epi-social-links .nav-title:hover{cursor:pointer}footer[role="contentinfo"] .epicurious-links .epi-social-links .links-list [class$="-link"]{display:inline-block;height:1.75rem;margin-right:.5rem;width:1.75rem}footer[role="contentinfo"] .epicurious-links .channel-links,footer[role="contentinfo"] .epicurious-links .helpful-links,footer[role="contentinfo"] .epicurious-links .fig-links{display:none}footer[role="contentinfo"] .epicurious-links .channel-links .nav-title,footer[role="contentinfo"] .epicurious-links .channel-links .nav-title a,footer[role="contentinfo"] .epicurious-links .helpful-links .nav-title,footer[role="contentinfo"] .epicurious-links .helpful-links .nav-title a,footer[role="contentinfo"] .epicurious-links .fig-links .nav-title,footer[role="contentinfo"] .epicurious-links .fig-links .nav-title a{font:bold .875rem/1.125rem "Renner",sans-serif;color:#fff;margin-bottom:18px;text-transform:uppercase;letter-spacing:1px}footer[role="contentinfo"] .corporate-info-wrap{background-color:#292929;padding-bottom:62px}footer[role="contentinfo"] .corporate-info{font:normal .8125rem/.8125rem "Renner",sans-serif;color:#868686}footer[role="contentinfo"] .corporate-info a:link,footer[role="contentinfo"] .corporate-info a:visited{color:#868686}footer[role="contentinfo"] .corporate-info>.section-title{display:block;height:23px;margin:0 0 17px;width:160px}footer[role="contentinfo"] .corporate-info .conde-nast-brands{display:inline-block;position:relative}footer[role="contentinfo"] .corporate-info .conde-nast-brands .nav-title{font:normal .75rem/0 "Renner",sans-serif;color:#868686;letter-spacing:1px;border:1px solid #5f5d5c;display:inline-block;height:0;padding:19px 13px 19px 0;text-align:center;vertical-align:middle;width:183px}footer[role="contentinfo"] .corporate-info .conde-nast-brands .nav-title:after{height:8px;margin-left:5px;margin-top:-5px;position:absolute;top:50%;transform:rotate(90deg)}footer[role="contentinfo"] .corporate-info .conde-nast-brands .nav-title:hover{cursor:pointer}footer[role="contentinfo"] .corporate-info .conde-nast-brands .conde-nast-brands-list{background-color:#292929;border:1px solid #5f5d5c;bottom:41px;display:none;line-height:21px;padding:10px 0;position:absolute;width:183px}footer[role="contentinfo"] .corporate-info .conde-nast-brands .conde-nast-brands-list .conde-nast-brand{display:block;margin:0 0 0 16px}footer[role="contentinfo"] .corporate-info .conde-nast-brands[aria-hidden="false"] .nav-title:after{margin-top:-1px;transform:rotate(-90deg)}footer[role="contentinfo"] .corporate-info .conde-nast-brands[aria-hidden="false"] .conde-nast-brands-list{display:block}footer[role="contentinfo"] .corporate-info .conde-nast-services,footer[role="contentinfo"] .corporate-info .legal-notice{margin-top:27px}footer[role="contentinfo"] .corporate-info .conde-nast-services{display:none}footer[role="contentinfo"] .corporate-info .conde-nast-services .conde-nast-service{font:bold .625rem/1.125rem "Renner",sans-serif;color:#868686;letter-spacing:1px}footer[role="contentinfo"] .corporate-info .legal-notice .title{display:none}footer[role="contentinfo"] .corporate-info .legal-notice p{font:normal .75rem/1rem "Renner",sans-serif;color:#868686;letter-spacing:1px;display:inline;margin-right:.375rem}@media only screen and (min-width: 768px){footer[role="contentinfo"] .epicurious-links,footer[role="contentinfo"] .corporate-info{padding:52px 0;width:44.75rem}footer[role="contentinfo"] .epicurious-links .epi-social-links{border-bottom:1px solid #fff;margin-bottom:1.25rem;padding-bottom:1.25rem}footer[role="contentinfo"] .epicurious-links .epi-social-links .nav-title{margin:0;width:50%}footer[role="contentinfo"] .epicurious-links .epi-social-links .links-list{display:inline-block;text-align:right;width:50%}footer[role="contentinfo"] .epicurious-links .epi-social-links .links-list [class$="-link"]{height:1.75rem;margin-left:.5rem;margin-right:0;width:1.75rem}footer[role="contentinfo"] .epicurious-links .channel-links,footer[role="contentinfo"] .epicurious-links .helpful-links,footer[role="contentinfo"] .epicurious-links .fig-links{display:inline-block;width:34%;vertical-align:top}footer[role="contentinfo"] .epicurious-links .channel-links [class$="-link"],footer[role="contentinfo"] .epicurious-links .helpful-links [class$="-link"],footer[role="contentinfo"] .epicurious-links .fig-links [class$="-link"]{display:block}footer[role="contentinfo"] .epicurious-links .fig-links{float:right;width:auto}footer[role="contentinfo"] .corporate-info-wrap{padding-bottom:0}footer[role="contentinfo"] .corporate-info>.section-title{display:inline-block;margin:0 17px 0 0;position:relative;top:5px}footer[role="contentinfo"] .corporate-info .conde-nast-services{display:block}footer[role="contentinfo"] .corporate-info .conde-nast-services .nav-title{display:none}footer[role="contentinfo"] .corporate-info .conde-nast-services .conde-nast-service{display:inline-block;margin:0 16px 0 0;text-transform:uppercase}}@media only screen and (min-width: 1024px){footer[role="contentinfo"] .epicurious-links,footer[role="contentinfo"] .corporate-info{width:62.75rem}footer[role="contentinfo"] .epicurious-links .epi-social-links{border-bottom:none;display:inline-block;width:40%}footer[role="contentinfo"] .epicurious-links .epi-social-links .nav-title{margin-bottom:1.25rem;width:50%}footer[role="contentinfo"] .epicurious-links .epi-social-links .links-list{display:block;text-align:left;width:100%}footer[role="contentinfo"] .epicurious-links .epi-social-links .links-list [class$="-link"]{font-size:11px;height:1.75rem;margin-left:0;margin-right:.5rem}footer[role="contentinfo"] .epicurious-links .channel-links,footer[role="contentinfo"] .epicurious-links .helpful-links{width:19%}footer[role="contentinfo"] .epicurious-links .fig-links{width:auto}footer[role="contentinfo"] .epicurious-links .helpful-links{margin-left:0}footer[role="contentinfo"] .corporate-info .conde-nast-services{float:right;margin-top:13px}footer[role="contentinfo"] .corporate-info .conde-nast-services .conde-nast-service{margin:0 0 0 16px}}@media screen, print{.printable footer[role="contentinfo"]{display:none}}
  </style>
  <link href="/static/css/search__3.23.0.css" rel="stylesheet"/>
  <script type="text/javascript">
   var digitalData = {
          "display" : "Search Results","pageType" : "search","section" : "search","canonical" : "https://www.epicurious.com/search/tofu%20chill","pageValue" : "all",
        };
  </script>
  <script defer="" src="https://assets.adobedtm.com/6372cf21ef88ee60bc2977a4898dcb5c7945a212/satelliteLib-b8937e0c536ed51fe92efb5ca25fc6f76fdeef0e.js">
  </script>
  <!-- Google Tag Manager -->
  <script type="text/javascript">
   (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
      new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
      j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
      'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
      })(window,document,'script','dataLayer','GTM-PCTXLQR');
  </script>
  <script async="" id="gpt-script" src="https://www.googletagservices.com/tag/js/gpt.js">
  </script>
  <script>
   window.googletag=window.googletag||{};window.googletag.cmd=window.googletag.cmd||[];window.cns=window.cns||{};window.cns.queue=[];window.cns.async=function(s,c){cns.queue.push({service:s,callback:c})};window.sparrowQueue=window.sparrowQueue||[];
  </script>
  <link href="https://securepubads.g.doubleclick.net" rel="preconnect"/>
  <link href="//aax.amazon-adsystem.com" rel="dns-prefetch"/>
  <link crossorigin="" href="//aax.amazon-adsystem.com" rel="preconnect"/>
  <script id="cns-head-include">
   !function(){"use strict";var n,t=(function(n,t){var r=function(){var n=0;function t(n){var t=[],r=0,i=0;this.push=function(s){r-i>=n&&++i>=n&&(i=0,r=n-1),t[r%n]=s,r++},this.asArray=function(){var s=t.slice(i,Math.min(r,n)),u=t.slice(0,Math.max(r-n,0));return s.concat(u)},this.list=t}function r(t,r){for(var i=r,s=0;s<t.length;s++){var u=t[s],a=i.r;a[u]||(a[u]={w:u,r:{},i:n++}),i=a[u]}return i}function i(n,t,r){var i;return r[n]?i=r[n]:(i=function(n,t){for(var r=[[t,0]],i={},s=[];r.length;){var u=r.shift(),a=u[0],e=u[1],o=a.r,f=n[e];if(void 0===f&&a.fn&&!i[a.i]?(i[a.i]=1,s.push(a.fn)):o[f]&&r.push([o[f],e+1]),o["#"])for(var h=e;h<=n.length;h++)r.push([o["#"],h]);f&&o["*"]&&r.push([o["*"],e+1])}return s}(n.split("."),t),r[n]=i),i}var s=function(){var s={w:"",r:{},i:n++},u={},a=new t(9999);function e(n,t){var i=r(n.split("."),s),a=i.fn||[];return a.push(t),i.fn=a,u={},function(){var n=a.indexOf(t);n>-1&&a.splice(n,1)}}function o(n,t){var r=Date.now();a.push([n,r]);for(var e=i(n,s,u),o={topic:n},f=0;f<e.length;f++)for(var h=e[f],c=0;c<h.length;c++)h[c](t,o)}this.emit=o,this.on=e,this.history=function(t){var s={w:"",r:{},i:n++};r(t.split("."),s).fn=1;for(var u=[],e={},o=a.asArray(),f=0;f<o.length;f++){var h=o[f];i(h[0],s,e).length&&u.push(h)}return u},this.publish=o,this.subscribe=e};return s.Ring=t,s}();n.exports=r}(n={exports:{}}),n.exports);window.cnBus=window.cnBus||new t,window.cns=window.cns||{};var r=window.cns;r.fastAdsHead="6.28.2",r.timing=r.timing||{},r.timing.headerStart=Date.now(),r.queue=r.queue||[],r.flags={}}();
  </script>
  <script async="" src="https://c.amazon-adsystem.com/aax2/apstag.js">
  </script>
  <script async="" src="https://js-sec.indexww.com/ht/htw-condenast.js">
  </script>
  <script type="text/javascript">
   window.__CORE_DATALAYER__ = {"content":{"contentLength":12,"display":"Search Results","pageAssets":"5a0330ea57e96a30a35d163c|57180141136b9a220ecd7dce|562a62dab3d63be14330b17c|54a422f56529d92b2c0096e8|54a422d96529d92b2c009609|54a4216a19925f464b3785c7|54a427be6529d92b2c00cd4c|54a42a5219925f464b37ea8a|54a4276219925f464b37c5f1|54a42e8319925f464b381eab|54a4332f6529d92b2c016045|54a4729919925f464b399731","pageType":"search","pageValue":"all","section":"search"},"page":{"canonical":"https://www.epicurious.com/search/tofu%20chill","canonicalPathName":"/search/tofu%20chill","pageURL":"https://www.epicurious.com/search/tofu%20chill?page=1"},"search":{"searchTerms":"tofu chill"}};
  </script>
 </head>
 <body class="search-page">
  <!-- NoScript - Google Tag Manager -->
  <noscript>
   <iframe height="0" src="https://www.googletagmanager.com/ns.html?id=GTM-PCTXLQR" style="display:none;visibility:hidden" width="0">
   </iframe>
  </noscript>
  <!--[if lte IE 9]>
      <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a target="_new" href="https://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
    <![endif]-->
  <span class="page-wrap" id="react-app">
   <span class="page" data-react-checksum="772623644" data-reactid="1" data-reactroot="">
    <div class="header-wrapper" data-reactid="2">
     <div class="header" data-reactid="3" role="banner">
      <h2 data-reactid="4" itemtype="https://schema.org/Organization">
       <a data-reactid="5" href="/" itemprop="url" title="Epicurious">
        Epicurious
       </a>
      </h2>
      <div class="search-form-container" data-reactid="6">
       <form action="/search/" autocomplete="off" data-reactid="7" method="get" role="search">
        <fieldset data-reactid="8">
         <button class="submit" data-reactid="9" type="submit">
          search
         </button>
         <input autocomplete="off" data-reactid="10" maxlength="120" name="terms" placeholder="Find a Recipe" type="text" value="tofu chill"/>
         <button class="filter mobile" data-reactid="11">
          filters
         </button>
         <button class="filter tablet" data-reactid="12">
          filter results
         </button>
        </fieldset>
       </form>
       <div class="ingredient-filters" data-reactid="13">
        <h3 data-reactid="14">
         Include/Exclude Ingredients
        </h3>
        <form class="include-ingredients" data-reactid="15">
         <fieldset data-reactid="16">
          <input aria-label="Include ingredients" data-reactid="17" placeholder="Include ingredients:" type="text"/>
          <button data-reactid="18">
           include
          </button>
         </fieldset>
        </form>
        <form class="exclude-ingredients" data-reactid="19">
         <fieldset data-reactid="20">
          <input aria-label="Exclude ingredients" data-reactid="21" placeholder="Exclude ingredients:" type="text"/>
          <button data-reactid="22">
           exclude
          </button>
         </fieldset>
        </form>
       </div>
       <button class="filter ingredient-filter" data-reactid="23">
        include/exclude ingredients
       </button>
       <div class="search-tags" data-reactid="24">
        <button class="clear-all" data-reactid="25">
         Clear all
        </button>
       </div>
      </div>
     </div>
     <div class="filters" data-reactid="26">
      <div data-reactid="27">
       <!-- react-empty: 28 -->
       <div class="filter-action-panel" data-reactid="29">
        <p data-reactid="30">
         <!-- react-text: 31 -->
         12
         <!-- /react-text -->
         <!-- react-text: 32 -->
         matching results
         <!-- /react-text -->
        </p>
        <button data-reactid="33">
         Apply
        </button>
        <button data-reactid="34">
         Cancel
        </button>
       </div>
      </div>
     </div>
    </div>
    <div class="search-results-status" data-reactid="35">
     <div class="search-tags" data-reactid="36">
      <button class="clear-all" data-reactid="37">
       Clear all
      </button>
     </div>
     <p class="results-message" data-reactid="38">
      <span class="matching-count" data-reactid="39">
       12
      </span>
      <!-- react-text: 40 -->
      matching results for
      <!-- /react-text -->
      <em class="terms" data-reactid="41">
       tofu chill
      </em>
     </p>
     <div class="search-sort-container" data-reactid="42">
      <div class="content-type-filter-options-menu" data-reactid="43">
       <label aria-expanded="false" data-reactid="44" for="content-type-filter-options-menu" role="button">
        <span class="options-menu-title" data-reactid="45">
         Show
        </span>
        <span class="selected-option-text" data-reactid="46">
         All Content
        </span>
       </label>
       <select data-reactid="47" id="content-type-filter-options-menu" name="content-type-filter">
        <option data-reactid="48" selected="" value="all">
         All Content
        </option>
        <option data-reactid="49" value="recipe">
         Recipes
        </option>
        <option data-reactid="50" value="article">
         Articles
        </option>
        <option data-reactid="51" disabled="" value="package">
         Guides
        </option>
        <option data-reactid="52" value="menu">
         Menus
        </option>
        <option data-reactid="53" value="gallery">
         Galleries
        </option>
        <option data-reactid="54" value="cnevideo">
         Videos
        </option>
       </select>
      </div>
      <div class="sort-filter-options-menu" data-reactid="55">
       <label aria-expanded="false" data-reactid="56" for="sort-filter-options-menu" role="button">
        <span class="options-menu-title" data-reactid="57">
         Sort by
        </span>
        <span class="selected-option-text" data-reactid="58">
         Relevance
        </span>
       </label>
       <select data-reactid="59" id="sort-filter-options-menu" name="sort-filter">
        <option data-reactid="60" selected="" value="relevance">
         Relevance
        </option>
        <option data-reactid="61" value="newest">
         Newest
        </option>
        <option data-reactid="62" value="highestRated">
         Highest Rated
        </option>
        <option data-reactid="63" value="mostReviewed">
         Most Reviewed
        </option>
        <option data-reactid="64" value="makeItAgain">
         Make Again %
        </option>
       </select>
      </div>
     </div>
    </div>
    <section data-query="tofu chill" data-reactid="65" role="main">
     <h3 class="section-title" data-reactid="66">
      Search Results
     </h3>
     <div class="results-group" data-group-number="1" data-reactid="67">
      <article class="article-content-card" data-has-quickview="false" data-index="0" data-reactid="68" itemscope="" itemtype="https://schema.org/ItemPage">
       <header class="summary" data-reactid="69">
        <strong class="tag" data-reactid="70">
         article
        </strong>
        <h4 class="hed" data-reactid="71" data-truncate="3" itemprop="name">
         <a data-reactid="72" href="/expert-advice/emily-gould-cooking-diary-article">
          What the Writer-Publisher-Mom Emily Gould Cooks in a Week
         </a>
        </h4>
        <p class="dek" data-reactid="73" data-truncate="1">
         The novelist and independent book publisher relies on intuition, leftovers, and some very good cookbooks to make dinner happen.
        </p>
       </header>
       <a class="photo-link" data-reactid="74" href="/expert-advice/emily-gould-cooking-diary-article">
        <div class="photo-wrap" data-reactid="75">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="76">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="77" href="/expert-advice/emily-gould-cooking-diary-article" itemprop="url" title="What the Writer-Publisher-Mom Emily Gould Cooks in a Week  ">
        <!-- react-text: 78 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 79 -->
        What the Writer-Publisher-Mom Emily Gould Cooks in a Week
        <!-- /react-text -->
        <!-- react-text: 80 -->
        ”
        <!-- /react-text -->
       </a>
      </article>
      <article class="article-content-card" data-has-quickview="false" data-index="1" data-reactid="81" itemscope="" itemtype="https://schema.org/ItemPage">
       <header class="summary" data-reactid="82">
        <strong class="tag" data-reactid="83">
         article
        </strong>
        <h4 class="hed" data-reactid="84" data-truncate="3" itemprop="name">
         <a data-reactid="85" href="/expert-advice/dirty-secrets-of-a-home-cook-article">
          Dirty Secrets of a Home Cook
         </a>
        </h4>
        <p class="dek" data-reactid="86" data-truncate="1">
         A food writer gives us a peek into what really happens behind the scenes in her kitchen. And some of it isn't pretty.
        </p>
       </header>
       <a class="photo-link" data-reactid="87" href="/expert-advice/dirty-secrets-of-a-home-cook-article">
        <div class="photo-wrap" data-reactid="88">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="89">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="90" href="/expert-advice/dirty-secrets-of-a-home-cook-article" itemprop="url" title="Dirty Secrets of a Home Cook">
        <!-- react-text: 91 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 92 -->
        Dirty Secrets of a Home Cook
        <!-- /react-text -->
        <!-- react-text: 93 -->
        ”
        <!-- /react-text -->
       </a>
      </article>
      <article class="article-content-card" data-has-quickview="false" data-index="2" data-reactid="94" itemscope="" itemtype="https://schema.org/ItemPage">
       <header class="summary" data-reactid="95">
        <strong class="tag" data-reactid="96">
         article
        </strong>
        <h4 class="hed" data-reactid="97" data-truncate="3" itemprop="name">
         <a data-reactid="98" href="/expert-advice/why-the-freezer-aisle-is-a-woks-best-friend-article">
          Frozen Vegetables Are a Wok's Best Friend
         </a>
        </h4>
        <p class="dek" data-reactid="99" data-truncate="1">
         All of the flavor, none of the prep work.
        </p>
       </header>
       <a class="photo-link" data-reactid="100" href="/expert-advice/why-the-freezer-aisle-is-a-woks-best-friend-article">
        <div class="photo-wrap" data-reactid="101">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="102">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="103" href="/expert-advice/why-the-freezer-aisle-is-a-woks-best-friend-article" itemprop="url" title="Frozen Vegetables Are a Wok's Best Friend">
        <!-- react-text: 104 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 105 -->
        Frozen Vegetables Are a Wok's Best Friend
        <!-- /react-text -->
        <!-- react-text: 106 -->
        ”
        <!-- /react-text -->
       </a>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="3" data-reactid="107" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="108">
        <strong class="tag" data-reactid="109">
         recipe
        </strong>
        <h4 class="hed" data-reactid="110" data-truncate="3" itemprop="name">
         <a data-reactid="111" href="/recipes/food/views/sea-bean-salad-with-daikon-and-cucumber-51199610">
          Sea Bean Salad with Daikon and Cucumber
         </a>
        </h4>
        <p class="dek" data-reactid="112" data-truncate="1">
         When we visited Kyoto, a few hours' ride from Tokyo on the famous Bullet train, we found a little restaurant in the heart of town that won us over with the names of dishes listed on the menu: Firecracker Tofu, Pickled Mixed Radish Salad, and the mysterious sounding Okonomiyaki. The chefs were clearly having fun at this place, and we were blown away by the depth of flavor they achieved with such simple preparations. We threw back some sake and tore through plate after plate of food. This salad is inspired by that meal, featuring quirky sea beans (a seaweed-like swamp/beach vegetable) and the haunting flavor of shiso (Japanese mint). You can find fresh sea beans at a gourmet market. If they're not available, substitute pencil-thin asparagus. Look for shiso in Asian markets, but substitute fresh cilantro if you can't find it.
        </p>
        <dl class="recipes-ratings-summary" data-reactid="113" data-reviews-count="0" data-reviews-rating="0" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="114">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="115">
          <dd class="rating" data-rating="unrated" data-reactid="116">
           <span data-reactid="117" itemprop="ratingValue">
            0
           </span>
           <!-- react-text: 118 -->
           /
           <!-- /react-text -->
           <span data-reactid="119" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="120" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="121">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="122" itemprop="reviewCount">
           0
          </dd>
         </span>
         <span class="make-again-container" data-reactid="123">
          <dt class="make-again-percentage-label" data-reactid="124">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="125">
           <!-- react-text: 126 -->
           0
           <!-- /react-text -->
           <!-- react-text: 127 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="128" href="/recipes/food/views/sea-bean-salad-with-daikon-and-cucumber-51199610">
        <div class="photo-wrap" data-reactid="129">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="130">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="131" href="/recipes/food/views/sea-bean-salad-with-daikon-and-cucumber-51199610" itemprop="url" title="Sea Bean Salad with Daikon and Cucumber">
        <!-- react-text: 132 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 133 -->
        Sea Bean Salad with Daikon and Cucumber
        <!-- /react-text -->
        <!-- react-text: 134 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="135">
        <a class="view-complete-item" data-reactid="136" href="/recipes/food/views/sea-bean-salad-with-daikon-and-cucumber-51199610">
         View Recipe
        </a>
        <div class="controls" data-reactid="137">
         <a class="show-quick-view" data-reactid="138" href="/recipes/food/views/sea-bean-salad-with-daikon-and-cucumber-51199610" title="Sea Bean Salad with Daikon and Cucumber">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="139">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="4" data-reactid="140" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="141">
        <strong class="tag" data-reactid="142">
         recipe
        </strong>
        <h4 class="hed" data-reactid="143" data-truncate="3" itemprop="name">
         <a data-reactid="144" href="/recipes/food/views/pickled-red-onions-51196620">
          Pickled Red Onions
         </a>
        </h4>
        <p class="dek" data-reactid="145" data-truncate="1">
         Vegan (when made with agave nectar or sugar)
This trick will alter and augment your cooking: Pour boiling water over sliced or diced red onions, then transfer them to a solution of vinegar, sweetener, and salt. The onions will brighten into a gaudy shade of purplish-pink and will keep indefinitely, mysteriously retaining their bright color and crisp texture. rather than slice, the onions, if they are headed for one of the cold soups.)
You can vary the cut of the onions—and also the amounts of sweet and salt. Use as a dramatically colorful and refreshing tiara atop dinner plates, open-faced sandwiches, salads, cheeses, grilled tofu, or fish—anything savory. I use these often as an ingredient in cold soups and saladitas. (Mince, rather than slice, the onions, if they are headed for one of the cold soups.)
• Use a very sharp knife or a food processor with a thin slicing attachment to cut the onions most easily.
        </p>
        <dl class="recipes-ratings-summary" data-reactid="146" data-reviews-count="5" data-reviews-rating="3.14" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="147">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="148">
          <dd class="rating" data-rating="3" data-reactid="149">
           <span data-reactid="150" itemprop="ratingValue">
            3
           </span>
           <!-- react-text: 151 -->
           /
           <!-- /react-text -->
           <span data-reactid="152" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="153" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="154">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="155" itemprop="reviewCount">
           5
          </dd>
         </span>
         <span class="make-again-container" data-reactid="156">
          <dt class="make-again-percentage-label" data-reactid="157">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="158">
           <!-- react-text: 159 -->
           60
           <!-- /react-text -->
           <!-- react-text: 160 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="161" href="/recipes/food/views/pickled-red-onions-51196620">
        <div class="photo-wrap" data-reactid="162">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="163">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="164" href="/recipes/food/views/pickled-red-onions-51196620" itemprop="url" title="Pickled Red Onions">
        <!-- react-text: 165 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 166 -->
        Pickled Red Onions
        <!-- /react-text -->
        <!-- react-text: 167 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="168">
        <a class="view-complete-item" data-reactid="169" href="/recipes/food/views/pickled-red-onions-51196620">
         View Recipe
        </a>
        <div class="controls" data-reactid="170">
         <a class="show-quick-view" data-reactid="171" href="/recipes/food/views/pickled-red-onions-51196620" title="Pickled Red Onions">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="172">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="5" data-reactid="173" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="174">
        <strong class="tag" data-reactid="175">
         recipe
        </strong>
        <h4 class="hed" data-reactid="176" data-truncate="3" itemprop="name">
         <a data-reactid="177" href="/recipes/food/views/new-wave-new-fave-baked-tofu-or-tempeh-394509">
          New Wave-New Fave Baked Tofu or Tempeh
         </a>
        </h4>
        <p class="dek" data-reactid="178" data-truncate="1">
         I've been doing the previous marinades forever. This new one is first cousin to a good barbecued tofu: piquant, sweet-hot-rich, and scintillatingly tasty. The tofu is baked in the marinade/sauce, which cooks down and coats it, caramelizing them. You'll probably have to soak the baking dish overnight before washing it, but it's worth it. Vary this using fruit juice concentrate instead of honey or sugar, and adding extra ginger, orange zest, or both. For an incendiary smokiness, add chipotle in adobo.
        </p>
        <dl class="recipes-ratings-summary" data-reactid="179" data-reviews-count="1" data-reviews-rating="3" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="180">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="181">
          <dd class="rating" data-rating="3" data-reactid="182">
           <span data-reactid="183" itemprop="ratingValue">
            3
           </span>
           <!-- react-text: 184 -->
           /
           <!-- /react-text -->
           <span data-reactid="185" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="186" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="187">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="188" itemprop="reviewCount">
           1
          </dd>
         </span>
         <span class="make-again-container" data-reactid="189">
          <dt class="make-again-percentage-label" data-reactid="190">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="191">
           <!-- react-text: 192 -->
           100
           <!-- /react-text -->
           <!-- react-text: 193 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="194" href="/recipes/food/views/new-wave-new-fave-baked-tofu-or-tempeh-394509">
        <div class="photo-wrap" data-reactid="195">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="196">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="197" href="/recipes/food/views/new-wave-new-fave-baked-tofu-or-tempeh-394509" itemprop="url" title="New Wave-New Fave Baked Tofu or Tempeh">
        <!-- react-text: 198 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 199 -->
        New Wave-New Fave Baked Tofu or Tempeh
        <!-- /react-text -->
        <!-- react-text: 200 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="201">
        <a class="view-complete-item" data-reactid="202" href="/recipes/food/views/new-wave-new-fave-baked-tofu-or-tempeh-394509">
         View Recipe
        </a>
        <div class="controls" data-reactid="203">
         <a class="show-quick-view" data-reactid="204" href="/recipes/food/views/new-wave-new-fave-baked-tofu-or-tempeh-394509" title="New Wave-New Fave Baked Tofu or Tempeh">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="205">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="6" data-reactid="206" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="207">
        <strong class="tag" data-reactid="208">
         recipe
        </strong>
        <h4 class="hed" data-reactid="209" data-truncate="3" itemprop="name">
         <a data-reactid="210" href="/recipes/food/views/vegan-mayonnaise-366490">
          Vegan Mayonnaise
         </a>
        </h4>
        <p class="dek" data-reactid="211" data-truncate="1">
         Wheat Free
No need to worry if your local market doesn't carry egg-free mayo. Just whip up some of your own. This recipe works very well as a sandwich spread or in any mayonnaise-based dressing. As long as you use wheat-free vinegar, this mayo is indeed wheat-free.
        </p>
        <dl class="recipes-ratings-summary" data-reactid="212" data-reviews-count="3" data-reviews-rating="1" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="213">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="214">
          <dd class="rating" data-rating="1" data-reactid="215">
           <span data-reactid="216" itemprop="ratingValue">
            1
           </span>
           <!-- react-text: 217 -->
           /
           <!-- /react-text -->
           <span data-reactid="218" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="219" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="220">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="221" itemprop="reviewCount">
           3
          </dd>
         </span>
         <span class="make-again-container" data-reactid="222">
          <dt class="make-again-percentage-label" data-reactid="223">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="224">
           <!-- react-text: 225 -->
           33
           <!-- /react-text -->
           <!-- react-text: 226 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="227" href="/recipes/food/views/vegan-mayonnaise-366490">
        <div class="photo-wrap" data-reactid="228">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="229">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="230" href="/recipes/food/views/vegan-mayonnaise-366490" itemprop="url" title="Vegan Mayonnaise">
        <!-- react-text: 231 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 232 -->
        Vegan Mayonnaise
        <!-- /react-text -->
        <!-- react-text: 233 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="234">
        <a class="view-complete-item" data-reactid="235" href="/recipes/food/views/vegan-mayonnaise-366490">
         View Recipe
        </a>
        <div class="controls" data-reactid="236">
         <a class="show-quick-view" data-reactid="237" href="/recipes/food/views/vegan-mayonnaise-366490" title="Vegan Mayonnaise">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="238">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="7" data-reactid="239" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="240">
        <strong class="tag" data-reactid="241">
         recipe
        </strong>
        <h4 class="hed" data-reactid="242" data-truncate="3" itemprop="name">
         <a data-reactid="243" href="/recipes/food/views/teriyaki-black-cod-with-sticky-rice-cakes-and-seared-baby-bok-choy-363330">
          Teriyaki Black Cod with Sticky Rice Cakes and Seared Baby Bok Choy
         </a>
        </h4>
        <p class="dek" data-reactid="244" data-truncate="1">
         A staple of classic Japanese cooking, teriyaki is wonderful with not only seafood but also poultry, beef, vegetables, and tofu. Often, however, this versatile sauce can be quite sweet. My version uses fresh orange juice, which adds just a touch of natural sweetness as well as some acidity to temper the sweet mirin. Pouring some of the teriyaki sauce into the hot pan with the fish further reduces it so the sauce really coats the fish with a deep, caramel glaze that enhances the delectable moist, buttery, and tender qualities of black cod perfectly. Other good fish for this dish are Alaskan cod, true cod, sablefish, or wild salmon. Searing each side of the sticky rice cake gives a nutty flavor and crisp texture. I also like to serve these rice cakes with vegetable stir-fries in place of plain rice. If you have a rice cooker, use it to prepare the rice according to the manufacturer's directions. If not, follow the instructions in the recipe to prepare it in a saucepan.
        </p>
        <dl class="recipes-ratings-summary" data-reactid="245" data-reviews-count="9" data-reviews-rating="3.25" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="246">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="247">
          <dd class="rating" data-rating="3.5" data-reactid="248">
           <span data-reactid="249" itemprop="ratingValue">
            3.5
           </span>
           <!-- react-text: 250 -->
           /
           <!-- /react-text -->
           <span data-reactid="251" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="252" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="253">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="254" itemprop="reviewCount">
           9
          </dd>
         </span>
         <span class="make-again-container" data-reactid="255">
          <dt class="make-again-percentage-label" data-reactid="256">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="257">
           <!-- react-text: 258 -->
           88
           <!-- /react-text -->
           <!-- react-text: 259 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="260" href="/recipes/food/views/teriyaki-black-cod-with-sticky-rice-cakes-and-seared-baby-bok-choy-363330">
        <div class="photo-wrap" data-reactid="261">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="262">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="263" href="/recipes/food/views/teriyaki-black-cod-with-sticky-rice-cakes-and-seared-baby-bok-choy-363330" itemprop="url" title="Teriyaki Black Cod with Sticky Rice Cakes and Seared Baby Bok Choy">
        <!-- react-text: 264 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 265 -->
        Teriyaki Black Cod with Sticky Rice Cakes and Seared Baby Bok Choy
        <!-- /react-text -->
        <!-- react-text: 266 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="267">
        <a class="view-complete-item" data-reactid="268" href="/recipes/food/views/teriyaki-black-cod-with-sticky-rice-cakes-and-seared-baby-bok-choy-363330">
         View Recipe
        </a>
        <div class="controls" data-reactid="269">
         <a class="show-quick-view" data-reactid="270" href="/recipes/food/views/teriyaki-black-cod-with-sticky-rice-cakes-and-seared-baby-bok-choy-363330" title="Teriyaki Black Cod with Sticky Rice Cakes and Seared Baby Bok Choy">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="271">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="8" data-reactid="272" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="273">
        <strong class="tag" data-reactid="274">
         recipe
        </strong>
        <h4 class="hed" data-reactid="275" data-truncate="3" itemprop="name">
         <a data-reactid="276" href="/recipes/food/views/vegan-chocolate-cheesecake-355990">
          Vegan Chocolate Cheesecake
         </a>
        </h4>
        <p class="dek" data-reactid="277" data-truncate="1">
         Combining bittersweet chocolate and cocoa powder intensifies the chocolaty essence of this cheesecake to the nth degree. Silken tofu brings a delicate creaminess to the filling while also taking the place of eggs by acting as a binding agent.
        </p>
        <dl class="recipes-ratings-summary" data-reactid="278" data-reviews-count="15" data-reviews-rating="2.76" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="279">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="280">
          <dd class="rating" data-rating="3" data-reactid="281">
           <span data-reactid="282" itemprop="ratingValue">
            3
           </span>
           <!-- react-text: 283 -->
           /
           <!-- /react-text -->
           <span data-reactid="284" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="285" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="286">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="287" itemprop="reviewCount">
           15
          </dd>
         </span>
         <span class="make-again-container" data-reactid="288">
          <dt class="make-again-percentage-label" data-reactid="289">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="290">
           <!-- react-text: 291 -->
           58
           <!-- /react-text -->
           <!-- react-text: 292 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="293" href="/recipes/food/views/vegan-chocolate-cheesecake-355990">
        <div class="photo-wrap" data-reactid="294">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="295">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="296" href="/recipes/food/views/vegan-chocolate-cheesecake-355990" itemprop="url" title="Vegan Chocolate Cheesecake">
        <!-- react-text: 297 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 298 -->
        Vegan Chocolate Cheesecake
        <!-- /react-text -->
        <!-- react-text: 299 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="300">
        <a class="view-complete-item" data-reactid="301" href="/recipes/food/views/vegan-chocolate-cheesecake-355990">
         View Recipe
        </a>
        <div class="controls" data-reactid="302">
         <a class="show-quick-view" data-reactid="303" href="/recipes/food/views/vegan-chocolate-cheesecake-355990" title="Vegan Chocolate Cheesecake">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="304">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="9" data-reactid="305" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="306">
        <strong class="tag" data-reactid="307">
         recipe
        </strong>
        <h4 class="hed" data-reactid="308" data-truncate="3" itemprop="name">
         <a data-reactid="309" href="/recipes/food/views/chilled-soba-with-tofu-and-sugar-snap-peas-242834">
          Chilled Soba with Tofu and Sugar Snap Peas
         </a>
        </h4>
        <p class="dek" data-reactid="310" data-truncate="1">
         A bowl of these refreshing noodles—a riff on a Japanese classic that gets topped with silky tofu—is clean and light, yet still hearty enough to make a satisfying meal.
        </p>
        <dl class="recipes-ratings-summary" data-reactid="311" data-reviews-count="8" data-reviews-rating="3.53" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="312">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="313">
          <dd class="rating" data-rating="3.5" data-reactid="314">
           <span data-reactid="315" itemprop="ratingValue">
            3.5
           </span>
           <!-- react-text: 316 -->
           /
           <!-- /react-text -->
           <span data-reactid="317" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="318" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="319">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="320" itemprop="reviewCount">
           8
          </dd>
         </span>
         <span class="make-again-container" data-reactid="321">
          <dt class="make-again-percentage-label" data-reactid="322">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="323">
           <!-- react-text: 324 -->
           75
           <!-- /react-text -->
           <!-- react-text: 325 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="326" href="/recipes/food/views/chilled-soba-with-tofu-and-sugar-snap-peas-242834">
        <div class="photo-wrap" data-reactid="327">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="328">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="329" href="/recipes/food/views/chilled-soba-with-tofu-and-sugar-snap-peas-242834" itemprop="url" title="Chilled Soba with Tofu and Sugar Snap Peas">
        <!-- react-text: 330 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 331 -->
        Chilled Soba with Tofu and Sugar Snap Peas
        <!-- /react-text -->
        <!-- react-text: 332 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="333">
        <a class="view-complete-item" data-reactid="334" href="/recipes/food/views/chilled-soba-with-tofu-and-sugar-snap-peas-242834">
         View Recipe
        </a>
        <div class="controls" data-reactid="335">
         <a class="show-quick-view" data-reactid="336" href="/recipes/food/views/chilled-soba-with-tofu-and-sugar-snap-peas-242834" title="Chilled Soba with Tofu and Sugar Snap Peas">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="337">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="10" data-reactid="338" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="339">
        <strong class="tag" data-reactid="340">
         recipe
        </strong>
        <h4 class="hed" data-reactid="341" data-truncate="3" itemprop="name">
         <a data-reactid="342" href="/recipes/food/views/meyer-lemon-cream-pies-239225">
          Meyer Lemon Cream Pies
         </a>
        </h4>
        <p class="dek" data-reactid="343" data-truncate="1">
         A Meyer lemon is a cross between a lemon and a mandarin orange. If you can't find any, substitute regular lemons. This pie's decadent cream filling is made from protein-rich tofu.
        </p>
        <dl class="recipes-ratings-summary" data-reactid="344" data-reviews-count="8" data-reviews-rating="2.5" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="345">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="346">
          <dd class="rating" data-rating="2.5" data-reactid="347">
           <span data-reactid="348" itemprop="ratingValue">
            2.5
           </span>
           <!-- react-text: 349 -->
           /
           <!-- /react-text -->
           <span data-reactid="350" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="351" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="352">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="353" itemprop="reviewCount">
           8
          </dd>
         </span>
         <span class="make-again-container" data-reactid="354">
          <dt class="make-again-percentage-label" data-reactid="355">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="356">
           <!-- react-text: 357 -->
           50
           <!-- /react-text -->
           <!-- react-text: 358 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="359" href="/recipes/food/views/meyer-lemon-cream-pies-239225">
        <div class="photo-wrap" data-reactid="360">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="361">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="362" href="/recipes/food/views/meyer-lemon-cream-pies-239225" itemprop="url" title="Meyer Lemon Cream Pies">
        <!-- react-text: 363 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 364 -->
        Meyer Lemon Cream Pies
        <!-- /react-text -->
        <!-- react-text: 365 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="366">
        <a class="view-complete-item" data-reactid="367" href="/recipes/food/views/meyer-lemon-cream-pies-239225">
         View Recipe
        </a>
        <div class="controls" data-reactid="368">
         <a class="show-quick-view" data-reactid="369" href="/recipes/food/views/meyer-lemon-cream-pies-239225" title="Meyer Lemon Cream Pies">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="370">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <article class="recipe-content-card" data-has-quickview="false" data-index="11" data-reactid="371" itemscope="" itemtype="https://schema.org/Recipe">
       <header class="summary" data-reactid="372">
        <strong class="tag" data-reactid="373">
         recipe
        </strong>
        <h4 class="hed" data-reactid="374" data-truncate="3" itemprop="name">
         <a data-reactid="375" href="/recipes/food/views/scallop-and-corn-pot-stickers-11846">
          Scallop and Corn Pot Stickers
         </a>
        </h4>
        <dl class="recipes-ratings-summary" data-reactid="376" data-reviews-count="9" data-reviews-rating="3.5" itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">
         <dt class="rating-label" data-reactid="377">
          Average user rating
         </dt>
         <span class="reviews-count-container" data-reactid="378">
          <dd class="rating" data-rating="3.5" data-reactid="379">
           <span data-reactid="380" itemprop="ratingValue">
            3.5
           </span>
           <!-- react-text: 381 -->
           /
           <!-- /react-text -->
           <span data-reactid="382" itemprop="bestRating">
            4
           </span>
           <meta content="0" data-reactid="383" itemprop="worstRating"/>
          </dd>
          <dt class="reviews-count-label" data-reactid="384">
           Reviews
          </dt>
          <dd class="reviews-count" data-reactid="385" itemprop="reviewCount">
           9
          </dd>
         </span>
         <span class="make-again-container" data-reactid="386">
          <dt class="make-again-percentage-label" data-reactid="387">
           Percentage of reviewers who will make this recipe again
          </dt>
          <dd class="make-again-percentage" data-reactid="388">
           <!-- react-text: 389 -->
           100
           <!-- /react-text -->
           <!-- react-text: 390 -->
           %
           <!-- /react-text -->
          </dd>
         </span>
        </dl>
       </header>
       <a class="photo-link" data-reactid="391" href="/recipes/food/views/scallop-and-corn-pot-stickers-11846">
        <div class="photo-wrap" data-reactid="392">
         <div class="component-lazy pending" data-component="Lazy" data-reactid="393">
         </div>
        </div>
       </a>
       <a class="view-complete-item" data-reactid="394" href="/recipes/food/views/scallop-and-corn-pot-stickers-11846" itemprop="url" title="Scallop and Corn Pot Stickers">
        <!-- react-text: 395 -->
        View “
        <!-- /react-text -->
        <!-- react-text: 396 -->
        Scallop and Corn Pot Stickers
        <!-- /react-text -->
        <!-- react-text: 397 -->
        ”
        <!-- /react-text -->
       </a>
       <div class="recipe-panel " data-reactid="398">
        <a class="view-complete-item" data-reactid="399" href="/recipes/food/views/scallop-and-corn-pot-stickers-11846">
         View Recipe
        </a>
        <div class="controls" data-reactid="400">
         <a class="show-quick-view" data-reactid="401" href="/recipes/food/views/scallop-and-corn-pot-stickers-11846" title="Scallop and Corn Pot Stickers">
          Quick view
         </a>
         <a class="toggle-compare-state" data-reactid="402">
          Compare Recipe
         </a>
        </div>
       </div>
      </article>
      <footer class="results-group-footer" data-reactid="403">
      </footer>
     </div>
     <nav class="common-pagination" data-reactid="404" data-total-pages="1" role="navigation">
      <h6 class="nav-title" data-reactid="405">
       Pagination
      </h6>
      <span class="the-current-page" data-reactid="406">
       1
      </span>
     </nav>
    </section>
    <!-- react-text: 407 -->
    <!-- /react-text -->
    <!-- react-empty: 408 -->
    <footer class="site-footer" data-reactid="409" role="contentinfo">
     <section class="corporate-info-wrap" data-reactid="410">
      <span class="corporate-info" data-reactid="411">
       <h3 class="section-title" data-reactid="412">
        Condé Nast
       </h3>
       <nav aria-hidden="true" class="conde-nast-brands" data-reactid="413">
        <h4 class="nav-title" data-reactid="414">
         Condé Nast Websites
        </h4>
        <ul class="conde-nast-brands-list" data-reactid="415">
         <li data-reactid="416">
          <a class="conde-nast-brand" data-reactid="417" data-track-location="footer" data-track-source="navigation" href="http://www.allure.com" rel="noopener noreferrer" target="_blank" title="Allure">
           Allure
          </a>
         </li>
         <li data-reactid="418">
          <a class="conde-nast-brand" data-reactid="419" data-track-location="footer" data-track-source="navigation" href="http://www.architecturaldigest.com" rel="noopener noreferrer" target="_blank" title="Architectural Digest">
           Architectural Digest
          </a>
         </li>
         <li data-reactid="420">
          <a class="conde-nast-brand" data-reactid="421" data-track-location="footer" data-track-source="navigation" href="http://www.arstechnica.com" rel="noopener noreferrer" target="_blank" title="Ars Technica">
           Ars Technica
          </a>
         </li>
         <li data-reactid="422">
          <a class="conde-nast-brand" data-reactid="423" data-track-location="footer" data-track-source="navigation" href="http://www.bonappetit.com" rel="noopener noreferrer" target="_blank" title="Bon Appétit">
           Bon Appétit
          </a>
         </li>
         <li data-reactid="424">
          <a class="conde-nast-brand" data-reactid="425" data-track-location="footer" data-track-source="navigation" href="http://www.brides.com" rel="noopener noreferrer" target="_blank" title="Brides.com">
           Brides.com
          </a>
         </li>
         <li data-reactid="426">
          <a class="conde-nast-brand" data-reactid="427" data-track-location="footer" data-track-source="navigation" href="http://www.concierge.com/cntraveler" rel="noopener noreferrer" target="_blank" title="Condé Nast Traveler">
           Condé Nast Traveler
          </a>
         </li>
         <li data-reactid="428">
          <a class="conde-nast-brand" data-reactid="429" data-track-location="footer" data-track-source="navigation" href="http://www.concierge.com" rel="noopener noreferrer" target="_blank" title="Concierge">
           Concierge
          </a>
         </li>
         <li data-reactid="430">
          <a class="conde-nast-brand" data-reactid="431" data-track-location="footer" data-track-source="navigation" href="http://www.details.com" rel="noopener noreferrer" target="_blank" title="Details">
           Details
          </a>
         </li>
         <li data-reactid="432">
          <a class="conde-nast-brand" data-reactid="433" data-track-location="footer" data-track-source="navigation" href="http://www.glamour.com" rel="noopener noreferrer" target="_blank" title="Glamour">
           Glamour
          </a>
         </li>
         <li data-reactid="434">
          <a class="conde-nast-brand" data-reactid="435" data-track-location="footer" data-track-source="navigation" href="http://www.golfdigest.com" rel="noopener noreferrer" target="_blank" title="Golf Digest">
           Golf Digest
          </a>
         </li>
         <li data-reactid="436">
          <a class="conde-nast-brand" data-reactid="437" data-track-location="footer" data-track-source="navigation" href="http://www.golfworld.com" rel="noopener noreferrer" target="_blank" title="Golf World">
           Golf World
          </a>
         </li>
         <li data-reactid="438">
          <a class="conde-nast-brand" data-reactid="439" data-track-location="footer" data-track-source="navigation" href="http://www.gq.com" rel="noopener noreferrer" target="_blank" title="GQ">
           GQ
          </a>
         </li>
         <li data-reactid="440">
          <a class="conde-nast-brand" data-reactid="441" data-track-location="footer" data-track-source="navigation" href="http://www.hotelchatter.com" rel="noopener noreferrer" target="_blank" title="Hotel Chatter">
           Hotel Chatter
          </a>
         </li>
         <li data-reactid="442">
          <a class="conde-nast-brand" data-reactid="443" data-track-location="footer" data-track-source="navigation" href="http://www.jaunted.com" rel="noopener noreferrer" target="_blank" title="Jaunted">
           Jaunted
          </a>
         </li>
         <li data-reactid="444">
          <a class="conde-nast-brand" data-reactid="445" data-track-location="footer" data-track-source="navigation" href="http://www.luckymag.com" rel="noopener noreferrer" target="_blank" title="Lucky">
           Lucky
          </a>
         </li>
         <li data-reactid="446">
          <a class="conde-nast-brand" data-reactid="447" data-track-location="footer" data-track-source="navigation" href="http://www.nutritiondata.com" rel="noopener noreferrer" target="_blank" title="NutritionData">
           NutritionData
          </a>
         </li>
         <li data-reactid="448">
          <a class="conde-nast-brand" data-reactid="449" data-track-location="footer" data-track-source="navigation" href="http://www.reddit.com" rel="noopener noreferrer" target="_blank" title="Reddit">
           Reddit
          </a>
         </li>
         <li data-reactid="450">
          <a class="conde-nast-brand" data-reactid="451" data-track-location="footer" data-track-source="navigation" href="http://www.self.com" rel="noopener noreferrer" target="_blank" title="Self">
           Self
          </a>
         </li>
         <li data-reactid="452">
          <a class="conde-nast-brand" data-reactid="453" data-track-location="footer" data-track-source="navigation" href="http://www.style.com" rel="noopener noreferrer" target="_blank" title="Style">
           Style
          </a>
         </li>
         <li data-reactid="454">
          <a class="conde-nast-brand" data-reactid="455" data-track-location="footer" data-track-source="navigation" href="http://www.teenvogue.com" rel="noopener noreferrer" target="_blank" title="Teen Vogue">
           Teen Vogue
          </a>
         </li>
         <li data-reactid="456">
          <a class="conde-nast-brand" data-reactid="457" data-track-location="footer" data-track-source="navigation" href="http://www.newyorker.com" rel="noopener noreferrer" target="_blank" title="The New Yorker">
           The New Yorker
          </a>
         </li>
         <li data-reactid="458">
          <a class="conde-nast-brand" data-reactid="459" data-track-location="footer" data-track-source="navigation" href="http://thescene.com" rel="noopener noreferrer" target="_blank" title="The Scene">
           The Scene
          </a>
         </li>
         <li data-reactid="460">
          <a class="conde-nast-brand" data-reactid="461" data-track-location="footer" data-track-source="navigation" href="http://www.vanityfair.com" rel="noopener noreferrer" target="_blank" title="Vanity Fair">
           Vanity Fair
          </a>
         </li>
         <li data-reactid="462">
          <a class="conde-nast-brand" data-reactid="463" data-track-location="footer" data-track-source="navigation" href="http://www.vegaschatter.com" rel="noopener noreferrer" target="_blank" title="Vegas Chatter">
           Vegas Chatter
          </a>
         </li>
         <li data-reactid="464">
          <a class="conde-nast-brand" data-reactid="465" data-track-location="footer" data-track-source="navigation" href="http://www.vogue.com" rel="noopener noreferrer" target="_blank" title="Vogue">
           Vogue
          </a>
         </li>
         <li data-reactid="466">
          <a class="conde-nast-brand" data-reactid="467" data-track-location="footer" data-track-source="navigation" href="http://www.wmagazine.com" rel="noopener noreferrer" target="_blank" title="W">
           W
          </a>
         </li>
         <li data-reactid="468">
          <a class="conde-nast-brand" data-reactid="469" data-track-location="footer" data-track-source="navigation" href="http://www.wired.com" rel="noopener noreferrer" target="_blank" title="Wired">
           Wired
          </a>
         </li>
        </ul>
       </nav>
       <nav class="conde-nast-services" data-reactid="470">
        <h4 class="nav-title" data-reactid="471">
         Condé Nast Services
        </h4>
        <ul data-reactid="472">
         <li data-reactid="473">
          <a class="conde-nast-service" data-reactid="474" data-track-location="footer" data-track-source="navigation" href="/services/subscriptions" title="Subscription Services">
           Subscription Services
          </a>
         </li>
         <li data-reactid="475">
          <a class="conde-nast-service" data-reactid="476" data-track-location="footer" data-track-source="navigation" href="http://www.condenast.com/careers" rel="noopener noreferrer" target="_blank" title="Condé Nast Careers">
           Careers
          </a>
         </li>
         <li data-reactid="477">
          <a class="conde-nast-service" data-reactid="478" data-track-location="footer" data-track-source="navigation" href="http://www.condenaststore.com/" rel="noopener noreferrer" target="_blank" title="Condé Nast Store">
           Condé Nast Store
          </a>
         </li>
         <li data-reactid="479">
          <a class="conde-nast-service" data-reactid="480" data-track-location="footer" data-track-source="navigation" href="http://www.condenast.com/reprints-permissions" rel="noopener noreferrer" target="_blank" title="Reprints/Permissions">
           Reprints/Permissions
          </a>
         </li>
        </ul>
       </nav>
       <article class="legal-notice" data-reactid="481">
        <h4 class="title" data-reactid="482">
         Legal Notice
        </h4>
        <p data-reactid="483">
         <!-- react-text: 484 -->
         ©
         <!-- /react-text -->
         <!-- react-text: 485 -->
         2019
         <!-- /react-text -->
         <!-- react-text: 486 -->
         Condé Nast. All rights reserved.
         <!-- /react-text -->
        </p>
        <p data-reactid="487">
         <!-- react-text: 488 -->
         Use of and/or registration on any portion of this site constitutes acceptance of our
         <!-- /react-text -->
         <a data-reactid="489" data-track-location="footer" data-track-source="navigation" href="http://www.condenast.com/privacy-policy" rel="noopener noreferrer" target="_blank" title="User Agreement">
          User Agreement
         </a>
         <!-- react-text: 490 -->
         (updated 5/25/18) and
         <!-- /react-text -->
         <a data-reactid="491" data-track-location="footer" data-track-source="navigation" href="http://www.condenast.com/privacy-policy#privacypolicy" rel="noopener noreferrer" target="_blank" title="Privacy Policy">
          Privacy Policy and Cookie Statement
         </a>
         <!-- react-text: 492 -->
         (updated 5/25/18).
         <!-- /react-text -->
        </p>
        <p data-reactid="493">
         <a data-reactid="494" data-track-location="footer" data-track-source="navigation" href="http://www.condenast.com/privacy-policy#privacypolicy-california" rel="noopener noreferrer" target="_blank" title="Your California Privacy Rights">
          Your California Privacy Rights
         </a>
        </p>
        <p data-reactid="495">
         The material on this site may not be reproduced, distributed, transmitted, cached or otherwise used, except with the prior written permission of Condé Nast.
        </p>
        <a class="ad-choice" data-reactid="496" data-track-location="footer" data-track-source="navigation" href="http://www.condenast.com/online-behavioral-advertising-oba-and-how-to-opt-out-of-oba/#clickheretoreadmoreaboutonlinebehavioraladvertising(oba)" rel="noopener noreferrer" target="_blank" title="Ad Choices">
         Ad Choices
        </a>
       </article>
      </span>
     </section>
    </footer>
    <!-- react-empty: 497 -->
    <!-- react-empty: 498 -->
   </span>
  </span>
  <div aria-hidden="true" aria-labelledby="cnid-modalLabel" class="modal cnid-modal hide fade" id="cnid-modal" role="dialog" tabindex="-1">
   <div class="frameContainer modal-body cnid-modal-body cnid-ios-scroll">
    <button aria-hidden="true" class="close cnid-close" data-dismiss="modal" type="button">
     x
    </button>
    <iframe class="cnid-signin-iframe" frameborder="0" height="100%" id="cnidClient" marginheight="0" marginwidth="0" src="" width="100%">
    </iframe>
   </div>
   <!-- loader overlay -->
   <div class="loader-container hide">
    <div class="cnid-overlay-bg">
    </div>
    <div class="cnid-loader">
     <img src="https://cnid.condenastdigital.com/client/assets/img/spinner.gif"/>
    </div>
   </div>
   <!-- alerts overlay -->
   <!-- overlay is used to display screen centered server-side error messages on mobile devices -->
   <div class="cnid-alerts-container hide">
    <div class="cnid-overlay-bg">
    </div>
    <div class="cnid-alert-message alert text-center alert-success">
     <p class="alert-txt">
     </p>
     <button class="btn-conde okay-btn cnid-btn" type="button">
      Okay
     </button>
    </div>
   </div>
  </div>
  <div class="modal-backdrop">
  </div>
  <script>
   var _app = {"ads":{"google":{"googleTagManagerId":"GTM-PCTXLQR"}},"cookieDomain":".epicurious.com","endpoints":{"contextual":"/api/dataintelligence/v1/content/recommended","rotd":"/api/content/v1/rotd/count/1"},"env":"PROD","facebook":{"appId":"1636080783276430"},"https":"true","media":{"bp":{"xs":0,"s":600,"m":768,"l":1024,"xl":1360,"w":1710}},"newsletters":{"current":[{"description":"Become a better cook instantly with this weekly report of our ten most helpful tips, tricks, and kitchen secrets. Don't miss it!","id":"5","name":"The Top Ten"},{"description":"Love recipes, but hate searching? We do the work for you. You'll get our favorite seasonal recipe plus collections of our exclusive editors' picks.","id":"5117","name":"Cook This Now"},{"description":"Get a daily dose of the hottest recipes from Epicurious, Bon Appétit, and other great sites.","id":"195169","name":"Trending Recipes"},{"id":"248781","name":"Announcements"},{"id":"248789","name":"Cook 90"},{"id":"248818","name":"Diabetes Friendly"},{"id":"248842","name":"Small Plates"},{"id":"248886","name":"Well Equipped"}]},"server":"https://www.epicurious.com","services":{"endpoints":{"articles":{"latest":"/api/search/v1/query?size=20&content=article&sort=newest&q="},"branded":{"article":"/api/branded/v1/article/:brandCode/:slug"},"content":{"channel":"/api/content/v1/channel/","component":"/api/content/v1/component","contextual":"/api/dataintelligence/v1/content/recommended","featuredIn":"/api/content/v1/featuredin/","homepage":"/api/content/v1/homepage","latestRecipes":"/api/content/v1/component/latestrecipes","memberLookup":"/api/users/v2/user/","navItems":"/api/content/v1/component/navitems","nutritionalInfo":"/api/nutritiondata/v2/","reviews":"/api/recipes/v2/","reviewsFeed":"/api/recipes/v3/","reviewsSuffix":"/reviews","reviewsFeedSuffix":"/reviews/feed","rotd":"/api/content/v1/rotd/count/1","search":"/api/content/v1/search","videoSearchByKeywords":"/api/video/v1/keywords/"},"contributors":{"details":"/api/contributors/v1/:contributor/bundle","feed":"/api/contributors/v1/:contributor/feed"},"cookbooks":{"details":"/api/cookbooks/v1/:slug","index":"/api/cookbooks/v1"},"menus":{"details":"/api/users/v1/:userId/menus/:menuId","index":"/api/users/v1/:userId/menus"},"photos":{"instagramPosts":"/api/instagram/v1","menuCover":"/api/photos/v1/menu-cover","searchCard":"/api/photos/v1/search-card","searchUtility":"/api/photos/v1/search-utility"},"recipeBox":{"search":"/api/recipe-box/v1/:userId/search/:term"},"recipes":{"byKeywords":"/api/recipes/v2/keywords/","byKeywordsForMenus":"/api/menus/v1/keywords/","latest":"/api/recipes/v2/latest"},"search":{"details":"/api/recipes/v3/detail","facets":"/api/search/v1/facets","query":"/api/search/v1/query","suggest":"/api/search/v1/suggest"},"users":{"authenticate":"/api/users/v2/authenticate","info":"/api/users/v2/user/:uuid","newsletterSubscriptions":"/api/newsletters/v1/subscription/:email","recipeBoxSearch":"/api/users/v1/:userId/recipe-box/search/:query","recipes":"/api/users/v1/:userId/recipes","reviews":"/api/users/v1/:userId/reviews","updateEmail":"/api/users/v2/user/email","updatePassword":"/api/users/v2/user/password","updateUsername":"/api/users/v2/user/displayname","updateSettings":"/api/users/v2/user"}}},"servicesHost":"https://services.epicurious.com","simpleReach":{"pid":"570d6b7d736b79bf1d000d27"},"user":{"cookies":{"keys":{"id":"amg_user_partner","username":"amg_user_info"},"names":["amg_user_ext","amg_user_info","amg_user_partner","amg_user_update","cn_uid","CN_userAuth"]},"email":{"regExp":{}},"password":{"regExp":{},"messages":{"requirements":"A password must be at least 6 characters long. It cannot begin or end with a space."}},"serviceKey":"NtibqP3y1qSJM/Gsy3blJgNWt/o=","serviceHost":"https://user-service.condenastdigital.com"},"userServiceHost":"https://user-service.condenastdigital.com","userServiceKey":"NtibqP3y1qSJM/Gsy3blJgNWt/o=","vulcan":{"host":"https://assets.epicurious.com","path":"/photos/"}};
  </script>
  <script type="text/javascript">
   window._state = "%7B%22context%22%3A%7B%22dispatcher%22%3A%7B%22stores%22%3A%7B%22AdStore%22%3A%7B%22displayLeaderboard%22%3Atrue%2C%22pageCreated%22%3Afalse%2C%22pageSlots%22%3A%7B%7D%2C%22env%22%3A%22development%22%2C%22pageConfig%22%3A%7B%22channel%22%3A%22search%22%2C%22slug%22%3A%22search%22%2C%22sub_channel%22%3A%22%22%2C%22targeting%22%3A%7B%22tags%22%3A%5B%22search%22%5D%7D%2C%22templateType%22%3A%22%22%7D%7D%2C%22ApplicationStore%22%3A%7B%22analyticsLocation%22%3A%22section1%22%2C%22analyticsSource%22%3A%22section1%22%2C%22config%22%3A%7B%22ads%22%3A%7B%22google%22%3A%7B%22googleTagManagerId%22%3A%22GTM-PCTXLQR%22%7D%7D%2C%22cookieDomain%22%3A%22.epicurious.com%22%2C%22endpoints%22%3A%7B%22contextual%22%3A%22%2Fapi%2Fdataintelligence%2Fv1%2Fcontent%2Frecommended%22%2C%22rotd%22%3A%22%2Fapi%2Fcontent%2Fv1%2Frotd%2Fcount%2F1%22%7D%2C%22env%22%3A%22PROD%22%2C%22facebook%22%3A%7B%22appId%22%3A%221636080783276430%22%7D%2C%22https%22%3A%22true%22%2C%22media%22%3A%7B%22bp%22%3A%7B%22xs%22%3A0%2C%22s%22%3A600%2C%22m%22%3A768%2C%22l%22%3A1024%2C%22xl%22%3A1360%2C%22w%22%3A1710%7D%7D%2C%22newsletters%22%3A%7B%22current%22%3A%5B%7B%22description%22%3A%22Become%20a%20better%20cook%20instantly%20with%20this%20weekly%20report%20of%20our%20ten%20most%20helpful%20tips%2C%20tricks%2C%20and%20kitchen%20secrets.%20Don't%20miss%20it!%22%2C%22id%22%3A%225%22%2C%22name%22%3A%22The%20Top%20Ten%22%7D%2C%7B%22description%22%3A%22Love%20recipes%2C%20but%20hate%20searching%3F%20We%20do%20the%20work%20for%20you.%20You'll%20get%20our%20favorite%20seasonal%20recipe%20plus%20collections%20of%20our%20exclusive%20editors'%20picks.%22%2C%22id%22%3A%225117%22%2C%22name%22%3A%22Cook%20This%20Now%22%7D%2C%7B%22description%22%3A%22Get%20a%20daily%20dose%20of%20the%20hottest%20recipes%20from%20Epicurious%2C%20Bon%20App%C3%A9tit%2C%20and%20other%20great%20sites.%22%2C%22id%22%3A%22195169%22%2C%22name%22%3A%22Trending%20Recipes%22%7D%2C%7B%22id%22%3A%22248781%22%2C%22name%22%3A%22Announcements%22%7D%2C%7B%22id%22%3A%22248789%22%2C%22name%22%3A%22Cook%2090%22%7D%2C%7B%22id%22%3A%22248818%22%2C%22name%22%3A%22Diabetes%20Friendly%22%7D%2C%7B%22id%22%3A%22248842%22%2C%22name%22%3A%22Small%20Plates%22%7D%2C%7B%22id%22%3A%22248886%22%2C%22name%22%3A%22Well%20Equipped%22%7D%5D%7D%2C%22server%22%3A%22https%3A%2F%2Fwww.epicurious.com%22%2C%22services%22%3A%7B%22endpoints%22%3A%7B%22articles%22%3A%7B%22latest%22%3A%22%2Fapi%2Fsearch%2Fv1%2Fquery%3Fsize%3D20%26content%3Darticle%26sort%3Dnewest%26q%3D%22%7D%2C%22branded%22%3A%7B%22article%22%3A%22%2Fapi%2Fbranded%2Fv1%2Farticle%2F%3AbrandCode%2F%3Aslug%22%7D%2C%22content%22%3A%7B%22channel%22%3A%22%2Fapi%2Fcontent%2Fv1%2Fchannel%2F%22%2C%22component%22%3A%22%2Fapi%2Fcontent%2Fv1%2Fcomponent%22%2C%22contextual%22%3A%22%2Fapi%2Fdataintelligence%2Fv1%2Fcontent%2Frecommended%22%2C%22featuredIn%22%3A%22%2Fapi%2Fcontent%2Fv1%2Ffeaturedin%2F%22%2C%22homepage%22%3A%22%2Fapi%2Fcontent%2Fv1%2Fhomepage%22%2C%22latestRecipes%22%3A%22%2Fapi%2Fcontent%2Fv1%2Fcomponent%2Flatestrecipes%22%2C%22memberLookup%22%3A%22%2Fapi%2Fusers%2Fv2%2Fuser%2F%22%2C%22navItems%22%3A%22%2Fapi%2Fcontent%2Fv1%2Fcomponent%2Fnavitems%22%2C%22nutritionalInfo%22%3A%22%2Fapi%2Fnutritiondata%2Fv2%2F%22%2C%22reviews%22%3A%22%2Fapi%2Frecipes%2Fv2%2F%22%2C%22reviewsFeed%22%3A%22%2Fapi%2Frecipes%2Fv3%2F%22%2C%22reviewsSuffix%22%3A%22%2Freviews%22%2C%22reviewsFeedSuffix%22%3A%22%2Freviews%2Ffeed%22%2C%22rotd%22%3A%22%2Fapi%2Fcontent%2Fv1%2Frotd%2Fcount%2F1%22%2C%22search%22%3A%22%2Fapi%2Fcontent%2Fv1%2Fsearch%22%2C%22videoSearchByKeywords%22%3A%22%2Fapi%2Fvideo%2Fv1%2Fkeywords%2F%22%7D%2C%22contributors%22%3A%7B%22details%22%3A%22%2Fapi%2Fcontributors%2Fv1%2F%3Acontributor%2Fbundle%22%2C%22feed%22%3A%22%2Fapi%2Fcontributors%2Fv1%2F%3Acontributor%2Ffeed%22%7D%2C%22cookbooks%22%3A%7B%22details%22%3A%22%2Fapi%2Fcookbooks%2Fv1%2F%3Aslug%22%2C%22index%22%3A%22%2Fapi%2Fcookbooks%2Fv1%22%7D%2C%22menus%22%3A%7B%22details%22%3A%22%2Fapi%2Fusers%2Fv1%2F%3AuserId%2Fmenus%2F%3AmenuId%22%2C%22index%22%3A%22%2Fapi%2Fusers%2Fv1%2F%3AuserId%2Fmenus%22%7D%2C%22photos%22%3A%7B%22instagramPosts%22%3A%22%2Fapi%2Finstagram%2Fv1%22%2C%22menuCover%22%3A%22%2Fapi%2Fphotos%2Fv1%2Fmenu-cover%22%2C%22searchCard%22%3A%22%2Fapi%2Fphotos%2Fv1%2Fsearch-card%22%2C%22searchUtility%22%3A%22%2Fapi%2Fphotos%2Fv1%2Fsearch-utility%22%7D%2C%22recipeBox%22%3A%7B%22search%22%3A%22%2Fapi%2Frecipe-box%2Fv1%2F%3AuserId%2Fsearch%2F%3Aterm%22%7D%2C%22recipes%22%3A%7B%22byKeywords%22%3A%22%2Fapi%2Frecipes%2Fv2%2Fkeywords%2F%22%2C%22byKeywordsForMenus%22%3A%22%2Fapi%2Fmenus%2Fv1%2Fkeywords%2F%22%2C%22latest%22%3A%22%2Fapi%2Frecipes%2Fv2%2Flatest%22%7D%2C%22search%22%3A%7B%22details%22%3A%22%2Fapi%2Frecipes%2Fv3%2Fdetail%22%2C%22facets%22%3A%22%2Fapi%2Fsearch%2Fv1%2Ffacets%22%2C%22query%22%3A%22%2Fapi%2Fsearch%2Fv1%2Fquery%22%2C%22suggest%22%3A%22%2Fapi%2Fsearch%2Fv1%2Fsuggest%22%7D%2C%22users%22%3A%7B%22authenticate%22%3A%22%2Fapi%2Fusers%2Fv2%2Fauthenticate%22%2C%22info%22%3A%22%2Fapi%2Fusers%2Fv2%2Fuser%2F%3Auuid%22%2C%22newsletterSubscriptions%22%3A%22%2Fapi%2Fnewsletters%2Fv1%2Fsubscription%2F%3Aemail%22%2C%22recipeBoxSearch%22%3A%22%2Fapi%2Fusers%2Fv1%2F%3AuserId%2Frecipe-box%2Fsearch%2F%3Aquery%22%2C%22recipes%22%3A%22%2Fapi%2Fusers%2Fv1%2F%3AuserId%2Frecipes%22%2C%22reviews%22%3A%22%2Fapi%2Fusers%2Fv1%2F%3AuserId%2Freviews%22%2C%22updateEmail%22%3A%22%2Fapi%2Fusers%2Fv2%2Fuser%2Femail%22%2C%22updatePassword%22%3A%22%2Fapi%2Fusers%2Fv2%2Fuser%2Fpassword%22%2C%22updateUsername%22%3A%22%2Fapi%2Fusers%2Fv2%2Fuser%2Fdisplayname%22%2C%22updateSettings%22%3A%22%2Fapi%2Fusers%2Fv2%2Fuser%22%7D%7D%7D%2C%22servicesHost%22%3A%22https%3A%2F%2Fservices.epicurious.com%22%2C%22simpleReach%22%3A%7B%22pid%22%3A%22570d6b7d736b79bf1d000d27%22%7D%2C%22user%22%3A%7B%22cookies%22%3A%7B%22keys%22%3A%7B%22id%22%3A%22amg_user_partner%22%2C%22username%22%3A%22amg_user_info%22%7D%2C%22names%22%3A%5B%22amg_user_ext%22%2C%22amg_user_info%22%2C%22amg_user_partner%22%2C%22amg_user_update%22%2C%22cn_uid%22%2C%22CN_userAuth%22%5D%7D%2C%22email%22%3A%7B%22regExp%22%3A%7B%7D%7D%2C%22password%22%3A%7B%22regExp%22%3A%7B%7D%2C%22messages%22%3A%7B%22requirements%22%3A%22A%20password%20must%20be%20at%20least%206%20characters%20long.%20It%20cannot%20begin%20or%20end%20with%20a%20space.%22%7D%7D%2C%22serviceKey%22%3A%22NtibqP3y1qSJM%2FGsy3blJgNWt%2Fo%3D%22%2C%22serviceHost%22%3A%22https%3A%2F%2Fuser-service.condenastdigital.com%22%7D%2C%22userServiceHost%22%3A%22https%3A%2F%2Fuser-service.condenastdigital.com%22%2C%22userServiceKey%22%3A%22NtibqP3y1qSJM%2FGsy3blJgNWt%2Fo%3D%22%2C%22vulcan%22%3A%7B%22host%22%3A%22https%3A%2F%2Fassets.epicurious.com%22%2C%22path%22%3A%22%2Fphotos%2F%22%7D%7D%2C%22pageName%22%3A%22search%22%2C%22siteFooter%22%3A%7B%22hasEpicuriousLinks%22%3Afalse%7D%7D%2C%22SearchStore%22%3A%7B%22activeFilters%22%3A%5B%5D%2C%22stagedFilters%22%3A%5B%5D%2C%22activeFilterGroup%22%3A%22%22%2C%22includeIngredients%22%3A%5B%5D%2C%22excludeIngredients%22%3A%5B%5D%2C%22stagedIncludeIngredients%22%3A%5B%5D%2C%22stagedExcludeIngredients%22%3A%5B%5D%2C%22api%22%3A%7B%22detailsUri%22%3A%22https%3A%2F%2Fservices.epicurious.com%2Fapi%2Frecipes%2Fv3%2Fdetail%22%2C%22facetUri%22%3A%22https%3A%2F%2Fservices.epicurious.com%2Fapi%2Fsearch%2Fv1%2Ffacets%22%2C%22searchUri%22%3A%22https%3A%2F%2Fservices.epicurious.com%2Fapi%2Fsearch%2Fv1%2Fquery%22%2C%22suggestUri%22%3A%22https%3A%2F%2Fservices.epicurious.com%2Fapi%2Fsearch%2Fv1%2Fsuggest%22%7D%2C%22compareRecipes%22%3A%5B%5D%2C%22numFound%22%3A12%2C%22moreResults%22%3Afalse%2C%22newSearch%22%3Afalse%2C%22page%22%3A%7B%22generatedAt%22%3A%222019-06-03T15%3A09%3A19.576Z%22%2C%22count%22%3A1%2C%22number%22%3A1%2C%22size%22%3A18%2C%22totalCount%22%3A12%2C%22previousNumber%22%3A1%7D%2C%22exclusiveFilters%22%3A%7B%7D%2C%22facets%22%3A%7B%22technique%22%3A%7B%22grill-barbecue%22%3A%7B%22id%22%3A%22grill-barbecue%22%2C%22name%22%3A%22Barbecue%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22bake%22%3A%7B%22id%22%3A%22bake%22%2C%22name%22%3A%22Bake%22%2C%22orderCount%22%3A0%2C%22count%22%3A3%7D%2C%22roast%22%3A%7B%22id%22%3A%22roast%22%2C%22name%22%3A%22Roast%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22braise%22%3A%7B%22id%22%3A%22braise%22%2C%22name%22%3A%22Braise%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22saute%22%3A%7B%22id%22%3A%22saute%22%2C%22name%22%3A%22Saut%C3%A9%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22no-cook%22%3A%7B%22id%22%3A%22no-cook%22%2C%22name%22%3A%22No-Cook%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22stir-fry%22%3A%7B%22id%22%3A%22stir-fry%22%2C%22name%22%3A%22Stir-Fry%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22pan-fry%22%3A%7B%22id%22%3A%22pan-fry%22%2C%22name%22%3A%22Pan-Fry%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22marinate%22%3A%7B%22id%22%3A%22marinate%22%2C%22name%22%3A%22Marinate%22%2C%22orderCount%22%3A0%2C%22count%22%3A2%7D%2C%22broil%22%3A%7B%22id%22%3A%22broil%22%2C%22name%22%3A%22Broil%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22stew%22%3A%7B%22id%22%3A%22stew%22%2C%22name%22%3A%22Stew%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22fry%22%3A%7B%22id%22%3A%22fry%22%2C%22name%22%3A%22Fry%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22chill%22%3A%7B%22id%22%3A%22chill%22%2C%22name%22%3A%22Chill%22%2C%22orderCount%22%3A0%2C%22count%22%3A9%7D%2C%22steam%22%3A%7B%22id%22%3A%22steam%22%2C%22name%22%3A%22Steam%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22simmer%22%3A%7B%22id%22%3A%22simmer%22%2C%22name%22%3A%22Simmer%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22poach%22%3A%7B%22id%22%3A%22poach%22%2C%22name%22%3A%22Poach%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22boil%22%3A%7B%22id%22%3A%22boil%22%2C%22name%22%3A%22Boil%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22brine%22%3A%7B%22id%22%3A%22brine%22%2C%22name%22%3A%22Brine%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22freeze-chill%22%3A%7B%22id%22%3A%22freeze-chill%22%2C%22name%22%3A%22Freeze%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22deep-fry%22%3A%7B%22id%22%3A%22deep-fry%22%2C%22name%22%3A%22Deep%20Fry%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22advance-prep-required%22%3A%7B%22id%22%3A%22advance-prep-required%22%2C%22name%22%3A%22Advance%20Prep%20Req'd%22%2C%22orderCount%22%3A0%2C%22count%22%3A2%7D%7D%2C%22meal%22%3A%7B%22dinner%22%3A%7B%22id%22%3A%22dinner%22%2C%22name%22%3A%22Dinner%22%2C%22orderCount%22%3A0%2C%22count%22%3A3%7D%2C%22dessert%22%3A%7B%22id%22%3A%22dessert%22%2C%22name%22%3A%22Dessert%22%2C%22orderCount%22%3A0%2C%22count%22%3A2%7D%2C%22appetizer%22%3A%7B%22id%22%3A%22appetizer%22%2C%22name%22%3A%22Appetizer%22%2C%22orderCount%22%3A0%2C%22count%22%3A2%7D%2C%22side%22%3A%7B%22id%22%3A%22side%22%2C%22name%22%3A%22Side%22%2C%22orderCount%22%3A0%2C%22count%22%3A3%7D%2C%22breakfast%22%3A%7B%22id%22%3A%22breakfast%22%2C%22name%22%3A%22Breakfast%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22lunch%22%3A%7B%22id%22%3A%22lunch%22%2C%22name%22%3A%22Lunch%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22brunch%22%3A%7B%22id%22%3A%22brunch%22%2C%22name%22%3A%22Brunch%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22buffet%22%3A%7B%22id%22%3A%22buffet%22%2C%22name%22%3A%22Buffet%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%7D%2C%22type%22%3A%7B%22soup-stew%22%3A%7B%22id%22%3A%22soup-stew%22%2C%22name%22%3A%22Soup%2FStew%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22salad%22%3A%7B%22id%22%3A%22salad%22%2C%22name%22%3A%22Salad%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22cookie%22%3A%7B%22id%22%3A%22cookie%22%2C%22name%22%3A%22Cookie%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22stuffing-dressing%22%3A%7B%22id%22%3A%22stuffing-dressing%22%2C%22name%22%3A%22Stuffing%2FDressing%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cake%22%3A%7B%22id%22%3A%22cake%22%2C%22name%22%3A%22Cake%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22bread%22%3A%7B%22id%22%3A%22bread%22%2C%22name%22%3A%22Bread%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22edible-gift%22%3A%7B%22id%22%3A%22edible-gift%22%2C%22name%22%3A%22Edible%20Gift%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22sandwich%22%3A%7B%22id%22%3A%22sandwich%22%2C%22name%22%3A%22Sandwich%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22sauce%22%3A%7B%22id%22%3A%22sauce%22%2C%22name%22%3A%22Sauce%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22cocktail%22%3A%7B%22id%22%3A%22cocktail%22%2C%22name%22%3A%22Cocktail%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22candy%22%3A%7B%22id%22%3A%22candy%22%2C%22name%22%3A%22Candy%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22condiment-spread%22%3A%7B%22id%22%3A%22condiment-spread%22%2C%22name%22%3A%22Condiment%2FSpread%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22casserole-gratin%22%3A%7B%22id%22%3A%22casserole-gratin%22%2C%22name%22%3A%22Casserole%2FGratin%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22frozen-dessert%22%3A%7B%22id%22%3A%22frozen-dessert%22%2C%22name%22%3A%22Frozen%20Dessert%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22salad-dressing%22%3A%7B%22id%22%3A%22salad-dressing%22%2C%22name%22%3A%22Salad%20Dressing%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22pastry%22%3A%7B%22id%22%3A%22pastry%22%2C%22name%22%3A%22Pastry%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22ice-cream%22%3A%7B%22id%22%3A%22ice-cream%22%2C%22name%22%3A%22Ice%20Cream%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22sangria%22%3A%7B%22id%22%3A%22sangria%22%2C%22name%22%3A%22Sangria%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22margarita%22%3A%7B%22id%22%3A%22margarita%22%2C%22name%22%3A%22Margarita%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22martini%22%3A%7B%22id%22%3A%22martini%22%2C%22name%22%3A%22Martini%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22iced-tea%22%3A%7B%22id%22%3A%22iced-tea%22%2C%22name%22%3A%22Iced%20Tea%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22aperitif%22%3A%7B%22id%22%3A%22aperitif%22%2C%22name%22%3A%22Aperitif%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22digestif%22%3A%7B%22id%22%3A%22digestif%22%2C%22name%22%3A%22Digestif%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22biscuit%22%3A%7B%22id%22%3A%22biscuit%22%2C%22name%22%3A%22Biscuit%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22brownie%22%3A%7B%22id%22%3A%22brownie%22%2C%22name%22%3A%22Brownie%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22burrito%22%3A%7B%22id%22%3A%22burrito%22%2C%22name%22%3A%22Burrito%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cheesecake%22%3A%7B%22id%22%3A%22cheesecake%22%2C%22name%22%3A%22Cheesecake%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22chili%22%3A%7B%22id%22%3A%22chili%22%2C%22name%22%3A%22Chili%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22chowder%22%3A%7B%22id%22%3A%22chowder%22%2C%22name%22%3A%22Chowder%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cobbler-crumble%22%3A%7B%22id%22%3A%22cobbler-crumble%22%2C%22name%22%3A%22Cobbler%2FCrumble%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22crepe%22%3A%7B%22id%22%3A%22crepe%22%2C%22name%22%3A%22Cr%C3%AApe%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cranberry-sauce%22%3A%7B%22id%22%3A%22cranberry-sauce%22%2C%22name%22%3A%22Cranberry%20Sauce%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cupcake%22%3A%7B%22id%22%3A%22cupcake%22%2C%22name%22%3A%22Cupcake%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22custard%22%3A%7B%22id%22%3A%22custard%22%2C%22name%22%3A%22Custard%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22dip%22%3A%7B%22id%22%3A%22dip%22%2C%22name%22%3A%22Dip%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22flat-bread%22%3A%7B%22id%22%3A%22flat-bread%22%2C%22name%22%3A%22Flat%20Bread%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22frittata%22%3A%7B%22id%22%3A%22frittata%22%2C%22name%22%3A%22Frittata%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22fritter%22%3A%7B%22id%22%3A%22fritter%22%2C%22name%22%3A%22Fritter%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22guacamole%22%3A%7B%22id%22%3A%22guacamole%22%2C%22name%22%3A%22Guacamole%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22hamburger%22%3A%7B%22id%22%3A%22hamburger%22%2C%22name%22%3A%22Hamburger%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%7D%2C%22special-consideration%22%3A%7B%22vegetarian%22%3A%7B%22id%22%3A%22vegetarian%22%2C%22name%22%3A%22Vegetarian%22%2C%22orderCount%22%3A0%2C%22count%22%3A6%7D%2C%22quick-and-easy%22%3A%7B%22id%22%3A%22quick-and-easy%22%2C%22name%22%3A%22Quick%20%26%20Easy%22%2C%22orderCount%22%3A0%2C%22count%22%3A2%7D%2C%22kid-friendly%22%3A%7B%22id%22%3A%22kid-friendly%22%2C%22name%22%3A%22Kid%20Friendly%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22healthy%22%3A%7B%22id%22%3A%22healthy%22%2C%22name%22%3A%22Healthy%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22wheat-gluten-free%22%3A%7B%22id%22%3A%22wheat-gluten-free%22%2C%22name%22%3A%22Wheat%2FGluten-Free%22%2C%22orderCount%22%3A0%2C%22count%22%3A6%7D%2C%22vegan%22%3A%7B%22id%22%3A%22vegan%22%2C%22name%22%3A%22Vegan%22%2C%22orderCount%22%3A0%2C%22count%22%3A5%7D%2C%22low-fat%22%3A%7B%22id%22%3A%22low-fat%22%2C%22name%22%3A%22Low%20Fat%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22low-no-sugar%22%3A%7B%22id%22%3A%22low-no-sugar%22%2C%22name%22%3A%22Low%2FNo%20Sugar%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22low-sodium%22%3A%7B%22id%22%3A%22low-sodium%22%2C%22name%22%3A%22Low%20Sodium%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22high-fiber%22%3A%7B%22id%22%3A%22high-fiber%22%2C%22name%22%3A%22High%20Fiber%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22kosher%22%3A%7B%22id%22%3A%22kosher%22%2C%22name%22%3A%22Kosher%22%2C%22orderCount%22%3A0%2C%22count%22%3A6%7D%2C%22low-cholesterol%22%3A%7B%22id%22%3A%22low-cholesterol%22%2C%22name%22%3A%22Low%20Cholesterol%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22raw%22%3A%7B%22id%22%3A%22raw%22%2C%22name%22%3A%22Raw%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22kosher-for-passover%22%3A%7B%22id%22%3A%22kosher-for-passover%22%2C%22name%22%3A%22Kosher%20for%20Passover%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22organic%22%3A%7B%22id%22%3A%22organic%22%2C%22name%22%3A%22Organic%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%7D%2C%22ingredient%22%3A%7B%22chicken%22%3A%7B%22id%22%3A%22chicken%22%2C%22name%22%3A%22Chicken%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22beef%22%3A%7B%22id%22%3A%22beef%22%2C%22name%22%3A%22Beef%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22fish%22%3A%7B%22id%22%3A%22fish%22%2C%22name%22%3A%22Fish%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22pork%22%3A%7B%22id%22%3A%22pork%22%2C%22name%22%3A%22Pork%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22vegetable%22%3A%7B%22id%22%3A%22vegetable%22%2C%22name%22%3A%22Vegetable%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22turkey%22%3A%7B%22id%22%3A%22turkey%22%2C%22name%22%3A%22Turkey%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22potato%22%3A%7B%22id%22%3A%22potato%22%2C%22name%22%3A%22Potato%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22pasta%22%3A%7B%22id%22%3A%22pasta%22%2C%22name%22%3A%22Pasta%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22seafood%22%3A%7B%22id%22%3A%22seafood%22%2C%22name%22%3A%22Seafood%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22egg%22%3A%7B%22id%22%3A%22egg%22%2C%22name%22%3A%22Egg%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22lamb%22%3A%7B%22id%22%3A%22lamb%22%2C%22name%22%3A%22Lamb%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22chocolate%22%3A%7B%22id%22%3A%22chocolate%22%2C%22name%22%3A%22Chocolate%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22cranberry%22%3A%7B%22id%22%3A%22cranberry%22%2C%22name%22%3A%22Cranberry%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22salmon%22%3A%7B%22id%22%3A%22salmon%22%2C%22name%22%3A%22Salmon%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22bean%22%3A%7B%22id%22%3A%22bean%22%2C%22name%22%3A%22Bean%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22shellfish%22%3A%7B%22id%22%3A%22shellfish%22%2C%22name%22%3A%22Shellfish%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22fruit%22%3A%7B%22id%22%3A%22fruit%22%2C%22name%22%3A%22Fruit%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22duck%22%3A%7B%22id%22%3A%22duck%22%2C%22name%22%3A%22Duck%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22shrimp%22%3A%7B%22id%22%3A%22shrimp%22%2C%22name%22%3A%22Shrimp%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22mushroom%22%3A%7B%22id%22%3A%22mushroom%22%2C%22name%22%3A%22Mushroom%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22tomato%22%3A%7B%22id%22%3A%22tomato%22%2C%22name%22%3A%22Tomato%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22rice%22%3A%7B%22id%22%3A%22rice%22%2C%22name%22%3A%22Rice%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22poultry%22%3A%7B%22id%22%3A%22poultry%22%2C%22name%22%3A%22Poultry%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22scallop%22%3A%7B%22id%22%3A%22scallop%22%2C%22name%22%3A%22Scallop%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22ham%22%3A%7B%22id%22%3A%22ham%22%2C%22name%22%3A%22Ham%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22carrot%22%3A%7B%22id%22%3A%22carrot%22%2C%22name%22%3A%22Carrot%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22eggplant%22%3A%7B%22id%22%3A%22eggplant%22%2C%22name%22%3A%22Eggplant%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22leafy-green%22%3A%7B%22id%22%3A%22leafy-green%22%2C%22name%22%3A%22Leafy%20Green%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22apple%22%3A%7B%22id%22%3A%22apple%22%2C%22name%22%3A%22Apple%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22green-bean%22%3A%7B%22id%22%3A%22green-bean%22%2C%22name%22%3A%22Green%20Bean%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22broccoli%22%3A%7B%22id%22%3A%22broccoli%22%2C%22name%22%3A%22Broccoli%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22zucchini%22%3A%7B%22id%22%3A%22zucchini%22%2C%22name%22%3A%22Zucchini%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cabbage%22%3A%7B%22id%22%3A%22cabbage%22%2C%22name%22%3A%22Cabbage%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22ground-beef%22%3A%7B%22id%22%3A%22ground-beef%22%2C%22name%22%3A%22Ground%20Beef%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22lemon%22%3A%7B%22id%22%3A%22lemon%22%2C%22name%22%3A%22Lemon%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22sweet-potato-yam%22%3A%7B%22id%22%3A%22sweet-potato-yam%22%2C%22name%22%3A%22Sweet%20Potato%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22citrus%22%3A%7B%22id%22%3A%22citrus%22%2C%22name%22%3A%22Citrus%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22kale%22%3A%7B%22id%22%3A%22kale%22%2C%22name%22%3A%22Kale%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22spinach%22%3A%7B%22id%22%3A%22spinach%22%2C%22name%22%3A%22Spinach%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%7D%2C%22cuisine%22%3A%7B%22italian%22%3A%7B%22id%22%3A%22italian%22%2C%22name%22%3A%22Italian%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22mexican%22%3A%7B%22id%22%3A%22mexican%22%2C%22name%22%3A%22Mexican%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22moroccan%22%3A%7B%22id%22%3A%22moroccan%22%2C%22name%22%3A%22Moroccan%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22french%22%3A%7B%22id%22%3A%22french%22%2C%22name%22%3A%22French%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22asian%22%3A%7B%22id%22%3A%22asian%22%2C%22name%22%3A%22Asian%22%2C%22orderCount%22%3A0%2C%22count%22%3A3%7D%2C%22indian%22%3A%7B%22id%22%3A%22indian%22%2C%22name%22%3A%22Indian%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22thai%22%3A%7B%22id%22%3A%22thai%22%2C%22name%22%3A%22Thai%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22mediterranean%22%3A%7B%22id%22%3A%22mediterranean%22%2C%22name%22%3A%22Mediterranean%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22middle-eastern%22%3A%7B%22id%22%3A%22middle-eastern%22%2C%22name%22%3A%22Middle%20Eastern%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22spanish-portuguese%22%3A%7B%22id%22%3A%22spanish-portuguese%22%2C%22name%22%3A%22Spanish%2FPortuguese%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22greek%22%3A%7B%22id%22%3A%22greek%22%2C%22name%22%3A%22Greek%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22american%22%3A%7B%22id%22%3A%22american%22%2C%22name%22%3A%22American%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22chinese%22%3A%7B%22id%22%3A%22chinese%22%2C%22name%22%3A%22Chinese%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cajun-creole%22%3A%7B%22id%22%3A%22cajun-creole%22%2C%22name%22%3A%22Cajun%2FCreole%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22central-south-american%22%3A%7B%22id%22%3A%22central-south-american%22%2C%22name%22%3A%22Central%2FS.%20American%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22southern%22%3A%7B%22id%22%3A%22southern%22%2C%22name%22%3A%22Southern%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22german%22%3A%7B%22id%22%3A%22german%22%2C%22name%22%3A%22German%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22african%22%3A%7B%22id%22%3A%22african%22%2C%22name%22%3A%22African%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22scandinavian%22%3A%7B%22id%22%3A%22scandinavian%22%2C%22name%22%3A%22Scandinavian%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22eastern-european-russian%22%3A%7B%22id%22%3A%22eastern-european-russian%22%2C%22name%22%3A%22Eastern%20European%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22irish%22%3A%7B%22id%22%3A%22irish%22%2C%22name%22%3A%22Irish%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22japanese%22%3A%7B%22id%22%3A%22japanese%22%2C%22name%22%3A%22Japanese%22%2C%22orderCount%22%3A0%2C%22count%22%3A3%7D%2C%22southwestern%22%3A%7B%22id%22%3A%22southwestern%22%2C%22name%22%3A%22Southwestern%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22vietnamese%22%3A%7B%22id%22%3A%22vietnamese%22%2C%22name%22%3A%22Vietnamese%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22english%22%3A%7B%22id%22%3A%22english%22%2C%22name%22%3A%22English%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22jewish%22%3A%7B%22id%22%3A%22jewish%22%2C%22name%22%3A%22Jewish%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22central-american-caribbean%22%3A%7B%22id%22%3A%22central-american-caribbean%22%2C%22name%22%3A%22Caribbean%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22latin-american%22%3A%7B%22id%22%3A%22latin-american%22%2C%22name%22%3A%22Latin%20American%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22tex-mex%22%3A%7B%22id%22%3A%22tex-mex%22%2C%22name%22%3A%22Tex-Mex%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22italian-american%22%3A%7B%22id%22%3A%22italian-american%22%2C%22name%22%3A%22Italian%20American%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22turkish%22%3A%7B%22id%22%3A%22turkish%22%2C%22name%22%3A%22Turkish%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22korean%22%3A%7B%22id%22%3A%22korean%22%2C%22name%22%3A%22Korean%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22southeast-asian%22%3A%7B%22id%22%3A%22southeast-asian%22%2C%22name%22%3A%22Southeast%20Asian%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22european%22%3A%7B%22id%22%3A%22european%22%2C%22name%22%3A%22European%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22british%22%3A%7B%22id%22%3A%22british%22%2C%22name%22%3A%22British%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cuban%22%3A%7B%22id%22%3A%22cuban%22%2C%22name%22%3A%22Cuban%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22south-american%22%3A%7B%22id%22%3A%22south-american%22%2C%22name%22%3A%22South%20American%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22nuevo-latino%22%3A%7B%22id%22%3A%22nuevo-latino%22%2C%22name%22%3A%22Nuevo%20Latino%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22californian%22%3A%7B%22id%22%3A%22californian%22%2C%22name%22%3A%22Californian%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22south-asian%22%3A%7B%22id%22%3A%22south-asian%22%2C%22name%22%3A%22South%20Asian%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%7D%2C%22occasion%22%3A%7B%22summer%22%3A%7B%22id%22%3A%22summer%22%2C%22name%22%3A%22Summer%22%2C%22orderCount%22%3A0%2C%22count%22%3A2%7D%2C%22fourth-of-july%22%3A%7B%22id%22%3A%22fourth-of-july%22%2C%22name%22%3A%22Fourth%20of%20July%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22fall%22%3A%7B%22id%22%3A%22fall%22%2C%22name%22%3A%22Fall%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22thanksgiving%22%3A%7B%22id%22%3A%22thanksgiving%22%2C%22name%22%3A%22Thanksgiving%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22christmas%22%3A%7B%22id%22%3A%22christmas%22%2C%22name%22%3A%22Christmas%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22new-years-eve%22%3A%7B%22id%22%3A%22new-years-eve%22%2C%22name%22%3A%22New%20Year's%20Eve%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22easter%22%3A%7B%22id%22%3A%22easter%22%2C%22name%22%3A%22Easter%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22passover%22%3A%7B%22id%22%3A%22passover%22%2C%22name%22%3A%22Passover%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22backyard-bbq%22%3A%7B%22id%22%3A%22backyard-bbq%22%2C%22name%22%3A%22Backyard%20BBQ%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22picnic%22%3A%7B%22id%22%3A%22picnic%22%2C%22name%22%3A%22Picnic%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22potluck%22%3A%7B%22id%22%3A%22potluck%22%2C%22name%22%3A%22Potluck%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22tailgating%22%3A%7B%22id%22%3A%22tailgating%22%2C%22name%22%3A%22Tailgating%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22birthday%22%3A%7B%22id%22%3A%22birthday%22%2C%22name%22%3A%22Birthday%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22party%22%3A%7B%22id%22%3A%22party%22%2C%22name%22%3A%22Party%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22super-bowl%22%3A%7B%22id%22%3A%22super-bowl%22%2C%22name%22%3A%22Super%20Bowl%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22winter%22%3A%7B%22id%22%3A%22winter%22%2C%22name%22%3A%22Winter%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22cocktail-party%22%3A%7B%22id%22%3A%22cocktail-party%22%2C%22name%22%3A%22Cocktail%20Party%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22christmas-eve%22%3A%7B%22id%22%3A%22christmas-eve%22%2C%22name%22%3A%22Christmas%20Eve%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22spring%22%3A%7B%22id%22%3A%22spring%22%2C%22name%22%3A%22Spring%22%2C%22orderCount%22%3A0%2C%22count%22%3A1%7D%2C%22valentines-day%22%3A%7B%22id%22%3A%22valentines-day%22%2C%22name%22%3A%22Valentine's%20Day%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22halloween%22%3A%7B%22id%22%3A%22halloween%22%2C%22name%22%3A%22Halloween%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22cinco-de-mayo%22%3A%7B%22id%22%3A%22cinco-de-mayo%22%2C%22name%22%3A%22Cinco%20de%20Mayo%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22wedding%22%3A%7B%22id%22%3A%22wedding%22%2C%22name%22%3A%22Wedding%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22mothers-day%22%3A%7B%22id%22%3A%22mothers-day%22%2C%22name%22%3A%22Mother's%20Day%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22st-patricks-day%22%3A%7B%22id%22%3A%22st-patricks-day%22%2C%22name%22%3A%22St.%20Patrick's%20Day%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22hanukkah%22%3A%7B%22id%22%3A%22hanukkah%22%2C%22name%22%3A%22Hanukkah%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22shower%22%3A%7B%22id%22%3A%22shower%22%2C%22name%22%3A%22Shower%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22mardi-gras%22%3A%7B%22id%22%3A%22mardi-gras%22%2C%22name%22%3A%22Mardi%20Gras%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22family-reunion%22%3A%7B%22id%22%3A%22family-reunion%22%2C%22name%22%3A%22Family%20Reunion%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22new-years-day%22%3A%7B%22id%22%3A%22new-years-day%22%2C%22name%22%3A%22New%20Year's%20Day%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22kentucky-derby%22%3A%7B%22id%22%3A%22kentucky-derby%22%2C%22name%22%3A%22Kentucky%20Derby%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22engagement-party%22%3A%7B%22id%22%3A%22engagement-party%22%2C%22name%22%3A%22Engagement%20Party%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22poker-game-night%22%3A%7B%22id%22%3A%22poker-game-night%22%2C%22name%22%3A%22Poker%2FGame%20Night%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22oscars%22%3A%7B%22id%22%3A%22oscars%22%2C%22name%22%3A%22Oscars%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22fathers-day%22%3A%7B%22id%22%3A%22fathers-day%22%2C%22name%22%3A%22Father's%20Day%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22anniversary%22%3A%7B%22id%22%3A%22anniversary%22%2C%22name%22%3A%22Anniversary%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22graduation%22%3A%7B%22id%22%3A%22graduation%22%2C%22name%22%3A%22Graduation%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22rosh-hashanah-yom-kippur%22%3A%7B%22id%22%3A%22rosh-hashanah-yom-kippur%22%2C%22name%22%3A%22Rosh%20Hashanah%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22ramadan%22%3A%7B%22id%22%3A%22ramadan%22%2C%22name%22%3A%22Ramadan%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%2C%22bastille-day%22%3A%7B%22id%22%3A%22bastille-day%22%2C%22name%22%3A%22Bastille%20Day%22%2C%22orderCount%22%3A0%2C%22count%22%3A0%7D%7D%7D%2C%22filterCount%22%3A12%2C%22historyPop%22%3Afalse%2C%22idWithQuickView%22%3A%22%22%2C%22initialFacets%22%3A%7B%22content%22%3A%7B%22recipe%22%3A9%2C%22article%22%3A3%7D%7D%2C%22inputTerms%22%3A%22tofu%20chill%22%2C%22searchTerms%22%3A%22tofu%20chill%22%2C%22refreshResults%22%3Afalse%2C%22resultGroups%22%3A%5Bnull%2C%7B%22items%22%3A%5B%7B%22id%22%3A%225a0330ea57e96a30a35d163c%22%2C%22dek%22%3A%22The%20novelist%20and%20independent%20book%20publisher%20relies%20on%20intuition%2C%20leftovers%2C%20and%20some%20very%20good%20cookbooks%20to%20make%20dinner%20happen.%22%2C%22hed%22%3A%22What%20the%20Writer-Publisher-Mom%20Emily%20Gould%20Cooks%20in%20a%20Week%20%20%22%2C%22pubDate%22%3A%222017-11-08T18%3A39%3A04.371Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Emily%20Gould%22%7D%5D%2C%22type%22%3A%22article%22%2C%22url%22%3A%22%2Fexpert-advice%2Femily-gould-cooking-diary-article%22%2C%22photoData%22%3A%7B%22id%22%3A%225a021ac7d63f7339eb97b547%22%2C%22filename%22%3A%22Small-Plates-Dinner-Diary-Emily-Gould-Alt-2.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22Photo%20by%20Caleb%20Adams%22%2C%22promoTitle%22%3A%22%22%2C%22title%22%3A%22Small%20Plates%20Dinner%20Diary%20Emily%20Gould%20Alt-2%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%7D%2C%7B%22id%22%3A%2257180141136b9a220ecd7dce%22%2C%22dek%22%3A%22A%20food%20writer%20gives%20us%20a%20peek%20into%20what%20really%20happens%20behind%20the%20scenes%20in%20her%20kitchen.%20And%20some%20of%20it%20isn't%20pretty.%22%2C%22hed%22%3A%22Dirty%20Secrets%20of%20a%20Home%20Cook%22%2C%22pubDate%22%3A%222016-04-21T23%3A30%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Laurie%20Woolever%22%7D%5D%2C%22type%22%3A%22article%22%2C%22url%22%3A%22%2Fexpert-advice%2Fdirty-secrets-of-a-home-cook-article%22%2C%22photoData%22%3A%7B%22id%22%3A%2254b5b5bb2889f660285a7982%22%2C%22filename%22%3A%22EP_20140912_boone-3_6x4-lpr.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22Photo%20by%20Rhoda%20Boone%22%2C%22promoTitle%22%3A%22%22%2C%22title%22%3A%22raw%20cubed%20beef%20chuck%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%7D%2C%7B%22id%22%3A%22562a62dab3d63be14330b17c%22%2C%22dek%22%3A%22All%20of%20the%20flavor%2C%20none%20of%20the%20prep%20work.%22%2C%22hed%22%3A%22Frozen%20Vegetables%20Are%20a%20Wok's%20Best%20Friend%22%2C%22pubDate%22%3A%222015-10-23T19%3A30%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Matt%20Rodbard%22%7D%5D%2C%22type%22%3A%22article%22%2C%22url%22%3A%22%2Fexpert-advice%2Fwhy-the-freezer-aisle-is-a-woks-best-friend-article%22%2C%22photoData%22%3A%7B%22id%22%3A%225570c1b281ac1e5023671e80%22%2C%22filename%22%3A%22EP-04142015-wok-7-6x4-CP.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22Photo%20by%20Chelsea%20Kyle%22%2C%22promoTitle%22%3A%22northern%20style%20carbon-steel%20round-bottomed%20wok%22%2C%22title%22%3A%22northern%20style%20carbon-steel%20round-bottomed%20wok%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%7D%2C%7B%22id%22%3A%2254a422f56529d92b2c0096e8%22%2C%22dek%22%3A%22When%20we%20visited%20Kyoto%2C%20a%20few%20hours'%20ride%20from%20Tokyo%20on%20the%20famous%20Bullet%20train%2C%20we%20found%20a%20little%20restaurant%20in%20the%20heart%20of%20town%20that%20won%20us%20over%20with%20the%20names%20of%20dishes%20listed%20on%20the%20menu%3A%20Firecracker%20Tofu%2C%20Pickled%20Mixed%20Radish%20Salad%2C%20and%20the%20mysterious%20sounding%20Okonomiyaki.%20The%20chefs%20were%20clearly%20having%20fun%20at%20this%20place%2C%20and%20we%20were%20blown%20away%20by%20the%20depth%20of%20flavor%20they%20achieved%20with%20such%20simple%20preparations.%20We%20threw%20back%20some%20sake%20and%20tore%20through%20plate%20after%20plate%20of%20food.%20This%20salad%20is%20inspired%20by%20that%20meal%2C%20featuring%20quirky%20sea%20beans%20(a%20seaweed-like%20swamp%2Fbeach%20vegetable)%20and%20the%20haunting%20flavor%20of%20shiso%20(Japanese%20mint).%20You%20can%20find%20fresh%20sea%20beans%20at%20a%20gourmet%20market.%20If%20they're%20not%20available%2C%20substitute%20pencil-thin%20asparagus.%20Look%20for%20shiso%20in%20Asian%20markets%2C%20but%20substitute%20fresh%20cilantro%20if%20you%20can't%20find%20it.%22%2C%22hed%22%3A%22Sea%20Bean%20Salad%20with%20Daikon%20and%20Cucumber%22%2C%22pubDate%22%3A%222013-10-14T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Rich%20Landau%20%22%7D%2C%7B%22name%22%3A%22%20Kate%20Jacoby%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fsea-bean-salad-with-daikon-and-cucumber-51199610%22%2C%22photoData%22%3A%7B%22id%22%3A%2254ad4bf76529d92b2c043930%22%2C%22filename%22%3A%2251199610_sea-bean-salad-daikon_1x1.jpg%22%2C%22caption%22%3A%22Sea%20Bean%20Salad%20with%20Daikon%20and%20Cucumber%22%2C%22credit%22%3A%22Michael%20Spain-Smith%22%2C%22promoTitle%22%3A%22Sea%20Bean%20Salad%20with%20Daikon%20and%20Cucumber%22%2C%22title%22%3A%22Sea%20Bean%20Salad%20with%20Daikon%20and%20Cucumber%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A0%2C%22ingredients%22%3A%5B%222%20large%20cucumbers%2C%20peeled%20(about%201%201%2F2%20pounds)%22%2C%221%20large%20daikon%20radish%2C%20peeled%22%2C%224%20scallions%22%2C%221%2F2%20pound%20sea%20beans%2C%20ends%20trimmed%22%2C%223%20tablespoons%20rice%20wine%20vinegar%22%2C%222%20tablespoons%20canola%20oil%22%2C%222%20tablespoons%20toasted%20sesame%20oil%22%2C%222%20tablespoons%20tamari%22%2C%222%20teaspoons%20black%20sesame%20seeds%22%2C%222%20teaspoons%20white%20sesame%20seeds%22%2C%221%20teaspoon%20sugar%22%2C%222%20fresh%20shiso%20leaves%2C%20finely%20chopped%22%5D%2C%22prepSteps%22%3A%5B%221.%20Cut%20the%20flesh%20of%20the%20cucumber%20into%20very%20thin%20noodle-like%20strips.%20Avoid%20the%20seeds%20by%20not%20cutting%20the%20very%20center%20of%20the%20cucumber.%20A%20mandoline%20works%20best%2C%20or%20use%20a%20knife%20and%20slice%20really%20thin.%22%2C%222.%20Cut%20the%20daikon%20into%20the%20same%20thin%20noodle-like%20strips.%20Here%20there%20are%20no%20seeds%2C%20so%20you%20can%20cut%20through%20the%20entire%20vegetable.%22%2C%223.%20Trim%20the%20roots%20of%20the%20scallions%2C%20then%20slice%20them%20into%20fine%20rings.%20Start%20at%20the%20white%20bottom%20and%20use%20about%20three-quarters%20of%20each%20scallion%2C%20until%20the%20leaves%20become%20much%20darker%20green%20and%20thicker.%22%2C%224.%20Combine%20the%20remaining%20ingredients%20in%20a%20medium%20bowl%20to%20ensure%20they%20are%20well%20mixed%2C%20then%20add%20all%20of%20the%20vegetables.%20Toss%20to%20combine%2C%20then%20cover%20and%20place%20in%20the%20refrigerator%20to%20marinate%20for%20at%20least%2030%20minutes%2C%20but%20no%20longer%20than%2024%20hours%20or%20they%20will%20get%20mushy.%20Serve%20chilled.%22%5D%2C%22reviewsCount%22%3A0%2C%22willMakeAgainPct%22%3A0%7D%2C%7B%22id%22%3A%2254a422d96529d92b2c009609%22%2C%22dek%22%3A%22Vegan%20(when%20made%20with%20agave%20nectar%20or%20sugar)%5CnThis%20trick%20will%20alter%20and%20augment%20your%20cooking%3A%20Pour%20boiling%20water%20over%20sliced%20or%20diced%20red%20onions%2C%20then%20transfer%20them%20to%20a%20solution%20of%20vinegar%2C%20sweetener%2C%20and%20salt.%20The%20onions%20will%20brighten%20into%20a%20gaudy%20shade%20of%20purplish-pink%20and%20will%20keep%20indefinitely%2C%20mysteriously%20retaining%20their%20bright%20color%20and%20crisp%20texture.%20rather%20than%20slice%2C%20the%20onions%2C%20if%20they%20are%20headed%20for%20one%20of%20the%20cold%20soups.)%5CnYou%20can%20vary%20the%20cut%20of%20the%20onions%E2%80%94and%20also%20the%20amounts%20of%20sweet%20and%20salt.%20Use%20as%20a%20dramatically%20colorful%20and%20refreshing%20tiara%20atop%20dinner%20plates%2C%20open-faced%20sandwiches%2C%20salads%2C%20cheeses%2C%20grilled%20tofu%2C%20or%20fish%E2%80%94anything%20savory.%20I%20use%20these%20often%20as%20an%20ingredient%20in%20cold%20soups%20and%20saladitas.%20(Mince%2C%20rather%20than%20slice%2C%20the%20onions%2C%20if%20they%20are%20headed%20for%20one%20of%20the%20cold%20soups.)%5Cn%E2%80%A2%20Use%20a%20very%20sharp%20knife%20or%20a%20food%20processor%20with%20a%20thin%20slicing%20attachment%20to%20cut%20the%20onions%20most%20easily.%22%2C%22hed%22%3A%22Pickled%20Red%20Onions%22%2C%22pubDate%22%3A%222013-10-02T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Mollie%20Katzen%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fpickled-red-onions-51196620%22%2C%22photoData%22%3A%7B%22id%22%3A%2257a8ae32b10b4fb03f234f38%22%2C%22filename%22%3A%22pickled-red-onions-2.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22%22%2C%22promoTitle%22%3A%22%22%2C%22title%22%3A%22pickled-red-onions-2.jpg%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A3.14%2C%22ingredients%22%3A%5B%221%20large%20red%20onion%20(3%2F4%20pound)%22%2C%223%20tablespoons%20vinegar%20(cider%2C%20red%20or%20white%20wine%2C%20or%20balsamic)%22%2C%221-2%20teaspoons%20agave%20nectar%2C%20light-colored%20honey%2C%20or%20sugar%22%2C%221%2F4%20teaspoon%20salt%22%5D%2C%22prepSteps%22%3A%5B%221.%20Put%20on%20a%20kettle%20of%20water%20to%20boil.%20Cut%20the%20onion%20into%20very%20thin%20slices%20or%20a%20mince%20and%20place%20it%20in%20a%20colander%20in%20the%20sink.%22%2C%222.%20In%20a%20bowl%20large%20enough%20to%20comfortably%20fit%20all%20the%20onion%2C%20combine%20the%20vinegar%2C%20sweetener%2C%20and%20salt%20and%20whisk%20until%20blended.%22%2C%223.%20Pour%20the%20boiling%20water%20over%20the%20onion%20and%20shake%20to%20drain.%20(It's%20fine%20if%20a%20little%20water%20still%20clings.)%22%2C%224.%20Add%20the%20onion%20to%20the%20vinegar%20solution%20and%20stir%20to%20coat.%20Let%20it%20sit%20for%20at%20least%20an%20hour%20or%20up%20to%20several%20days%2C%20covered%20and%20refrigerated%2C%20occasionally%20stirring%20and%2For%20shaking%20to%20allow%20maximum%20exposure%20to%20the%20liquid.%20Store%20in%20a%20jar%20with%20a%20tight-fitting%20lid%20in%20the%20refrigerator.%22%2C%22For%20beautiful%2C%20exotic%20pickled%20fruit%2C%20add%20fresh%20or%20frozen%20cherries%2C%20blueberries%2C%20or%20raspberries%E2%80%94or%20some%20small%20watermelon%20chunks%E2%80%94to%20the%20onion%20after%20the%20first%20hour%20of%20sitting%20time%20*%20Add%20any%20of%20the%20following%20to%20the%20pickle%20mixture%3A%20Raw%20broccoli%20stems%2C%20peeled%20and%20cut%20into%20slender%20matchsticks%20*%20Raw%20fennel%2C%20cut%20into%20thin%20slices%20*%20Lightly%20steamed%20carrot%20slices%20*%20Lightly%20steamed%20cauliflower%2C%20cut%20into%201-inch%20florets%22%5D%2C%22reviewsCount%22%3A5%2C%22willMakeAgainPct%22%3A60%7D%2C%7B%22id%22%3A%2254a4216a19925f464b3785c7%22%2C%22dek%22%3A%22I've%20been%20doing%20the%20previous%20marinades%20forever.%20This%20new%20one%20is%20first%20cousin%20to%20a%20good%20barbecued%20tofu%3A%20piquant%2C%20sweet-hot-rich%2C%20and%20scintillatingly%20tasty.%20The%20tofu%20is%20baked%20in%20the%20marinade%2Fsauce%2C%20which%20cooks%20down%20and%20coats%20it%2C%20caramelizing%20them.%20You'll%20probably%20have%20to%20soak%20the%20baking%20dish%20overnight%20before%20washing%20it%2C%20but%20it's%20worth%20it.%20Vary%20this%20using%20fruit%20juice%20concentrate%20instead%20of%20honey%20or%20sugar%2C%20and%20adding%20extra%20ginger%2C%20orange%20zest%2C%20or%20both.%20For%20an%20incendiary%20smokiness%2C%20add%20chipotle%20in%20adobo.%22%2C%22hed%22%3A%22New%20Wave-New%20Fave%20Baked%20Tofu%20or%20Tempeh%22%2C%22pubDate%22%3A%222012-02-10T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Crescent%20Dragonwagon%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fnew-wave-new-fave-baked-tofu-or-tempeh-394509%22%2C%22photoData%22%3A%7B%22id%22%3A%225a0ddb046e013d11dde39630%22%2C%22filename%22%3A%22no-recipe-card-green-15112017.jpg%22%2C%22caption%22%3A%22No%20Recipe%20Card-%20GREEN%22%2C%22credit%22%3A%22Photo%20by%20Chelsea%20Kyle%22%2C%22colors%22%3A%7B%22average%22%3A%22%23000000%22%7D%2C%22type%22%3A%22photo%22%7D%2C%22aggregateRating%22%3A3%2C%22ingredients%22%3A%5B%221%2F3%20cup%20natural%2C%20unhydrogenated%20peanut%20butter%22%2C%221%2F3%20cup%20tamari%20or%20shoyu%20soy%20sauce%22%2C%221%2F3%20cup%20honey%2C%20light%20brown%20sugar%2C%20maple%20syrup%2C%20or%20thawed%2C%20undiluted%20frozen%20apple%20or%20pineapple%20juice%20concentrate%22%2C%221%2F4%20cup%20apple%20cider%20vinegar%22%2C%224%20to%206%20cloves%20garlic%2C%20quartered%20lengthwise%22%2C%22About%201%20tablespoon%20chopped%20fresh%20ginger%20(optional)%22%2C%221%20to%202%20tablespoons%20tomato%20paste%20or%20ketchup%22%2C%221%20canned%20chipotle%20pepper%20in%20adobo%20sauce%2C%201%2F2%20teaspoon%20cayenne%2C%20or%201%20fresh%20serrano%20or%20jalape%C3%B1o%20pepper%2C%20de-stemmed%22%2C%22Juice%20and%20grated%20zest%20of%201%20orange%20(optional%2C%20but%20good)%22%2C%2212%20to%2014%20ounces%20drained%2C%20sliced%20traditional%20water-packed%20firm%20or%20extra-firm%20tofu%20or%20tempeh%22%2C%22Vegetable%20oil%20cooking%20spray%22%5D%2C%22prepSteps%22%3A%5B%221.%20Combine%20the%20peanut%20butter%2C%20tamari%2C%20honey%2C%20apple%20cider%20vinegar%2C%20garlic%2C%20ginger%2C%20tomato%20paste%2C%20chipotle%2C%20and%20orange%20juice%20and%20zest%20in%20a%20food%20processor%20and%20buzz%20until%20the%20ginger%20is%20finely%20chopped.%22%2C%222.%20To%20use%20the%20marinade%2C%20place%20the%20tofu%20in%20a%20nonreactive%20bowl%20or%20zip-top%20bag%20and%20pour%20or%20spoon%20this%20luscious%20mixture%20over%20it.%20Refrigerate%20the%20tofu%2C%20covered%2C%20overnight.%22%2C%223.%20The%20next%20day%2C%20preheat%20the%20oven%20to%20375%C2%B0F%20and%20generously%20spray%20a%20nonreactive%20baking%20dish%20with%20oil%20(I%20use%20an%208%20or%209%20by%2012-inch%20deep%20glass%20baking%20dish).%22%2C%224.%20Place%20the%20tofu%20and%20its%20marinade%20in%20the%20baking%20dish%2C%20spreading%20the%20marinade%20as%20needed%20so%20both%20sides%20of%20the%20tofu%20slices%20get%20a%20good%20smear%20of%20it.%20Bake%2C%20turning%20once%2C%20until%20fragrant%2C%20firmed%20up%2C%20and%20golden%20to%20deep%20brown%20in%20spots%20with%20the%20marinade%20considerably%20thickened%2C%20about%2030%20minutes.%22%5D%2C%22reviewsCount%22%3A1%2C%22willMakeAgainPct%22%3A100%7D%2C%7B%22id%22%3A%2254a427be6529d92b2c00cd4c%22%2C%22dek%22%3A%22Wheat%20Free%5CnNo%20need%20to%20worry%20if%20your%20local%20market%20doesn't%20carry%20egg-free%20mayo.%20Just%20whip%20up%20some%20of%20your%20own.%20This%20recipe%20works%20very%20well%20as%20a%20sandwich%20spread%20or%20in%20any%20mayonnaise-based%20dressing.%20As%20long%20as%20you%20use%20wheat-free%20vinegar%2C%20this%20mayo%20is%20indeed%20wheat-free.%22%2C%22hed%22%3A%22Vegan%20Mayonnaise%22%2C%22pubDate%22%3A%222011-06-23T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Joni%20Marie%20Newman%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fvegan-mayonnaise-366490%22%2C%22photoData%22%3A%7B%22id%22%3A%2254b2afd611c5d6af478b2759%22%2C%22filename%22%3A%22366490_vegan-mayonnaise_1x1.jpg%22%2C%22caption%22%3A%22Vegan%20Mayonnaise%22%2C%22credit%22%3A%22Rockport%20Publishers%22%2C%22promoTitle%22%3A%22Vegan%20Mayonnaise%22%2C%22title%22%3A%22Vegan%20Mayonnaise%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A1%2C%22ingredients%22%3A%5B%227%20ounces%20(195%20g)%20extra-firm%20tofu%2C%20drained%20and%20pressed%22%2C%221%2F4%20cup%20(35%20g)%20raw%20cashews%2C%20ground%20into%20a%20very%20fine%20powder%22%2C%221%20tablespoon%20(15%20ml)%20lemon%20juice%22%2C%221%20tablespoon%20(12%20g)%20raw%20sugar%20or%20(21%20g)%20agave%20nectar%22%2C%221%201%2F2%20teaspoons%20brown%20or%20Dijon%20mustard%22%2C%221%20teaspoon%20apple%20cider%20or%20rice%20wine%20vinegar%22%2C%221%2F2%20teaspoon%20sea%20salt%22%2C%226%20tablespoons%20(90%20ml)%20canola%20oil%22%5D%2C%22prepSteps%22%3A%5B%22Place%20the%20tofu%2C%20cashews%2C%20lemon%20juice%2C%20sugar%2C%20mustard%2C%20vinegar%2C%20and%20salt%20in%20a%20blender%20or%20food%20processor%20and%20process%20until%20smooth.%22%2C%22Slowly%20drizzle%20in%20the%20oil%20and%20pulse%20until%20you%20get%20the%20consistency%20that%20you%20like.%22%2C%22Store%20in%20an%20airtight%20container%20in%20the%20refrigerator%20for%20up%20to%202%20weeks.%22%5D%2C%22reviewsCount%22%3A3%2C%22willMakeAgainPct%22%3A33%7D%2C%7B%22id%22%3A%2254a42a5219925f464b37ea8a%22%2C%22dek%22%3A%22A%20staple%20of%20classic%20Japanese%20cooking%2C%20teriyaki%20is%20wonderful%20with%20not%20only%20seafood%20but%20also%20poultry%2C%20beef%2C%20vegetables%2C%20and%20tofu.%20Often%2C%20however%2C%20this%20versatile%20sauce%20can%20be%20quite%20sweet.%20My%20version%20uses%20fresh%20orange%20juice%2C%20which%20adds%20just%20a%20touch%20of%20natural%20sweetness%20as%20well%20as%20some%20acidity%20to%20temper%20the%20sweet%20mirin.%20Pouring%20some%20of%20the%20teriyaki%20sauce%20into%20the%20hot%20pan%20with%20the%20fish%20further%20reduces%20it%20so%20the%20sauce%20really%20coats%20the%20fish%20with%20a%20deep%2C%20caramel%20glaze%20that%20enhances%20the%20delectable%20moist%2C%20buttery%2C%20and%20tender%20qualities%20of%20black%20cod%20perfectly.%20Other%20good%20fish%20for%20this%20dish%20are%20Alaskan%20cod%2C%20true%20cod%2C%20sablefish%2C%20or%20wild%20salmon.%20Searing%20each%20side%20of%20the%20sticky%20rice%20cake%20gives%20a%20nutty%20flavor%20and%20crisp%20texture.%20I%20also%20like%20to%20serve%20these%20rice%20cakes%20with%20vegetable%20stir-fries%20in%20place%20of%20plain%20rice.%20If%20you%20have%20a%20rice%20cooker%2C%20use%20it%20to%20prepare%20the%20rice%20according%20to%20the%20manufacturer's%20directions.%20If%20not%2C%20follow%20the%20instructions%20in%20the%20recipe%20to%20prepare%20it%20in%20a%20saucepan.%22%2C%22hed%22%3A%22Teriyaki%20Black%20Cod%20with%20Sticky%20Rice%20Cakes%20and%20Seared%20Baby%20Bok%20Choy%22%2C%22pubDate%22%3A%222011-03-11T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Dean%20Rucker%22%7D%2C%7B%22name%22%3A%22%20Marah%20Stets%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fteriyaki-black-cod-with-sticky-rice-cakes-and-seared-baby-bok-choy-363330%22%2C%22photoData%22%3A%7B%22id%22%3A%2256098f2d62fa7a9917c1d93e%22%2C%22filename%22%3A%22363330_hires.jpg%22%2C%22caption%22%3A%22Teriyaki%20Black%20Cod%20with%20Sticky%20Rice%20Cakes%20and%20Seared%20Baby%20Bok%20Choy%22%2C%22credit%22%3A%22Cookbook%20cover%20image%20courtesy%20of%20Random%20House%22%2C%22promoTitle%22%3A%22Teriyaki%20Black%20Cod%20with%20Sticky%20Rice%20Cakes%20and%20Seared%20Baby%20Bok%20Choy%22%2C%22title%22%3A%22Teriyaki%20Black%20Cod%20with%20Sticky%20Rice%20Cakes%20and%20Seared%20Baby%20Bok%20Choy%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A3.25%2C%22ingredients%22%3A%5B%229%20baby%20bok%20choy%2C%20halved%20lengthwise%22%2C%223%2F4%20cup%20sushi%20rice%22%2C%22Grapeseed%20or%20canola%20oil%20spray%22%2C%222%20tablespoons%20sliced%20scallions%20(white%20and%20green%20parts)%22%2C%221%20teaspoon%20minced%20garlic%22%2C%221%20tablespoon%20minced%20peeled%20fresh%20ginger%22%2C%221%20tablespoon%20unseasoned%20rice%20vinegar%22%2C%221%201%2F2%20teaspoons%20mirin%22%2C%22Pinch%20of%20kosher%20salt%22%2C%22Pinch%20of%20freshly%20ground%20black%20pepper%22%2C%221%2F2%20cup%20low-sodium%20soy%20sauce%22%2C%223%2F4%20cup%20fresh%20orange%20juice%20(from%203%20oranges)%22%2C%221%2F4%20cup%20mirin%22%2C%221%20teaspoon%20minced%20peeled%20fresh%20ginger%22%2C%221%2F2%20teaspoon%20cornstarch%22%2C%226%20(4-ounce)%20skinless%20black%20cod%20fillets%2C%20each%201%20inch%20thick%22%2C%221%2F4%20teaspoon%20freshly%20ground%20black%20pepper%22%2C%22Grapeseed%20or%20canola%20oil%20spray%22%2C%221%2F2%20cup%20thinly%20sliced%20scallions%20(white%20and%20light%20green%20parts)%2C%20for%20serving%22%2C%221%20tablespoon%20sesame%20seeds%2C%20toasted%2C%20for%20serving%22%5D%2C%22prepSteps%22%3A%5B%22Bring%20a%20large%20pot%20of%20water%20to%20a%20rapid%20boil.%20Prepare%20a%20bowl%20of%20ice%20water.%20Add%20the%20bok%20choy%20to%20the%20boiling%20water%20and%20cook%20for%2030%20seconds.%20Drain%20the%20bok%20choy%20and%20immediately%20transfer%20it%20to%20the%20ice%20water%20for%202%20minutes%20to%20cool.%20Drain%20the%20bok%20choy%20and%20set%20aside%20on%20a%20clean%20kitchen%20towel%20to%20soak%20up%20excess%20moisture.%22%2C%22Prepare%20the%20sticky%20rice%20cakes.%20Put%20the%20rice%20in%20a%20large%20bowl%20and%20cover%20with%20cold%20water.%20Use%20your%20hand%20to%20swish%20the%20rice%20around%20a%20few%20times.%20Drain%20and%20repeat%20until%20the%20water%20in%20the%20bowl%20is%20clear%3B%20you%20may%20need%20to%20rinse%20it%20several%20times.%22%2C%22Put%20the%20rice%20in%20a%20small%2C%20heavy-bottomed%20saucepan%20and%20add%20water%20to%20cover%20by%201%20inch.%20Cover%20the%20pan%3B%20for%20best%20results%2C%20do%20not%20uncover%20the%20pan%20at%20any%20time%20during%20cooking.%20Bring%20to%20a%20boil%20over%20medium-high%20heat%2C%204%20to%205%20minutes%3B%20you%20will%20be%20able%20to%20tell%20the%20water%20is%20boiling%20by%20the%20large%20amount%20of%20steam%20pouring%20out%20from%20under%20the%20lid.%20Reduce%20the%20heat%20to%20low%20and%20simmer%2C%20covered%2C%20for%2010%20minutes.%20Remove%20the%20pan%20from%20the%20heat%20and%20let%20stand%2C%20covered%2C%20for%2015%20minutes.%22%2C%22Spray%20a%20small%20saut%C3%A9%20pan%20with%20grapeseed%20oil%20and%20heat%20over%20medium%20heat.%20Add%20the%20scallions%2C%20garlic%2C%20and%20ginger%20and%20cook%2C%20stirring%2C%20until%20just%20softened%20and%20fragrant%2C%20about%2030%20seconds.%20Fold%20the%20scallion%20mixture%20into%20the%20warm%2C%20cooked%20rice%20along%20with%20the%20vinegar%2C%20mirin%2C%20salt%2C%20and%20pepper.%22%2C%22Line%20a%20platter%20or%20baking%20sheet%20with%20parchment%20paper%20sprayed%20with%20oil%20or%20with%20waxed%20paper.%20Have%20a%20separate%20bowl%20of%20water%20ready.%20Dip%20your%20hands%20into%20the%20water%20and%20scoop%20up%201%2F4%20cup%20rice.%20Form%20it%20into%20a%20tightly%20packed%20cake%20about%202%20inches%20thick%20and%20place%20the%20cake%20on%20the%20platter.%20Repeat%20with%20the%20remaining%20rice%20to%20form%20five%20more%20cakes.%20Set%20aside%20in%20the%20refrigerator.%22%2C%22Meanwhile%2C%20in%20a%20small%20saucepan%2C%20combine%20the%20soy%20sauce%2C%20orange%20juice%2C%20mirin%2C%20and%20ginger.%20Bring%20to%20a%20boil%20and%20reduce%20the%20heat%20to%20low.%20Simmer%20just%20until%20reduced%20by%20half%2C%2030%20to%2040%20minutes.%20In%20a%20small%20dish%2C%20mix%20the%20cornstarch%20and%201%20teaspoon%20water%20and%20stir%20this%20slurry%20into%20the%20simmering%20sauce.%20Simmer%2030%20seconds%20and%20remove%20the%20pan%20from%20the%20heat.%22%5D%2C%22reviewsCount%22%3A9%2C%22willMakeAgainPct%22%3A88%7D%2C%7B%22id%22%3A%2254a4276219925f464b37c5f1%22%2C%22dek%22%3A%22Combining%20bittersweet%20chocolate%20and%20cocoa%20powder%20intensifies%20the%20chocolaty%20essence%20of%20this%20cheesecake%20to%20the%20nth%20degree.%20Silken%20tofu%20brings%20a%20delicate%20creaminess%20to%20the%20filling%20while%20also%20taking%20the%20place%20of%20eggs%20by%20acting%20as%20a%20binding%20agent.%22%2C%22hed%22%3A%22Vegan%20Chocolate%20Cheesecake%22%2C%22pubDate%22%3A%222009-10-15T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Gina%20Marie%20Miraglia%20Eriquez%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fvegan-chocolate-cheesecake-355990%22%2C%22photoData%22%3A%7B%22id%22%3A%225609a773e0acd286555dba9e%22%2C%22filename%22%3A%22355990_hires.jpg%22%2C%22caption%22%3A%22Vegan%20Chocolate%20Cheesecake%22%2C%22credit%22%3A%22Romulo%20Yanes%22%2C%22promoTitle%22%3A%22Vegan%20Chocolate%20Cheesecake%22%2C%22title%22%3A%22Vegan%20Chocolate%20Cheesecake%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A2.76%2C%22ingredients%22%3A%5B%221%201%2F4%20cups%20chocolate%20or%20regular%20graham%20cracker%20crumbs%20(from%20nine%205-by%202%201%2F2-inch%20graham%20crackers)%22%2C%223%20tablespoons%20sugar%22%2C%224%20tablespoons%20Earth%20Balance%20vegan%20buttery%20spread%2C%20melted%20and%20cooled%2C%20plus%20additional%20for%20greasing%20pan%22%2C%222%201%2F4%20cups%20sugar%2C%20divided%22%2C%221%2F3%20cup%20water%22%2C%228%20ounces%20bittersweet%20chocolate%20(no%20more%20than%2060%25%20cacao)%2C%20chopped%22%2C%222%20(1-pound%20packages%20silken%20tofu%2C%20drained%22%2C%221%2F4%20cup%20unsweetened%20cocoa%20powder%20(not%20Dutch-process)%22%2C%222%20(8-ounces)%20containers%20soy%20cream%20cheese%20at%20room%20temperature%22%2C%221%20teaspoon%20pure%20vanilla%20extract%22%2C%22Rounded%201%2F4%20teaspoon%20salt%22%2C%22Equipment%3A%20a%209-inch%20springform%20pan%22%5D%2C%22prepSteps%22%3A%5B%22Preheat%20oven%20to%20350%C2%B0F%20with%20racks%20in%20middle%20and%20lower%20third%20and%20put%20a%20baking%20sheet%20on%20lower%20rack.%20Flip%20bottom%20of%20springform%20pan%20so%20lip%20is%20facing%20down%2C%20then%20lock%20in%20place.%20Grease%20bottom%20and%20side%20of%20pan.%22%2C%22Stir%20together%20all%20crust%20ingredients%2C%20then%20press%20onto%20bottom%20and%201%20inch%20up%20side%20of%20pan.%20Bake%20until%20set%2C%2010%20to%2012%20minutes%2C%20then%20cool%20completely%2C%20about%2045%20minutes.%22%2C%22Heat%201%20cup%20sugar%20in%20a%201%201%2F2-to%202-quart%20heavy%20saucepan%20over%20medium%20heat%2C%20stirring%20with%20a%20fork%20to%20heat%20sugar%20evenly%2C%20until%20it%20starts%20to%20melt%2C%20then%20stop%20stirring%20and%20cook%2C%20swirling%20pan%20occasionally%20so%20sugar%20melts%20evenly%2C%20until%20it%20is%20dark%20amber.%20Remove%20from%20heat%20and%20carefully%20stir%20in%20water%20(mixture%20will%20bubble%20up%20and%20steam%20and%20caramel%20will%20harden)%2C%20then%20cook%20over%20medium-low%20heat%2C%20stirring%2C%20until%20caramel%20has%20dissolved.%20Remove%20from%20heat%20and%20whisk%20in%20chopped%20chocolate%20until%20smooth.%20Cool%20fudge%20sauce%20slightly.%22%2C%22Pur%C3%A9e%20tofu%20and%20cocoa%20in%20a%20food%20processor%20until%20smooth.%22%2C%22Beat%20soy%20cream%20cheese%20and%20remaining%201%201%2F4%20cups%20sugar%20with%20an%20electric%20mixer%20at%20medium-high%20speed%20until%20fluffy.%20At%20low%20speed%2C%20beat%20in%20tofu%20pur%C3%A9e%2C%20vanilla%2C%20salt%2C%20and%20fudge%20sauce%20until%20incorporated.%22%2C%22Pour%20filling%20into%20crust%20and%20bake%20on%20middle%20rack%20until%20top%20of%20cake%20is%20shiny%20but%20center%20is%20still%20slightly%20wobbly%20when%20pan%20is%20gently%20shaken%2C%20about%201%20hour.%20Turn%20oven%20off%20and%20leave%20cake%20in%20oven%201%20hour%20more.%22%2C%22Run%20a%20knife%20around%20top%20edge%20of%20cake%20to%20loosen%2C%20then%20cool%20completely%20in%20pan%20on%20rack%20(cake%20will%20continue%20to%20set%20as%20it%20cools).%20Chill%20cake%2C%20loosely%20covered%2C%20at%20least%206%20hours.%20Remove%20side%20of%20pan%20and%20transfer%20cake%20to%20a%20plate.%20Bring%20to%20room%20temperature%20before%20serving%20if%20desired.%22%5D%2C%22reviewsCount%22%3A15%2C%22willMakeAgainPct%22%3A58%7D%2C%7B%22id%22%3A%2254a42e8319925f464b381eab%22%2C%22dek%22%3A%22A%20bowl%20of%20these%20refreshing%20noodles%E2%80%94a%20riff%20on%20a%20Japanese%20classic%20that%20gets%20topped%20with%20silky%20tofu%E2%80%94is%20clean%20and%20light%2C%20yet%20still%20hearty%20enough%20to%20make%20a%20satisfying%20meal.%22%2C%22hed%22%3A%22Chilled%20Soba%20with%20Tofu%20and%20Sugar%20Snap%20Peas%22%2C%22pubDate%22%3A%222008-09-18T16%3A43%3A55.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22%20Lillian%20Chou%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fchilled-soba-with-tofu-and-sugar-snap-peas-242834%22%2C%22photoData%22%3A%7B%22id%22%3A%22560d78b17b55306961bf3470%22%2C%22filename%22%3A%22242834_hires.jpg%22%2C%22caption%22%3A%22Chilled%20Soba%20with%20Tofu%20and%20Sugar%20Snap%20Peas%22%2C%22credit%22%3A%22Romulo%20Yanes%22%2C%22promoTitle%22%3A%22Chilled%20Soba%20with%20Tofu%20and%20Sugar%20Snap%20Peas%22%2C%22title%22%3A%22Chilled%20Soba%20with%20Tofu%20and%20Sugar%20Snap%20Peas%22%2C%22orientation%22%3A%22portrait%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A3.53%2C%22ingredients%22%3A%5B%221%20large%20dried%20shiitake%20mushroom%22%2C%222%201%2F2%20cups%20water%22%2C%228%20(1-inch)%20pieces%20kombu%20(dried%20kelp)%22%2C%221%2F2%20cup%20soy%20sauce%20(preferably%20Japanese)%22%2C%221%2F4%20cup%20mirin%20(Japanese%20sweet%20rice%20wine)%22%2C%223%20tablespoons%20ponzu%20sauce%20(not%20containing%20dashi)%22%2C%221%20tablespoon%20sugar%22%2C%221%20tablespoon%20Asian%20sesame%20oil%22%2C%221%20pound%20sugar%20snap%20peas%2C%20thinly%20sliced%22%2C%2210%20ounces%20baby%20spinach%20(16%20cups)%22%2C%221%20pound%20dried%20soba%20noodles%22%2C%221%20(14-%20to%2018-ounce)%20package%20silken%20tofu%22%2C%221%20cup%20thinly%20sliced%20scallions%2C%20divided%22%2C%222%20tablespoons%20thin%20matchsticks%20of%20peeled%20ginger%22%5D%2C%22prepSteps%22%3A%5B%22Simmer%20mushroom%20in%20water%20in%20a%20small%20saucepan%2C%20covered%2C%2015%20minutes.%20Add%20kombu%20and%20barely%20simmer%2C%20covered%2C%205%20minutes.%20Remove%20from%20heat%20and%20let%20stand%2C%20covered%2C%205%20minutes.%20Strain%20through%20a%20fine-mesh%20sieve%20into%20a%20large%20glass%20measure%2C%20pressing%20on%20and%20discarding%20solids.%20Return%202%20cups%20liquid%20(add%20water%20if%20necessary)%20to%20saucepan.%20Add%20soy%20sauce%2C%20mirin%2C%20ponzu%2C%20sugar%2C%20and%201%2F4%20teaspoon%20salt%20and%20bring%20to%20a%20boil%2C%20stirring%20until%20sugar%20has%20dissolved.%20Remove%20from%20heat.%20Stir%20in%20sesame%20oil%2C%20then%20cool%20in%20pan%20in%20a%20large%20ice%20bath.%22%2C%22Blanch%20sugar%20snaps%20in%20a%20large%20pot%20of%20unsalted%20boiling%20water%20until%20crisp-tender%2C%20about%202%20minutes.%20Transfer%20with%20a%20slotted%20spoon%20to%20a%20large%20colander%20set%20in%20ice%20bath%20to%20stop%20cooking.%20Lift%20colander%20to%20drain.%20Transfer%20sugar%20snaps%20to%20a%20bowl.%20Meanwhile%2C%20return%20water%20to%20a%20boil.%20Blanch%20spinach%20until%20just%20wilted%2C%20about%2030%20seconds%2C%20then%20cool%20and%20drain%20in%20same%20manner.%20Squeeze%20out%20excess%20water.%20Add%20to%20sugar%20snaps.%22%2C%22Return%20water%20to%20a%20boil.%22%2C%22Add%20noodles%20and%20cook%20according%20to%20package%20directions%2C%20stirring%20occasionally%2C%20until%20tender.%20Drain%20in%20colander%20and%20rinse%20with%20cold%20water.%20Cool%20in%20ice%20bath%20until%20very%20cold%20(add%20more%20ice%20to%20water%20as%20necessary).%20Drain%20well.%22%2C%22Carefully%20drain%20tofu%20and%20pat%20dry.%20Cut%20into%203%2F4-inch%20cubes.%22%2C%22Whisk%20sauce%2C%20then%20pour%201%201%2F2%20cups%20sauce%20into%20a%20large%20bowl.%20Add%20noodles%2C%20sugar%20snaps%2C%20spinach%2C%20and%20half%20of%20scallions%20and%20toss.%20Serve%20in%20shallow%20bowls%2C%20topped%20with%20tofu%2C%20remaining%20scallions%2C%20and%20ginger.%20Drizzle%20with%20some%20of%20remaining%20sauce%20and%20serve%20remainder%20on%20the%20side.%22%5D%2C%22reviewsCount%22%3A8%2C%22willMakeAgainPct%22%3A75%7D%2C%7B%22id%22%3A%2254a4332f6529d92b2c016045%22%2C%22dek%22%3A%22A%20Meyer%20lemon%20is%20a%20cross%20between%20a%20lemon%20and%20a%20mandarin%20orange.%20If%20you%20can't%20find%20any%2C%20substitute%20regular%20lemons.%20This%20pie's%20decadent%20cream%20filling%20is%20made%20from%20protein-rich%20tofu.%22%2C%22hed%22%3A%22Meyer%20Lemon%20Cream%20Pies%22%2C%22pubDate%22%3A%222007-07-16T04%3A09%3A02.000Z%22%2C%22author%22%3A%5B%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fmeyer-lemon-cream-pies-239225%22%2C%22photoData%22%3A%7B%22id%22%3A%2256f30156c98a9a676e4e6bce%22%2C%22filename%22%3A%22239225_hires.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22Photo%20by%20Yunhee%20Kim%22%2C%22promoTitle%22%3A%22%22%2C%22title%22%3A%22Meyer%20Lemon%20Cream%20Pies%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A2.5%2C%22ingredients%22%3A%5B%221%201%2F4%20cups%20graham-cracker%20crumbs%22%2C%222%20tablespoons%20sugar%22%2C%225%20tablespoons%20unsalted%20butter%2C%20melted%22%2C%222%20(12-ounce)%20containers%20firm%20silken%20tofu%20(such%20as%20Mori-Nu)%22%2C%22Grated%20zest%20and%20juice%20of%202%20Meyer%20lemons%22%2C%221%2F2%20cup%20confectioners'%20sugar%22%5D%2C%22prepSteps%22%3A%5B%221.%20Preheat%20oven%20to%20350%C2%B0F.%22%2C%222.%20In%20a%20medium%20bowl%2C%20mix%20together%20all%20the%20crust%20ingredients.%20Press%20the%20mixture%20into%20the%20bottom%20and%20sides%20of%20four%20tartlet%20molds%20or%204-ounce%20ramekins.%22%2C%223.%20Bake%20until%20golden%20brown%2C%208%20to%2010%20minutes.%20Remove%20and%20let%20cool%20completely.%22%2C%224.%20In%20a%20blender%2C%20combine%20all%20the%20filling%20ingredients%20until%20smooth%2C%20spoon%20the%20mixture%20into%20the%20crusts%2C%20and%20refrigerate%20for%20at%20least%201%20hour.%22%5D%2C%22reviewsCount%22%3A8%2C%22willMakeAgainPct%22%3A50%7D%2C%7B%22id%22%3A%2254a4729919925f464b399731%22%2C%22dek%22%3A%22%22%2C%22hed%22%3A%22Scallop%20and%20Corn%20Pot%20Stickers%22%2C%22pubDate%22%3A%222004-08-20T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fscallop-and-corn-pot-stickers-11846%22%2C%22photoData%22%3A%7B%22id%22%3A%225a0ddb06f110de5830af9a10%22%2C%22filename%22%3A%22no-recipe-card-red-15112017.jpg%22%2C%22caption%22%3A%22No%20Recipe%20card-%20RED%22%2C%22credit%22%3A%22Photo%20by%20Chelsea%20Kyle%22%2C%22colors%22%3A%7B%22average%22%3A%22%23000000%22%7D%2C%22type%22%3A%22photo%22%7D%2C%22aggregateRating%22%3A3.5%2C%22ingredients%22%3A%5B%221%2F2%20pound%20sea%20scallops%22%2C%221%2F4%20teaspoon%20salt%22%2C%221%2F4%20cup%20soft%20tofu%20(preferably%20silken)%22%2C%221%2F4%20cup%20cooked%20corn%22%2C%221%2F4%20cup%20minced%20red%20bell%20pepper%22%2C%223%20tablespoons%20minced%20scallion%22%2C%222%20tablespoons%20finely%20chopped%20fresh%20coriander%22%2C%22eighteen%203-to-4%20inch%20round%20won%20ton%20or%20dumpling%20or%20gyozo%20wrappers%2C%C2%A0thawed%20if%20frozen%22%2C%22cornstarch%20for%20dusting%20tray%22%2C%22Sesame%20Vinaigrette%22%5D%2C%22prepSteps%22%3A%5B%22Discard%20small%20tough%20muscle%20from%20side%20of%20each%20scallop%20and%20in%20a%20food%20processor%20pur%C3%A9e%20half%20scallops%20with%20salt.%20With%20motor%20running%20add%20tofu%20in%20a%20stream%20and%20blend%20until%20just%20combined.%22%2C%22Transfer%20scallop%20mousse%20to%20a%20small%20bowl.%20Chop%20fine%20remaining%20scallops%20and%20stir%20into%20mousse%20with%20corn%2C%20bell%20pepper%2C%20scallion%2C%20and%20coriander.%22%2C%22Put%20about%201%20tablespoon%20filling%20in%20center%20of%201%20wrapper%20and%20moisten%20edge%20of%20wrapper.%20Gather%20edge%20of%20wrapper%20up%20and%20around%20filling%2C%20pleating%20edge.%20Gently%20squeeze%20middle%20of%20pot%20sticker%20to%20form%20a%20waist%2C%20keeping%20filling%20level%20with%20top%20of%20wrapper.%20(Pot%20sticker%20will%20resemble%20a%20sack%20filled%20to%20top.)%22%2C%22Make%2017%20more%20pot%20stickers%20in%20same%20manner%20and%20arrange%20on%20a%20tray%20dusted%20lightly%20with%20cornstarch.%20Pot%20stickers%20may%20be%20made%20up%20to%20this%20point%201%20day%20ahead%20and%20chilled%2C%20covered%20with%20plastic%20wrap.%22%2C%22In%20a%20large%20non-stick%20skillet%20heat%20oil%20over%20moderately%20high%20heat%20until%20hot%20but%20not%20smoking%20and%20fry%20pot-sticker%20bottoms%20until%20golden%2C%20about%201%20minute.%20Add%20water%20and%20steam%20pot%20stickers%2C%20covered%2C%203%20to%204%20minutes%2C%20or%20until%20filling%20is%20springy%20to%20touch.%20Remove%20lid%20and%20cook%20pot%20stickers%20until%20liquid%20is%20evaporated%20and%20bottoms%20are%20recrisped.%22%2C%22Serve%20pot%20stickers%20with%20vinaigrette%20and%20garnish%20with%20coriander.%22%5D%2C%22reviewsCount%22%3A9%2C%22willMakeAgainPct%22%3A100%7D%5D%2C%22page%22%3A%7B%22generatedAt%22%3A%222019-06-03T15%3A09%3A19.576Z%22%2C%22count%22%3A1%2C%22number%22%3A1%2C%22size%22%3A18%2C%22totalCount%22%3A12%2C%22previousNumber%22%3A1%7D%7D%5D%2C%22resultGroupDisplaySize%22%3A18%2C%22spellcheck%22%3A%7B%22requested%22%3A%22tofu%20chill%22%7D%2C%22suggestions%22%3A%5B%5D%2C%22walkthrough%22%3A%7B%7D%2C%22query%22%3A%7B%22page%22%3A1%7D%2C%22items%22%3A%5B%7B%22id%22%3A%225a0330ea57e96a30a35d163c%22%2C%22dek%22%3A%22The%20novelist%20and%20independent%20book%20publisher%20relies%20on%20intuition%2C%20leftovers%2C%20and%20some%20very%20good%20cookbooks%20to%20make%20dinner%20happen.%22%2C%22hed%22%3A%22What%20the%20Writer-Publisher-Mom%20Emily%20Gould%20Cooks%20in%20a%20Week%20%20%22%2C%22pubDate%22%3A%222017-11-08T18%3A39%3A04.371Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Emily%20Gould%22%7D%5D%2C%22type%22%3A%22article%22%2C%22url%22%3A%22%2Fexpert-advice%2Femily-gould-cooking-diary-article%22%2C%22photoData%22%3A%7B%22id%22%3A%225a021ac7d63f7339eb97b547%22%2C%22filename%22%3A%22Small-Plates-Dinner-Diary-Emily-Gould-Alt-2.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22Photo%20by%20Caleb%20Adams%22%2C%22promoTitle%22%3A%22%22%2C%22title%22%3A%22Small%20Plates%20Dinner%20Diary%20Emily%20Gould%20Alt-2%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%7D%2C%7B%22id%22%3A%2257180141136b9a220ecd7dce%22%2C%22dek%22%3A%22A%20food%20writer%20gives%20us%20a%20peek%20into%20what%20really%20happens%20behind%20the%20scenes%20in%20her%20kitchen.%20And%20some%20of%20it%20isn't%20pretty.%22%2C%22hed%22%3A%22Dirty%20Secrets%20of%20a%20Home%20Cook%22%2C%22pubDate%22%3A%222016-04-21T23%3A30%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Laurie%20Woolever%22%7D%5D%2C%22type%22%3A%22article%22%2C%22url%22%3A%22%2Fexpert-advice%2Fdirty-secrets-of-a-home-cook-article%22%2C%22photoData%22%3A%7B%22id%22%3A%2254b5b5bb2889f660285a7982%22%2C%22filename%22%3A%22EP_20140912_boone-3_6x4-lpr.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22Photo%20by%20Rhoda%20Boone%22%2C%22promoTitle%22%3A%22%22%2C%22title%22%3A%22raw%20cubed%20beef%20chuck%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%7D%2C%7B%22id%22%3A%22562a62dab3d63be14330b17c%22%2C%22dek%22%3A%22All%20of%20the%20flavor%2C%20none%20of%20the%20prep%20work.%22%2C%22hed%22%3A%22Frozen%20Vegetables%20Are%20a%20Wok's%20Best%20Friend%22%2C%22pubDate%22%3A%222015-10-23T19%3A30%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Matt%20Rodbard%22%7D%5D%2C%22type%22%3A%22article%22%2C%22url%22%3A%22%2Fexpert-advice%2Fwhy-the-freezer-aisle-is-a-woks-best-friend-article%22%2C%22photoData%22%3A%7B%22id%22%3A%225570c1b281ac1e5023671e80%22%2C%22filename%22%3A%22EP-04142015-wok-7-6x4-CP.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22Photo%20by%20Chelsea%20Kyle%22%2C%22promoTitle%22%3A%22northern%20style%20carbon-steel%20round-bottomed%20wok%22%2C%22title%22%3A%22northern%20style%20carbon-steel%20round-bottomed%20wok%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%7D%2C%7B%22id%22%3A%2254a422f56529d92b2c0096e8%22%2C%22dek%22%3A%22When%20we%20visited%20Kyoto%2C%20a%20few%20hours'%20ride%20from%20Tokyo%20on%20the%20famous%20Bullet%20train%2C%20we%20found%20a%20little%20restaurant%20in%20the%20heart%20of%20town%20that%20won%20us%20over%20with%20the%20names%20of%20dishes%20listed%20on%20the%20menu%3A%20Firecracker%20Tofu%2C%20Pickled%20Mixed%20Radish%20Salad%2C%20and%20the%20mysterious%20sounding%20Okonomiyaki.%20The%20chefs%20were%20clearly%20having%20fun%20at%20this%20place%2C%20and%20we%20were%20blown%20away%20by%20the%20depth%20of%20flavor%20they%20achieved%20with%20such%20simple%20preparations.%20We%20threw%20back%20some%20sake%20and%20tore%20through%20plate%20after%20plate%20of%20food.%20This%20salad%20is%20inspired%20by%20that%20meal%2C%20featuring%20quirky%20sea%20beans%20(a%20seaweed-like%20swamp%2Fbeach%20vegetable)%20and%20the%20haunting%20flavor%20of%20shiso%20(Japanese%20mint).%20You%20can%20find%20fresh%20sea%20beans%20at%20a%20gourmet%20market.%20If%20they're%20not%20available%2C%20substitute%20pencil-thin%20asparagus.%20Look%20for%20shiso%20in%20Asian%20markets%2C%20but%20substitute%20fresh%20cilantro%20if%20you%20can't%20find%20it.%22%2C%22hed%22%3A%22Sea%20Bean%20Salad%20with%20Daikon%20and%20Cucumber%22%2C%22pubDate%22%3A%222013-10-14T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Rich%20Landau%20%22%7D%2C%7B%22name%22%3A%22%20Kate%20Jacoby%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fsea-bean-salad-with-daikon-and-cucumber-51199610%22%2C%22photoData%22%3A%7B%22id%22%3A%2254ad4bf76529d92b2c043930%22%2C%22filename%22%3A%2251199610_sea-bean-salad-daikon_1x1.jpg%22%2C%22caption%22%3A%22Sea%20Bean%20Salad%20with%20Daikon%20and%20Cucumber%22%2C%22credit%22%3A%22Michael%20Spain-Smith%22%2C%22promoTitle%22%3A%22Sea%20Bean%20Salad%20with%20Daikon%20and%20Cucumber%22%2C%22title%22%3A%22Sea%20Bean%20Salad%20with%20Daikon%20and%20Cucumber%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A0%2C%22ingredients%22%3A%5B%222%20large%20cucumbers%2C%20peeled%20(about%201%201%2F2%20pounds)%22%2C%221%20large%20daikon%20radish%2C%20peeled%22%2C%224%20scallions%22%2C%221%2F2%20pound%20sea%20beans%2C%20ends%20trimmed%22%2C%223%20tablespoons%20rice%20wine%20vinegar%22%2C%222%20tablespoons%20canola%20oil%22%2C%222%20tablespoons%20toasted%20sesame%20oil%22%2C%222%20tablespoons%20tamari%22%2C%222%20teaspoons%20black%20sesame%20seeds%22%2C%222%20teaspoons%20white%20sesame%20seeds%22%2C%221%20teaspoon%20sugar%22%2C%222%20fresh%20shiso%20leaves%2C%20finely%20chopped%22%5D%2C%22prepSteps%22%3A%5B%221.%20Cut%20the%20flesh%20of%20the%20cucumber%20into%20very%20thin%20noodle-like%20strips.%20Avoid%20the%20seeds%20by%20not%20cutting%20the%20very%20center%20of%20the%20cucumber.%20A%20mandoline%20works%20best%2C%20or%20use%20a%20knife%20and%20slice%20really%20thin.%22%2C%222.%20Cut%20the%20daikon%20into%20the%20same%20thin%20noodle-like%20strips.%20Here%20there%20are%20no%20seeds%2C%20so%20you%20can%20cut%20through%20the%20entire%20vegetable.%22%2C%223.%20Trim%20the%20roots%20of%20the%20scallions%2C%20then%20slice%20them%20into%20fine%20rings.%20Start%20at%20the%20white%20bottom%20and%20use%20about%20three-quarters%20of%20each%20scallion%2C%20until%20the%20leaves%20become%20much%20darker%20green%20and%20thicker.%22%2C%224.%20Combine%20the%20remaining%20ingredients%20in%20a%20medium%20bowl%20to%20ensure%20they%20are%20well%20mixed%2C%20then%20add%20all%20of%20the%20vegetables.%20Toss%20to%20combine%2C%20then%20cover%20and%20place%20in%20the%20refrigerator%20to%20marinate%20for%20at%20least%2030%20minutes%2C%20but%20no%20longer%20than%2024%20hours%20or%20they%20will%20get%20mushy.%20Serve%20chilled.%22%5D%2C%22reviewsCount%22%3A0%2C%22willMakeAgainPct%22%3A0%7D%2C%7B%22id%22%3A%2254a422d96529d92b2c009609%22%2C%22dek%22%3A%22Vegan%20(when%20made%20with%20agave%20nectar%20or%20sugar)%5CnThis%20trick%20will%20alter%20and%20augment%20your%20cooking%3A%20Pour%20boiling%20water%20over%20sliced%20or%20diced%20red%20onions%2C%20then%20transfer%20them%20to%20a%20solution%20of%20vinegar%2C%20sweetener%2C%20and%20salt.%20The%20onions%20will%20brighten%20into%20a%20gaudy%20shade%20of%20purplish-pink%20and%20will%20keep%20indefinitely%2C%20mysteriously%20retaining%20their%20bright%20color%20and%20crisp%20texture.%20rather%20than%20slice%2C%20the%20onions%2C%20if%20they%20are%20headed%20for%20one%20of%20the%20cold%20soups.)%5CnYou%20can%20vary%20the%20cut%20of%20the%20onions%E2%80%94and%20also%20the%20amounts%20of%20sweet%20and%20salt.%20Use%20as%20a%20dramatically%20colorful%20and%20refreshing%20tiara%20atop%20dinner%20plates%2C%20open-faced%20sandwiches%2C%20salads%2C%20cheeses%2C%20grilled%20tofu%2C%20or%20fish%E2%80%94anything%20savory.%20I%20use%20these%20often%20as%20an%20ingredient%20in%20cold%20soups%20and%20saladitas.%20(Mince%2C%20rather%20than%20slice%2C%20the%20onions%2C%20if%20they%20are%20headed%20for%20one%20of%20the%20cold%20soups.)%5Cn%E2%80%A2%20Use%20a%20very%20sharp%20knife%20or%20a%20food%20processor%20with%20a%20thin%20slicing%20attachment%20to%20cut%20the%20onions%20most%20easily.%22%2C%22hed%22%3A%22Pickled%20Red%20Onions%22%2C%22pubDate%22%3A%222013-10-02T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Mollie%20Katzen%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fpickled-red-onions-51196620%22%2C%22photoData%22%3A%7B%22id%22%3A%2257a8ae32b10b4fb03f234f38%22%2C%22filename%22%3A%22pickled-red-onions-2.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22%22%2C%22promoTitle%22%3A%22%22%2C%22title%22%3A%22pickled-red-onions-2.jpg%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A3.14%2C%22ingredients%22%3A%5B%221%20large%20red%20onion%20(3%2F4%20pound)%22%2C%223%20tablespoons%20vinegar%20(cider%2C%20red%20or%20white%20wine%2C%20or%20balsamic)%22%2C%221-2%20teaspoons%20agave%20nectar%2C%20light-colored%20honey%2C%20or%20sugar%22%2C%221%2F4%20teaspoon%20salt%22%5D%2C%22prepSteps%22%3A%5B%221.%20Put%20on%20a%20kettle%20of%20water%20to%20boil.%20Cut%20the%20onion%20into%20very%20thin%20slices%20or%20a%20mince%20and%20place%20it%20in%20a%20colander%20in%20the%20sink.%22%2C%222.%20In%20a%20bowl%20large%20enough%20to%20comfortably%20fit%20all%20the%20onion%2C%20combine%20the%20vinegar%2C%20sweetener%2C%20and%20salt%20and%20whisk%20until%20blended.%22%2C%223.%20Pour%20the%20boiling%20water%20over%20the%20onion%20and%20shake%20to%20drain.%20(It's%20fine%20if%20a%20little%20water%20still%20clings.)%22%2C%224.%20Add%20the%20onion%20to%20the%20vinegar%20solution%20and%20stir%20to%20coat.%20Let%20it%20sit%20for%20at%20least%20an%20hour%20or%20up%20to%20several%20days%2C%20covered%20and%20refrigerated%2C%20occasionally%20stirring%20and%2For%20shaking%20to%20allow%20maximum%20exposure%20to%20the%20liquid.%20Store%20in%20a%20jar%20with%20a%20tight-fitting%20lid%20in%20the%20refrigerator.%22%2C%22For%20beautiful%2C%20exotic%20pickled%20fruit%2C%20add%20fresh%20or%20frozen%20cherries%2C%20blueberries%2C%20or%20raspberries%E2%80%94or%20some%20small%20watermelon%20chunks%E2%80%94to%20the%20onion%20after%20the%20first%20hour%20of%20sitting%20time%20*%20Add%20any%20of%20the%20following%20to%20the%20pickle%20mixture%3A%20Raw%20broccoli%20stems%2C%20peeled%20and%20cut%20into%20slender%20matchsticks%20*%20Raw%20fennel%2C%20cut%20into%20thin%20slices%20*%20Lightly%20steamed%20carrot%20slices%20*%20Lightly%20steamed%20cauliflower%2C%20cut%20into%201-inch%20florets%22%5D%2C%22reviewsCount%22%3A5%2C%22willMakeAgainPct%22%3A60%7D%2C%7B%22id%22%3A%2254a4216a19925f464b3785c7%22%2C%22dek%22%3A%22I've%20been%20doing%20the%20previous%20marinades%20forever.%20This%20new%20one%20is%20first%20cousin%20to%20a%20good%20barbecued%20tofu%3A%20piquant%2C%20sweet-hot-rich%2C%20and%20scintillatingly%20tasty.%20The%20tofu%20is%20baked%20in%20the%20marinade%2Fsauce%2C%20which%20cooks%20down%20and%20coats%20it%2C%20caramelizing%20them.%20You'll%20probably%20have%20to%20soak%20the%20baking%20dish%20overnight%20before%20washing%20it%2C%20but%20it's%20worth%20it.%20Vary%20this%20using%20fruit%20juice%20concentrate%20instead%20of%20honey%20or%20sugar%2C%20and%20adding%20extra%20ginger%2C%20orange%20zest%2C%20or%20both.%20For%20an%20incendiary%20smokiness%2C%20add%20chipotle%20in%20adobo.%22%2C%22hed%22%3A%22New%20Wave-New%20Fave%20Baked%20Tofu%20or%20Tempeh%22%2C%22pubDate%22%3A%222012-02-10T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Crescent%20Dragonwagon%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fnew-wave-new-fave-baked-tofu-or-tempeh-394509%22%2C%22photoData%22%3A%7B%22id%22%3A%225a0ddb046e013d11dde39630%22%2C%22filename%22%3A%22no-recipe-card-green-15112017.jpg%22%2C%22caption%22%3A%22No%20Recipe%20Card-%20GREEN%22%2C%22credit%22%3A%22Photo%20by%20Chelsea%20Kyle%22%2C%22colors%22%3A%7B%22average%22%3A%22%23000000%22%7D%2C%22type%22%3A%22photo%22%7D%2C%22aggregateRating%22%3A3%2C%22ingredients%22%3A%5B%221%2F3%20cup%20natural%2C%20unhydrogenated%20peanut%20butter%22%2C%221%2F3%20cup%20tamari%20or%20shoyu%20soy%20sauce%22%2C%221%2F3%20cup%20honey%2C%20light%20brown%20sugar%2C%20maple%20syrup%2C%20or%20thawed%2C%20undiluted%20frozen%20apple%20or%20pineapple%20juice%20concentrate%22%2C%221%2F4%20cup%20apple%20cider%20vinegar%22%2C%224%20to%206%20cloves%20garlic%2C%20quartered%20lengthwise%22%2C%22About%201%20tablespoon%20chopped%20fresh%20ginger%20(optional)%22%2C%221%20to%202%20tablespoons%20tomato%20paste%20or%20ketchup%22%2C%221%20canned%20chipotle%20pepper%20in%20adobo%20sauce%2C%201%2F2%20teaspoon%20cayenne%2C%20or%201%20fresh%20serrano%20or%20jalape%C3%B1o%20pepper%2C%20de-stemmed%22%2C%22Juice%20and%20grated%20zest%20of%201%20orange%20(optional%2C%20but%20good)%22%2C%2212%20to%2014%20ounces%20drained%2C%20sliced%20traditional%20water-packed%20firm%20or%20extra-firm%20tofu%20or%20tempeh%22%2C%22Vegetable%20oil%20cooking%20spray%22%5D%2C%22prepSteps%22%3A%5B%221.%20Combine%20the%20peanut%20butter%2C%20tamari%2C%20honey%2C%20apple%20cider%20vinegar%2C%20garlic%2C%20ginger%2C%20tomato%20paste%2C%20chipotle%2C%20and%20orange%20juice%20and%20zest%20in%20a%20food%20processor%20and%20buzz%20until%20the%20ginger%20is%20finely%20chopped.%22%2C%222.%20To%20use%20the%20marinade%2C%20place%20the%20tofu%20in%20a%20nonreactive%20bowl%20or%20zip-top%20bag%20and%20pour%20or%20spoon%20this%20luscious%20mixture%20over%20it.%20Refrigerate%20the%20tofu%2C%20covered%2C%20overnight.%22%2C%223.%20The%20next%20day%2C%20preheat%20the%20oven%20to%20375%C2%B0F%20and%20generously%20spray%20a%20nonreactive%20baking%20dish%20with%20oil%20(I%20use%20an%208%20or%209%20by%2012-inch%20deep%20glass%20baking%20dish).%22%2C%224.%20Place%20the%20tofu%20and%20its%20marinade%20in%20the%20baking%20dish%2C%20spreading%20the%20marinade%20as%20needed%20so%20both%20sides%20of%20the%20tofu%20slices%20get%20a%20good%20smear%20of%20it.%20Bake%2C%20turning%20once%2C%20until%20fragrant%2C%20firmed%20up%2C%20and%20golden%20to%20deep%20brown%20in%20spots%20with%20the%20marinade%20considerably%20thickened%2C%20about%2030%20minutes.%22%5D%2C%22reviewsCount%22%3A1%2C%22willMakeAgainPct%22%3A100%7D%2C%7B%22id%22%3A%2254a427be6529d92b2c00cd4c%22%2C%22dek%22%3A%22Wheat%20Free%5CnNo%20need%20to%20worry%20if%20your%20local%20market%20doesn't%20carry%20egg-free%20mayo.%20Just%20whip%20up%20some%20of%20your%20own.%20This%20recipe%20works%20very%20well%20as%20a%20sandwich%20spread%20or%20in%20any%20mayonnaise-based%20dressing.%20As%20long%20as%20you%20use%20wheat-free%20vinegar%2C%20this%20mayo%20is%20indeed%20wheat-free.%22%2C%22hed%22%3A%22Vegan%20Mayonnaise%22%2C%22pubDate%22%3A%222011-06-23T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Joni%20Marie%20Newman%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fvegan-mayonnaise-366490%22%2C%22photoData%22%3A%7B%22id%22%3A%2254b2afd611c5d6af478b2759%22%2C%22filename%22%3A%22366490_vegan-mayonnaise_1x1.jpg%22%2C%22caption%22%3A%22Vegan%20Mayonnaise%22%2C%22credit%22%3A%22Rockport%20Publishers%22%2C%22promoTitle%22%3A%22Vegan%20Mayonnaise%22%2C%22title%22%3A%22Vegan%20Mayonnaise%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A1%2C%22ingredients%22%3A%5B%227%20ounces%20(195%20g)%20extra-firm%20tofu%2C%20drained%20and%20pressed%22%2C%221%2F4%20cup%20(35%20g)%20raw%20cashews%2C%20ground%20into%20a%20very%20fine%20powder%22%2C%221%20tablespoon%20(15%20ml)%20lemon%20juice%22%2C%221%20tablespoon%20(12%20g)%20raw%20sugar%20or%20(21%20g)%20agave%20nectar%22%2C%221%201%2F2%20teaspoons%20brown%20or%20Dijon%20mustard%22%2C%221%20teaspoon%20apple%20cider%20or%20rice%20wine%20vinegar%22%2C%221%2F2%20teaspoon%20sea%20salt%22%2C%226%20tablespoons%20(90%20ml)%20canola%20oil%22%5D%2C%22prepSteps%22%3A%5B%22Place%20the%20tofu%2C%20cashews%2C%20lemon%20juice%2C%20sugar%2C%20mustard%2C%20vinegar%2C%20and%20salt%20in%20a%20blender%20or%20food%20processor%20and%20process%20until%20smooth.%22%2C%22Slowly%20drizzle%20in%20the%20oil%20and%20pulse%20until%20you%20get%20the%20consistency%20that%20you%20like.%22%2C%22Store%20in%20an%20airtight%20container%20in%20the%20refrigerator%20for%20up%20to%202%20weeks.%22%5D%2C%22reviewsCount%22%3A3%2C%22willMakeAgainPct%22%3A33%7D%2C%7B%22id%22%3A%2254a42a5219925f464b37ea8a%22%2C%22dek%22%3A%22A%20staple%20of%20classic%20Japanese%20cooking%2C%20teriyaki%20is%20wonderful%20with%20not%20only%20seafood%20but%20also%20poultry%2C%20beef%2C%20vegetables%2C%20and%20tofu.%20Often%2C%20however%2C%20this%20versatile%20sauce%20can%20be%20quite%20sweet.%20My%20version%20uses%20fresh%20orange%20juice%2C%20which%20adds%20just%20a%20touch%20of%20natural%20sweetness%20as%20well%20as%20some%20acidity%20to%20temper%20the%20sweet%20mirin.%20Pouring%20some%20of%20the%20teriyaki%20sauce%20into%20the%20hot%20pan%20with%20the%20fish%20further%20reduces%20it%20so%20the%20sauce%20really%20coats%20the%20fish%20with%20a%20deep%2C%20caramel%20glaze%20that%20enhances%20the%20delectable%20moist%2C%20buttery%2C%20and%20tender%20qualities%20of%20black%20cod%20perfectly.%20Other%20good%20fish%20for%20this%20dish%20are%20Alaskan%20cod%2C%20true%20cod%2C%20sablefish%2C%20or%20wild%20salmon.%20Searing%20each%20side%20of%20the%20sticky%20rice%20cake%20gives%20a%20nutty%20flavor%20and%20crisp%20texture.%20I%20also%20like%20to%20serve%20these%20rice%20cakes%20with%20vegetable%20stir-fries%20in%20place%20of%20plain%20rice.%20If%20you%20have%20a%20rice%20cooker%2C%20use%20it%20to%20prepare%20the%20rice%20according%20to%20the%20manufacturer's%20directions.%20If%20not%2C%20follow%20the%20instructions%20in%20the%20recipe%20to%20prepare%20it%20in%20a%20saucepan.%22%2C%22hed%22%3A%22Teriyaki%20Black%20Cod%20with%20Sticky%20Rice%20Cakes%20and%20Seared%20Baby%20Bok%20Choy%22%2C%22pubDate%22%3A%222011-03-11T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Dean%20Rucker%22%7D%2C%7B%22name%22%3A%22%20Marah%20Stets%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fteriyaki-black-cod-with-sticky-rice-cakes-and-seared-baby-bok-choy-363330%22%2C%22photoData%22%3A%7B%22id%22%3A%2256098f2d62fa7a9917c1d93e%22%2C%22filename%22%3A%22363330_hires.jpg%22%2C%22caption%22%3A%22Teriyaki%20Black%20Cod%20with%20Sticky%20Rice%20Cakes%20and%20Seared%20Baby%20Bok%20Choy%22%2C%22credit%22%3A%22Cookbook%20cover%20image%20courtesy%20of%20Random%20House%22%2C%22promoTitle%22%3A%22Teriyaki%20Black%20Cod%20with%20Sticky%20Rice%20Cakes%20and%20Seared%20Baby%20Bok%20Choy%22%2C%22title%22%3A%22Teriyaki%20Black%20Cod%20with%20Sticky%20Rice%20Cakes%20and%20Seared%20Baby%20Bok%20Choy%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A3.25%2C%22ingredients%22%3A%5B%229%20baby%20bok%20choy%2C%20halved%20lengthwise%22%2C%223%2F4%20cup%20sushi%20rice%22%2C%22Grapeseed%20or%20canola%20oil%20spray%22%2C%222%20tablespoons%20sliced%20scallions%20(white%20and%20green%20parts)%22%2C%221%20teaspoon%20minced%20garlic%22%2C%221%20tablespoon%20minced%20peeled%20fresh%20ginger%22%2C%221%20tablespoon%20unseasoned%20rice%20vinegar%22%2C%221%201%2F2%20teaspoons%20mirin%22%2C%22Pinch%20of%20kosher%20salt%22%2C%22Pinch%20of%20freshly%20ground%20black%20pepper%22%2C%221%2F2%20cup%20low-sodium%20soy%20sauce%22%2C%223%2F4%20cup%20fresh%20orange%20juice%20(from%203%20oranges)%22%2C%221%2F4%20cup%20mirin%22%2C%221%20teaspoon%20minced%20peeled%20fresh%20ginger%22%2C%221%2F2%20teaspoon%20cornstarch%22%2C%226%20(4-ounce)%20skinless%20black%20cod%20fillets%2C%20each%201%20inch%20thick%22%2C%221%2F4%20teaspoon%20freshly%20ground%20black%20pepper%22%2C%22Grapeseed%20or%20canola%20oil%20spray%22%2C%221%2F2%20cup%20thinly%20sliced%20scallions%20(white%20and%20light%20green%20parts)%2C%20for%20serving%22%2C%221%20tablespoon%20sesame%20seeds%2C%20toasted%2C%20for%20serving%22%5D%2C%22prepSteps%22%3A%5B%22Bring%20a%20large%20pot%20of%20water%20to%20a%20rapid%20boil.%20Prepare%20a%20bowl%20of%20ice%20water.%20Add%20the%20bok%20choy%20to%20the%20boiling%20water%20and%20cook%20for%2030%20seconds.%20Drain%20the%20bok%20choy%20and%20immediately%20transfer%20it%20to%20the%20ice%20water%20for%202%20minutes%20to%20cool.%20Drain%20the%20bok%20choy%20and%20set%20aside%20on%20a%20clean%20kitchen%20towel%20to%20soak%20up%20excess%20moisture.%22%2C%22Prepare%20the%20sticky%20rice%20cakes.%20Put%20the%20rice%20in%20a%20large%20bowl%20and%20cover%20with%20cold%20water.%20Use%20your%20hand%20to%20swish%20the%20rice%20around%20a%20few%20times.%20Drain%20and%20repeat%20until%20the%20water%20in%20the%20bowl%20is%20clear%3B%20you%20may%20need%20to%20rinse%20it%20several%20times.%22%2C%22Put%20the%20rice%20in%20a%20small%2C%20heavy-bottomed%20saucepan%20and%20add%20water%20to%20cover%20by%201%20inch.%20Cover%20the%20pan%3B%20for%20best%20results%2C%20do%20not%20uncover%20the%20pan%20at%20any%20time%20during%20cooking.%20Bring%20to%20a%20boil%20over%20medium-high%20heat%2C%204%20to%205%20minutes%3B%20you%20will%20be%20able%20to%20tell%20the%20water%20is%20boiling%20by%20the%20large%20amount%20of%20steam%20pouring%20out%20from%20under%20the%20lid.%20Reduce%20the%20heat%20to%20low%20and%20simmer%2C%20covered%2C%20for%2010%20minutes.%20Remove%20the%20pan%20from%20the%20heat%20and%20let%20stand%2C%20covered%2C%20for%2015%20minutes.%22%2C%22Spray%20a%20small%20saut%C3%A9%20pan%20with%20grapeseed%20oil%20and%20heat%20over%20medium%20heat.%20Add%20the%20scallions%2C%20garlic%2C%20and%20ginger%20and%20cook%2C%20stirring%2C%20until%20just%20softened%20and%20fragrant%2C%20about%2030%20seconds.%20Fold%20the%20scallion%20mixture%20into%20the%20warm%2C%20cooked%20rice%20along%20with%20the%20vinegar%2C%20mirin%2C%20salt%2C%20and%20pepper.%22%2C%22Line%20a%20platter%20or%20baking%20sheet%20with%20parchment%20paper%20sprayed%20with%20oil%20or%20with%20waxed%20paper.%20Have%20a%20separate%20bowl%20of%20water%20ready.%20Dip%20your%20hands%20into%20the%20water%20and%20scoop%20up%201%2F4%20cup%20rice.%20Form%20it%20into%20a%20tightly%20packed%20cake%20about%202%20inches%20thick%20and%20place%20the%20cake%20on%20the%20platter.%20Repeat%20with%20the%20remaining%20rice%20to%20form%20five%20more%20cakes.%20Set%20aside%20in%20the%20refrigerator.%22%2C%22Meanwhile%2C%20in%20a%20small%20saucepan%2C%20combine%20the%20soy%20sauce%2C%20orange%20juice%2C%20mirin%2C%20and%20ginger.%20Bring%20to%20a%20boil%20and%20reduce%20the%20heat%20to%20low.%20Simmer%20just%20until%20reduced%20by%20half%2C%2030%20to%2040%20minutes.%20In%20a%20small%20dish%2C%20mix%20the%20cornstarch%20and%201%20teaspoon%20water%20and%20stir%20this%20slurry%20into%20the%20simmering%20sauce.%20Simmer%2030%20seconds%20and%20remove%20the%20pan%20from%20the%20heat.%22%5D%2C%22reviewsCount%22%3A9%2C%22willMakeAgainPct%22%3A88%7D%2C%7B%22id%22%3A%2254a4276219925f464b37c5f1%22%2C%22dek%22%3A%22Combining%20bittersweet%20chocolate%20and%20cocoa%20powder%20intensifies%20the%20chocolaty%20essence%20of%20this%20cheesecake%20to%20the%20nth%20degree.%20Silken%20tofu%20brings%20a%20delicate%20creaminess%20to%20the%20filling%20while%20also%20taking%20the%20place%20of%20eggs%20by%20acting%20as%20a%20binding%20agent.%22%2C%22hed%22%3A%22Vegan%20Chocolate%20Cheesecake%22%2C%22pubDate%22%3A%222009-10-15T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22Gina%20Marie%20Miraglia%20Eriquez%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fvegan-chocolate-cheesecake-355990%22%2C%22photoData%22%3A%7B%22id%22%3A%225609a773e0acd286555dba9e%22%2C%22filename%22%3A%22355990_hires.jpg%22%2C%22caption%22%3A%22Vegan%20Chocolate%20Cheesecake%22%2C%22credit%22%3A%22Romulo%20Yanes%22%2C%22promoTitle%22%3A%22Vegan%20Chocolate%20Cheesecake%22%2C%22title%22%3A%22Vegan%20Chocolate%20Cheesecake%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A2.76%2C%22ingredients%22%3A%5B%221%201%2F4%20cups%20chocolate%20or%20regular%20graham%20cracker%20crumbs%20(from%20nine%205-by%202%201%2F2-inch%20graham%20crackers)%22%2C%223%20tablespoons%20sugar%22%2C%224%20tablespoons%20Earth%20Balance%20vegan%20buttery%20spread%2C%20melted%20and%20cooled%2C%20plus%20additional%20for%20greasing%20pan%22%2C%222%201%2F4%20cups%20sugar%2C%20divided%22%2C%221%2F3%20cup%20water%22%2C%228%20ounces%20bittersweet%20chocolate%20(no%20more%20than%2060%25%20cacao)%2C%20chopped%22%2C%222%20(1-pound%20packages%20silken%20tofu%2C%20drained%22%2C%221%2F4%20cup%20unsweetened%20cocoa%20powder%20(not%20Dutch-process)%22%2C%222%20(8-ounces)%20containers%20soy%20cream%20cheese%20at%20room%20temperature%22%2C%221%20teaspoon%20pure%20vanilla%20extract%22%2C%22Rounded%201%2F4%20teaspoon%20salt%22%2C%22Equipment%3A%20a%209-inch%20springform%20pan%22%5D%2C%22prepSteps%22%3A%5B%22Preheat%20oven%20to%20350%C2%B0F%20with%20racks%20in%20middle%20and%20lower%20third%20and%20put%20a%20baking%20sheet%20on%20lower%20rack.%20Flip%20bottom%20of%20springform%20pan%20so%20lip%20is%20facing%20down%2C%20then%20lock%20in%20place.%20Grease%20bottom%20and%20side%20of%20pan.%22%2C%22Stir%20together%20all%20crust%20ingredients%2C%20then%20press%20onto%20bottom%20and%201%20inch%20up%20side%20of%20pan.%20Bake%20until%20set%2C%2010%20to%2012%20minutes%2C%20then%20cool%20completely%2C%20about%2045%20minutes.%22%2C%22Heat%201%20cup%20sugar%20in%20a%201%201%2F2-to%202-quart%20heavy%20saucepan%20over%20medium%20heat%2C%20stirring%20with%20a%20fork%20to%20heat%20sugar%20evenly%2C%20until%20it%20starts%20to%20melt%2C%20then%20stop%20stirring%20and%20cook%2C%20swirling%20pan%20occasionally%20so%20sugar%20melts%20evenly%2C%20until%20it%20is%20dark%20amber.%20Remove%20from%20heat%20and%20carefully%20stir%20in%20water%20(mixture%20will%20bubble%20up%20and%20steam%20and%20caramel%20will%20harden)%2C%20then%20cook%20over%20medium-low%20heat%2C%20stirring%2C%20until%20caramel%20has%20dissolved.%20Remove%20from%20heat%20and%20whisk%20in%20chopped%20chocolate%20until%20smooth.%20Cool%20fudge%20sauce%20slightly.%22%2C%22Pur%C3%A9e%20tofu%20and%20cocoa%20in%20a%20food%20processor%20until%20smooth.%22%2C%22Beat%20soy%20cream%20cheese%20and%20remaining%201%201%2F4%20cups%20sugar%20with%20an%20electric%20mixer%20at%20medium-high%20speed%20until%20fluffy.%20At%20low%20speed%2C%20beat%20in%20tofu%20pur%C3%A9e%2C%20vanilla%2C%20salt%2C%20and%20fudge%20sauce%20until%20incorporated.%22%2C%22Pour%20filling%20into%20crust%20and%20bake%20on%20middle%20rack%20until%20top%20of%20cake%20is%20shiny%20but%20center%20is%20still%20slightly%20wobbly%20when%20pan%20is%20gently%20shaken%2C%20about%201%20hour.%20Turn%20oven%20off%20and%20leave%20cake%20in%20oven%201%20hour%20more.%22%2C%22Run%20a%20knife%20around%20top%20edge%20of%20cake%20to%20loosen%2C%20then%20cool%20completely%20in%20pan%20on%20rack%20(cake%20will%20continue%20to%20set%20as%20it%20cools).%20Chill%20cake%2C%20loosely%20covered%2C%20at%20least%206%20hours.%20Remove%20side%20of%20pan%20and%20transfer%20cake%20to%20a%20plate.%20Bring%20to%20room%20temperature%20before%20serving%20if%20desired.%22%5D%2C%22reviewsCount%22%3A15%2C%22willMakeAgainPct%22%3A58%7D%2C%7B%22id%22%3A%2254a42e8319925f464b381eab%22%2C%22dek%22%3A%22A%20bowl%20of%20these%20refreshing%20noodles%E2%80%94a%20riff%20on%20a%20Japanese%20classic%20that%20gets%20topped%20with%20silky%20tofu%E2%80%94is%20clean%20and%20light%2C%20yet%20still%20hearty%20enough%20to%20make%20a%20satisfying%20meal.%22%2C%22hed%22%3A%22Chilled%20Soba%20with%20Tofu%20and%20Sugar%20Snap%20Peas%22%2C%22pubDate%22%3A%222008-09-18T16%3A43%3A55.000Z%22%2C%22author%22%3A%5B%7B%22name%22%3A%22%20Lillian%20Chou%22%7D%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fchilled-soba-with-tofu-and-sugar-snap-peas-242834%22%2C%22photoData%22%3A%7B%22id%22%3A%22560d78b17b55306961bf3470%22%2C%22filename%22%3A%22242834_hires.jpg%22%2C%22caption%22%3A%22Chilled%20Soba%20with%20Tofu%20and%20Sugar%20Snap%20Peas%22%2C%22credit%22%3A%22Romulo%20Yanes%22%2C%22promoTitle%22%3A%22Chilled%20Soba%20with%20Tofu%20and%20Sugar%20Snap%20Peas%22%2C%22title%22%3A%22Chilled%20Soba%20with%20Tofu%20and%20Sugar%20Snap%20Peas%22%2C%22orientation%22%3A%22portrait%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A3.53%2C%22ingredients%22%3A%5B%221%20large%20dried%20shiitake%20mushroom%22%2C%222%201%2F2%20cups%20water%22%2C%228%20(1-inch)%20pieces%20kombu%20(dried%20kelp)%22%2C%221%2F2%20cup%20soy%20sauce%20(preferably%20Japanese)%22%2C%221%2F4%20cup%20mirin%20(Japanese%20sweet%20rice%20wine)%22%2C%223%20tablespoons%20ponzu%20sauce%20(not%20containing%20dashi)%22%2C%221%20tablespoon%20sugar%22%2C%221%20tablespoon%20Asian%20sesame%20oil%22%2C%221%20pound%20sugar%20snap%20peas%2C%20thinly%20sliced%22%2C%2210%20ounces%20baby%20spinach%20(16%20cups)%22%2C%221%20pound%20dried%20soba%20noodles%22%2C%221%20(14-%20to%2018-ounce)%20package%20silken%20tofu%22%2C%221%20cup%20thinly%20sliced%20scallions%2C%20divided%22%2C%222%20tablespoons%20thin%20matchsticks%20of%20peeled%20ginger%22%5D%2C%22prepSteps%22%3A%5B%22Simmer%20mushroom%20in%20water%20in%20a%20small%20saucepan%2C%20covered%2C%2015%20minutes.%20Add%20kombu%20and%20barely%20simmer%2C%20covered%2C%205%20minutes.%20Remove%20from%20heat%20and%20let%20stand%2C%20covered%2C%205%20minutes.%20Strain%20through%20a%20fine-mesh%20sieve%20into%20a%20large%20glass%20measure%2C%20pressing%20on%20and%20discarding%20solids.%20Return%202%20cups%20liquid%20(add%20water%20if%20necessary)%20to%20saucepan.%20Add%20soy%20sauce%2C%20mirin%2C%20ponzu%2C%20sugar%2C%20and%201%2F4%20teaspoon%20salt%20and%20bring%20to%20a%20boil%2C%20stirring%20until%20sugar%20has%20dissolved.%20Remove%20from%20heat.%20Stir%20in%20sesame%20oil%2C%20then%20cool%20in%20pan%20in%20a%20large%20ice%20bath.%22%2C%22Blanch%20sugar%20snaps%20in%20a%20large%20pot%20of%20unsalted%20boiling%20water%20until%20crisp-tender%2C%20about%202%20minutes.%20Transfer%20with%20a%20slotted%20spoon%20to%20a%20large%20colander%20set%20in%20ice%20bath%20to%20stop%20cooking.%20Lift%20colander%20to%20drain.%20Transfer%20sugar%20snaps%20to%20a%20bowl.%20Meanwhile%2C%20return%20water%20to%20a%20boil.%20Blanch%20spinach%20until%20just%20wilted%2C%20about%2030%20seconds%2C%20then%20cool%20and%20drain%20in%20same%20manner.%20Squeeze%20out%20excess%20water.%20Add%20to%20sugar%20snaps.%22%2C%22Return%20water%20to%20a%20boil.%22%2C%22Add%20noodles%20and%20cook%20according%20to%20package%20directions%2C%20stirring%20occasionally%2C%20until%20tender.%20Drain%20in%20colander%20and%20rinse%20with%20cold%20water.%20Cool%20in%20ice%20bath%20until%20very%20cold%20(add%20more%20ice%20to%20water%20as%20necessary).%20Drain%20well.%22%2C%22Carefully%20drain%20tofu%20and%20pat%20dry.%20Cut%20into%203%2F4-inch%20cubes.%22%2C%22Whisk%20sauce%2C%20then%20pour%201%201%2F2%20cups%20sauce%20into%20a%20large%20bowl.%20Add%20noodles%2C%20sugar%20snaps%2C%20spinach%2C%20and%20half%20of%20scallions%20and%20toss.%20Serve%20in%20shallow%20bowls%2C%20topped%20with%20tofu%2C%20remaining%20scallions%2C%20and%20ginger.%20Drizzle%20with%20some%20of%20remaining%20sauce%20and%20serve%20remainder%20on%20the%20side.%22%5D%2C%22reviewsCount%22%3A8%2C%22willMakeAgainPct%22%3A75%7D%2C%7B%22id%22%3A%2254a4332f6529d92b2c016045%22%2C%22dek%22%3A%22A%20Meyer%20lemon%20is%20a%20cross%20between%20a%20lemon%20and%20a%20mandarin%20orange.%20If%20you%20can't%20find%20any%2C%20substitute%20regular%20lemons.%20This%20pie's%20decadent%20cream%20filling%20is%20made%20from%20protein-rich%20tofu.%22%2C%22hed%22%3A%22Meyer%20Lemon%20Cream%20Pies%22%2C%22pubDate%22%3A%222007-07-16T04%3A09%3A02.000Z%22%2C%22author%22%3A%5B%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fmeyer-lemon-cream-pies-239225%22%2C%22photoData%22%3A%7B%22id%22%3A%2256f30156c98a9a676e4e6bce%22%2C%22filename%22%3A%22239225_hires.jpg%22%2C%22caption%22%3A%22%22%2C%22credit%22%3A%22Photo%20by%20Yunhee%20Kim%22%2C%22promoTitle%22%3A%22%22%2C%22title%22%3A%22Meyer%20Lemon%20Cream%20Pies%22%2C%22orientation%22%3A%22landscape%22%2C%22restrictCropping%22%3Afalse%7D%2C%22aggregateRating%22%3A2.5%2C%22ingredients%22%3A%5B%221%201%2F4%20cups%20graham-cracker%20crumbs%22%2C%222%20tablespoons%20sugar%22%2C%225%20tablespoons%20unsalted%20butter%2C%20melted%22%2C%222%20(12-ounce)%20containers%20firm%20silken%20tofu%20(such%20as%20Mori-Nu)%22%2C%22Grated%20zest%20and%20juice%20of%202%20Meyer%20lemons%22%2C%221%2F2%20cup%20confectioners'%20sugar%22%5D%2C%22prepSteps%22%3A%5B%221.%20Preheat%20oven%20to%20350%C2%B0F.%22%2C%222.%20In%20a%20medium%20bowl%2C%20mix%20together%20all%20the%20crust%20ingredients.%20Press%20the%20mixture%20into%20the%20bottom%20and%20sides%20of%20four%20tartlet%20molds%20or%204-ounce%20ramekins.%22%2C%223.%20Bake%20until%20golden%20brown%2C%208%20to%2010%20minutes.%20Remove%20and%20let%20cool%20completely.%22%2C%224.%20In%20a%20blender%2C%20combine%20all%20the%20filling%20ingredients%20until%20smooth%2C%20spoon%20the%20mixture%20into%20the%20crusts%2C%20and%20refrigerate%20for%20at%20least%201%20hour.%22%5D%2C%22reviewsCount%22%3A8%2C%22willMakeAgainPct%22%3A50%7D%2C%7B%22id%22%3A%2254a4729919925f464b399731%22%2C%22dek%22%3A%22%22%2C%22hed%22%3A%22Scallop%20and%20Corn%20Pot%20Stickers%22%2C%22pubDate%22%3A%222004-08-20T04%3A00%3A00.000Z%22%2C%22author%22%3A%5B%5D%2C%22type%22%3A%22recipe%22%2C%22url%22%3A%22%2Frecipes%2Ffood%2Fviews%2Fscallop-and-corn-pot-stickers-11846%22%2C%22photoData%22%3A%7B%22id%22%3A%225a0ddb06f110de5830af9a10%22%2C%22filename%22%3A%22no-recipe-card-red-15112017.jpg%22%2C%22caption%22%3A%22No%20Recipe%20card-%20RED%22%2C%22credit%22%3A%22Photo%20by%20Chelsea%20Kyle%22%2C%22colors%22%3A%7B%22average%22%3A%22%23000000%22%7D%2C%22type%22%3A%22photo%22%7D%2C%22aggregateRating%22%3A3.5%2C%22ingredients%22%3A%5B%221%2F2%20pound%20sea%20scallops%22%2C%221%2F4%20teaspoon%20salt%22%2C%221%2F4%20cup%20soft%20tofu%20(preferably%20silken)%22%2C%221%2F4%20cup%20cooked%20corn%22%2C%221%2F4%20cup%20minced%20red%20bell%20pepper%22%2C%223%20tablespoons%20minced%20scallion%22%2C%222%20tablespoons%20finely%20chopped%20fresh%20coriander%22%2C%22eighteen%203-to-4%20inch%20round%20won%20ton%20or%20dumpling%20or%20gyozo%20wrappers%2C%C2%A0thawed%20if%20frozen%22%2C%22cornstarch%20for%20dusting%20tray%22%2C%22Sesame%20Vinaigrette%22%5D%2C%22prepSteps%22%3A%5B%22Discard%20small%20tough%20muscle%20from%20side%20of%20each%20scallop%20and%20in%20a%20food%20processor%20pur%C3%A9e%20half%20scallops%20with%20salt.%20With%20motor%20running%20add%20tofu%20in%20a%20stream%20and%20blend%20until%20just%20combined.%22%2C%22Transfer%20scallop%20mousse%20to%20a%20small%20bowl.%20Chop%20fine%20remaining%20scallops%20and%20stir%20into%20mousse%20with%20corn%2C%20bell%20pepper%2C%20scallion%2C%20and%20coriander.%22%2C%22Put%20about%201%20tablespoon%20filling%20in%20center%20of%201%20wrapper%20and%20moisten%20edge%20of%20wrapper.%20Gather%20edge%20of%20wrapper%20up%20and%20around%20filling%2C%20pleating%20edge.%20Gently%20squeeze%20middle%20of%20pot%20sticker%20to%20form%20a%20waist%2C%20keeping%20filling%20level%20with%20top%20of%20wrapper.%20(Pot%20sticker%20will%20resemble%20a%20sack%20filled%20to%20top.)%22%2C%22Make%2017%20more%20pot%20stickers%20in%20same%20manner%20and%20arrange%20on%20a%20tray%20dusted%20lightly%20with%20cornstarch.%20Pot%20stickers%20may%20be%20made%20up%20to%20this%20point%201%20day%20ahead%20and%20chilled%2C%20covered%20with%20plastic%20wrap.%22%2C%22In%20a%20large%20non-stick%20skillet%20heat%20oil%20over%20moderately%20high%20heat%20until%20hot%20but%20not%20smoking%20and%20fry%20pot-sticker%20bottoms%20until%20golden%2C%20about%201%20minute.%20Add%20water%20and%20steam%20pot%20stickers%2C%20covered%2C%203%20to%204%20minutes%2C%20or%20until%20filling%20is%20springy%20to%20touch.%20Remove%20lid%20and%20cook%20pot%20stickers%20until%20liquid%20is%20evaporated%20and%20bottoms%20are%20recrisped.%22%2C%22Serve%20pot%20stickers%20with%20vinaigrette%20and%20garnish%20with%20coriander.%22%5D%2C%22reviewsCount%22%3A9%2C%22willMakeAgainPct%22%3A100%7D%5D%7D%7D%7D%2C%22options%22%3A%7B%22optimizePromiseCallback%22%3Afalse%7D%2C%22plugins%22%3A%7B%7D%7D%2C%22plugins%22%3A%7B%7D%7D";
  </script>
  <script async="" src="/static/js/dist/search__3.23.0.js">
  </script>
  <script>
   // Drop meta data about ads on page.
    window.cns = window.cns || {}; window.cns.pageContext = {"templateType":"search","channel":"search","server":"production","slug":"search","subChannel":"","keywords":{"tags":["search","tofu%252520chill","food","content"],"platform":"autopilot","copilotid":""}};
  </script>
  <script id="esi-1">
   var dl=(window.dataLayer||[])[0];window.CN_STACK_TEMP=(dl&&dl.site&&dl.site.appVersion==='multi-tenant')?'verso':'unknown';
  </script>
  <script id="cns-config-include">
   window.cns = window.cns || {}; window.cns.config = {
  "config": {
    "ad_unit": {
      "generate_path": "function (opts) { var category = opts.category; if (category.match(/^expert-advice/)) { category = \"expert-advice\"; } else if (category.match(/^recipes-menus/)) { category = \"recipes-menus\"; } else if (category.match(/^ingredients/)) { category = \"ingredients\"; } else if (category.match(/^holidays-events/)) { category = \"holidays-events\"; } else if (category.match(/^tags/)) { category = \"misc\"; } else if (category.match(/^about/)) { category = \"about\"; } var contentType = opts.contentType; if (contentType.match(/^undefined/) && category.match(/^about/)) { contentType = \"site-info\"; } return \"3379/conde.epi/\" + opts.position + \"/\" + category + \"/\" + contentType + \"/\" + opts.instance; }",
      "generate_legacy_path": "function(opts) { return \"3379/epi.\" + opts.suffix + \"/\" + opts.channel + (opts.subChannel && \"/\" + opts.subChannel) }",
      "map": {
        "content_type": {
          "article": [
            "article",
            "package",
            "recipe",
            "recipebox"
          ],
          "bundle": [
            "_default",
            "archive",
            "channel",
            "cookbook",
            "home",
            "menu",
            "tag_page"
          ],
          "contributor": [
            "contributor"
          ],
          "gallery": [
            "gallery_slideshow"
          ],
          "search": [
            "search"
          ],
          "site-info": []
        }
      }
    },
    "request_vp_range": {
      "_default": {
        "desktop": 800,
        "tablet": 800,
        "mobile": 400
      }
    },
    "network": 3379,
    "slot": {
      "__auid_one": "epi",
      "sets": {
        "_default": [
          "_out_of_page"
        ],
        "archive": [
          "_out_of_page",
          "banner_top",
          "pushdown",
          "box_top",
          "box_bottom",
          "epi_parallax"
        ],
        "article": [
          "_out_of_page",
          "banner_top",
          "pushdown",
          "box_top",
          "box_bottom",
          "epi_parallax",
          "recipe_riser",
          "sponsor_logo",
          "railBoxTabletAd1"
        ],
        "channel": [
          "_out_of_page",
          "banner_top",
          "pushdown",
          "box_top",
          "box_bottom",
          "banner_bottom",
          "epi_parallax",
          "nativeFeaturedItem"
        ],
        "contributor": [
          "_out_of_page",
          "banner_top",
          "box_top",
          "box_bottom"
        ],
        "cookbook": [
          "_out_of_page",
          "box_top"
        ],
        "gallery_slideshow": [
          "_out_of_page",
          "box_intro_slideshow",
          "interstitial_slideshow",
          "box_slideshow",
          "banner_top_slideshow",
          "listicle_divider"
        ],
        "home": [
          "_out_of_page",
          "banner_top",
          "box_top",
          "box_bottom",
          "banner_bottom",
          "epi_parallax",
          "nativeFeaturedItem"
        ],
        "menu": [
          "_out_of_page",
          "banner_top",
          "pushdown",
          "box_bottom",
          "recipe_riser",
          "epi_parallax"
        ],
        "newsletter": [],
        "package": [
          "_out_of_page",
          "banner_top",
          "pushdown",
          "box_top",
          "box_middle",
          "box_bottom",
          "banner_bottom",
          "recipe_riser",
          "epi_parallax",
          "railBoxTabletAd1"
        ],
        "recipe": [
          "_out_of_page",
          "banner_top",
          "pushdown",
          "box_top",
          "recipe_detail",
          "box_bottom",
          "epi_parallax",
          "recipe_riser",
          "railBoxTabletAd1"
        ],
        "recipebox": [
          "_out_of_page",
          "header",
          "box_top"
        ],
        "search": [
          "_out_of_page",
          "search_box_top",
          "search_box_middle",
          "search_box_bottom",
          "epi_parallax"
        ],
        "tag_page": [
          "_out_of_page",
          "banner_top",
          "pushdown",
          "box_top",
          "box_bottom",
          "epi_parallax",
          "nativeTagResult",
          "railBoxTabletAd1"
        ]
      },
      "types": {
        "_default": {
          "suffix": "dart",
          "insert_after_react_ready": true,
          "render": {
            "slot": {
              "top": "body"
            }
          }
        },
        "_out_of_page": {
          "_default": {
            "position": "interstitial",
            "refresh": false,
            "isOutOfPage": true,
            "can_be_hidden": true,
            "render": {
              "slot": {
                "top": ".ad__slot--out-of-page"
              }
            }
          }
        },
        "banner_bottom": {
          "_default": {
            "position": "footer",
            "sizes": {
              "desktop": [
                "728x90",
                "970x250",
                "970x90"
              ],
              "tablet": [
                "728x90",
                "970x250",
                "970x90"
              ],
              "mobile": false
            },
            "render": {
              "desktop": {
                "slot": {
                  "bottom": "aside.site-bottomBanner-ad-wrap"
                }
              },
              "tablet": {
                "slot": {
                  "bottom": "aside.site-bottomBanner-ad-wrap"
                }
              }
            },
            "request_vp_range": {
              "desktop": 400,
              "tablet": 400,
              "mobile": 300
            }
          }
        },
        "banner_top": {
          "_default": {
            "position": "hero",
            "static_refresh_size": true,
            "can_be_hidden": true,
            "sizes": {
              "desktop": [
                "728x90",
                "970x90",
                "970x250",
                "9x1",
                "1140x380",
                "9x3",
                "10x1"
              ],
              "tablet": [
                "728x90",
                "970x90",
                "970x250",
                "9x1",
                "1140x380",
                "9x3",
                "8x1"
              ],
              "mobile": [
                "300x50",
                "320x50",
                "300x150",
                "320x150",
                "9x1",
                "3x1"
              ]
            },
            "data": {
              "jivox-ad-id": "constellation-crown"
            },
            "render": {
              "slot": {
                "bottom": "aside.site-header-ad-wrap"
              }
            }
          },
          "home": {
            "sizes": {
              "desktop": [
                "728x90",
                "970x90",
                "970x250",
                "970x418",
                "970x66",
                "1140x380",
                "9x1",
                "9x3"
              ],
              "tablet": [
                "728x90",
                "970x90",
                "970x250",
                "970x418",
                "970x66",
                "1140x380",
                "9x1",
                "9x3"
              ],
              "mobile": [
                "300x50",
                "320x50",
                "300x150",
                "320x150",
                "9x1"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.site-pushdown-ad-wrap"
              }
            }
          }
        },
        "banner_top_slideshow": {
          "_default": {
            "position": "hero",
            "static_refresh_size": true,
            "can_be_hidden": true,
            "sizes": {
              "desktop": false,
              "tablet": [
                "728x90",
                "8x1"
              ],
              "mobile": [
                "300x50",
                "320x50",
                "300x150",
                "320x150",
                "9x1",
                "3x1"
              ]
            },
            "render": {
              "slot": {
                "bottom": ".bannerTopSlideshow-ad-wrap"
              }
            }
          }
        },
        "bottomBanner": {
          "_default": {
            "position": "footer",
            "sizes": {
              "desktop": [
                "728x90",
                "970x66",
                "970x418",
                "970x250",
                "970x90",
                "62x88",
                "88x32",
                "196x31",
                "1140x380",
                "900x300"
              ],
              "tablet": [
                "728x90",
                "970x66",
                "970x418",
                "970x250",
                "970x90",
                "62x88",
                "88x32",
                "196x31",
                "1140x380",
                "900x300"
              ],
              "mobile": false
            },
            "render": {
              "slot": {
                "bottom": "aside.site-bottomBanner-ad-wrap"
              }
            },
            "request_vp_range": {
              "desktop": 400,
              "tablet": 400,
              "mobile": 300
            }
          }
        },
        "box_bottom": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": [
                "300x250",
                "300x600"
              ],
              "tablet": [
                "300x250",
                "300x600"
              ],
              "mobile": false
            },
            "render": {
              "slot": {
                "bottom": "aside.box-bottom"
              }
            }
          },
          "channel": {
            "sizes": {
              "mobile": [
                "300x50",
                "320x50",
                "300x150",
                "320x150",
                "300x250"
              ]
            }
          },
          "contributor": {
            "sizes": {
              "desktop": [
                "-300x600"
              ],
              "tablet": [
                "-300x600"
              ],
              "mobile": [
                "300x250"
              ]
            },
            "render": {
              "slot": {
                "bottom": ".contributors2-1"
              }
            }
          },
          "menu": {
            "sizes": {
              "desktop": [
                "-300x600"
              ],
              "tablet": [
                "-300x600"
              ],
              "mobile": [
                "300x250",
                "320x50",
                "300x150",
                "320x150",
                "9x2"
              ]
            }
          }
        },
        "box_intro_slideshow": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": [
                "300x250",
                "300x600"
              ],
              "tablet": [
                "300x250",
                "300x600"
              ],
              "mobile": false
            },
            "render": {
              "slot": {
                "bottom": ".boxIntroSlideshow-ad-wrap"
              }
            }
          }
        },
        "box_middle": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": [
                "300x250",
                "300x600"
              ],
              "tablet": [
                "300x250",
                "300x600"
              ],
              "mobile": [
                "300x250"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.box-middle"
              }
            }
          }
        },
        "box_slideshow": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": [
                "300x250"
              ],
              "tablet": [
                "300x250"
              ],
              "mobile": [
                "300x50",
                "320x50",
                "300x150",
                "320x150",
                "300x250",
                "9x3"
              ]
            },
            "render": {
              "slot": {
                "bottom": ".boxSlideshow-ad-wrap"
              }
            }
          }
        },
        "box_top": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": [
                "300x250",
                "300x600"
              ],
              "tablet": [
                "300x250",
                "300x600"
              ],
              "mobile": [
                "300x50"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.box-top"
              }
            }
          },
          "article": {
            "sizes": {
              "mobile": [
                "320x50",
                "300x150",
                "320x150",
                "300x250"
              ]
            }
          },
          "channel": {
            "sizes": {
              "mobile": [
                "320x50",
                "300x150",
                "320x150",
                "300x250"
              ]
            }
          },
          "contributor": {
            "sizes": {
              "desktop": [
                "-300x600"
              ],
              "tablet": [
                "-300x600"
              ],
              "mobile": [
                "300x250",
                "-300x50"
              ]
            }
          },
          "cookbook": {
            "sizes": {
              "desktop": [
                "-300x600"
              ],
              "tablet": [
                "-300x600"
              ],
              "mobile": [
                "300x250"
              ]
            }
          },
          "home": {
            "sizes": {
              "mobile": [
                "320x50",
                "300x150",
                "320x150",
                "300x250"
              ]
            }
          },
          "menu": {
            "sizes": {
              "desktop": [
                "728x90",
                "970x250"
              ],
              "tablet": [
                "728x90",
                "970x250"
              ],
              "mobile": [
                "320x50",
                "300x150",
                "320x150",
                "300x250"
              ]
            }
          },
          "package": {
            "sizes": {
              "mobile": [
                "320x50",
                "300x150",
                "320x150",
                "300x250"
              ]
            }
          },
          "recipe": {
            "sizes": {
              "mobile": [
                "320x50",
                "300x150",
                "320x150",
                "300x250"
              ]
            }
          },
          "tag_page": {
            "sizes": {
              "mobile": [
                "320x50",
                "300x150",
                "320x150",
                "300x250"
              ]
            }
          }
        },
        "search_box_top": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": [
                "300x250",
                "2x2"
              ],
              "tablet": [
                "300x250",
                "2x2"
              ],
              "mobile": [
                "300x250",
                "2x2"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.search_box_top"
              }
            }
          }
        },
        "search_box_middle": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": [
                "300x250",
                "2x2"
              ],
              "tablet": [
                "300x250",
                "2x2"
              ],
              "mobile": [
                "300x250",
                "2x2"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.search_box_middle"
              }
            }
          }
        },
        "search_box_bottom": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": [
                "300x250",
                "2x2"
              ],
              "tablet": [
                "300x250",
                "2x2"
              ],
              "mobile": [
                "300x250",
                "2x2"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.search_box_bottom"
              }
            }
          }
        },
        "epi_parallax": {
          "_default": {
            "position": "mid-content",
            "static_refresh_size": true,
            "sizes": {
              "desktop": [
                "9x2"
              ],
              "tablet": [
                "9x2"
              ],
              "mobile": [
                "9x2",
                "9x3"
              ]
            },
            "render": {
              "desktop": {
                "slot": {
                  "bottom": "aside.parallax-ad-wrap"
                }
              },
              "tablet": {
                "slot": {
                  "bottom": "aside.parallax-ad-wrap"
                }
              },
              "mobile": {
                "slot": {
                  "bottom": "aside.parallax-ad-wrap"
                }
              }
            }
          },
          "home": {
            "render": {
              "desktop": {
                "slot": {
                  "bottom": "aside.parallax-ad-wrap"
                }
              },
              "tablet": {
                "slot": {
                  "bottom": "aside.parallax-ad-wrap"
                }
              },
              "mobile": {
                "slot": {
                  "bottom": "aside.parallax-mobile-ad-wrap"
                }
              }
            }
          }
        },
        "featuredItems2_CHANNEL": {
          "_default": {
            "position": "sponsor",
            "should_use_legacy_path": true,
            "sizes": {
              "desktop": false,
              "tablet": false,
              "mobile": [
                "300x250"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.mobile-featured-items-ad.featuredItems2"
              }
            }
          }
        },
        "footer": {
          "_default": {
            "position": "footer",
            "sizes": {
              "desktop": [
                "728x90",
                "1600x400",
                "970x250",
                "970x90",
                "9x1",
                "9x2"
              ],
              "tablet": [
                "728x90",
                "970x250",
                "970x90",
                "9x1",
                "9x2"
              ],
              "mobile": [
                "300x50",
                "320x50",
                "9x1",
                "9x2"
              ]
            },
            "render": {
              "slot": {
                "before": "footer"
              }
            },
            "request_vp_range": {
              "desktop": 400,
              "tablet": 400,
              "mobile": 300
            }
          }
        },
        "header": {
          "_default": {
            "position": "hero",
            "static_refresh_size": true,
            "can_be_hidden": true,
            "sizes": {
              "desktop": [
                "728x90",
                "970x250",
                "970x90",
                "9x1",
                "9x3",
                "10x1"
              ],
              "tablet": [
                "728x90",
                "970x90",
                "9x1",
                "9x3",
                "8x1"
              ],
              "mobile": [
                "300x50",
                "320x50",
                "300x150",
                "320x150",
                "9x1",
                "9x3",
                "3x1"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.site-header-ad-wrap"
              }
            }
          }
        },
        "inline_banner": {
          "_default": {
            "position": "mid-content",
            "static_refresh_size": true,
            "sizes": {
              "desktop": [
                "728x90",
                "970x250",
                "970x90"
              ],
              "tablet": [
                "728x90",
                "970x90"
              ],
              "mobile": false
            }
          }
        },
        "inline_box": {
          "_default": {
            "position": "mid-content",
            "static_refresh_size": true,
            "sizes": {
              "desktop": false,
              "tablet": [
                "300x250",
                "320x50",
                "300x50"
              ],
              "mobile": [
                "300x250",
                "320x50",
                "300x50"
              ]
            }
          }
        },
        "interstitial_slideshow": {
          "_default": {
            "position": "mid-gallery",
            "static_refresh_size": true,
            "sizes": {
              "desktop": [
                "300x250",
                "300x600",
                "9x5"
              ],
              "tablet": [
                "300x250",
                "300x600",
                "9x5"
              ],
              "mobile": [
                "300x250",
                "300x600",
                "9x5"
              ]
            },
            "render": {
              "slot": {
                "bottom": ".interstitialSlideshow-ad-wrap"
              }
            }
          }
        },
        "listicle_divider": {
          "_default": {
            "position": "mid-content",
            "static_refresh_size": true,
            "sizes": {
              "desktop": [
                "728x90"
              ],
              "tablet": [
                "728x90"
              ],
              "mobile": [
                "300x50",
                "320x50",
                "300x150",
                "320x150"
              ]
            },
            "render": {
              "slot": {
                "after": {
                  "every": 10,
                  "el": ".landscape-slide",
                  "when": "function condition() {\n                    return true;\n                  }",
                  "in": {
                    "el": "[data-presentation=\"listicle\"]",
                    "when": "function condition() {\n                      return true;\n                    }"
                  }
                }
              }
            }
          }
        },
        "mobileBanner": {
          "_default": {
            "position": "hero",
            "static_refresh_size": true,
            "can_be_hidden": true,
            "sizes": {
              "desktop": false,
              "tablet": false,
              "mobile": [
                "300x50",
                "320x50",
                "300x150",
                "320x150",
                "9x1",
                "3x1"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.mobileBanner-ad-wrap"
              }
            }
          }
        },
        "nativeFeaturedItem": {
          "_default": {
            "position": "sponsor",
            "should_use_legacy_path": true,
            "refresh": false,
            "can_be_hidden": true,
            "sizes": {
              "desktop": [
                "348x412"
              ],
              "tablet": [
                "348x412"
              ],
              "mobile": [
                "348x412"
              ]
            },
            "render": {
              "slot": {
                "before": ".featured-items [class$=\"-featured-item\"]:nth-of-type(3)"
              }
            }
          }
        },
        "nativeTagResult": {
          "_default": {
            "position": "sponsor",
            "should_use_legacy_path": true,
            "refresh": false,
            "can_be_hidden": true,
            "sizes": {
              "desktop": [
                "684x146"
              ],
              "tablet": [
                "684x146"
              ],
              "mobile": [
                "684x146"
              ]
            },
            "render": {
              "slot": {
                "before": ".tag-items [class$=\"-tag-item\"]:nth-of-type(3)"
              }
            }
          }
        },
        "pushdown": {
          "_default": {
            "position": "mid-content",
            "static_refresh_size": true,
            "sizes": {
              "desktop": [
                "970x418",
                "970x66"
              ],
              "tablet": [
                "970x418",
                "970x66"
              ],
              "mobile": false
            },
            "render": {
              "slot": {
                "bottom": "aside.site-pushdown-ad-wrap"
              }
            }
          }
        },
        "railBoxTabletAd1": {
          "_default": {
            "position": "rail",
            "sizes": {
              "desktop": false,
              "tablet": [
                "300x250"
              ],
              "mobile": false
            },
            "render": {
              "slot": {
                "bottom": ".railBoxTabletAd1-ad-wrap"
              }
            }
          }
        },
        "recipe_detail": {
          "_default": {
            "position": "sponsor",
            "should_use_legacy_path": true,
            "refresh": false,
            "can_be_hidden": true,
            "sizes": {
              "desktop": [
                "538x153"
              ],
              "tablet": [
                "538x153"
              ],
              "mobile": [
                "288x150"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.native-recipe-ad"
              }
            }
          }
        },
        "recipe_riser": {
          "_default": {
            "position": "sponsor",
            "should_use_legacy_path": true,
            "can_be_hidden": true,
            "refresh": false,
            "sizes": {
              "desktop": [
                "227x108"
              ],
              "tablet": [
                "227x108"
              ],
              "mobile": [
                "288x77"
              ]
            },
            "render": {
              "slot": {
                "bottom": ".recipe-riser-ad"
              }
            }
          }
        },
        "sponsor_logo": {
          "_default": {
            "position": "sponsor",
            "sizes": {
              "desktop": [
                "120x60"
              ],
              "tablet": [
                "120x60"
              ],
              "mobile": [
                "120x60"
              ]
            },
            "render": {
              "slot": {
                "bottom": "aside.sponsorLogo-ad-wrap"
              }
            }
          }
        }
      }
    }
  },
  "plugins": {
    "amazon_match_buy": {},
    "index_exchange": {},
    "4d": {
      "xid_pixels": true
    }
  },
  "buildDate": "2019-05-23T18:39:30.990Z"
}
  </script>
  <script id="cns-footer-include">
   !function(){"use strict";!function(e,t){function n(e){this.time=e.time,this.target=e.target,this.rootBounds=e.rootBounds,this.boundingClientRect=e.boundingClientRect,this.intersectionRect=e.intersectionRect||{top:0,bottom:0,left:0,right:0,width:0,height:0},this.isIntersecting=!!e.intersectionRect;var t=this.boundingClientRect,n=t.width*t.height,r=this.intersectionRect,i=r.width*r.height;this.intersectionRatio=n?i/n:this.isIntersecting?1:0}function r(e,t){var n,r,i,o=t||{};if("function"!=typeof e)throw new Error("callback must be a function");if(o.root&&1!=o.root.nodeType)throw new Error("root must be an Element");this._checkForIntersections=(n=this._checkForIntersections.bind(this),r=this.THROTTLE_TIMEOUT,i=null,function(){i||(i=setTimeout(function(){n(),i=null},r))}),this._callback=e,this._observationTargets=[],this._queuedEntries=[],this._rootMarginValues=this._parseRootMargin(o.rootMargin),this.thresholds=this._initThresholds(o.threshold),this.root=o.root||null,this.rootMargin=this._rootMarginValues.map(function(e){return e.value+e.unit}).join(" ")}function i(e,t,n,r){"function"==typeof e.addEventListener?e.addEventListener(t,n,r||!1):"function"==typeof e.attachEvent&&e.attachEvent("on"+t,n)}function o(e,t,n,r){"function"==typeof e.removeEventListener?e.removeEventListener(t,n,r||!1):"function"==typeof e.detatchEvent&&e.detatchEvent("on"+t,n)}function a(e){var t;try{t=e.getBoundingClientRect()}catch(e){}return t?(t.width&&t.height||(t={top:t.top,right:t.right,bottom:t.bottom,left:t.left,width:t.right-t.left,height:t.bottom-t.top}),t):{top:0,bottom:0,left:0,right:0,width:0,height:0}}function s(e,t){for(var n=t;n;){if(n==e)return!0;n=c(n)}return!1}function c(e){var t=e.parentNode;return t&&11==t.nodeType&&t.host?t.host:t}"IntersectionObserver"in e&&"IntersectionObserverEntry"in e&&"intersectionRatio"in e.IntersectionObserverEntry.prototype?"isIntersecting"in e.IntersectionObserverEntry.prototype||Object.defineProperty(e.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}}):(r.prototype.THROTTLE_TIMEOUT=100,r.prototype.POLL_INTERVAL=null,r.prototype.USE_MUTATION_OBSERVER=!0,r.prototype.observe=function(e){if(!this._observationTargets.some(function(t){return t.element==e})){if(!e||1!=e.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:e,entry:null}),this._monitorIntersections(),this._checkForIntersections()}},r.prototype.unobserve=function(e){this._observationTargets=this._observationTargets.filter(function(t){return t.element!=e}),this._observationTargets.length||(this._unmonitorIntersections(),this._unregisterInstance())},r.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorIntersections(),this._unregisterInstance()},r.prototype.takeRecords=function(){var e=this._queuedEntries.slice();return this._queuedEntries=[],e},r.prototype._initThresholds=function(e){var t=e||[0];return Array.isArray(t)||(t=[t]),t.sort().filter(function(e,t,n){if("number"!=typeof e||isNaN(e)||e<0||e>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return e!==n[t-1]})},r.prototype._parseRootMargin=function(e){var t=(e||"0px").split(/\s+/).map(function(e){var t=/^(-?\d*\.?\d+)(px|%)$/.exec(e);if(!t)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(t[1]),unit:t[2]}});return t[1]=t[1]||t[0],t[2]=t[2]||t[0],t[3]=t[3]||t[1],t},r.prototype._monitorIntersections=function(){this._monitoringIntersections||(this._monitoringIntersections=!0,this.POLL_INTERVAL?this._monitoringInterval=setInterval(this._checkForIntersections,this.POLL_INTERVAL):(i(e,"resize",this._checkForIntersections,!0),i(t,"scroll",this._checkForIntersections,!0),this.USE_MUTATION_OBSERVER&&"MutationObserver"in e&&(this._domObserver=new MutationObserver(this._checkForIntersections),this._domObserver.observe(t,{attributes:!0,childList:!0,characterData:!0,subtree:!0}))))},r.prototype._unmonitorIntersections=function(){this._monitoringIntersections&&(this._monitoringIntersections=!1,clearInterval(this._monitoringInterval),this._monitoringInterval=null,o(e,"resize",this._checkForIntersections,!0),o(t,"scroll",this._checkForIntersections,!0),this._domObserver&&(this._domObserver.disconnect(),this._domObserver=null))},r.prototype._checkForIntersections=function(){var t=this._rootIsInDom(),r=t?this._getRootRect():{top:0,bottom:0,left:0,right:0,width:0,height:0};this._observationTargets.forEach(function(i){var o=i.element,s=a(o),c=this._rootContainsTarget(o),u=i.entry,l=t&&c&&this._computeTargetAndRootIntersection(o,r),f=i.entry=new n({time:e.performance&&performance.now&&performance.now(),target:o,boundingClientRect:s,rootBounds:r,intersectionRect:l});u?t&&c?this._hasCrossedThreshold(u,f)&&this._queuedEntries.push(f):u&&u.isIntersecting&&this._queuedEntries.push(f):this._queuedEntries.push(f)},this),this._queuedEntries.length&&this._callback(this.takeRecords(),this)},r.prototype._computeTargetAndRootIntersection=function(n,r){if("none"!=e.getComputedStyle(n).display){for(var i,o,s,u,l,f,d,g,p=a(n),h=c(n),m=!1;!m;){var v=null,_=1==h.nodeType?e.getComputedStyle(h):{};if("none"==_.display)return;if(h==this.root||h==t?(m=!0,v=r):h!=t.body&&h!=t.documentElement&&"visible"!=_.overflow&&(v=a(h)),v&&(i=v,o=p,s=Math.max(i.top,o.top),u=Math.min(i.bottom,o.bottom),l=Math.max(i.left,o.left),g=u-s,!(p=(d=(f=Math.min(i.right,o.right))-l)>=0&&g>=0&&{top:s,bottom:u,left:l,right:f,width:d,height:g})))break;h=c(h)}return p}},r.prototype._getRootRect=function(){var e;if(this.root)e=a(this.root);else{var n=t.documentElement,r=t.body;e={top:0,left:0,right:n.clientWidth||r.clientWidth,width:n.clientWidth||r.clientWidth,bottom:n.clientHeight||r.clientHeight,height:n.clientHeight||r.clientHeight}}return this._expandRectByRootMargin(e)},r.prototype._expandRectByRootMargin=function(e){var t=this._rootMarginValues.map(function(t,n){return"px"==t.unit?t.value:t.value*(n%2?e.width:e.height)/100}),n={top:e.top-t[0],right:e.right+t[1],bottom:e.bottom+t[2],left:e.left-t[3]};return n.width=n.right-n.left,n.height=n.bottom-n.top,n},r.prototype._hasCrossedThreshold=function(e,t){var n=e&&e.isIntersecting?e.intersectionRatio||0:-1,r=t.isIntersecting?t.intersectionRatio||0:-1;if(n!==r)for(var i=0;i<this.thresholds.length;i++){var o=this.thresholds[i];if(o==n||o==r||o<n!=o<r)return!0}},r.prototype._rootIsInDom=function(){return!this.root||s(t,this.root)},r.prototype._rootContainsTarget=function(e){return s(this.root||t,e)},r.prototype._registerInstance=function(){},r.prototype._unregisterInstance=function(){},e.IntersectionObserver=r,e.IntersectionObserverEntry=n)}(window,document);var commonjsGlobal="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function createCommonjsModule(e,t){return e(t={exports:{}},t.exports),t.exports}var usertiming=createCommonjsModule(function(e){!function(t){void 0===t&&(t={}),void 0===t.performance&&(t.performance={}),t._perfRefForUserTimingPolyfill=t.performance,t.performance.userTimingJsNow=!1,t.performance.userTimingJsNowPrefixed=!1,t.performance.userTimingJsUserTiming=!1,t.performance.userTimingJsUserTimingPrefixed=!1,t.performance.userTimingJsPerformanceTimeline=!1,t.performance.userTimingJsPerformanceTimelinePrefixed=!1;var n,r,i=[],o=[],a=null;if("function"!=typeof t.performance.now){for(t.performance.userTimingJsNow=!0,o=["webkitNow","msNow","mozNow"],n=0;n<o.length;n++)if("function"==typeof t.performance[o[n]]){t.performance.now=t.performance[o[n]],t.performance.userTimingJsNowPrefixed=!0;break}var s=+new Date;t.performance.timing&&t.performance.timing.navigationStart?s=t.performance.timing.navigationStart:"undefined"!=typeof process&&"function"==typeof process.hrtime&&(s=process.hrtime(),t.performance.now=function(){var e=process.hrtime(s);return 1e3*e[0]+1e-6*e[1]}),"function"!=typeof t.performance.now&&(Date.now?t.performance.now=function(){return Date.now()-s}:t.performance.now=function(){return+new Date-s})}var c=function(){},u=function(){},l=[],f=!1,d=!1;if("function"!=typeof t.performance.getEntries||"function"!=typeof t.performance.mark){for("function"==typeof t.performance.getEntries&&"function"!=typeof t.performance.mark&&(d=!0),t.performance.userTimingJsPerformanceTimeline=!0,i=["webkit","moz"],o=["getEntries","getEntriesByName","getEntriesByType"],n=0;n<o.length;n++)for(r=0;r<i.length;r++)a=i[r]+o[n].substr(0,1).toUpperCase()+o[n].substr(1),"function"==typeof t.performance[a]&&(t.performance[o[n]]=t.performance[a],t.performance.userTimingJsPerformanceTimelinePrefixed=!0);c=function(e){l.push(e),"measure"===e.entryType&&(f=!0)};var g=function(){f&&(l.sort(function(e,t){return e.startTime-t.startTime}),f=!1)};if(u=function(e,t){for(n=0;n<l.length;)l[n].entryType!==e||void 0!==t&&l[n].name!==t?n++:l.splice(n,1)},"function"!=typeof t.performance.getEntries||d){var p=t.performance.getEntries;t.performance.getEntries=function(){g();var e=l.slice(0);return d&&p&&(Array.prototype.push.apply(e,p.call(t.performance)),e.sort(function(e,t){return e.startTime-t.startTime})),e}}if("function"!=typeof t.performance.getEntriesByType||d){var h=t.performance.getEntriesByType;t.performance.getEntriesByType=function(e){if(void 0===e||"mark"!==e&&"measure"!==e)return d&&h?h.call(t.performance,e):[];"measure"===e&&g();var r=[];for(n=0;n<l.length;n++)l[n].entryType===e&&r.push(l[n]);return r}}if("function"!=typeof t.performance.getEntriesByName||d){var m=t.performance.getEntriesByName;t.performance.getEntriesByName=function(e,r){if(r&&"mark"!==r&&"measure"!==r)return d&&m?m.call(t.performance,e,r):[];void 0!==r&&"measure"===r&&g();var i=[];for(n=0;n<l.length;n++)void 0!==r&&l[n].entryType!==r||l[n].name===e&&i.push(l[n]);return d&&m&&(Array.prototype.push.apply(i,m.call(t.performance,e,r)),i.sort(function(e,t){return e.startTime-t.startTime})),i}}}if("function"!=typeof t.performance.mark){for(t.performance.userTimingJsUserTiming=!0,i=["webkit","moz","ms"],o=["mark","measure","clearMarks","clearMeasures"],n=0;n<o.length;n++)for(r=0;r<i.length;r++)a=i[r]+o[n].substr(0,1).toUpperCase()+o[n].substr(1),"function"==typeof t.performance[a]&&(t.performance[o[n]]=t.performance[a],t.performance.userTimingJsUserTimingPrefixed=!0);var v={};"function"!=typeof t.performance.mark&&(t.performance.mark=function(e){var n=t.performance.now();if(void 0===e)throw new SyntaxError("Mark name must be specified");if(t.performance.timing&&e in t.performance.timing)throw new SyntaxError("Mark name is not allowed");v[e]||(v[e]=[]),v[e].push(n),c({entryType:"mark",name:e,startTime:n,duration:0})}),"function"!=typeof t.performance.clearMarks&&(t.performance.clearMarks=function(e){e?v[e]=[]:v={},u("mark",e)}),"function"!=typeof t.performance.measure&&(t.performance.measure=function(e,n,r){var i=t.performance.now();if(void 0===e)throw new SyntaxError("Measure must be specified");if(n){var o=0;if(t.performance.timing&&n in t.performance.timing){if("navigationStart"!==n&&0===t.performance.timing[n])throw new Error(n+" has a timing of 0");o=t.performance.timing[n]-t.performance.timing.navigationStart}else{if(!(n in v))throw new Error(n+" mark not found");o=v[n][v[n].length-1]}var a=i;if(r)if(a=0,t.performance.timing&&r in t.performance.timing){if("navigationStart"!==r&&0===t.performance.timing[r])throw new Error(r+" has a timing of 0");a=t.performance.timing[r]-t.performance.timing.navigationStart}else{if(!(r in v))throw new Error(r+" mark not found");a=v[r][v[r].length-1]}c({entryType:"measure",name:e,startTime:o,duration:a-o})}else c({entryType:"measure",name:e,startTime:0,duration:i})}),"function"!=typeof t.performance.clearMeasures&&(t.performance.clearMeasures=function(e){u("measure",e)})}e.exports=t.performance}("undefined"!=typeof window?window:void 0)}),_isObject=function(e){return"object"==typeof e?null!==e:"function"==typeof e},_anObject=function(e){if(!_isObject(e))throw TypeError(e+" is not an object!");return e},_fails=function(e){try{return!!e()}catch(e){return!0}},_descriptors=!_fails(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a}),_global=createCommonjsModule(function(e){var t=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=t)}),document$1=_global.document,is=_isObject(document$1)&&_isObject(document$1.createElement),_domCreate=function(e){return is?document$1.createElement(e):{}},_ie8DomDefine=!_descriptors&&!_fails(function(){return 7!=Object.defineProperty(_domCreate("div"),"a",{get:function(){return 7}}).a}),_toPrimitive=function(e,t){if(!_isObject(e))return e;var n,r;if(t&&"function"==typeof(n=e.toString)&&!_isObject(r=n.call(e)))return r;if("function"==typeof(n=e.valueOf)&&!_isObject(r=n.call(e)))return r;if(!t&&"function"==typeof(n=e.toString)&&!_isObject(r=n.call(e)))return r;throw TypeError("Can't convert object to primitive value")},dP=Object.defineProperty,f=_descriptors?Object.defineProperty:function(e,t,n){if(_anObject(e),t=_toPrimitive(t,!0),_anObject(n),_ie8DomDefine)try{return dP(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e},_objectDp={f:f},_propertyDesc=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}},_hide=_descriptors?function(e,t,n){return _objectDp.f(e,t,_propertyDesc(1,n))}:function(e,t,n){return e[t]=n,e},hasOwnProperty={}.hasOwnProperty,_has=function(e,t){return hasOwnProperty.call(e,t)},id=0,px=Math.random(),_uid=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++id+px).toString(36))},_core=createCommonjsModule(function(e){var t=e.exports={version:"2.5.3"};"number"==typeof __e&&(__e=t)}),_redefine=createCommonjsModule(function(e){var t=_uid("src"),n=Function.toString,r=(""+n).split("toString");_core.inspectSource=function(e){return n.call(e)},(e.exports=function(e,n,i,o){var a="function"==typeof i;a&&(_has(i,"name")||_hide(i,"name",n)),e[n]!==i&&(a&&(_has(i,t)||_hide(i,t,e[n]?""+e[n]:r.join(String(n)))),e===_global?e[n]=i:o?e[n]?e[n]=i:_hide(e,n,i):(delete e[n],_hide(e,n,i)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[t]||n.call(this)})}),_defined=function(e){if(void 0==e)throw TypeError("Can't call method on  "+e);return e},SHARED="__core-js_shared__",store=_global[SHARED]||(_global[SHARED]={}),_shared=function(e){return store[e]||(store[e]={})},_wks=createCommonjsModule(function(e){var t=_shared("wks"),n=_global.Symbol,r="function"==typeof n;(e.exports=function(e){return t[e]||(t[e]=r&&n[e]||(r?n:_uid)("Symbol."+e))}).store=t}),_fixReWks=function(e,t,n){var r=_wks(e),i=n(_defined,r,""[e]),o=i[0],a=i[1];_fails(function(){var t={};return t[r]=function(){return 7},7!=""[e](t)})&&(_redefine(String.prototype,e,o),_hide(RegExp.prototype,r,2==t?function(e,t){return a.call(e,this,t)}:function(e){return a.call(e,this)}))},toString={}.toString,_cof=function(e){return toString.call(e).slice(8,-1)},MATCH=_wks("match"),_isRegexp=function(e){var t;return _isObject(e)&&(void 0!==(t=e[MATCH])?!!t:"RegExp"==_cof(e))};_fixReWks("split",2,function(e,t,n){var r=_isRegexp,i=n,o=[].push;if("c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length){var a=void 0===/()??/.exec("")[1];n=function(e,t){var n=String(this);if(void 0===e&&0===t)return[];if(!r(e))return i.call(n,e,t);var s,c,u,l,f,d=[],g=(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":""),p=0,h=void 0===t?4294967295:t>>>0,m=new RegExp(e.source,g+"g");for(a||(s=new RegExp("^"+m.source+"$(?!\\s)",g));(c=m.exec(n))&&!((u=c.index+c[0].length)>p&&(d.push(n.slice(p,c.index)),!a&&c.length>1&&c[0].replace(s,function(){for(f=1;f<arguments.length-2;f++)void 0===arguments[f]&&(c[f]=void 0)}),c.length>1&&c.index<n.length&&o.apply(d,c.slice(1)),l=c[0].length,p=u,d.length>=h));)m.lastIndex===c.index&&m.lastIndex++;return p===n.length?!l&&m.test("")||d.push(""):d.push(n.slice(p)),d.length>h?d.slice(0,h):d}}else"0".split(void 0,0).length&&(n=function(e,t){return void 0===e&&0===t?[]:i.call(this,e,t)});return[function(r,i){var o=e(this),a=void 0==r?void 0:r[t];return void 0!==a?a.call(r,o,i):n.call(String(o),r,i)},n]});var _iobject=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==_cof(e)?e.split(""):Object(e)},_toIobject=function(e){return _iobject(_defined(e))},ceil=Math.ceil,floor=Math.floor,_toInteger=function(e){return isNaN(e=+e)?0:(e>0?floor:ceil)(e)},min=Math.min,_toLength=function(e){return e>0?min(_toInteger(e),9007199254740991):0},max=Math.max,min$1=Math.min,_toAbsoluteIndex=function(e,t){return(e=_toInteger(e))<0?max(e+t,0):min$1(e,t)},_arrayIncludes=function(e){return function(t,n,r){var i,o=_toIobject(t),a=_toLength(o.length),s=_toAbsoluteIndex(r,a);if(e&&n!=n){for(;a>s;)if((i=o[s++])!=i)return!0}else for(;a>s;s++)if((e||s in o)&&o[s]===n)return e||s||0;return!e&&-1}},shared=_shared("keys"),_sharedKey=function(e){return shared[e]||(shared[e]=_uid(e))},arrayIndexOf=_arrayIncludes(!1),IE_PROTO=_sharedKey("IE_PROTO"),_objectKeysInternal=function(e,t){var n,r=_toIobject(e),i=0,o=[];for(n in r)n!=IE_PROTO&&_has(r,n)&&o.push(n);for(;t.length>i;)_has(r,n=t[i++])&&(~arrayIndexOf(o,n)||o.push(n));return o},_enumBugKeys="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(","),_objectKeys=Object.keys||function(e){return _objectKeysInternal(e,_enumBugKeys)},_objectDps=_descriptors?Object.defineProperties:function(e,t){_anObject(e);for(var n,r=_objectKeys(t),i=r.length,o=0;i>o;)_objectDp.f(e,n=r[o++],t[n]);return e},document$2=_global.document,_html=document$2&&document$2.documentElement,IE_PROTO$1=_sharedKey("IE_PROTO"),Empty=function(){},PROTOTYPE="prototype",createDict=function(){var e,t=_domCreate("iframe"),n=_enumBugKeys.length;for(t.style.display="none",_html.appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("<script>document.F=Object<\/script>"),e.close(),createDict=e.F;n--;)delete createDict[PROTOTYPE][_enumBugKeys[n]];return createDict()},_objectCreate=Object.create||function(e,t){var n;return null!==e?(Empty[PROTOTYPE]=_anObject(e),n=new Empty,Empty[PROTOTYPE]=null,n[IE_PROTO$1]=e):n=createDict(),void 0===t?n:_objectDps(n,t)},_redefineAll=function(e,t,n){for(var r in t)_redefine(e,r,t[r],n);return e},_aFunction=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e},_ctx=function(e,t,n){if(_aFunction(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}},_anInstance=function(e,t,n,r){if(!(e instanceof t)||void 0!==r&&r in e)throw TypeError(n+": incorrect invocation!");return e},_iterCall=function(e,t,n,r){try{return r?t(_anObject(n)[0],n[1]):t(n)}catch(t){var i=e.return;throw void 0!==i&&_anObject(i.call(e)),t}},_iterators={},ITERATOR=_wks("iterator"),ArrayProto=Array.prototype,_isArrayIter=function(e){return void 0!==e&&(_iterators.Array===e||ArrayProto[ITERATOR]===e)},TAG=_wks("toStringTag"),ARG="Arguments"==_cof(function(){return arguments}()),tryGet=function(e,t){try{return e[t]}catch(e){}},_classof=function(e){var t,n,r;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=tryGet(t=Object(e),TAG))?n:ARG?_cof(t):"Object"==(r=_cof(t))&&"function"==typeof t.callee?"Arguments":r},ITERATOR$1=_wks("iterator"),core_getIteratorMethod=_core.getIteratorMethod=function(e){if(void 0!=e)return e[ITERATOR$1]||e["@@iterator"]||_iterators[_classof(e)]},_forOf=createCommonjsModule(function(e){var t={},n={},r=e.exports=function(e,r,i,o,a){var s,c,u,l,f=a?function(){return e}:core_getIteratorMethod(e),d=_ctx(i,o,r?2:1),g=0;if("function"!=typeof f)throw TypeError(e+" is not iterable!");if(_isArrayIter(f)){for(s=_toLength(e.length);s>g;g++)if((l=r?d(_anObject(c=e[g])[0],c[1]):d(e[g]))===t||l===n)return l}else for(u=f.call(e);!(c=u.next()).done;)if((l=_iterCall(u,d,c.value,r))===t||l===n)return l};r.BREAK=t,r.RETURN=n}),_library=!1,PROTOTYPE$1="prototype",$export=function(e,t,n){var r,i,o,a,s=e&$export.F,c=e&$export.G,u=e&$export.S,l=e&$export.P,f=e&$export.B,d=c?_global:u?_global[t]||(_global[t]={}):(_global[t]||{})[PROTOTYPE$1],g=c?_core:_core[t]||(_core[t]={}),p=g[PROTOTYPE$1]||(g[PROTOTYPE$1]={});for(r in c&&(n=t),n)o=((i=!s&&d&&void 0!==d[r])?d:n)[r],a=f&&i?_ctx(o,_global):l&&"function"==typeof o?_ctx(Function.call,o):o,d&&_redefine(d,r,o,e&$export.U),g[r]!=o&&_hide(g,r,a),l&&p[r]!=o&&(p[r]=o)};_global.core=_core,$export.F=1,$export.G=2,$export.S=4,$export.P=8,$export.B=16,$export.W=32,$export.U=64,$export.R=128;var _export=$export,def=_objectDp.f,TAG$1=_wks("toStringTag"),_setToStringTag=function(e,t,n){e&&!_has(e=n?e:e.prototype,TAG$1)&&def(e,TAG$1,{configurable:!0,value:t})},IteratorPrototype={};_hide(IteratorPrototype,_wks("iterator"),function(){return this});var _iterCreate=function(e,t,n){e.prototype=_objectCreate(IteratorPrototype,{next:_propertyDesc(1,n)}),_setToStringTag(e,t+" Iterator")},_toObject=function(e){return Object(_defined(e))},IE_PROTO$2=_sharedKey("IE_PROTO"),ObjectProto=Object.prototype,_objectGpo=Object.getPrototypeOf||function(e){return e=_toObject(e),_has(e,IE_PROTO$2)?e[IE_PROTO$2]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?ObjectProto:null},ITERATOR$2=_wks("iterator"),BUGGY=!([].keys&&"next"in[].keys()),FF_ITERATOR="@@iterator",KEYS="keys",VALUES="values",returnThis=function(){return this},_iterDefine=function(e,t,n,r,i,o,a){_iterCreate(n,t,r);var s,c,u,l=function(e){if(!BUGGY&&e in p)return p[e];switch(e){case KEYS:case VALUES:return function(){return new n(this,e)}}return function(){return new n(this,e)}},f=t+" Iterator",d=i==VALUES,g=!1,p=e.prototype,h=p[ITERATOR$2]||p[FF_ITERATOR]||i&&p[i],m=!BUGGY&&h||l(i),v=i?d?l("entries"):m:void 0,_="Array"==t&&p.entries||h;if(_&&(u=_objectGpo(_.call(new e)))!==Object.prototype&&u.next&&(_setToStringTag(u,f,!0),_library||_has(u,ITERATOR$2)||_hide(u,ITERATOR$2,returnThis)),d&&h&&h.name!==VALUES&&(g=!0,m=function(){return h.call(this)}),_library&&!a||!BUGGY&&!g&&p[ITERATOR$2]||_hide(p,ITERATOR$2,m),_iterators[t]=m,_iterators[f]=returnThis,i)if(s={values:d?m:l(VALUES),keys:o?m:l(KEYS),entries:v},a)for(c in s)c in p||_redefine(p,c,s[c]);else _export(_export.P+_export.F*(BUGGY||g),t,s);return s},_iterStep=function(e,t){return{value:t,done:!!e}},SPECIES=_wks("species"),_setSpecies=function(e){var t=_global[e];_descriptors&&t&&!t[SPECIES]&&_objectDp.f(t,SPECIES,{configurable:!0,get:function(){return this}})},_meta=createCommonjsModule(function(e){var t=_uid("meta"),n=_objectDp.f,r=0,i=Object.isExtensible||function(){return!0},o=!_fails(function(){return i(Object.preventExtensions({}))}),a=function(e){n(e,t,{value:{i:"O"+ ++r,w:{}}})},s=e.exports={KEY:t,NEED:!1,fastKey:function(e,n){if(!_isObject(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!_has(e,t)){if(!i(e))return"F";if(!n)return"E";a(e)}return e[t].i},getWeak:function(e,n){if(!_has(e,t)){if(!i(e))return!0;if(!n)return!1;a(e)}return e[t].w},onFreeze:function(e){return o&&s.NEED&&i(e)&&!_has(e,t)&&a(e),e}}}),_validateCollection=function(e,t){if(!_isObject(e)||e._t!==t)throw TypeError("Incompatible receiver, "+t+" required!");return e},dP$1=_objectDp.f,fastKey=_meta.fastKey,SIZE=_descriptors?"_s":"size",getEntry=function(e,t){var n,r=fastKey(t);if("F"!==r)return e._i[r];for(n=e._f;n;n=n.n)if(n.k==t)return n},_collectionStrong={getConstructor:function(e,t,n,r){var i=e(function(e,o){_anInstance(e,i,t,"_i"),e._t=t,e._i=_objectCreate(null),e._f=void 0,e._l=void 0,e[SIZE]=0,void 0!=o&&_forOf(o,n,e[r],e)});return _redefineAll(i.prototype,{clear:function(){for(var e=_validateCollection(this,t),n=e._i,r=e._f;r;r=r.n)r.r=!0,r.p&&(r.p=r.p.n=void 0),delete n[r.i];e._f=e._l=void 0,e[SIZE]=0},delete:function(e){var n=_validateCollection(this,t),r=getEntry(n,e);if(r){var i=r.n,o=r.p;delete n._i[r.i],r.r=!0,o&&(o.n=i),i&&(i.p=o),n._f==r&&(n._f=i),n._l==r&&(n._l=o),n[SIZE]--}return!!r},forEach:function(e){_validateCollection(this,t);for(var n,r=_ctx(e,arguments.length>1?arguments[1]:void 0,3);n=n?n.n:this._f;)for(r(n.v,n.k,this);n&&n.r;)n=n.p},has:function(e){return!!getEntry(_validateCollection(this,t),e)}}),_descriptors&&dP$1(i.prototype,"size",{get:function(){return _validateCollection(this,t)[SIZE]}}),i},def:function(e,t,n){var r,i,o=getEntry(e,t);return o?o.v=n:(e._l=o={i:i=fastKey(t,!0),k:t,v:n,p:r=e._l,n:void 0,r:!1},e._f||(e._f=o),r&&(r.n=o),e[SIZE]++,"F"!==i&&(e._i[i]=o)),e},getEntry:getEntry,setStrong:function(e,t,n){_iterDefine(e,t,function(e,n){this._t=_validateCollection(e,t),this._k=n,this._l=void 0},function(){for(var e=this._k,t=this._l;t&&t.r;)t=t.p;return this._t&&(this._l=t=t?t.n:this._t._f)?_iterStep(0,"keys"==e?t.k:"values"==e?t.v:[t.k,t.v]):(this._t=void 0,_iterStep(1))},n?"entries":"values",!n,!0),_setSpecies(t)}},ITERATOR$3=_wks("iterator"),SAFE_CLOSING=!1;try{var riter=[7][ITERATOR$3]();riter.return=function(){SAFE_CLOSING=!0}}catch(e){}var _iterDetect=function(e,t){if(!t&&!SAFE_CLOSING)return!1;var n=!1;try{var r=[7],i=r[ITERATOR$3]();i.next=function(){return{done:n=!0}},r[ITERATOR$3]=function(){return i},e(r)}catch(e){}return n},f$1={}.propertyIsEnumerable,_objectPie={f:f$1},gOPD=Object.getOwnPropertyDescriptor,f$2=_descriptors?gOPD:function(e,t){if(e=_toIobject(e),t=_toPrimitive(t,!0),_ie8DomDefine)try{return gOPD(e,t)}catch(e){}if(_has(e,t))return _propertyDesc(!_objectPie.f.call(e,t),e[t])},_objectGopd={f:f$2},check=function(e,t){if(_anObject(e),!_isObject(t)&&null!==t)throw TypeError(t+": can't set as prototype!")},_setProto={set:Object.setPrototypeOf||("__proto__"in{}?function(e,t,n){try{(n=_ctx(Function.call,_objectGopd.f(Object.prototype,"__proto__").set,2))(e,[]),t=!(e instanceof Array)}catch(e){t=!0}return function(e,r){return check(e,r),t?e.__proto__=r:n(e,r),e}}({},!1):void 0),check:check},setPrototypeOf=_setProto.set,_inheritIfRequired=function(e,t,n){var r,i=t.constructor;return i!==n&&"function"==typeof i&&(r=i.prototype)!==n.prototype&&_isObject(r)&&setPrototypeOf&&setPrototypeOf(e,r),e},_collection=function(e,t,n,r,i,o){var a=_global[e],s=a,c=i?"set":"add",u=s&&s.prototype,l={},f=function(e){var t=u[e];_redefine(u,e,"delete"==e?function(e){return!(o&&!_isObject(e))&&t.call(this,0===e?0:e)}:"has"==e?function(e){return!(o&&!_isObject(e))&&t.call(this,0===e?0:e)}:"get"==e?function(e){return o&&!_isObject(e)?void 0:t.call(this,0===e?0:e)}:"add"==e?function(e){return t.call(this,0===e?0:e),this}:function(e,n){return t.call(this,0===e?0:e,n),this})};if("function"==typeof s&&(o||u.forEach&&!_fails(function(){(new s).entries().next()}))){var d=new s,g=d[c](o?{}:-0,1)!=d,p=_fails(function(){d.has(1)}),h=_iterDetect(function(e){new s(e)}),m=!o&&_fails(function(){for(var e=new s,t=5;t--;)e[c](t,t);return!e.has(-0)});h||((s=t(function(t,n){_anInstance(t,s,e);var r=_inheritIfRequired(new a,t,s);return void 0!=n&&_forOf(n,i,r[c],r),r})).prototype=u,u.constructor=s),(p||m)&&(f("delete"),f("has"),i&&f("get")),(m||g)&&f(c),o&&u.clear&&delete u.clear}else s=r.getConstructor(t,e,i,c),_redefineAll(s.prototype,n),_meta.NEED=!0;return _setToStringTag(s,e),l[e]=s,_export(_export.G+_export.W+_export.F*(s!=a),l),o||r.setStrong(s,e,i),s},SET="Set",es6_set=_collection(SET,function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}},{add:function(e){return _collectionStrong.def(_validateCollection(this,SET),e=0===e?0:e,e)}},_collectionStrong),_createProperty=function(e,t,n){t in e?_objectDp.f(e,t,_propertyDesc(0,n)):e[t]=n};_export(_export.S+_export.F*!_iterDetect(function(e){}),"Array",{from:function(e){var t,n,r,i,o=_toObject(e),a="function"==typeof this?this:Array,s=arguments.length,c=s>1?arguments[1]:void 0,u=void 0!==c,l=0,f=core_getIteratorMethod(o);if(u&&(c=_ctx(c,s>2?arguments[2]:void 0,2)),void 0==f||a==Array&&_isArrayIter(f))for(n=new a(t=_toLength(o.length));t>l;l++)_createProperty(n,l,u?c(o[l],l):o[l]);else for(i=f.call(o),n=new a;!(r=i.next()).done;l++)_createProperty(n,l,u?_iterCall(i,c,[r.value,l],!0):r.value);return n.length=l,n}});var f$3=Object.getOwnPropertySymbols,_objectGops={f:f$3},$assign=Object.assign,_objectAssign=!$assign||_fails(function(){var e={},t={},n=Symbol(),r="abcdefghijklmnopqrst";return e[n]=7,r.split("").forEach(function(e){t[e]=e}),7!=$assign({},e)[n]||Object.keys($assign({},t)).join("")!=r})?function(e,t){for(var n=_toObject(e),r=arguments.length,i=1,o=_objectGops.f,a=_objectPie.f;r>i;)for(var s,c=_iobject(arguments[i++]),u=o?_objectKeys(c).concat(o(c)):_objectKeys(c),l=u.length,f=0;l>f;)a.call(c,s=u[f++])&&(n[s]=c[s]);return n}:$assign;_export(_export.S+_export.F,"Object",{assign:_objectAssign});var prefix="ads.";function emitEvent(e,t,n){window.cnBus.emit(prefix+t+"."+e,n)}var levels={debug:emitEvent.bind(null,"debug"),info:emitEvent.bind(null,"info"),warn:emitEvent.bind(null,"warn"),error:emitEvent.bind(null,"error")},debug=levels.debug,error=levels.error,warn=levels.warn,styling={debug:"color:darkgreen",info:"color:darkblue"};function EventEmitter(e){return Object.keys(levels).reduce(function(t,n){return t[n]=function(t,r){return levels[n](e+"."+t,r)},t},{})}function addStyling(e,t){styling[e]&&(t[1]&&(t[2]=t[1]),t[0]="%c"+t[0],t[1]=styling[e])}function render(e,t){var n=t.topic,r=n.split("."),i=r[r.length-1],o=console[i],a=[n];e&&a.push(e),addStyling(i,a),o.apply(console,a)}function addDefaultSubscriptions(e,t){t&&e.on("ads.#.debug",render),e.on("ads.#.info",render),e.on("ads.#.warn",render),e.on("ads.#.error",render)}function handlePromiseError(e){return function(t){return emitEvent("error",e,t)}}function pathToArray(e){return e.split?e.split("."):e}function get(e,t){t=pathToArray(t);for(var n=0;e&&n<t.length;n++)e=e[t[n]];return e}function set(e,t,n){for(var r=(t=pathToArray(t)).length-1,i=t[r],o=0;o<r;o++){var a=t[o];!e[a]&&o<r&&(e[a]={}),e=e[t[o]]}return{oldValue:e&&e[i],newValue:e&&(e[i]=n)}}function pick(e,t){var n={};return t.forEach(function(t){var r=get(e,t);r&&set(n,t,r)}),n}function convertSizeToString(e){Array.isArray(e)&&e.map(function(e){return Array.isArray(e)?e.join("x"):e}).join()}function getSizesObjectToString(e){return e.getSizes(window.innerWidth,window.innerHeight).map(function(e){return"object"==typeof e?e.getWidth()+"x"+e.getHeight():e}).join()}function SlotMetricsReport(e){var t=e.slot.getSlotElementId();Object.defineProperties(this,{adUnitPath:{value:e.slot.getAdUnitPath(),writable:!1,enumerable:!0},advertiserId:{value:e.advertiserId,writable:!1,enumerable:!0},campaignId:{value:e.campaignId,writable:!1,enumerable:!0},creativeId:{value:e.creativeId,writable:!1,enumerable:!0},isBackfill:{value:e.isBackfill,writable:!1,enumerable:!0},isEmpty:{value:e.isEmpty,writable:!1,enumerable:!0},lineItemId:{value:e.lineItemId,writable:!1,enumerable:!0},outOfPage:{value:e.slot.getOutOfPage(),writable:!1,enumerable:!0},requested:{value:Date.now(),writable:!1,enumerable:!0},size:{value:convertSizeToString(e.size),writable:!1,enumerable:!0},sizes:{value:getSizesObjectToString(e.slot),writable:!1,enumerable:!0},slotElementId:{value:t,writable:!1,enumerable:!0},instance:{value:t.split("_").pop(),writable:!1,enumerable:!0},slotTargeting:{value:e.slot.getTargetingMap(),writable:!1,enumerable:!0}}),Object.freeze(this)}Object.assign({emitEvent:emitEvent,EventEmitter:EventEmitter,handlePromiseError:handlePromiseError},levels,{addDefaultSubscriptions:addDefaultSubscriptions});var cloneArray=function(e){return Array.prototype.slice.apply(e)},debounce=function(e,t){var n;return function(){var r=this,i=arguments;clearTimeout(n),n=setTimeout(function(){return e.apply(r,i)},t)}},cumulativeArgumentDebounce=function(e,t){var n,r=[];return function(){var i=this;r.push(cloneArray(arguments)),clearTimeout(n),n=setTimeout(function(){e.apply(i,[cloneArray(r)]),r.length=0},t)}},errorMessage="Ads -- Missing page context",errorParamMessage=errorMessage+" parameter : ",requiredKeys=["templateType"],expectedKeys=["channel","server"];function validate(e){requiredKeys.forEach(function(t){!e.templateType&&error(""+errorParamMessage+t)}),expectedKeys.forEach(function(t){!e[t]&&warn(""+errorParamMessage+t)})}function getPageContext(e){var t=e.cns&&e.cns.pageContext;if(t)return t.templateType=t.templateType||t.template_type,t.subChannel=t.subChannel||t.sub_channel,validate(t),t;error(errorMessage)}var bufferPeriod=1e3,startTs=Date.now(),fields=["adUnitPath","advertiserId","campaignId","companyIds","creativeId","creativeTemplateId","device","instance","inViewPercentage","isBackfill","isEmpty","isEmpty","isFirstImpression","isFirstImpressionViewable","isFirstMoneyImpression","isFirstMoneyImpressionViewable","isFirstMoneyRequested","isFirstRequested","isRefresh","labelIds","lineItemId","outOfPage","requestNumber","size","sizes","slotElementId","slotTargeting","sourceAgnosticCreativeId","sourceAgnosticLineItemId"],sentPageTargeting=!1,sendEvent=cumulativeArgumentDebounce(function(e){var t=e.map(function(e){return e[0]}),n=JSON.stringify(t)||"",r="https://wren.condenastdigital.com/1.0/conde/events?topic=wren.events.ads&api_key=d3Jlbg",i=!1;if(navigator&&"function"==typeof navigator.sendBeacon&&"function"==typeof window.Blob&&(i=navigator.sendBeacon(r,n)),!i)if(n.length<1500){var o=r+"&data="+encodeURIComponent(n);(new Image).src=o}else{var a=new XMLHttpRequest;a.open("POST",r,!0),a.setRequestHeader("Content-type","application/json"),a.send(n)}},bufferPeriod);function delta(){return parseFloat(((Date.now()-startTs)/1e3).toFixed(1))}function decorate(e){return e.delta=delta(),e.pageContext=getPageContext(window),get(e,"pageContext.device")&&delete e.pageContext.device,e._device=!0,e._geo=!0,e._did=!0,e._ref=!0,e._xid=!0,e._key=get(window,"cns.runtimeId"),e}function add(e){sendEvent(decorate(e))}function onStart(){var e={type:"page"};e.targeting=getPageTargeting(),add(e)}function slotEventPayload(e,t){var n={},r=new SlotMetricsReport(e);return fields.forEach(function(i){null!=r[i]&&(n[i]=r[i]),null!=e[i]&&(n[i]=e[i]),null!=t[i]&&(n[i]=t[i])}),n.companyIds&&!n.companyIds.length&&delete n.companyIds,decorate(n),n}function onSlotRenderEnded(e,t){void 0===t&&(t={});var n=slotEventPayload(e,t);n.type="slotRenderEnded",sendEvent(n),sentPageTargeting||(sentPageTargeting=!0,onStart())}function onImpressionViewable(e,t){if(void 0===t&&(t={}),e.inViewPercentage&&(0===e.inViewPercentage||100===e.inViewPercentage)){var n=slotEventPayload(e,t);n.type="impressionViewable",sendEvent(n)}}function onSlotVisibilityChanged(e,t){void 0===t&&(t={});var n=slotEventPayload(e,t);n.type="visibilityChanged",sendEvent(n)}function onSlotOnload(e,t){void 0===t&&(t={});var n=slotEventPayload(e,t);n.type="onLoad",sendEvent(n)}function markStart(){startTs=Date.now(),window.cnBus.on("ads.environment.adblock.detected",function(){return add({type:"adblock",detected:!0})}),window.cnBus.on("ads.environment.adblock.notdetected",function(){return add({type:"adblock",detected:!1})})}var wrenCollector={add:add,markStart:markStart,onImpressionViewable:onImpressionViewable,onSlotOnload:onSlotOnload,onSlotRenderEnded:onSlotRenderEnded,onSlotVisibilityChanged:onSlotVisibilityChanged,onStart:onStart,sendEvent:sendEvent},minInterval=50;function deprecated(e,t){return void 0===t&&(t="unnamed"),function(){warn("function "+t+" is deprecated"),wrenCollector.add({type:"deprecatedFunctionCall",name:t});for(var n=arguments.length,r=new Array(n),i=0;i<n;i++)r[i]=arguments[i];return e.apply(null,r)}}function til(e,t,n){n=Math.max(n||minInterval,minInterval);try{if(e())try{return t()}catch(e){error("til",e)}}catch(e){}setTimeout(til.bind(null,e,t,n),n)}function find(e,t){for(var n=0;n<e.length;n++)if(t(e[n]))return e[n]}function any(e,t){return!!find(e,t)}function all(e,t){for(var n=0;n<e.length;n++)if(!t(e[n]))return!1;return!0}function uniq(e){return Array.from(new Set(e))}function difference(e,t){return e.filter(function(e){return-1===t.indexOf(e)})}function applyTargeting(e,t){Object.keys(t).forEach(function(n){return e.setTargeting(n,t[n])})}function shouldSetSlotSize(e,t,n){var r=e&&Array.isArray(e),i=e&&2===e.length&&e[0]===e[1]===1;return n.hasStaticRefreshSize&&r&&!t&&!i}function getPageTargeting(){var e=window.googletag.pubads();return e.getTargetingKeys().reduce(function(t,n){return t[n]=e.getTargeting(n),t},{})}function setSlotSize(e,t,n){t.defineSizeMapping(e.sizeMapping().addSize([0,0],n).build())}function getSizeStringAsArray(e){return e.split("x").map(function(e){return parseInt(e,10)})}function sizesToArray(e){return e?e.map(getSizeStringAsArray):[]}function getSlotById(e){return find(window.googletag.pubads().getSlots(),function(t){return t.getSlotElementId()===e})}function getSizeMapping(e){var t=e.getSizeMapping(),n=t.desktop,r=t.tablet,i=t.mobile;return window.googletag.sizeMapping().addSize([1024,0],n).addSize([768,0],r).addSize([0,0],i).build()}function domCall(e,t,n){return n||(n=e,e=document),e[t](n)}function getElementById(e,t){return domCall(e,"getElementById",t)}function find$1(e,t){return domCall(e,"querySelector",t)}function findAll(e,t){return Array.prototype.slice.call(domCall(e,"querySelectorAll",t))}function setStyle(e,t){for(var n=Object.keys(t),r=0;r<n.length;r++){var i=n[r];e.style[i]=t[i]}}function addClasses(e,t){for(var n=Object.keys(t),r=0;r<n.length;r++)e.classList.add(t[n[r]])}function setElementData(e,t){for(var n=Object.keys(t),r=0;r<n.length;r++){var i=n[r];e.setAttribute("data-"+i,t[i])}}function createElement(e,t){var n=document.createElement(e);return t&&Object.keys(t).forEach(function(e){n[e]=t[e]}),n}var isCNSAdsSlotSizeClassRegex=new RegExp(/^cns-ads-slot-size-/);function ContainerStyler(e){var t,n,r=new EventEmitter("ContainerStyler").debug;function i(e){setStyle(e,{height:"0px",width:"0px",minWidth:"0px",minHeight:"0px"})}function o(e,t){setStyle(e,{height:t[1]+"px",minHeight:t[1]+"px",width:t[0]+"px",minWidth:t[0]+"px"})}t=createElement("style"),n=document.createTextNode(""),t.classList.add("cns-ads-iframe-styles"),t.appendChild(n),document.head.appendChild(t),e?(t.sheet.insertRule('iframe[id^="google_ads_iframe"],div[id*="google_ads_iframe"] {margin: 0 auto;padding: 0;}',t.sheet.cssRules.length),t.sheet.insertRule('.cns-ads-slot-size-9x1 iframe[id^="google_ads_iframe"],.cns-ads-slot-size-9x1 div[id*="google_ads_iframe"] {height: 0;width: 100%;min-width: 100%;}',t.sheet.cssRules.length)):t.sheet.insertRule('iframe[id^="google_ads_iframe"],div[id*="google_ads_iframe"] {margin: 0 auto;padding: 0;height: 0;width: 100%;min-width: 100%;}',t.sheet.cssRules.length),t.sheet.insertRule(".cns-ads-stage { margin: 0 auto; padding: 0; width: 100%; }",t.sheet.cssRules.length),t.sheet.insertRule('[data-slot-type="_out_of_page"] {position: absolute;z-index: -1;}',t.sheet.cssRules.length),this.updateContainer=function(t,n){var a,s=n.isEmpty,c=n.size,u=n.slot,l=t.parentNode;r("ContainerStyler",{container:t,stage:l,isEmpty:s,size:c,id:u.getSlotElementId()}),s?function(e,t){var n=t.classList;n.remove("cns-ads-slot-state-filled"),n.add("cns-ads-slot-state-empty"),i(e)}(t,l):(function(e){var t=e.classList;t.remove("cns-ads-slot-state-empty");for(var n=0;n<t.length;n++)isCNSAdsSlotSizeClassRegex.test(t[n])&&t.remove(t[n])}(l),function(e,t){addClasses(e,["cns-ads-slot-state-filled","cns-ads-slot-size-"+(t&&t[0]&&t[1]&&t[0]+"x"+t[1])])}(l,c),function(e,t){t||i(e)}(t,c),e||(a=["height","width","padding","margin"],[t,l].forEach(function(e){a.forEach(function(t){e.removeAttribute(t)})}),function(e){return 9===e[0]}(c)||function(e,t,n){var r='[id^="google_ads_iframe"]:not([id$="to_be_removed__"]):not([id$="hidden__"])',i=find$1(t,"iframe"+r),a=find$1(t,"div"+r);o(e,n),o(i,n),o(a,n)}(t,l,c)))}}function getCookie(e,t){for(var n=(t=t||document.cookie).split(";"),r=RegExp("^\\s*"+e+"=\\s*(.*?)\\s*$"),i=0;i<n.length;i++){var o=n[i].match(r);if(o)return o[1]}}_fixReWks("replace",2,function(e,t,n){return[function(r,i){var o=e(this),a=void 0==r?void 0:r[t];return void 0!==a?a.call(r,o,i):n.call(String(o),r,i)},n]}),_fixReWks("match",1,function(e,t,n){return[function(n){var r=e(this),i=void 0==n?void 0:n[t];return void 0!==i?i.call(n,r):new RegExp(n)[t](String(r))},n]});var alphanumeric=new RegExp(/[^a-zA-Z0-9]/g),cookieKey="CN_xid",isValidLength=function(e){return e.length>=32&&e.length<=150};function getPPID(){var e=getCookie(cookieKey);if(!e)return!1;var t=e.replace(alphanumeric,"");return isValidLength(t)&&t}function setPPID(e){var t=getPPID();t&&e.setPublisherProvidedId(t)}function updateCorrelatorInterval(){set(window,"cns.flags.shouldCorrelatorUpdate",!0);var e=setInterval(function(){get(window,"cns.flags.shouldCorrelatorUpdate")?window.googletag.pubads().updateCorrelator():clearInterval(e)},3e4)}var dP$2=_objectDp.f,FProto=Function.prototype,nameRE=/^\s*function ([^ (]*)/,NAME="name";function pixel(e){var t=e.campaign,n=e.name,r=e.meta;window.sparrowQueue.push(function(){window.sparrow.track(t,n,r)})}NAME in FProto||_descriptors&&dP$2(FProto,NAME,{configurable:!0,get:function(){try{return(""+this).match(nameRE)[1]}catch(e){return""}}}),window.sparrowQueue=window.sparrowQueue||[];var eventMatcher={slotImpressionViewable:"slot_impression_viewable",slotRendered:"slot_rendered",slotImpression:"slot_loaded",slotRequested:"slot_requested"};function transformPayload(e){var t=e.slotTargeting,n=e.pageTargeting;return{dim1:JSON.stringify({adBlock:n.adblock&&n.adblock.join(),channel:e.channel,device:e.device,server:e.server,subChannel:e.subChannel,template:e.templateType,version:e.version}),dim2:JSON.stringify({adUnitPath:e.adUnitPath,advertiserId:e.advertiserId,campaignId:e.campaignId,creativeId:e.creativeId,elementId:e.slotElementId,instance:e.instance,isBackfill:e.isBackfill,isEmpty:e.isEmpty,isFirstImpression:e.isFirstImpression,isFirstImpressionViewable:e.isFirstImpressionViewable,isFirstRequested:e.isFirstRequested,isFirstMoneyImpression:e.isFirstMoneyImpression,isFirstMoneyImpressionViewable:e.isFirstMoneyImpressionViewable,isFirstMoneyRequested:e.isFirstMoneyRequested,isRefresh:e.requestNumber>0,keywords:e.keywords,lineItemId:e.lineItemId,name:t.ctx_slot_name&&t.ctx_slot_name.join(),outOfPage:e.outOfPage,requestNumber:e.requestNumber.toString(),size:e.size,sizes:e.sizes,slug:e.slug,suffix:e.suffix}),dim3:JSON.stringify({footerStart:e.footerStart,headerStart:e.headerStart,navigationStart:get(performance,"timing.navigationStart"),pubAdsReady:e.pubadsReady,injected:e.injected,viewable:e.viewable,viewport:e.viewport,impression:e.impression}),dim4:JSON.stringify(Object.assign({},e.slotTargeting,e.pageTargeting))}}function transformName(e){var t=Object.keys(eventMatcher).filter(function(t){return t===e})[0];return eventMatcher[t]||e}function emitSparrowPixel(e,t){pixel({campaign:"cns_ads",name:transformName(e),meta:transformPayload(t)})}var version="6.28.2";function setPubadsReadyMetric(){performance.mark("GPT-Init")}function setAdsReadyMetric(){performance.mark("ATP-Init")}function setFirstRequestedMetric(){performance.mark("ATP-First-Request"),performance.measure("ATP-Init-To-First-Request","ATP-Init","ATP-First-Request")}function setFirstMoneyRequestedMetric(){performance.mark("ATP-First-Money-Request"),performance.measure("ATP-Init-To-First-Money-Request","ATP-Init","ATP-First-Money-Request")}function setFirstImpressionMetric(){performance.mark("ATP-First-Impression"),performance.measure("ATP-Init-To-First-Impression","ATP-Init","ATP-First-Impression")}function setFirstMoneyImpressionMetric(){performance.mark("ATP-First-Money-Impression"),performance.measure("ATP-Init-To-First-Money-Impression","ATP-Init","ATP-First-Money-Impression")}function setFirstViewableMetric(){performance.mark("ATP-First-Viewable-Impression"),performance.measure("ATP-Init-To-Viewable-Impression","ATP-Init","ATP-First-Viewable-Impression")}function setFirstMoneyViewableMetric(){performance.mark("ATP-First-Money-Viewable-Impression"),performance.measure("ATP-Init-To-Money-Viewable-Impression","ATP-Init","ATP-First-Money-Viewable-Impression")}window.BOOMR_mq=window.BOOMR_mq||[],window.BOOMR_mq.push(["addVar","cnsLib",version]);var events={adsReady:setAdsReadyMetric,pubadsReady:setPubadsReadyMetric,firstRequested:setFirstRequestedMetric,firstMoneyRequested:setFirstMoneyRequestedMetric,firstImpression:setFirstImpressionMetric,firstMoneyImpression:setFirstMoneyImpressionMetric,firstImpressionViewable:setFirstViewableMetric,firstMoneyImpressionViewable:setFirstMoneyViewableMetric};function emitBoomPixel(e){events[e]?events[e]():error("boomerang-rum-collector.eventNotDefined")}function getViewportTemplate(){var e=window.innerWidth;return e<768?"mobile":e<1024?"tablet":"desktop"}function PubadsCollector(){var e=getViewportTemplate(),t={},n={isFirstRequested:!1,isFirstImpression:!1,isImpressionViewable:!1},r=!0,i=!0,o=!0;function a(e,t,r,i){var o=t.slot,a=o.getOutOfPage(),s=o.getAdUnitPath().match(/\.cm\//),c=t.isEmpty;return a||s||c||(n[e]=n[e]?n[e]:r+i),n[e]&&n[e]===r+i}this.onSlotRenderEnded=function(n){var i=n.slot.getSlotElementId(),o=t[i]||{},s=function(e){var n=new SlotMetricsReport(e),r=t[e.slot.getAdUnitPath()]||{},i=window.cns,o=i.pageContext||{},a=getPageTargeting(),s=i.timing||{};return Object.assign({},r,n,o,{pageTargeting:a,version:version},s)}(n),c=o&&o.requestNumber>=0?o.requestNumber+1:0,u=a("isFirstRequested",n,i,c),l={device:e,adBlock:get(window,"cns.pageContext.adBlock")||!1,isRefresh:o&&o.requestNumber>=0,requestNumber:c,injected:Date.now(),isFirstMoneyRequested:u,isFirstRequested:r,viewport:"",impression:"",viewable:""},f=Object.assign(o,l,s);t[i]=f,emitSparrowPixel("slotRendered",f),wrenCollector.onSlotRenderEnded(n,l),r&&(emitBoomPixel("firstRequested"),r=!1),u&&emitBoomPixel("firstMoneyRequested")},this.onSlotVisibilityChanged=function(e){var n=e.slot.getSlotElementId(),r=t[n]||{};r.viewport=r.viewport||Date.now(),wrenCollector.onSlotVisibilityChanged(e,{})},this.onSlotOnload=function(e){var n=e.slot.getSlotElementId(),r=t[n]||{};r.isFirstMoneyImpression=a("isFirstImpression",e,n,r.requestNumber),r.isFirstImpression=i,r.impression=r.impression||Date.now(),emitSparrowPixel("slotImpression",r),wrenCollector.onSlotOnload(e,{isFirstImpression:r.isFirstImpression,isFirstMoneyImpression:r.isFirstMoneyImpression}),r.isFirstMoneyImpression&&emitBoomPixel("firstMoneyImpression"),i&&(emitBoomPixel("firstImpression"),i=!1)},this.onImpressionViewable=function(e){var n=e.slot.getSlotElementId(),r=t[n]||{};r.viewable=r.viewable||Date.now(),r.isFirstMoneyImpressionViewable=a("isImpressionViewable",e,n,r.requestNumber),r.isFirstImpressionViewable=o,emitSparrowPixel("slotImpressionViewable",r),wrenCollector.onImpressionViewable(e,{isFirstImpressionViewable:o,isFirstMoneyImpressionViewable:r.isFirstMoneyImpressionViewable}),r.isFirstMoneyImpressionViewable&&emitBoomPixel("firstMoneyImpressionViewable"),o&&(emitBoomPixel("firstImpressionViewable"),o=!1)},this.emitReady=function(){var e=get(window,"cns.timing.pubadsReady")||Date.now();set(window,"cns.timing.pubadsReady",e),emitBoomPixel("pubadsReady"),wrenCollector.markStart()}}var UNSCOPABLES=_wks("unscopables"),ArrayProto$1=Array.prototype;void 0==ArrayProto$1[UNSCOPABLES]&&_hide(ArrayProto$1,UNSCOPABLES,{});var _addToUnscopables=function(e){ArrayProto$1[UNSCOPABLES][e]=!0},$includes=_arrayIncludes(!0);_export(_export.P,"Array",{includes:function(e){return $includes(this,e,arguments.length>1?arguments[1]:void 0)}}),_addToUnscopables("includes");var stickySizes=["728x90","970x90","970x250","300x50","320x50"],stickyIsSize=function(e){return stickySizes.includes(e)};function stickyIsEligible(e,t,n){return"hero_0"===e&&t.isSticky&&Array.isArray(n)&&stickyIsSize(n.join("x"))}var pubadsCollector=new PubadsCollector;function GPTRouter(e,t,n,r){var i=new ContainerStyler(e.getSingleInstance().getPageDefinition().isVerso);window.googletag=window.googletag||{},window.googletag.cmd=window.googletag.cmd||[];var o=window.googletag,a={slotRenderEnded:[function(t){try{var n=t.slot.getSlotElementId(),a=e.getSingleInstance().getSlotDefinitionFromGPTSlot(t.slot),s=document.getElementById(n);s&&i.updateContainer(s,t);var c=t.size,u=t.isEmpty,l=t.slot;shouldSetSlotSize(c,u,a)&&setSlotSize(o,l,c),stickyIsEligible(n,a,c)&&r.emit("ads.stickyBanner.hero.slotRenderEnded."+c.join("x")),u&&r.emit("ads.slotRenderEnded."+n+".empty")}catch(e){error("onSlotRenderEnded",{event:t,ex:e})}},t.onSlotRenderEnded,n.onSlotRenderEnded,pubadsCollector.onSlotRenderEnded],impressionViewable:[function(t){try{var n=t.slot.getSlotElementId(),i=e.getSingleInstance().getSlotDefinitionFromGPTSlot(t.slot);"hero_0"===n&&i.isSticky&&r.emit("ads.stickyBanner.hero.impressionViewable",t)}catch(e){error("onImpressionViewable",{event:t,ex:e})}},t.onImpressionViewable,pubadsCollector.onImpressionViewable],slotOnload:[pubadsCollector.onSlotOnload],slotVisibilityChanged:[pubadsCollector.onSlotVisibilityChanged]};o.cmd.push(function(){var t=o.pubads();setPPID(t),t.enableSingleRequest(),t.disableInitialLoad(),t.setCentering(!0),function(e,t){Object.keys(e).forEach(function(n){e[n].forEach(function(e){return t.addEventListener(n,e)})})}(a,t),e.getSingleInstance().getPageDefinition().forChildren&&t.setTagForChildDirectedTreatment(!0),updateCorrelatorInterval(),o.enableServices(),pubadsCollector.emitReady(),r.emit("ads.pubadsReady")})}function hasEmail(e){return new RegExp("([a-zA-Z0-9._+-]+(@|%40|%2540)[a-zA-Z0-9._-]+.[a-zA-Z0-9._-]+)","gi").test(e)}function hasCreditCard(e){var t=e.match(/3(?:[47]\d([ -]?)\d{4}(?:\1\d{4}){2}|0[0-5]\d{11}|[68]\d{12})|4(?:\d\d\d)?([ -]?)\d{4}(?:\2\d{4}){2}$|^6011([ -]?)\d{4}(?:\3\d{4}){2}|5[1-5]\d\d([ -]?)\d{4}(?:\4\d{4}){2}|2014\d{11}$|^2149\d{11}|2131\d{11}$|^1800\d{11}$|^3\d{15}/);return!(null===t||!t.length)}function hasMacAddress(e){var t=e.match(/((\d|([a-f]|[A-F])){2}:){5}(\d|([a-f]|[A-F])){2}/);return!(null===t||!t.length)}function hasIP(e){var t=e.match(/((0|1[0-9]{0,2}|2[0-9]?|2[0-4][0-9]|25[0-5]|[3-9][0-9]?)\.){3}(0|1[0-9]{0,2}|2[0-9]?|2[0-4][0-9]|25[0-5]|[3-9][0-9]?)/);return!(null===t||!t.length)}function hasPII(){return any([document.referrer,document.location.href],function(e){return hasEmail(e)||hasCreditCard(e)||hasMacAddress(e)||hasIP(e)})}function detect(e){var t,n,r=!1,i=25,o={},a={},s=4e3,c="pub_300x250 pub_300x250m pub_728x90 text-ad textAd text_ad text_ads text-ads text-ad-links",u="width: 1px !important; height: 1px !important; position: absolute !important; left: -10000px !important; top: -1000px !important;";function l(){return function(t){r||(r=!0,Object.keys(a).forEach(function(e){clearTimeout(a[e])}),Object.keys(o).forEach(function(e){window.document.body.removeChild(o[e])}),e(t))}}function f(){setTimeout(function(){var e;e=l(),a.detected=setTimeout(function(){e(!1)},s),function(e){o.cosmetic=document.createElement("div"),o.cosmetic.setAttribute("class",c),o.cosmetic.setAttribute("style",u),window.document.body.appendChild(o.cosmetic),function e(t){var n=o.cosmetic;if(null!==window.document.body.getAttribute("abp")||null===n.offsetParent||0===n.offsetHeight||0===n.offsetLeft||0===n.offsetTop||0===n.offsetWidth||0===n.clientHeight||0===n.clientWidth)return t(!0);if(window.getComputedStyle){var r=window.getComputedStyle(n,null);if("none"===r.getPropertyValue("display")||"hidden"===r.getPropertyValue("visibility"))return t(!0)}a.cosmetic=setTimeout(function(){e(t)},i)}(e)}(l())},1)}t=l(),(n=new XMLHttpRequest).open("GET","/hotzones/src/ads.js",!0),n.onreadystatechange=function(){4===n.readyState&&0===n.status&&t(!0)},n.send(),"complete"===document.readyState?f():document.addEventListener("DOMContentLoaded",f,!1)}function AdBlockDetect(e){detect(function(t){t?e.emit("ads.environment.adblock.detected"):e.emit("ads.environment.adblock.notdetected"),set(window,"cns.pageContext.adBlock",t)})}function debugStyles(){var e=document.createElement("style"),t=document.createTextNode("");e.classList.add("ads-debug-styles"),e.appendChild(t),document.head.appendChild(e),e.sheet.insertRule(".cns-ads-stage {\n      box-sizing: border-box;\n      border: 5px solid black;\n      display: block !important;\n    }",e.sheet.cssRules.length),e.sheet.insertRule(".cns-ads-slot-state-empty {\n      border: 5px solid red;\n    }",e.sheet.cssRules.length),e.sheet.insertRule(".cns-ads-slot-state-filled {\n      border: 5px solid green;\n    }",e.sheet.cssRules.length)}var SPECIES$1=_wks("species"),_speciesConstructor=function(e,t){var n,r=_anObject(e).constructor;return void 0===r||void 0==(n=_anObject(r)[SPECIES$1])?t:_aFunction(n)},_invoke=function(e,t,n){var r=void 0===n;switch(t.length){case 0:return r?e():e.call(n);case 1:return r?e(t[0]):e.call(n,t[0]);case 2:return r?e(t[0],t[1]):e.call(n,t[0],t[1]);case 3:return r?e(t[0],t[1],t[2]):e.call(n,t[0],t[1],t[2]);case 4:return r?e(t[0],t[1],t[2],t[3]):e.call(n,t[0],t[1],t[2],t[3])}return e.apply(n,t)},process$1=_global.process,setTask=_global.setImmediate,clearTask=_global.clearImmediate,MessageChannel=_global.MessageChannel,Dispatch=_global.Dispatch,counter=0,queue={},ONREADYSTATECHANGE="onreadystatechange",defer,channel,port,run=function(){var e=+this;if(queue.hasOwnProperty(e)){var t=queue[e];delete queue[e],t()}},listener=function(e){run.call(e.data)};setTask&&clearTask||(setTask=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return queue[++counter]=function(){_invoke("function"==typeof e?e:Function(e),t)},defer(counter),counter},clearTask=function(e){delete queue[e]},"process"==_cof(process$1)?defer=function(e){process$1.nextTick(_ctx(run,e,1))}:Dispatch&&Dispatch.now?defer=function(e){Dispatch.now(_ctx(run,e,1))}:MessageChannel?(channel=new MessageChannel,port=channel.port2,channel.port1.onmessage=listener,defer=_ctx(port.postMessage,port,1)):_global.addEventListener&&"function"==typeof postMessage&&!_global.importScripts?(defer=function(e){_global.postMessage(e+"","*")},_global.addEventListener("message",listener,!1)):defer=ONREADYSTATECHANGE in _domCreate("script")?function(e){_html.appendChild(_domCreate("script"))[ONREADYSTATECHANGE]=function(){_html.removeChild(this),run.call(e)}}:function(e){setTimeout(_ctx(run,e,1),0)});var _task={set:setTask,clear:clearTask},macrotask=_task.set,Observer=_global.MutationObserver||_global.WebKitMutationObserver,process$2=_global.process,Promise$1=_global.Promise,isNode="process"==_cof(process$2),_microtask=function(){var e,t,n,r=function(){var r,i;for(isNode&&(r=process$2.domain)&&r.exit();e;){i=e.fn,e=e.next;try{i()}catch(r){throw e?n():t=void 0,r}}t=void 0,r&&r.enter()};if(isNode)n=function(){process$2.nextTick(r)};else if(!Observer||_global.navigator&&_global.navigator.standalone)if(Promise$1&&Promise$1.resolve){var i=Promise$1.resolve();n=function(){i.then(r)}}else n=function(){macrotask.call(_global,r)};else{var o=!0,a=document.createTextNode("");new Observer(r).observe(a,{characterData:!0}),n=function(){a.data=o=!o}}return function(r){var i={fn:r,next:void 0};t&&(t.next=i),e||(e=i,n()),t=i}};function PromiseCapability(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=_aFunction(t),this.reject=_aFunction(n)}var f$4=function(e){return new PromiseCapability(e)},_newPromiseCapability={f:f$4},_perform=function(e){try{return{e:!1,v:e()}}catch(e){return{e:!0,v:e}}},_promiseResolve=function(e,t){if(_anObject(e),_isObject(t)&&t.constructor===e)return t;var n=_newPromiseCapability.f(e);return(0,n.resolve)(t),n.promise},task=_task.set,microtask=_microtask(),PROMISE="Promise",TypeError$1=_global.TypeError,process$3=_global.process,$Promise=_global[PROMISE],isNode$1="process"==_classof(process$3),empty=function(){},Internal,newGenericPromiseCapability,OwnPromiseCapability,Wrapper,newPromiseCapability=newGenericPromiseCapability=_newPromiseCapability.f,USE_NATIVE=!!function(){try{var e=$Promise.resolve(1),t=(e.constructor={})[_wks("species")]=function(e){e(empty,empty)};return(isNode$1||"function"==typeof PromiseRejectionEvent)&&e.then(empty)instanceof t}catch(e){}}(),isThenable=function(e){var t;return!(!_isObject(e)||"function"!=typeof(t=e.then))&&t},notify=function(e,t){if(!e._n){e._n=!0;var n=e._c;microtask(function(){for(var r=e._v,i=1==e._s,o=0,a=function(t){var n,o,a=i?t.ok:t.fail,s=t.resolve,c=t.reject,u=t.domain;try{a?(i||(2==e._h&&onHandleUnhandled(e),e._h=1),!0===a?n=r:(u&&u.enter(),n=a(r),u&&u.exit()),n===t.promise?c(TypeError$1("Promise-chain cycle")):(o=isThenable(n))?o.call(n,s,c):s(n)):c(r)}catch(e){c(e)}};n.length>o;)a(n[o++]);e._c=[],e._n=!1,t&&!e._h&&onUnhandled(e)})}},onUnhandled=function(e){task.call(_global,function(){var t,n,r,i=e._v,o=isUnhandled(e);if(o&&(t=_perform(function(){isNode$1?process$3.emit("unhandledRejection",i,e):(n=_global.onunhandledrejection)?n({promise:e,reason:i}):(r=_global.console)&&r.error&&r.error("Unhandled promise rejection",i)}),e._h=isNode$1||isUnhandled(e)?2:1),e._a=void 0,o&&t.e)throw t.v})},isUnhandled=function(e){return 1!==e._h&&0===(e._a||e._c).length},onHandleUnhandled=function(e){task.call(_global,function(){var t;isNode$1?process$3.emit("rejectionHandled",e):(t=_global.onrejectionhandled)&&t({promise:e,reason:e._v})})},$reject=function(e){var t=this;t._d||(t._d=!0,(t=t._w||t)._v=e,t._s=2,t._a||(t._a=t._c.slice()),notify(t,!0))},$resolve=function(e){var t,n=this;if(!n._d){n._d=!0,n=n._w||n;try{if(n===e)throw TypeError$1("Promise can't be resolved itself");(t=isThenable(e))?microtask(function(){var r={_w:n,_d:!1};try{t.call(e,_ctx($resolve,r,1),_ctx($reject,r,1))}catch(e){$reject.call(r,e)}}):(n._v=e,n._s=1,notify(n,!1))}catch(e){$reject.call({_w:n,_d:!1},e)}}};USE_NATIVE||($Promise=function(e){_anInstance(this,$Promise,PROMISE,"_h"),_aFunction(e),Internal.call(this);try{e(_ctx($resolve,this,1),_ctx($reject,this,1))}catch(e){$reject.call(this,e)}},Internal=function(e){this._c=[],this._a=void 0,this._s=0,this._d=!1,this._v=void 0,this._h=0,this._n=!1},Internal.prototype=_redefineAll($Promise.prototype,{then:function(e,t){var n=newPromiseCapability(_speciesConstructor(this,$Promise));return n.ok="function"!=typeof e||e,n.fail="function"==typeof t&&t,n.domain=isNode$1?process$3.domain:void 0,this._c.push(n),this._a&&this._a.push(n),this._s&&notify(this,!1),n.promise},catch:function(e){return this.then(void 0,e)}}),OwnPromiseCapability=function(){var e=new Internal;this.promise=e,this.resolve=_ctx($resolve,e,1),this.reject=_ctx($reject,e,1)},_newPromiseCapability.f=newPromiseCapability=function(e){return e===$Promise||e===Wrapper?new OwnPromiseCapability(e):newGenericPromiseCapability(e)}),_export(_export.G+_export.W+_export.F*!USE_NATIVE,{Promise:$Promise}),_setToStringTag($Promise,PROMISE),_setSpecies(PROMISE),Wrapper=_core[PROMISE],_export(_export.S+_export.F*!USE_NATIVE,PROMISE,{reject:function(e){var t=newPromiseCapability(this);return(0,t.reject)(e),t.promise}}),_export(_export.S+_export.F*(_library||!USE_NATIVE),PROMISE,{resolve:function(e){return _promiseResolve(_library&&this===Wrapper?$Promise:this,e)}}),_export(_export.S+_export.F*!(USE_NATIVE&&_iterDetect(function(e){$Promise.all(e).catch(empty)})),PROMISE,{all:function(e){var t=this,n=newPromiseCapability(t),r=n.resolve,i=n.reject,o=_perform(function(){var n=[],o=0,a=1;_forOf(e,!1,function(e){var s=o++,c=!1;n.push(void 0),a++,t.resolve(e).then(function(e){c||(c=!0,n[s]=e,--a||r(n))},i)}),--a||r(n)});return o.e&&i(o.v),n.promise},race:function(e){var t=this,n=newPromiseCapability(t),r=n.reject,i=_perform(function(){_forOf(e,!1,function(e){t.resolve(e).then(n.resolve,r)})});return i.e&&r(i.v),n.promise}});var pollingTime=750,maxPollingTime=15e3;function getRaven(){var e=Date.now();return new Promise(function(t,n){!function r(){if(!1===window.shouldSentrySample)n(new Error("Raven is not enabled"));else{var i=window.Raven;i?t(i):Date.now()-e>=maxPollingTime?n(new Error("Raven has not loaded")):setTimeout(r,pollingTime)}}()})}function stringifyPayload(e){var t=e;try{t=JSON.stringify(e)}catch(e){t="Unable to stringify payload"}return t}function startSentry(e){var t=[],n=e.subscribe("#.warn",function(e,n){var r=n.topic;t.push({topic:r,payload:stringifyPayload(e),level:"warning"})}),r=e.subscribe("#.error",function(e,n){var r=n.topic;t.push({topic:r,payload:stringifyPayload(e),level:"error"})});getRaven().then(function(e){e.setTagsContext({adsLibVersion:version});for(var n=function(t){var n=t.topic,r=t.payload,i=t.level;e.captureMessage(n,{level:i,tags:{topic:n},extra:{payload:r}})};t.length;)n(t.shift());t.push=n}).catch(function(){n(),r(),t=null})}var isEnum=_objectPie.f,_objectToArray=function(e){return function(t){for(var n,r=_toIobject(t),i=_objectKeys(r),o=i.length,a=0,s=[];o>a;)isEnum.call(r,n=i[a++])&&s.push(e?[n,r[n]]:r[n]);return s}},$values=_objectToArray(!1);function isPlainObject(e){return!!e&&e.constructor===Object}function concatUniques(e){if(!(e=e.filter(Array.isArray)).length)return[];var t=e.shift();return Array.from(new Set(t.concat.apply(t,e)))}function mergeBase(e,t,n,r){var i;return isPlainObject(t)?i=e.filter(function(e){return isPlainObject(e[n])}):Array.isArray(t)&&(i=e.filter(function(e){return Array.isArray(e[n])})),i&&i.length&&(t=merge(i.map(function(e){return e[n]}),r)),t}function merge(e,t){var n=e.filter(function(e){return!!e});if(n<2)return e[0];var r=concatUniques(n.filter(function(e){return!!e}).map(Object.keys)),i=n[0];return r.reduce(function(e,r){var i=n.filter(function(e){return void 0!==e[r]});if(t){for(var o=!1,a=i[0][r],s=1;s<i.length;s++){var c=t(a,i[s][r],r);void 0!==c&&(a=c,o=!0)}if(o)return e[r]=a,e}for(var u=n.length-1;u>=0;u--){var l=n[u][r];if(void 0!==l)return e[r]=mergeBase(n,l,r,t),e}return e},i)}function mergeViewportSizes(e,t){var n={};return Object.keys(e).forEach(function(r){if(n[r]=e[r]||[],t&&void 0!==t[r])if(!1===t[r]||!t[r]&&!1===e[r])n[r]=!1;else{n[r]=concatUniques([e[r],t[r]]);var i=n[r].filter(function(e){return e&&"-"===e[0]}),o=i.map(function(e){return e.slice(1)}),a=i.concat(o);n[r]=difference(n[r],a)}}),n}function mergeObjectsOfArrays(e){return concatUniques(e.map(Object.keys)).reduce(function(t,n){var r=e.map(function(e){return e[n]}).filter(Array.isArray);return r.length&&(t[n]=concatUniques(r)),t},{})}_export(_export.S,"Object",{values:function(e){return $values(e)}});var isRunningOnClient="undefined"!=typeof window;function isObject(e){return"object"==typeof e&&e.constructor===Object}function getRender(e){return pick(e,["desktop","tablet","mobile","constellation","slot"])}function stringToFunction(string){return eval("("+string+")")}function slotComplexRenderPreProcessor(e){Object.values(e||{}).forEach(function(e){isObject(e)&&e.every&&e.el&&(e.when&&(e.when=isRunningOnClient&&stringToFunction(e.when)||e.when.toString()),e.in&&e.in.el&&e.in.when&&(e.in.when=isRunningOnClient&&stringToFunction(e.in.when)||e.in.when.toString()))})}function slotComplexRenderProcessor(e){e&&(e.slot?slotComplexRenderPreProcessor(e.slot):Object.values(e).forEach(function(e){slotComplexRenderPreProcessor(e.slot)}))}function mergePlugins(e,t){return Object.keys(t).reduce(function(n,r){var i=merge([{},e[r],t[r]],function(e,t){if(!1!==e&&!0===t)return e});return i&&(n[r]=i),n},{})}function mergeSlotTypeDefinitions(e,t){return Object.keys(t).reduce(function(n,r){var i=mergeAdTechConfigs(e[r],t[r]);return i&&(n[r]=i),n},{})}var specialKeys={types:function(e,t){if(isObject(e))return mergeSlotTypeDefinitions(e,t)},groups:function(e,t){return e?isObject(e)?concatUniques([e,t]):void 0:t},targeting:function(e,t){return e?isObject(e)?mergeObjectsOfArrays([e,t]):void 0:t},position:function(e,t){return e?isObject(e)?mergeObjectsOfArrays([e,t]):void 0:t},content_type:function(e,t){return e?isObject(e)?mergeObjectsOfArrays([e,t]):void 0:t},sizes:function(e,t){if(isObject(e))return mergeViewportSizes(e,t)},render:function(e,t){return slotComplexRenderProcessor(e),slotComplexRenderProcessor(t),getRender(e?t||e:t)},plugins:mergePlugins};function adConfigMerger(e,t,n){var r;return specialKeys[n]?r=specialKeys[n](e,t):Array.isArray(e)&&Array.isArray(t)&&(r=t),r}function mergeAdTechConfigs(e,t){return merge([{},e,t],adConfigMerger)}var errorMessage$1="Ads -- Ad unit path generation error : ",matcher="[^A-Za-z0-9]";function dashSlugify(e){var t=new RegExp(matcher,"g");return e&&e.toString().toLowerCase().replace(t,"-").replace(/-+/g,"-").replace(/(^-|-$)/g,"")}function evalPath(fnString,options){try{var pathFn=eval("("+fnString+")");if("function"==typeof pathFn)return pathFn(options);error(errorMessage$1+" generation function is not a function")}catch(e){e(errorMessage$1+" generation function cannot be evaluated")}}function searchMap(e,t){return Object.keys(e).reduce(function(n,r){return find(e[r],function(e){return e===t})?r:n},!1)}function findCategory(e){var t=e.channel,n=t?dashSlugify(t):"misc";return"home"===n?"homepage":n}function findContentType(e){var t=get(e,"adUnit.map.contentType");t||error(errorMessage$1+" Content type map is missing in the config");var n=searchMap(t,e.templateType);return n||error(errorMessage$1+" contentType is undefined"),n}function buildAdUnitPath(e){var t=e.position,n=e.network,r=e.positionCount,i=e.contentType||findContentType(e),o=findCategory(e),a={network:n,position:t,category:o,contentType:i,instance:r};return set(window,"cns.adUnit.contentType",i),set(window,"cns.adUnit.category",o),evalPath(get(e,"adUnit.generatePath"),a)}function buildLegacyPath(e){return evalPath(get(e,"adUnit.generateLegacyPath"),e)}function buildOverridePath(e){return e.network+"/"+e.override.replace(/,/g,"/")}function slugifyChannels(e){var t=e.channel,n=e.subChannel;return{channel:dashSlugify(t)||"",subChannel:dashSlugify(n)||""}}function generatePathOptions(e,t){var n=e.positionCount,r=e.network,i=e.override,o=e.suffix,a=e.templateType,s=e.slotName,c=e.shouldUseLegacyPath,u=e.position,l=slugifyChannels(e),f=l.channel,d=l.subChannel;return{adUnit:t.adUnit,network:r,override:i,templateType:a,positionCount:n,shouldUseLegacyPath:c,slotName:s,channel:f,subChannel:d,suffix:o,contentType:t.contentType,position:u}}function getAdUnitPath(e,t){var n,r=generatePathOptions(e,t);return(n=r.override?buildOverridePath(r):r.shouldUseLegacyPath?buildLegacyPath(r):buildAdUnitPath(r))||error(errorMessage$1),debug(e.slotName+".adUnitPathGenerated",n),n}var _flags=function(){var e=_anObject(this),t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t};function decode(e){return decodeURIComponent(e.replace(/\+/g," "))}function querystring(e){for(var t,n=/([^=?&]+)=?([^&]*)/g,r={};t=n.exec(e);){var i=decode(t[1]),o=decode(t[2]);i in r||(r[i]=o)}return r}_descriptors&&"g"!=/./g.flags&&_objectDp.f(RegExp.prototype,"flags",{configurable:!0,get:_flags}),_fixReWks("search",1,function(e,t,n){return[function(n){var r=e(this),i=void 0==n?void 0:n[t];return void 0!==i?i.call(n,r):new RegExp(n)[t](String(r))},n]});var parse=querystring;function getFeatures(e){return e&&"string"==typeof e?e.split(",").reduce(function(e,t){return e[t]=!0,e},{}):{}}var queryParameters=parse(document.location.search)||{},featureFlags=getFeatures(queryParameters.feature_flags);featureFlags.ao_norefresh&&(window.cns.flags.shouldNotRefresh=!0);var SlotCounter=function(){var e={};this.next=function(t){e[t]=e[t]||0;var n=e[t];return e[t]++,n}},PositionCounter=function(){var e={};this.next=function(t){e[t]=e[t]||1;var n=e[t];return e[t]++,n}};function defineReadOnlyProperties(e,t){for(var n=Object.keys(t),r={},i=0;i<n.length;i++){var o=n[i];r[o]={value:t[o],writable:!1,enumerable:!0}}return Object.defineProperties(e,r)}function freeze(e){try{return Object.freeze(e)}catch(e){throw new Error('Must use "new" keyword to instantiate, must support Object.freeze.')}}function matchVariantPattern(e,t){var n=!1;return t.forEach(function(t){!n&&e[t]&&(n=e[t])}),n||e._default||e.__default}function getSpecificityPattern(e){var t=e.slug,n=e.channel,r=e.subChannel,i=e.templateType;return[t,n+"_"+r+"_"+i,n+"_"+i,""+i]}function getSlotNamesForPage(e,t){var n=getSpecificityPattern(e);return matchVariantPattern(get(t,"slot.sets"),n)}function getConfig(){return get(window,"cns.config.config")}function getBrandAdUnitId(){return get(getConfig(),"slot.__auid_one")}function getAdUnit(){var e=get(window,"cns.config.config.ad_unit")||{};return{generatePath:e.generate_path,generateLegacyPath:e.generate_legacy_path,map:{contentType:get(e,"map.content_type")}}}function getNetwork(){return get(window,"cns.config.config.network")}function getViewportRange(e,t,n){var r=getConfig()[n],i=r&&matchVariantPattern(r,e);return i&&i[t]||i||0}function getPathOverride(){return queryParameters&&queryParameters.ao_iu}function getVersoFlag(e){var t=get(e,"keywords.platform")||[];return!(!t.length||"verso"!==t[0])}function getOverrideVpRange(e,t){return get(t,"request_vp_range."+e)}function CompleteDefiner(e,t,n){var r=new SlotCounter,i=new PositionCounter,o=getSpecificityPattern(e),a=getConfig(),s=a.slot.types,c=getSlotNamesForPage(e,a),u=s._default||{},l={forChildren:"for_children",hasStaticRefreshSize:"static_refresh_size",canBeHidden:"can_be_hidden",shouldWaitForReact:"insert_after_react_ready",requiredTargeting:"required_targeting",isSticky:"is_sticky"};function f(e){var t=e.render;return t&&(t.slot||t[n]&&t[n].slot)}function d(e,t,r,i){e||warn("Invalid sizes: unable to define '"+r+"' on "+n+".",{definition:i,slotName:r}),t||warn("Invalid render: unable to define: '"+r+"' on "+n,{definition:i,slotName:r})}var g=freeze(c.reduce(function(e,r){var i=mergeAdTechConfigs(mergeAdTechConfigs(u,s[r]._default),function(e){var n=matchVariantPattern(s[e],o);return t?mergeAdTechConfigs(n,t):n}(r));return function(e,t,n){var r=t.sizes,i=r&&r[n]&&r[n].length,o=r&&!1===r[n],a=f(t),s=i&&!o;return!!t.isOutOfPage||(d(s,a,e,t),i&&!o&&a)}(r,i,n)&&(e[r]=freeze(i)),e},{})),p=freeze(Object.keys(g)),h=new function(){defineReadOnlyProperties(this,{slug:e.slug,server:e.server,keywords:e.keywords,channel:e.channel||"misc",subChannel:e.subChannel,device:n,templateType:e.templateType,contentType:e.contentType,forChildren:e[l.forChildren],slotNames:p,network:getNetwork(),brand:getBrandAdUnitId(),requestViewportRange:getViewportRange(o,n,"request_vp_range"),adUnit:getAdUnit(),isVerso:getVersoFlag(e)}),freeze(this)};function m(t){var o=g[t],a="cm"===o.suffix;function s(e,n){var o=this;e=void 0!==e?e:r.next(t),defineReadOnlyProperties(this,{id:t+"_"+e,slotCount:e,positionCount:n=void 0!==n?n:i.next(this.position)}),this.getAdUnitPath=function(){return getAdUnitPath(o,h)},freeze(this)}this.getRenderBlock=function(){return f(o)},this.getSizes=function(){return o.sizes[n]},this.getSizesArray=function(){return sizesToArray(o.sizes[n])},this.getSizeMapping=function(){return{desktop:sizesToArray(o.sizes.desktop),tablet:sizesToArray(o.sizes.tablet),mobile:sizesToArray(o.sizes.mobile)}},this.shouldWaitUntilVisibleBeforeDisplay=function(){var e=o[l.canBeHidden];return!a&&!e},this.getCustomData=function(){return o.data},this.isSticky=o.isSticky,s.prototype=this,this.getSlotDefinition=function(){return new s},this.getSlotDefinitionFromGPTSlot=function(e){var t=parseInt(e.getTargeting("pos_instance")[0],10);return new s(parseInt(e.getTargeting("ctx_slot_instance")[0],10),t)},defineReadOnlyProperties(this,{slotName:t,isCM:a,isOutOfPage:!!o.isOutOfPage,refresh:o.refresh,isSticky:o[l.isSticky],hasStaticRefreshSize:!!o[l.hasStaticRefreshSize],suffix:o.suffix,channel:e.channel,subChannel:e.subChannel,templateType:e.templateType,override:getPathOverride(),brand:getBrandAdUnitId(),network:getNetwork(),shouldUseLegacyPath:o.should_use_legacy_path,shouldWaitForReact:!!o[l.shouldWaitForReact],requiredTargeting:o[l.requiredTargeting]||[],position:o.position,overrideRequestViewportRange:getOverrideVpRange(n,o)}),freeze(this)}this.getSlotTypeDefinition=function(e){return new m(e)},this.getSlotDefinitionFromGPTSlot=function(e){var t=e.getSlotElementId().split("_");return t.pop(),new m(t.join("_")).getSlotDefinitionFromGPTSlot(e)},this.getPageDefinition=function(){return h},freeze(this)}var reactReadyEvent="react.ready";function onReactReady(){set(window,"_cne.pageCreated",!0)}function enableCNE(e){if(e.history(reactReadyEvent).length)return onReactReady();e.on(reactReadyEvent,onReactReady)}var es6_array_iterator=_iterDefine(Array,"Array",function(e,t){this._t=_toIobject(e),this._i=0,this._k=t},function(){var e=this._t,t=this._k,n=this._i++;return!e||n>=e.length?(this._t=void 0,_iterStep(1)):_iterStep(0,"keys"==t?n:"values"==t?e[n]:[n,e[n]])},"values");_iterators.Arguments=_iterators.Array,_addToUnscopables("keys"),_addToUnscopables("values"),_addToUnscopables("entries");for(var ITERATOR$4=_wks("iterator"),TO_STRING_TAG=_wks("toStringTag"),ArrayValues=_iterators.Array,DOMIterables={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},collections=_objectKeys(DOMIterables),i=0;i<collections.length;i++){var NAME$1=collections[i],explicit=DOMIterables[NAME$1],Collection=_global[NAME$1],proto=Collection&&Collection.prototype,key;if(proto&&(proto[ITERATOR$4]||_hide(proto,ITERATOR$4,ArrayValues),proto[TO_STRING_TAG]||_hide(proto,TO_STRING_TAG,NAME$1),_iterators[NAME$1]=ArrayValues,explicit))for(key in es6_array_iterator)proto[key]||_redefine(proto,key,es6_array_iterator[key],!0)}var fastdom=createCommonjsModule(function(e){!function(t){var n=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.msRequestAnimationFrame||function(e){return setTimeout(e,16)};function r(){this.reads=[],this.writes=[],this.raf=n.bind(t)}function i(e){e.scheduled||(e.scheduled=!0,e.raf(function(e){var t,n=e.writes,r=e.reads;try{o(r),o(n)}catch(e){t=e}if(e.scheduled=!1,(r.length||n.length)&&i(e),t){if(!e.catch)throw t;e.catch(t)}}.bind(null,e)))}function o(e){for(var t;t=e.shift();)t()}function a(e,t){var n=e.indexOf(t);return!!~n&&!!e.splice(n,1)}r.prototype={constructor:r,measure:function(e,t){var n=t?e.bind(t):e;return this.reads.push(n),i(this),n},mutate:function(e,t){var n=t?e.bind(t):e;return this.writes.push(n),i(this),n},clear:function(e){return a(this.reads,e)||a(this.writes,e)},extend:function(e){if("object"!=typeof e)throw new Error("expected object");var t=Object.create(this);return function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])}(t,e),t.fastdom=this,t.initialize&&t.initialize(),t},catch:null};var s=t.fastdom=t.fastdom||new r;e.exports=s}("undefined"!=typeof window?window:commonjsGlobal)}),eval2=eval;function getText(e){for(var t="",n=e.childNodes,r=0;r<n.length;r++){var i=n[r];8!==i.nodeType&&(t+=1!==i.nodeType?i.nodeValue:getText(i))}return t}function setMeta(e,t,n){var r=getText(n[t]);return{index:t,isOdd:!!(t%2),isEven:!(t%2),isFirst:0===t,isLast:t===e-1,characterCount:r.split("").length,wordCount:r.split(" ").length}}function isValidComplexInjection(e){return"string"==typeof e.el&&"number"==typeof e.every&&("object"==typeof e.in&&"string"==typeof e.in.el||"string"==typeof e.in)}var insertionMethodMap={top:"prepend",bottom:"append",after:"after"};function normalizeMethod(e){return insertionMethodMap[e]||e}var insertionMethods={before:function(e){return e.previousSibling},above:function(e){return e.previousSibling},after:function(e){return e.nextSibling},below:function(e){return e.nextSibling},prepend:function(e){return e.firstElementChild},append:function(e){return e.lastElementChild}};function getInsertionTarget(e,t){if(insertionMethods[t])return insertionMethods[t](e);console.error("unknown insertion method for getInsertionTarget",{el:e,method:t})}function alreadyExists(e,t){var n=getInsertionTarget(e,t),r=n&&n.classList&&n.classList.contains("cns-ads-stage"),i=n&&n.firstChild,o=i&&i.classList&&i.classList.contains("cns-ads-stage");return!(!r&&!o)}function checkEvery(e){var t=e.injectionBlock,n=e.index;return"number"==typeof t.every&&!!t.every&&"number"==typeof n}function checkCustomCondition(e){return"function"==typeof e.customConditionFn}var shouldAddSlotConditions=[{name:"every",check:checkEvery,fn:function(e){return(e.index+1)%e.injectionBlock.every==0}},{name:"custom condition",check:checkCustomCondition,fn:function(e){return(0,e.customConditionFn)(e.domNode,e.meta)}}];function shouldAddSlot(e){for(var t=0;t<shouldAddSlotConditions.length;t++){var n="shouldAddSlot."+shouldAddSlotConditions[t].name;if(shouldAddSlotConditions[t].check(e)){var r=void 0;try{r=shouldAddSlotConditions[t].fn(e)}catch(t){debug(n+".conditionThrew",{ex:t,facts:e})}if(!r)return debug(n+".conditionNotMet",e),r;debug(n+".conditionFalse",e)}else debug(n+".checkFailed",e)}return!0}function getParentSelector(e){return"string"==typeof e?e:e.el}function getEvalResult(e){if(e)try{return eval2("("+e+")")}catch(e){error("seriesInjection",e)}}function getDomNodesForInjectionBlock(e){var t=0,n=0,r=find$1(getParentSelector(e.in));if(!r)return[];for(var i=findAll(r,e.el),o=i.length,a=getEvalResult(e.when),s=[],c=0;c<o;c++){var u=i[c],l=setMeta(o,c,i);t+=l.characterCount,n+=l.wordCount,l.accumulatedCharacterCount=t,l.accumulatedWordCount=n,shouldAddSlot({index:c,domNode:u,meta:l,customConditionFn:a,injectionBlock:e})&&s.push(u)}return s}function getCandidateElementsFromRenderBlock(e){return Object.keys(e).reduce(function(t,n){var r,i=e[n];return"string"==typeof i?r=findAll(i):isValidComplexInjection(i)?r=getDomNodesForInjectionBlock(i):(r=[],error("invalid",i)),n=normalizeMethod(n),(r=r.filter(function(e){return!alreadyExists(e,n)}))&&r.length&&(t[n]=r),t},{})}var PromiseLock=function(){var e;return function(t){return function(){for(var n=arguments.length,r=new Array(n),i=0;i<n;i++)r[i]=arguments[i];if(e){var o=e.then(function(){return t.apply(void 0,r)});return e=o.then(function(){}),o}return e=t.apply(void 0,r)}}};function createContainerEl(e,t,n){var r=createElement("div",{id:e+"_"+t});return addClasses(r,["cns-ads-container"]),setStyle(r,{margin:"0px auto",boxSizing:"content-box"}),setElementData(r,{"ad-seq":t}),n&&setElementData(r,n),r}function createAdDivs(e,t,n,r){var i="cns-ads-slot-type-",o=e.replace(new RegExp("_","g"),"-").toLowerCase(),a=createElement("div",{id:""+i+o+"-"+t});return addClasses(a,["cns-ads-stage",i+o,i+o+"-"+t]),setElementData(a,{name:e+"_"+t,"slot-type":e}),r||setStyle(a,{fontSize:0,lineHeight:0,overflow:"hidden"}),"_out_of_page"===e&&addClasses(a,["cns-ads-slot-type-out-of-page"]),a.appendChild(createContainerEl(e,t,n)),a}function InjectRefreshDisplayInjectionStrategy(e,t,n,r){window.googletag=window.googletag||{};var i=window.googletag,o={after:function(e,t){return e.parentNode.insertBefore(t,e.nextSibling)},prepend:function(e,t){return e.insertBefore(t,e.children[0])},append:function(e,t){return e.appendChild(t)},before:function(e,t){return e.parentNode.insertBefore(t,e)}};this.insertSlot=function(a,s,c,u,l){fastdom.mutate(function(){var f=createAdDivs(s.slotName,s.slotCount,s.getCustomData(),r);!function(e,t,n){o[t]?o[t](e,n):e[t](n)}(c,u,f),l(f,s,function(){!function(r,o){var a=t.getSingleInstance().getPageDefinition();e(["refresh"],{slotDefinition:o,slot:r,pageDefinition:a},function(e){e?(applyTargeting(r,e),n.reset(o),i.pubads().refresh([r],{changeCorrelator:!1}),debug("refreshing."+r.getSlotElementId())):error("slot targeting is missing",a,o)})}(a,s)})})}}var allowedIntersectionOptions=["threshold","rootMargin"],defaultIntersectionObserverOptions={threshold:0,rootMargin:"0px 0px"},_ref=new EventEmitter("VisibilityObserver"),debug$1=_ref.debug,error$1=_ref.error;function isIntersecting(e){return any(e,function(e){return e.isIntersecting})}function hasHigherIntersectionRatio(e,t){return void 0===e||any(t,function(t){return t.intersectionRatio>=(e||0)})}function getIntersectionObserverOptions(e){return Object.assign({},defaultIntersectionObserverOptions,pick(e,allowedIntersectionOptions))}function observeEvents(e,t,n,r){fastdom.measure(function(){try{var i=new IntersectionObserver(function(r){hasHigherIntersectionRatio(t.intersectionRatio,r)&&isIntersecting(r)?(debug$1("visible",{el:e,entries:r}),n(!0,i)):(debug$1("notVisible",{el:e,entries:r}),n(!1,i))},getIntersectionObserverOptions(t));i.observe(e)}catch(e){r(e)}})}function onIntersection(e,t,n){observeEvents(e,t,function(e){return n(e)},function(e){return error$1("onIntersection",e)})}function onceVisible(e,t){return new Promise(function(n,r){observeEvents(e,t,function(e,t){e&&(n(),t.disconnect())},r)})}function reactRule(e,t){return!e||t}function targetingRule(e,t,n){var r=Object.keys(n),i=Object.keys(t);return all(e,function(e){return find(r,function(t){return t===e})||find(i,function(t){return t===e})})}function canRequest(e){var t=e.slotTypeDefinition,n=e.pageTargeting,r=e.slotTargeting,i=e.reactReady,o=!!r,a=targetingRule(t.requiredTargeting,r,n),s=reactRule(t.shouldWaitForReact,i),c=o&&a&&s;return debug("canRequest."+t.slotName+"."+c,{slotTypeDefinition:t,pageTargeting:n,slotTargeting:r,reactReady:i}),c}function UnassumingInsert(e,t,n,r){window.googletag=window.googletag||{};var i=window.googletag,o=t.withTargeting,a=r.getSingleInstance().getPageDefinition().isVerso,s=new InjectRefreshDisplayInjectionStrategy(o,r,n,a),c=!1;var u=(new PromiseLock)(function(e){var t=e.getSingleInstance().getPageDefinition();return o(["service"],{pageDefinition:t},function(n){if(n)return applyTargeting(i.pubads(),n),Promise.all(t.slotNames.map(function(r){var a,u,l,f,d=e.getSingleInstance().getSlotTypeDefinition(r);return u=function(e,r){return o(["slot"],{pageTargeting:n,slotTypeDefinition:d,reactReady:c,el:e},function(o){if(o)if(canRequest({slotTypeDefinition:d,pageTargeting:n,slotTargeting:o,reactReady:c})){var a,u=d.getSlotDefinition(),l=(a=u).isOutOfPage?i.defineOutOfPageSlot(a.getAdUnitPath(),a.id):i.defineSlot(a.getAdUnitPath(),a.getSizesArray(),a.id).defineSizeMapping(getSizeMapping(a));l?(l.addService(window.googletag.pubads()),applyTargeting(l,o),s.insertSlot(l,u,e,r,function(e,t){return function(n,r,o){var a=function(e){if(e.shouldWaitUntilVisibleBeforeDisplay())return onceVisible}(r),s=function(){var e=r.id;debug("insert.display",e),i.display(e),o()},c=e.requestViewportRange,u=t.overrideRequestViewportRange;if(a)return a(n,{rootMargin:(void 0!==u?u:c)+"px 0px"}).then(s);s()}}(t,d))):error("the slot cannot be defined",u,l)}else debug(d.slotName+".notRequestable",d,c,n,o);else error("slot type targeting is missing",t,d)})},f=(a=d).getRenderBlock(),l=getCandidateElementsFromRenderBlock(f),Promise.all(Object.keys(l).map(function(e){return debug("candidatesByMethod."+a.slotName,{method:e,els:l[e],definition:a}),Promise.all(l[e].map(function(t){return u(t,e)}))}))}));error("page targeting is missing",t)}).catch(handlePromiseError("insert error")).then(function(){return new Promise(function(e){return fastdom.mutate(function(){return setTimeout(e,1e3)})})}).catch(handlePromiseError("impossible mutate error"))});function l(t){i.pubadsReady?t():e.on("ads.pubadsReady",t)}function f(t){e.history("react.ready").length?t():e.on("react.ready",t)}f(function(){c=!0}),this.insert=function(e){l(function(){u(e)})},this.insertForReact=function(t){l(function(){f(function(){var n;u(t),n=debounce(function(){return u(t)},500),e.on("react.ready",n),e.on("#.componentDidMount.#",n),e.on("#.componentDidUpdate.#",n)})})}}var _stringContext=function(e,t,n){if(_isRegexp(t))throw TypeError("String#"+n+" doesn't accept regex!");return String(_defined(e))},MATCH$1=_wks("match"),_failsIsRegexp=function(e){var t=/./;try{"/./"[e](t)}catch(n){try{return t[MATCH$1]=!1,!"/./"[e](t)}catch(e){}}return!0},INCLUDES="includes";_export(_export.P+_export.F*_failsIsRegexp(INCLUDES),"String",{includes:function(e){return!!~_stringContext(this,e,INCLUDES).indexOf(e,arguments.length>1?arguments[1]:void 0)}});var always=function(){return!0};function LifecycleRegistrar(e){var t={};function n(e){return e&&"object"==typeof e&&"function"==typeof e.then}function r(e){var t={};e.unshift({});for(var n=0;n<e.length;n++){var r=e[n];if(!r)return!1;Object.assign(t,r)}return t}e.forEach(function(e){t[e]=[]}),this.register=function(n,r,i){if(i||(i=r,r=always),!e.includes(n))throw new Error(n+" not registered in LifeCycle");t[n].push({when:r,fn:i})},this.apply=function(e){for(var i=arguments.length,o=new Array(i>1?i-1:0),a=1;a<i;a++)o[a-1]=arguments[a];var s=[];e.forEach(function(e){t[e].forEach(function(e){var t=e.when,n=e.fn;t.apply(void 0,o)&&s.push(n)})});var c=s.map(function(e){return e.apply(void 0,o)});return any(c,n)?Promise.all(c).then(r):r(c)}}function clearTargetingByPrefix(e,t){e.forEach(function(e){e.getTargetingKeys().forEach(function(n){return 0===n.indexOf(t)&&e.clearTargeting(n)})})}function intersect(e,t){return void 0===e&&(e=[]),void 0===t&&(t=[]),e.filter(function(e){return t.indexOf(e)>-1})}function getSizesFromSlot(e){return e.getSizes(window.innerWidth,window.innerHeight).map(function(e){return e.getWidth()+"x"+e.getHeight()})}function getValidSizesFromSlot(e,t){return intersect(getSizesFromSlot(e),t)}function hasValidSize(e,t){return e.getSizes&&getValidSizesFromSlot(e,t).length>0}function createTimeOut(e,t,n){return n=n||"timed out",new Promise(function(r,i){var o,a=!1,s=function(e){return function(t){a||(a=!0,e(t))}},c=s(r),u=s(i);return setTimeout(function(){a||(o&&o(),u(new Error(n)))},t),e(c,u,function(e){return o=e})})}var marketName="amazon_match_buy",timeoutLength=1e3,validSizes=["300x250","300x600","320x50","300x50","728x90","970x250"],apstagConfig={pubID:"3035",adServer:"googletag",bidTimeout:1e3,deals:!0,params:{}};function AmazonMatchBuy(){var e=new EventEmitter(marketName),t=e.debug,n=e.warn;function r(e){return{slotID:e.getSlotElementId(),sizes:getValidSizesFromSlot(e,validSizes).map(function(e){return getSizeStringAsArray(e)})}}function i(e,t){window.apstag._Q.push([e,t])}window.apstag=window.apstag||{init:function(){i("i",arguments)},fetchBids:function(){i("f",arguments)},_Q:[]},apstagConfig.params.si_section=getPageContext(window).channel||"",window.apstag.init(apstagConfig),this.startAuction=function(e){return t("startAuction",e.map(function(e){return e.getSlotElementId()})),createTimeOut(function(i,o,a){var s=!1;a(function(){s=!0,t("timeout",e.map(function(e){return e.getSlotElementId()})),i(e.map(function(){return{}}))}),window.apstag.fetchBids({slots:e.map(r),bidTimeout:timeoutLength},function(r){try{s||(t("complete",r),window.apstag.setDisplayBids(),i(e.map(function(){return{}})))}catch(e){n("cannotHandleBidsBack",e),o(e)}})},timeoutLength)},this.isSlotEligible=function(e){return hasValidSize(e,validSizes)}}var timeoutLength$1=1e3,marketName$1="index_exchange",targetingPrefix="vnd_indx_",validSizes$1=["300x50","300x250","300x600","300x1050","320x50","728x90","970x90","970x250"];function IndexExchange(){var e=new EventEmitter(marketName$1).debug;function t(e){var t=getValidSizesFromSlot(e,validSizes$1),n=e.getSlotElementId();return{addTargeting:function(){},getMeta:function(){return{id:n,sizes:t}}}}function n(n){return createTimeOut(function(r,i,o){var a=!1;o(function(){e("timeout."+n.getSlotElementId(),n),a=!0,r({})}),window.headertag.condeFetchDemand(t(n),function(i,o){if(!a){var s=Object.keys(o).reduce(function(e,t){return e[targetingPrefix+t]=o[t],n.setTargeting(targetingPrefix+t,o[t]),e},{});e("complete."+n.getSlotElementId(),{bids:o,meta:t(n).getMeta(),targeting:s}),r({})}})},timeoutLength$1)}function r(e){return hasValidSize(e,validSizes$1)}window.headertag=window.headertag||{},window.headertag.cmd=window.headertag.cmd||[],window.headertag.cmd.push(setTimeout(function(){},0)),this.startAuction=function(t){return e("startAuction",t.map(function(e){return e.getSlotElementId()})),new Promise(function(e){return til(function(){return window.headertag.condeFetchDemand},function(){return e()})}).then(function(){clearTargetingByPrefix(t,targetingPrefix);var e=t.filter(r);return Promise.all(e.map(n))})},this.isSlotEligible=r}function collectPromises(e,t){var n=cumulativeArgumentDebounce(function(t){var n=[],r=[],i=[],o=function(e){return i.forEach(function(t){return t(e)})};t.forEach(function(e){r.push(e[0]),i.push(e[1]),n.push(e[2])}),e(n).then(function(e){return e?e.length!==n.length?o(new Error("collectPromises: Number of results must equal number of original items")):e.forEach(function(e,t){return r[t](e)}):r.forEach(function(e){return e()})}).catch(o)},t=t||0);return function(e){return new Promise(function(t,r){return n(function(e){t(e)},r,e)})}}function areAuctionsEnabled(){return!featureFlags.ads_disable_auctions}function isAuctionEnabled(e,t){return!!(e&&e.plugins||{})[t]}function createSlotAuctionEligible(e){return function(t){var n=t.slotDefinition,r=t.slot;return!get(window,"cns.flags.shouldNotAuction")&&!n.isOutOfPage&&!n.isCM&&e.isSlotEligible(r)}}function createStartAuction(e){return collectPromises(function(t){return e.startAuction(t.map(function(e){return e.slot}))})}var auctioneer={areAuctionsEnabled:areAuctionsEnabled,isAuctionEnabled:isAuctionEnabled,createSlotAuctionEligible:createSlotAuctionEligible,createStartAuction:createStartAuction},cookieCacheName="cn_4dsgcache",userData;function gatherNamesAndScores(e,t){var n=(get(window,e)||[]).map(function(e){return e[t]});return n.length&&n||""}function get4Dsg(e){var t=[],n="0";if(e){t=e;var r=new Date;r.setTime(r.getTime()+6048e5),document.cookie=cookieCacheName+"="+t.join(":")+"; expires="+r.toGMTString()+"; path=/"}else{var i=getCookie(cookieCacheName);i&&(t=i.split(":"),n="1")}return{sgData:t,isCached:n}}function get4DTargeting(){var e=window,t="_4d.context.keywords.list",n="_4d.context.entities",r="SparrowCache.event",i=get4Dsg(get(e,"_4d.user.sg"));return{vnd_4d_sg:i.sgData,vnd_4d_cached:i.isCached,vnd_4d_ctx_topics:gatherNamesAndScores(n,"name"),vnd_4d_ctx_topic_sc:gatherNamesAndScores(n,"score"),vnd_4d_ctx_entities:gatherNamesAndScores(n,"name"),vnd_4d_ctx_ent_sc:gatherNamesAndScores(n,"score"),vnd_4d_ctx_keywords:gatherNamesAndScores(t,"keyword"),vnd_4d_ctx_kw_sc:gatherNamesAndScores(t,"score"),vnd_4d_sid:get(e,r+".sID")||getCookie("sID"),vnd_4d_pid:get(e,r+".pID")||getCookie("pID"),vnd_4d_usr_topics:gatherNamesAndScores("_4d.user.topics","name"),vnd_4d_xid:getCookie("CN_xid")}}function getUserSegments(){var e=getCookie("CN_segments");return{usr_segments:e?e.split("|"):[]}}function getReferrer(e){var t=null,n=null,r=sessionStorage.getItem("ctx_ses_soc"),i={fb:"facebook.com",tw:"t.co",rd:"reddit.com",pn:"pinterest.com",ig:"instagram.com",glp:"plus.url.google.com",tbl:"t.umblr.com",qq:"qzone.qq.com",we:"weibo.com",hb:"habbo.com",vk:"vk.com",rr:"renren.com",or:"orkut.google.com",sn:"snapchat.com"};return Object.keys(i).forEach(function(o){var a=i[o];null!==e.match(a)&&(t=a,n=o,r=r||sessionStorage.setItem("ctx_ses_soc",o))}),{ctx_ses_soc:r,ctx_ref_soc:n,ctx_ref_url:t}}function isStorageEnabled(){try{return window.localStorage.setItem("testKey","1"),window.localStorage.removeItem("testKey"),!0}catch(e){return!1}}function checkDate(e,t){return t>e}function trimDate(e,t){return e?e.toString().split(",").filter(function(e){var n=parseInt(e,10);return checkDate(t,n)}):[]}function timeTravel(e,t){var n=new Date(e).getDate()-t;return new Date(e).setDate(n)}function getSessionData(){var e=(new Date).getTime(),t=timeTravel(e,1),n=timeTravel(e,30),r=parseInt(sessionStorage.getItem("session-visits"),10)||0;sessionStorage.setItem("session-visits",(r+1).toString());var i=sessionStorage.getItem("session-visits"),o=localStorage.getItem("session-visit-dates"),a=localStorage.getItem("total-visits");r||(o=o?o+","+e:e);var s=a?a+","+e:e,c=trimDate(s,t),u=trimDate(s,n),l=trimDate(o,n);return localStorage.setItem("total-visits",u.join(",")),localStorage.setItem("session-visit-dates",l.join(",")),{usr_pvc_bs:i,usr_pvc_24hr:c.length,usr_pvc_30d:u.length,usr_svc_30d:l.length}}function getUserBuckets(){var e=localStorage.getItem("usr_bkt_eva"),t=sessionStorage.getItem("usr_bkt_ses");return e||(e=Math.floor(100*Math.random())+1,localStorage.setItem("usr_bkt_eva",e)),t||(t=Math.floor(100*Math.random())+1,sessionStorage.setItem("usr_bkt_ses",t)),{usr_bkt_eva:e,usr_bkt_ses:t,usr_bkt_pv:Math.floor(100*Math.random())+1}}function getMediaBuy(){return{mbid:(parse(document.location.search)||{}).mbid}}function getUserAuth(){return{usr_auth:(!!getCookie("pay_ent_sub")||!!getCookie("ee_status")).toString()}}function resetUserData(){userData=!1}function getUserGid(){var e,t=getCookie("_ga");return new RegExp(/^GA1.2./).test(t)&&(e=t.split("GA1.2.")[1]),{usr_gid:e}}function getUserDataPageTargeting(){if(!isStorageEnabled())return{};if(userData)return userData;var e=document.referrer;return userData=Object.assign({},getUserBuckets(),getSessionData(),getReferrer(e),getMediaBuy(),getUserAuth(),getUserGid())}function AdobeAudienceManager(){function e(e,t){var n=t[0],r=t[1],i="vnd_aam_"+n.toLowerCase(),o=e[i]||[];return o.push(r),e[i]=o,e}this.getTargeting=function(){var t=getCookie("aamconde"),n=getCookie("aam_uuid"),r=t&&function(t){return decodeURIComponent(t).split(";").map(function(e){return e.split("=")}).reduce(e,{})}(t),i=n&&{vnd_aam_uuid:[decodeURIComponent(n)]};return Object.assign({},i,r)}}function Proximic(){this.getTargeting=function(){var e=get(window,"CN.ad.proximic.pxData.data");return e?{vnd_prx_segments:e}:{}}}function append(e){return new Promise(function(t,n){var r=document.createElement("script");["src","targ"].forEach(function(t){return!e[t]&&n(new Error("Missing required parameter: "+t))}),["src","targ","async","defer"].forEach(function(t){r[t]=e[t]}),r.onload=function(){t()},r.onerror=function(e){n(e)},e.targ.appendChild(r)})}function getArs(){var e,t=new EventEmitter("Ars").debug;function n(){var e=get(window,"CN.ad.arsaccelerator.kws")||[];return e.length?(t("is trending"),{vnd_ars_data:e}):(t("is not trending"),{})}return e=getPageContext(window).templateType.toLowerCase().indexOf("article")>-1,t("is "+(e?"":"not")+" eligible"),e?(set(window,"CN.ad.arsaccelerator",{}),append({src:"https://cdn.accelerator.arsdev.net/h/"+encodeURIComponent(window.location.href.split("?")[0]),targ:document.head,async:!0}).then(function(){return{getTargeting:n}})):Promise.resolve()}function fromCamelToSnake(e){return e.replace(/([a-z])([A-Z])/g,"$1_$2").toLowerCase()}function set$1(e,t,n){void 0===e[t]&&(e[t]=n)}function push(e,t,n){e[t]=e[t]||[],e[t].push(n)}function contains(e,t){return-1!==e.indexOf(t)}function startsWith(e,t){return e.slice(0,t.length)===t}function getTargeting(e,t,n,r){for(var i=r.el,o=e.length,a={},s=i;s;)1===s.nodeType&&function(){var r=s.dataset;Object.keys(r).forEach(function(i){var s=r[i];if(startsWith(i,e)&&"string"==typeof s){var c=fromCamelToSnake(i.slice(o)),u=contains(t,c)?s.split(","):s;contains(n,c)?push(a,c,u):set$1(a,c,u)}})}(),s=s.parentNode;return a}var invalidSpecialCharacters=new RegExp("[\"',=!#~;<>\\]+*^()[\\s]","g"),consecutiveUnderscores=/_+/g,consecutiveDashes=/-+/g,leadingTrailingUnderscores=/(^_|_$)/g,leadingTrailingDashes=/(^-|-$)/g,leadingNumbers=/^[0-9]/,allowedTypes=["string","number"],isAllowedType=function(e){return allowedTypes.indexOf(typeof e)>=0},isValidValue=function(e){return isAllowedType(e)};function toArray(e){return Array.isArray(e)?e:[e]}function isValidKey(e){return(e=e.toString().trim()).length&&!e.match(invalidSpecialCharacters)&&e.length<=20&&!e.match(leadingNumbers)}function applyGPTLimits(e){return e.toString().toLowerCase().replace(invalidSpecialCharacters,"_").replace(consecutiveUnderscores,"_").replace(leadingTrailingUnderscores,"")}function push$1(e,t,n){e[t]=e[t]||[],e[t].push(n)}function sanitizeWithDashes(e){return e.toString().toLowerCase().replace(invalidSpecialCharacters,"-").replace(consecutiveDashes,"-").replace(leadingTrailingDashes,"")}function sanitize(e){for(var t={},n={},r=Object.keys(e),i=0;i<r.length;i++){var o=r[i];if(isValidKey(o))for(var a=toArray(e[o]),s=0;s<a.length;s++){var c=a[s];isValidValue(c)?push$1(t,o,applyGPTLimits(c)):push$1(n,o,c)}else n[o]=e[o]}return{sanitized:t,errors:n}}function getAllKeywordTargeting(e){void 0===e&&(e={});var t={};return Object.keys(e).forEach(function(n){t["cnt_"+n]=e[n]}),t}function TargetingLifecycle(e,t){var n=new LifecycleRegistrar(["service","slot","refresh"]),r=new AdobeAudienceManager,i=new Proximic;function o(e){if(!1===e)return e;var t=sanitize(e),n=t.errors,r=t.sanitized;return n&&Object.keys(n).length&&debug("targetingSanitizationErrors",{errors:n,sanitized:r}),r}if(getArs().then(function(e){e&&n.register("service",e.getTargeting)}).catch(handlePromiseError("script failed to fetch")),n.register("service",function(e){var t=e.pageDefinition;return Object.assign({env_device_type:t.device,ctx_template:t.templateType,ctx_page_channel:sanitizeWithDashes(t.channel),ctx_page_sub_channel:t.subChannel,env_server:t.server,ctx_cns_version:version,ctx_page_slug:t.slug},getAllKeywordTargeting(t.keywords))}),n.register("service",t.getTargeting),n.register("service",getUserDataPageTargeting),n.register("service",r.getTargeting),n.register("service",i.getTargeting),n.register("service",getUserSegments),n.register("service",function(){var e={};if(queryParameters){var t=queryParameters.ao_test,n=queryParameters.service_targeting;if(t&&(e.ao_test=t.split(",")),n){var r=JSON.parse(n);Object.keys(r).forEach(function(t){e[t]=r[t]})}}return e}),n.register("service",get4DTargeting),n.register("slot",function(e){var t=e.slotTypeDefinition;return{pos:t.position,ctx_slot_type:t.slotName,ctx_slot_rn:0}}),n.register("slot",getTargeting.bind(null,"ads",["cnt_tags","cnt_cm"],[])),n.register("refresh",function(e){var t=e.slotDefinition;return{pos_instance:t.positionCount,ctx_slot_instance:t.slotCount,ctx_slot_name:t.id}}),auctioneer.areAuctionsEnabled()){if(auctioneer.isAuctionEnabled(e,"amazon_match_buy")){var a=new AmazonMatchBuy;n.register("refresh",auctioneer.createSlotAuctionEligible(a),auctioneer.createStartAuction(a))}if(auctioneer.isAuctionEnabled(e,"index_exchange")){var s=new IndexExchange;n.register("refresh",auctioneer.createSlotAuctionEligible(s),auctioneer.createStartAuction(s))}}this.register=n.register,this.withTargeting=function(e,t,r){return Promise.resolve(n.apply(e,t)).then(o).then(r)}}function UniqueTimerStore(){var e={};function t(t){var n=e[t];n&&(clearTimeout(n),e[t]=null)}this.startTimer=function(n,r,i){t(n),e[n]=setTimeout(function(){t(n),r()},i)},this.endTimer=t}function KeyCounter(){var e={};this.increment=function(t){e[t]||(e[t]=0),e[t]+=1},this.remove=function(t){e[t]&&delete e[t]},this.getCount=function(t){return e[t]||0}}function RefreshControl(e,t){var n=t.withTargeting,r=new EventEmitter("RefreshControl").debug,i=new KeyCounter,o=new KeyCounter,a=new Set,s=new Set,c=new Set,u=new UniqueTimerStore,l=3e4,f=[["aged",function(e){return a.has(e)}],["impressions",function(e){return o.getCount(e)}],["visible",function(e){return c.has(e)}]],d=function(e){return!Number.isNaN(parseFloat(e))},g=function(e){return e+".refresh_"+i.getCount(e)},p=function(t){return e.getSingleInstance().getSlotDefinitionFromGPTSlot(t)},h=function(){return e.getSingleInstance().getPageDefinition()},m=cumulativeArgumentDebounce(function(e){var t=uniq(e.map(function(e){return e[0]}));window.cns.flags.shouldNotRefresh?r("window.cns.flags.shouldNotRefresh"):(r("refreshing."+t.map(function(e){return g(e)}).join(",")),t.forEach(function(e){return y(p(getSlotById(e)))}),window.googletag.pubads().refresh(t.map(getSlotById),{changeCorrelator:!1}))},100);function v(e){r("onChange."+e+".("+f.map(function(t){return t[0]+":"+t[1](e)}).join(",")+")"),all(f,function(t){return t[1](e)})&&function(e){var t=h(),o=getSlotById(e),a=p(o);return r("setTargeting."+g(e)),o.setTargeting("ctx_slot_rn",i.getCount(e)),n(["refresh"],{pageDefinition:t,slotDefinition:a,slot:o},function(e){Object.keys(e).forEach(function(t){return o.setTargeting(t,e[t])})})}(e).then(function(){m(e)})}function _(e,t){var n;n=t,n=parseInt(n,10),t=d(n)&&n>l?n:l,u.startTimer(e,function(){a.add(e),v(e)},t),r("willRefreshIn."+e+"."+t)}function y(e){var t=e.id;o.remove(t),a.delete(t),_(t,e.refresh)}function b(e){return!e.isCM&&!e.isOutOfPage&&!window.cns.flags.shouldNotRefresh&&!1!==e.refresh}this.reset=function(e){b(e)?y(e):r("slotNotRefreshable."+e.id)},this.onSlotRenderEnded=function(e){var t=e.slot;i.increment(p(t).id)},this.onImpressionViewable=function(e){var t=e.slot.getSlotElementId();o.increment(t),r(t+".impressionIncremented"),v(t),b(p(e.slot))&&function(e){if(!s.has(e)){var t=getElementById(e);s.add(e),onIntersection(t,{},function(t){t?(c.add(e),v(e)):c.delete(e)})}}(t)},this.disableRefresh=function(e){u.endTimer(e)},this.delayRefresh=_}function ShareOfVoice(){var e=[],t=[],n=[];function r(e,t){t&&-1===e.indexOf(t)&&e.push(t)}this.getTargeting=function(){return{ctx_advertisers:e,ctx_line_items:t,ctx_creatives:n}},this.onSlotRenderEnded=function(i){var o=i.advertiserId,a=i.lineItemId,s=i.creativeId;r(e,o),r(t,a),r(n,s)}}function setSheet(){var e=document.createElement("style");return e.id="cns_version",e.appendChild(document.createTextNode("")),document.head.appendChild(e),e.sheet}function addCSSRule(e,t,n){return e.insertRule&&e.insertRule(t+"{"+n+"}",0)||e.addRule&&e.addRule(t,n,0)}function renderVersion(){var e='content: "ADS V:'+version+'";color:#fff;background-color:#f00;position:fixed;top:0;right:0;padding:4px 8px;z-index:2147483647;';addCSSRule(setSheet(),"body::after",e)}function cnsMetricsApi(){return function(e){e({emit:pixel})}}function CNSAdsAPI(e,t,n,r){function i(e){var t=e.device,n=void 0===t?"desktop":t,r=e.server,i=void 0===r?"staging":r;return new Promise(function(e,t){i&&n||t(),e()})}function o(){return!0===get(window,"cns.pageContext.adBlock")}function a(e,n){var r=e.frameElement.parentElement.parentElement.id;"number"==typeof n&&n>0?t.delayRefresh(r,n):t.disableRefresh(r)}function s(e){var t=window.cns.pageContext,i=new CompleteDefiner(Object.assign({},t,e),null,getViewportTemplate());n.reset(function(){return i}),r.insert(n)}function c(){resetUserData(),window.googletag.cmd.push(function(){window.googletag.pubads().clear(),window.googletag.destroySlots()}),fastdom.mutate(function(){for(var e=document.querySelectorAll(".cns-ads-stage"),t=0;t<e.length;t++)e[t].remove()})}function u(e){console.warn("AddSlot is deprecated. To render this slot "+e+" add it to the config's set using pageContext: "+window.cns.pageContext),r.insert(n)}this.executeCallback=function(e){e({environment:i,setRefreshFor:a,adBlock:{installed:deprecated(function(){},"adblock.installed"),blocked:deprecated(o,"adblock.blocked")},pages:{create:s,destroy:c,get:function(){return{slots:{add:deprecated(u,"slots.add"),get:deprecated(function(){},"slots.get"),refresh:deprecated(function(){},"slots.refresh"),destroy:deprecated(function(){},"slots.destroy")}}}}})}}function CNSShim(e,t,n,r){var i,o=new CNSAdsAPI(e,t,n,r);i={ads:o.executeCallback,metrics:cnsMetricsApi()},window.cns.async=function(e,t){i[e](t)},window.cns.queue.forEach(function(e){var t=e.service,n=e.callback;window.cns.async(t,n)}),delete window.cns.queue}function getConfig$1(e){return e.cns&&e.cns.config}function SourceOfTruth(e){var t;this.getSingleInstance=function(){return t||(t=e()),t},this.reset=function(n){t=n?n():e()}}_export(_export.S,"Number",{isNaN:function(e){return e!=e}});for(var TYPED=_uid("typed_array"),VIEW=_uid("view"),ABV=!(!_global.ArrayBuffer||!_global.DataView),CONSTR=ABV,i$1=0,l=9,Typed,TypedArrayConstructors="Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array".split(",");i$1<l;)(Typed=_global[TypedArrayConstructors[i$1++]])?(_hide(Typed.prototype,TYPED,!0),_hide(Typed.prototype,VIEW,!0)):CONSTR=!1;var _typed={ABV:ABV,CONSTR:CONSTR,TYPED:TYPED,VIEW:VIEW},_toIndex=function(e){if(void 0===e)return 0;var t=_toInteger(e),n=_toLength(t);if(t!==n)throw RangeError("Wrong length!");return n},hiddenKeys=_enumBugKeys.concat("length","prototype"),f$5=Object.getOwnPropertyNames||function(e){return _objectKeysInternal(e,hiddenKeys)},_objectGopn={f:f$5},_arrayFill=function(e){for(var t=_toObject(this),n=_toLength(t.length),r=arguments.length,i=_toAbsoluteIndex(r>1?arguments[1]:void 0,n),o=r>2?arguments[2]:void 0,a=void 0===o?n:_toAbsoluteIndex(o,n);a>i;)t[i++]=e;return t},_typedBuffer=createCommonjsModule(function(e,t){var n=_objectGopn.f,r=_objectDp.f,i="prototype",o="Wrong index!",a=_global.ArrayBuffer,s=_global.DataView,c=_global.Math,u=_global.RangeError,l=_global.Infinity,f=a,d=c.abs,g=c.pow,p=c.floor,h=c.log,m=c.LN2,v=_descriptors?"_b":"buffer",_=_descriptors?"_l":"byteLength",y=_descriptors?"_o":"byteOffset";function b(e,t,n){var r,i,o,a=new Array(n),s=8*n-t-1,c=(1<<s)-1,u=c>>1,f=23===t?g(2,-24)-g(2,-77):0,v=0,_=e<0||0===e&&1/e<0?1:0;for((e=d(e))!=e||e===l?(i=e!=e?1:0,r=c):(r=p(h(e)/m),e*(o=g(2,-r))<1&&(r--,o*=2),(e+=r+u>=1?f/o:f*g(2,1-u))*o>=2&&(r++,o/=2),r+u>=c?(i=0,r=c):r+u>=1?(i=(e*o-1)*g(2,t),r+=u):(i=e*g(2,u-1)*g(2,t),r=0));t>=8;a[v++]=255&i,i/=256,t-=8);for(r=r<<t|i,s+=t;s>0;a[v++]=255&r,r/=256,s-=8);return a[--v]|=128*_,a}function w(e,t,n){var r,i=8*n-t-1,o=(1<<i)-1,a=o>>1,s=i-7,c=n-1,u=e[c--],f=127&u;for(u>>=7;s>0;f=256*f+e[c],c--,s-=8);for(r=f&(1<<-s)-1,f>>=-s,s+=t;s>0;r=256*r+e[c],c--,s-=8);if(0===f)f=1-a;else{if(f===o)return r?NaN:u?-l:l;r+=g(2,t),f-=a}return(u?-1:1)*r*g(2,f-t)}function S(e){return e[3]<<24|e[2]<<16|e[1]<<8|e[0]}function T(e){return[255&e]}function E(e){return[255&e,e>>8&255]}function I(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]}function P(e){return b(e,52,8)}function x(e){return b(e,23,4)}function A(e,t,n){r(e[i],t,{get:function(){return this[n]}})}function O(e,t,n,r){var i=_toIndex(+n);if(i+t>e[_])throw u(o);var a=e[v]._b,s=i+e[y],c=a.slice(s,s+t);return r?c:c.reverse()}function C(e,t,n,r,i,a){var s=_toIndex(+n);if(s+t>e[_])throw u(o);for(var c=e[v]._b,l=s+e[y],f=r(+i),d=0;d<t;d++)c[l+d]=f[a?d:t-d-1]}if(_typed.ABV){if(!_fails(function(){a(1)})||!_fails(function(){new a(-1)})||_fails(function(){return new a,new a(1.5),new a(NaN),"ArrayBuffer"!=a.name})){for(var R,k=(a=function(e){return _anInstance(this,a),new f(_toIndex(e))})[i]=f[i],j=n(f),M=0;j.length>M;)(R=j[M++])in a||_hide(a,R,f[R]);_library||(k.constructor=a)}var D=new s(new a(2)),F=s[i].setInt8;D.setInt8(0,2147483648),D.setInt8(1,2147483649),!D.getInt8(0)&&D.getInt8(1)||_redefineAll(s[i],{setInt8:function(e,t){F.call(this,e,t<<24>>24)},setUint8:function(e,t){F.call(this,e,t<<24>>24)}},!0)}else a=function(e){_anInstance(this,a,"ArrayBuffer");var t=_toIndex(e);this._b=_arrayFill.call(new Array(t),0),this[_]=t},s=function(e,t,n){_anInstance(this,s,"DataView"),_anInstance(e,a,"DataView");var r=e[_],i=_toInteger(t);if(i<0||i>r)throw u("Wrong offset!");if(i+(n=void 0===n?r-i:_toLength(n))>r)throw u("Wrong length!");this[v]=e,this[y]=i,this[_]=n},_descriptors&&(A(a,"byteLength","_l"),A(s,"buffer","_b"),A(s,"byteLength","_l"),A(s,"byteOffset","_o")),_redefineAll(s[i],{getInt8:function(e){return O(this,1,e)[0]<<24>>24},getUint8:function(e){return O(this,1,e)[0]},getInt16:function(e){var t=O(this,2,e,arguments[1]);return(t[1]<<8|t[0])<<16>>16},getUint16:function(e){var t=O(this,2,e,arguments[1]);return t[1]<<8|t[0]},getInt32:function(e){return S(O(this,4,e,arguments[1]))},getUint32:function(e){return S(O(this,4,e,arguments[1]))>>>0},getFloat32:function(e){return w(O(this,4,e,arguments[1]),23,4)},getFloat64:function(e){return w(O(this,8,e,arguments[1]),52,8)},setInt8:function(e,t){C(this,1,e,T,t)},setUint8:function(e,t){C(this,1,e,T,t)},setInt16:function(e,t){C(this,2,e,E,t,arguments[2])},setUint16:function(e,t){C(this,2,e,E,t,arguments[2])},setInt32:function(e,t){C(this,4,e,I,t,arguments[2])},setUint32:function(e,t){C(this,4,e,I,t,arguments[2])},setFloat32:function(e,t){C(this,4,e,x,t,arguments[2])},setFloat64:function(e,t){C(this,8,e,P,t,arguments[2])}});_setToStringTag(a,"ArrayBuffer"),_setToStringTag(s,"DataView"),_hide(s[i],_typed.VIEW,!0),t.ArrayBuffer=a,t.DataView=s}),_isArray=Array.isArray||function(e){return"Array"==_cof(e)},SPECIES$2=_wks("species"),_arraySpeciesConstructor=function(e){var t;return _isArray(e)&&("function"!=typeof(t=e.constructor)||t!==Array&&!_isArray(t.prototype)||(t=void 0),_isObject(t)&&null===(t=t[SPECIES$2])&&(t=void 0)),void 0===t?Array:t},_arraySpeciesCreate=function(e,t){return new(_arraySpeciesConstructor(e))(t)},_arrayMethods=function(e,t){var n=1==e,r=2==e,i=3==e,o=4==e,a=6==e,s=5==e||a,c=t||_arraySpeciesCreate;return function(t,u,l){for(var f,d,g=_toObject(t),p=_iobject(g),h=_ctx(u,l,3),m=_toLength(p.length),v=0,_=n?c(t,m):r?c(t,0):void 0;m>v;v++)if((s||v in p)&&(d=h(f=p[v],v,g),e))if(n)_[v]=d;else if(d)switch(e){case 3:return!0;case 5:return f;case 6:return v;case 2:_.push(f)}else if(o)return!1;return a?-1:i||o?o:_}},_arrayCopyWithin=[].copyWithin||function(e,t){var n=_toObject(this),r=_toLength(n.length),i=_toAbsoluteIndex(e,r),o=_toAbsoluteIndex(t,r),a=arguments.length>2?arguments[2]:void 0,s=Math.min((void 0===a?r:_toAbsoluteIndex(a,r))-o,r-i),c=1;for(o<i&&i<o+s&&(c=-1,o+=s-1,i+=s-1);s-- >0;)o in n?n[i]=n[o]:delete n[i],i+=c,o+=c;return n},_typedArray=createCommonjsModule(function(e){if(_descriptors){var t=_library,n=_global,r=_fails,i=_export,o=_typed,a=_typedBuffer,s=_ctx,c=_anInstance,u=_propertyDesc,l=_hide,f=_redefineAll,d=_toInteger,g=_toLength,p=_toIndex,h=_toAbsoluteIndex,m=_toPrimitive,v=_has,_=_classof,y=_isObject,b=_toObject,w=_isArrayIter,S=_objectCreate,T=_objectGpo,E=_objectGopn.f,I=core_getIteratorMethod,P=_uid,x=_wks,A=_arrayMethods,O=_arrayIncludes,C=_speciesConstructor,R=es6_array_iterator,k=_iterators,j=_iterDetect,M=_setSpecies,D=_arrayFill,F=_arrayCopyWithin,N=_objectDp,$=_objectGopd,V=N.f,L=$.f,z=n.RangeError,U=n.TypeError,B=n.Uint8Array,q=Array.prototype,G=a.ArrayBuffer,W=a.DataView,K=A(0),H=A(2),Y=A(3),J=A(4),Z=A(5),Q=A(6),X=O(!0),ee=O(!1),te=R.values,ne=R.keys,re=R.entries,ie=q.lastIndexOf,oe=q.reduce,ae=q.reduceRight,se=q.join,ce=q.sort,ue=q.slice,le=q.toString,fe=q.toLocaleString,de=x("iterator"),ge=x("toStringTag"),pe=P("typed_constructor"),he=P("def_constructor"),me=o.CONSTR,ve=o.TYPED,_e=o.VIEW,ye=A(1,function(e,t){return Ee(C(e,e[he]),t)}),be=r(function(){return 1===new B(new Uint16Array([1]).buffer)[0]}),we=!!B&&!!B.prototype.set&&r(function(){new B(1).set({})}),Se=function(e,t){var n=d(e);if(n<0||n%t)throw z("Wrong offset!");return n},Te=function(e){if(y(e)&&ve in e)return e;throw U(e+" is not a typed array!")},Ee=function(e,t){if(!(y(e)&&pe in e))throw U("It is not a typed array constructor!");return new e(t)},Ie=function(e,t){return Pe(C(e,e[he]),t)},Pe=function(e,t){for(var n=0,r=t.length,i=Ee(e,r);r>n;)i[n]=t[n++];return i},xe=function(e,t,n){V(e,t,{get:function(){return this._d[n]}})},Ae=function(e){var t,n,r,i,o,a,c=b(e),u=arguments.length,l=u>1?arguments[1]:void 0,f=void 0!==l,d=I(c);if(void 0!=d&&!w(d)){for(a=d.call(c),r=[],t=0;!(o=a.next()).done;t++)r.push(o.value);c=r}for(f&&u>2&&(l=s(l,arguments[2],2)),t=0,n=g(c.length),i=Ee(this,n);n>t;t++)i[t]=f?l(c[t],t):c[t];return i},Oe=function(){for(var e=0,t=arguments.length,n=Ee(this,t);t>e;)n[e]=arguments[e++];return n},Ce=!!B&&r(function(){fe.call(new B(1))}),Re=function(){return fe.apply(Ce?ue.call(Te(this)):Te(this),arguments)},ke={copyWithin:function(e,t){return F.call(Te(this),e,t,arguments.length>2?arguments[2]:void 0)},every:function(e){return J(Te(this),e,arguments.length>1?arguments[1]:void 0)},fill:function(e){return D.apply(Te(this),arguments)},filter:function(e){return Ie(this,H(Te(this),e,arguments.length>1?arguments[1]:void 0))},find:function(e){return Z(Te(this),e,arguments.length>1?arguments[1]:void 0)},findIndex:function(e){return Q(Te(this),e,arguments.length>1?arguments[1]:void 0)},forEach:function(e){K(Te(this),e,arguments.length>1?arguments[1]:void 0)},indexOf:function(e){return ee(Te(this),e,arguments.length>1?arguments[1]:void 0)},includes:function(e){return X(Te(this),e,arguments.length>1?arguments[1]:void 0)},join:function(e){return se.apply(Te(this),arguments)},lastIndexOf:function(e){return ie.apply(Te(this),arguments)},map:function(e){return ye(Te(this),e,arguments.length>1?arguments[1]:void 0)},reduce:function(e){return oe.apply(Te(this),arguments)},reduceRight:function(e){return ae.apply(Te(this),arguments)},reverse:function(){for(var e,t=Te(this).length,n=Math.floor(t/2),r=0;r<n;)e=this[r],this[r++]=this[--t],this[t]=e;return this},some:function(e){return Y(Te(this),e,arguments.length>1?arguments[1]:void 0)},sort:function(e){return ce.call(Te(this),e)},subarray:function(e,t){var n=Te(this),r=n.length,i=h(e,r);return new(C(n,n[he]))(n.buffer,n.byteOffset+i*n.BYTES_PER_ELEMENT,g((void 0===t?r:h(t,r))-i))}},je=function(e,t){return Ie(this,ue.call(Te(this),e,t))},Me=function(e){Te(this);var t=Se(arguments[1],1),n=this.length,r=b(e),i=g(r.length),o=0;if(i+t>n)throw z("Wrong length!");for(;o<i;)this[t+o]=r[o++]},De={entries:function(){return re.call(Te(this))},keys:function(){return ne.call(Te(this))},values:function(){return te.call(Te(this))}},Fe=function(e,t){return y(e)&&e[ve]&&"symbol"!=typeof t&&t in e&&String(+t)==String(t)},Ne=function(e,t){return Fe(e,t=m(t,!0))?u(2,e[t]):L(e,t)},$e=function(e,t,n){return!(Fe(e,t=m(t,!0))&&y(n)&&v(n,"value"))||v(n,"get")||v(n,"set")||n.configurable||v(n,"writable")&&!n.writable||v(n,"enumerable")&&!n.enumerable?V(e,t,n):(e[t]=n.value,e)};me||($.f=Ne,N.f=$e),i(i.S+i.F*!me,"Object",{getOwnPropertyDescriptor:Ne,defineProperty:$e}),r(function(){le.call({})})&&(le=fe=function(){return se.call(this)});var Ve=f({},ke);f(Ve,De),l(Ve,de,De.values),f(Ve,{slice:je,set:Me,constructor:function(){},toString:le,toLocaleString:Re}),xe(Ve,"buffer","b"),xe(Ve,"byteOffset","o"),xe(Ve,"byteLength","l"),xe(Ve,"length","e"),V(Ve,ge,{get:function(){return this[ve]}}),e.exports=function(e,a,s,u){var f=e+((u=!!u)?"Clamped":"")+"Array",d="get"+e,h="set"+e,m=n[f],v=m||{},b=m&&T(m),w=!m||!o.ABV,I={},P=m&&m.prototype,x=function(e,t){V(e,t,{get:function(){return function(e,t){var n=e._d;return n.v[d](t*a+n.o,be)}(this,t)},set:function(e){return function(e,t,n){var r=e._d;u&&(n=(n=Math.round(n))<0?0:n>255?255:255&n),r.v[h](t*a+r.o,n,be)}(this,t,e)},enumerable:!0})};w?(m=s(function(e,t,n,r){c(e,m,f,"_d");var i,o,s,u,d=0,h=0;if(y(t)){if(!(t instanceof G||"ArrayBuffer"==(u=_(t))||"SharedArrayBuffer"==u))return ve in t?Pe(m,t):Ae.call(m,t);i=t,h=Se(n,a);var v=t.byteLength;if(void 0===r){if(v%a)throw z("Wrong length!");if((o=v-h)<0)throw z("Wrong length!")}else if((o=g(r)*a)+h>v)throw z("Wrong length!");s=o/a}else s=p(t),i=new G(o=s*a);for(l(e,"_d",{b:i,o:h,l:o,e:s,v:new W(i)});d<s;)x(e,d++)}),P=m.prototype=S(Ve),l(P,"constructor",m)):r(function(){m(1)})&&r(function(){new m(-1)})&&j(function(e){new m,new m(null),new m(1.5),new m(e)},!0)||(m=s(function(e,t,n,r){var i;return c(e,m,f),y(t)?t instanceof G||"ArrayBuffer"==(i=_(t))||"SharedArrayBuffer"==i?void 0!==r?new v(t,Se(n,a),r):void 0!==n?new v(t,Se(n,a)):new v(t):ve in t?Pe(m,t):Ae.call(m,t):new v(p(t))}),K(b!==Function.prototype?E(v).concat(E(b)):E(v),function(e){e in m||l(m,e,v[e])}),m.prototype=P,t||(P.constructor=m));var A=P[de],O=!!A&&("values"==A.name||void 0==A.name),C=De.values;l(m,pe,!0),l(P,ve,f),l(P,_e,!0),l(P,he,m),(u?new m(1)[ge]==f:ge in P)||V(P,ge,{get:function(){return f}}),I[f]=m,i(i.G+i.W+i.F*(m!=v),I),i(i.S,f,{BYTES_PER_ELEMENT:a}),i(i.S+i.F*r(function(){v.of.call(m,1)}),f,{from:Ae,of:Oe}),"BYTES_PER_ELEMENT"in P||l(P,"BYTES_PER_ELEMENT",a),i(i.P,f,ke),M(f),i(i.P+i.F*we,f,{set:Me}),i(i.P+i.F*!O,f,De),t||P.toString==le||(P.toString=le),i(i.P+i.F*r(function(){new m(1).slice()}),f,{slice:je}),i(i.P+i.F*(r(function(){return[1,2].toLocaleString()!=new m([1,2]).toLocaleString()})||!r(function(){P.toLocaleString.call([1,2])})),f,{toLocaleString:Re}),k[f]=O?A:C,t||O||l(P,de,C)}}else e.exports=function(){}});function generate(e,t){var n,r=window.crypto||window.msCrypto;n=r?function(e){return r.getRandomValues(new Uint8Array(e))}:function(e){for(var t=[],n=0;n<e;n++)t.push(Math.floor(254*Math.random()));return t};for(var i=(2<<Math.log(e.length-1)/Math.LN2)-1,o=Math.ceil(1.6*i*t/e.length),a="";a.length<t;)for(var s=n(o),c=0;c<o;c++){var u=s[c]&i;if(e[u]&&(a+=e[u]).length===t)return a}}_typedArray("Uint8",1,function(e){return function(t,n,r){return e(this,t,n,r)}});var runtimeId=generate("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",13),cns=window.cns;function about(){return{buildDate:cns.buildDate,fastAdsHead:cns.fastAdsHead,fastAdsFooter:cns.fastAdsFooter,runtimeId:queryParameters.runtimeId||runtimeId}}function attachListeners(e,t){var n=getConfig$1(window),r=new ShareOfVoice,i=new TargetingLifecycle(n,r),o=new RefreshControl(t,i),a=new UnassumingInsert(e,i,o,t);new CNSShim(e,o,t,a),new GPTRouter(t,o,r,e),emitBoomPixel("adsReady"),cns.addTargeting=i.register,AdBlockDetect(e),featureFlags.ads_debug_outline&&debugStyles(),startSentry(e),a.insert(t),a.insertForReact(t)}function startFooter(){var e=window.cnBus;featureFlags.show_version&&renderVersion(),addDefaultSubscriptions(e,featureFlags.bus_log),"info"===queryParameters.ao_tools&&append({src:"https://ad-tools.condenastdigital.com/ads-"+queryParameters.ao_tools+"/prod/index.js",targ:document.head}),queryParameters.ap_noads||hasPII()||til(function(){return cns.pageContext},function(){var t=new SourceOfTruth(function(){var e=getViewportTemplate();return new CompleteDefiner(getPageContext(window),null,e)});attachListeners(e,t),enableCNE(e)})}set(window,"cns.buildDate",getConfig$1(window).buildDate),set(window,"cns.fastAdsFooter",version),set(window,"cns.runtimeId",queryParameters.runtimeId||runtimeId),set(window,"cns.about",about),set(window,"cns.timing.footerStart",Date.now()),startFooter()}();
  </script>
  <script>
   (function(){
    var w = window;
    w.CN = w.CN || {};
    w.CN.ad = w.CN.ad || {};
    w.CN.ad.proximic = {};

    var s = document.createElement('script');
    s.src = 'https://segment-data.zqtk.net/conde-nast?url=' + encodeURIComponent(window.location.href);
    s.defer = true;
    document.head.appendChild(s);
  })();
  </script>
  <iframe height="0" scrolling="no" src="https://js-sec.indexww.com/um/ixmatch.html" style="display: none;" width="0">
  </iframe>
  <script async="" src="/hotzones/src/pixelpropagate.js?cb=1099">
  </script>
  <script>
   (function userSegments(doc) {
  function addScript(src) {
    var s = document.createElement('script');
    s.src = src;
    s.async = true;
    document.body.appendChild(s);
  }

  addScript('/user-context?referrer=' + encodeURIComponent(document.referrer) + '&verso=false');
})(document)
  </script>
  <script id="cne-interlude-script">
   (function insertInterlude(brand, domain) {
    if (window.CN_STACK_TEMP === 'verso') {
      return;
    }

    var src = 'https://' + domain + '/interlude/' + brand + '.js';

    var s = document.createElement('script');
    s.src = src;
    s.async = true;
    document.head.appendChild(s);
  })('epicurious', 'player.cnevids.com');
  </script>
  <script async="" id="conde-polar" src="https://cdn.mediavoice.com/nativeads/script/condenastcorporate/conde-asa-polar-master.js">
  </script>
  <script>
   (function() {
function DQ() {
  var queue = window.sparrowQueue;
  this.push = fn => fn();
  window.sparrowQueue = this;
  while (queue.length) {
    queue.shift()();
  }
}
function e(t, e) {
  var n, a, o;
  a = !1, n = document.createElement("script"), n.type = "text/javascript", n.src = t, n.onload = n.onreadystatechange = function() {
    a || this.readyState && "complete" != this.readyState || (a = !0, e ? e() : !0)
  }, o = document.getElementsByTagName("script")[0], o.parentNode.insertBefore(n, o)
}
if(location.search.indexOf('no_sparrow')<0){
e("https://pixel.condenastdigital.com/config/v2/production/epicurious.config.js", function() {
  e("https://pixel.condenastdigital.com/sparrow.min.js", function() { 
    if (window.SparrowConfigV2) {
      window.sparrow = new window.Sparrow(window.SparrowConfigV2); 
      new DQ();
    }
  })
})}
})()
  </script>
  <!-- START Parse.ly Include: Async -->
  <div id="parsely-root" style="display: none">
   <a data-parsely-site="epicurious.com" href="https://parsely.com" id="parsely-cfg">
    Powered by the Parse.ly Publisher Platform (P3).
   </a>
  </div>
  <script type="text/javascript">
   (function(w, d, s) {
      function go() {
          var js,
              fjs = d.getElementsByTagName(s)[0],
              load = function(url, id, opts) {
                  if (d.getElementById(id)) {return;}
                  js = d.createElement(s);
                  js.src = url;
                  js.id = id;
                  if (opts && opts.divId) {
                      document.getElementById(opts.divId).appendChild(js);
                  } else {
                      fjs.parentNode.insertBefore(js, fjs);
                  }
              };
          load('https://d1z2jf7jlzjs58.cloudfront.net/p.js', 'parsely', { divId : 'parsely-root'});
      }
      go();
  }(window, document, 'script'));
  </script>
  <!-- END Parse.ly Include: Async -->
  <script type="text/javascript">
   if (document.querySelectorAll('.embed-instagram').length > 0) {
      EPI.onCompleteActions.push(function () {
        var script = document.createElement('script');
        script.async = true;
        script.defer = true;
        script.src = "https://platform.instagram.com/en_US/embeds.js";
        document.getElementsByTagName('head')[0].appendChild(script);
      });
    }

    if (document.querySelectorAll('.embed-twitter').length > 0) {
      EPI.onCompleteActions.push(function () {
        var script = document.createElement('script');
        script.async = true;
        script.defer = true;
        script.src = "https://platform.twitter.com/widgets.js";
        document.getElementsByTagName('head')[0].appendChild(script);
      });
    }

    if (document.querySelectorAll('body.recipe-detail, body.article, body.gallery-page').length) {
      EPI.onCompleteActions.push(function () {
        var script = document.createElement('script');
        script.async = true;
        script.defer = true;
        script.src = "https://wms.assoc-amazon.com/20070822/US/js/auto-tagger.js?tag=epicuriousfig-20&locale=US&overwrite=Y";
        document.getElementsByTagName('head')[0].appendChild(script);
      });
    }

    if (document.querySelectorAll('.fb-video').length > 0) {
      window.fbAsyncInit = function () {
        FB.init({
          appId      : '1636080783276430',
          xfbml      : true,
          version    : 'v2.10'
        });
      };

      EPI.onCompleteActions.push(function () {
        (function (d, s, id) {
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s); js.id = id;
        js.src = "https://connect.facebook.net/en_US/sdk.js";
        fjs.parentNode.insertBefore(js, fjs);
        }(document, 'script', 'facebook-jssdk'));
      });
    }
  </script>
  <div id="amzn-assoc-ad-b564d740-ff5e-49fe-bf49-faf18447a2e4">
  </div>
  <script async="" src="//z-na.amazon-adsystem.com/widgets/onejs?MarketPlace=US&amp;adInstanceId=b564d740-ff5e-49fe-bf49-faf18447a2e4">
  </script>
  <script>
   (function (root) {
/* -- Data -- */
root.__INITIAL_STATE__ || (root.__INITIAL_STATE__ = {});
root.__INITIAL_STATE__.config = {"ads":{"google":{"googleTagManagerId":"GTM-PCTXLQR"}},"cookieDomain":".epicurious.com","endpoints":{"contextual":"\u002Fapi\u002Fdataintelligence\u002Fv1\u002Fcontent\u002Frecommended","rotd":"\u002Fapi\u002Fcontent\u002Fv1\u002Frotd\u002Fcount\u002F1"},"env":"PROD","facebook":{"appId":"1636080783276430"},"https":"true","media":{"bp":{"xs":0,"s":600,"m":768,"l":1024,"xl":1360,"w":1710}},"newsletters":{"current":[{"description":"Become a better cook instantly with this weekly report of our ten most helpful tips, tricks, and kitchen secrets. Don't miss it!","id":"5","name":"The Top Ten"},{"description":"Love recipes, but hate searching? We do the work for you. You'll get our favorite seasonal recipe plus collections of our exclusive editors' picks.","id":"5117","name":"Cook This Now"},{"description":"Get a daily dose of the hottest recipes from Epicurious, Bon Appétit, and other great sites.","id":"195169","name":"Trending Recipes"},{"id":"248781","name":"Announcements"},{"id":"248789","name":"Cook 90"},{"id":"248818","name":"Diabetes Friendly"},{"id":"248842","name":"Small Plates"},{"id":"248886","name":"Well Equipped"}]},"server":"https:\u002F\u002Fwww.epicurious.com","services":{"endpoints":{"articles":{"latest":"\u002Fapi\u002Fsearch\u002Fv1\u002Fquery?size=20&content=article&sort=newest&q="},"branded":{"article":"\u002Fapi\u002Fbranded\u002Fv1\u002Farticle\u002F:brandCode\u002F:slug"},"content":{"channel":"\u002Fapi\u002Fcontent\u002Fv1\u002Fchannel\u002F","component":"\u002Fapi\u002Fcontent\u002Fv1\u002Fcomponent","contextual":"\u002Fapi\u002Fdataintelligence\u002Fv1\u002Fcontent\u002Frecommended","featuredIn":"\u002Fapi\u002Fcontent\u002Fv1\u002Ffeaturedin\u002F","homepage":"\u002Fapi\u002Fcontent\u002Fv1\u002Fhomepage","latestRecipes":"\u002Fapi\u002Fcontent\u002Fv1\u002Fcomponent\u002Flatestrecipes","memberLookup":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002F","navItems":"\u002Fapi\u002Fcontent\u002Fv1\u002Fcomponent\u002Fnavitems","nutritionalInfo":"\u002Fapi\u002Fnutritiondata\u002Fv2\u002F","reviews":"\u002Fapi\u002Frecipes\u002Fv2\u002F","reviewsFeed":"\u002Fapi\u002Frecipes\u002Fv3\u002F","reviewsSuffix":"\u002Freviews","reviewsFeedSuffix":"\u002Freviews\u002Ffeed","rotd":"\u002Fapi\u002Fcontent\u002Fv1\u002Frotd\u002Fcount\u002F1","search":"\u002Fapi\u002Fcontent\u002Fv1\u002Fsearch","videoSearchByKeywords":"\u002Fapi\u002Fvideo\u002Fv1\u002Fkeywords\u002F"},"contributors":{"details":"\u002Fapi\u002Fcontributors\u002Fv1\u002F:contributor\u002Fbundle","feed":"\u002Fapi\u002Fcontributors\u002Fv1\u002F:contributor\u002Ffeed"},"cookbooks":{"details":"\u002Fapi\u002Fcookbooks\u002Fv1\u002F:slug","index":"\u002Fapi\u002Fcookbooks\u002Fv1"},"menus":{"details":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Fmenus\u002F:menuId","index":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Fmenus"},"photos":{"instagramPosts":"\u002Fapi\u002Finstagram\u002Fv1","menuCover":"\u002Fapi\u002Fphotos\u002Fv1\u002Fmenu-cover","searchCard":"\u002Fapi\u002Fphotos\u002Fv1\u002Fsearch-card","searchUtility":"\u002Fapi\u002Fphotos\u002Fv1\u002Fsearch-utility"},"recipeBox":{"search":"\u002Fapi\u002Frecipe-box\u002Fv1\u002F:userId\u002Fsearch\u002F:term"},"recipes":{"byKeywords":"\u002Fapi\u002Frecipes\u002Fv2\u002Fkeywords\u002F","byKeywordsForMenus":"\u002Fapi\u002Fmenus\u002Fv1\u002Fkeywords\u002F","latest":"\u002Fapi\u002Frecipes\u002Fv2\u002Flatest"},"search":{"details":"\u002Fapi\u002Frecipes\u002Fv3\u002Fdetail","facets":"\u002Fapi\u002Fsearch\u002Fv1\u002Ffacets","query":"\u002Fapi\u002Fsearch\u002Fv1\u002Fquery","suggest":"\u002Fapi\u002Fsearch\u002Fv1\u002Fsuggest"},"users":{"authenticate":"\u002Fapi\u002Fusers\u002Fv2\u002Fauthenticate","info":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002F:uuid","newsletterSubscriptions":"\u002Fapi\u002Fnewsletters\u002Fv1\u002Fsubscription\u002F:email","recipeBoxSearch":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Frecipe-box\u002Fsearch\u002F:query","recipes":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Frecipes","reviews":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Freviews","updateEmail":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002Femail","updatePassword":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002Fpassword","updateUsername":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002Fdisplayname","updateSettings":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser"}}},"servicesHost":"https:\u002F\u002Fservices.epicurious.com","simpleReach":{"pid":"570d6b7d736b79bf1d000d27"},"user":{"cookies":{"keys":{"id":"amg_user_partner","username":"amg_user_info"},"names":["amg_user_ext","amg_user_info","amg_user_partner","amg_user_update","cn_uid","CN_userAuth"]},"email":{"regExp":/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i},"password":{"regExp":/^[a-zA-Z0-9!"\#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~][a-zA-Z0-9 !"\#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]{4,253}[a-zA-Z0-9!"\#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]$/,"messages":{"requirements":"A password must be at least 6 characters long. It cannot begin or end with a space."}},"serviceKey":"NtibqP3y1qSJM\u002FGsy3blJgNWt\u002Fo=","serviceHost":"https:\u002F\u002Fuser-service.condenastdigital.com"},"userServiceHost":"https:\u002F\u002Fuser-service.condenastdigital.com","userServiceKey":"NtibqP3y1qSJM\u002FGsy3blJgNWt\u002Fo=","vulcan":{"host":"https:\u002F\u002Fassets.epicurious.com","path":"\u002Fphotos\u002F"}};
root.__INITIAL_STATE__.siteHeader = {"config":{"ads":{"google":{"googleTagManagerId":"GTM-PCTXLQR"}},"cookieDomain":".epicurious.com","endpoints":{"contextual":"\u002Fapi\u002Fdataintelligence\u002Fv1\u002Fcontent\u002Frecommended","rotd":"\u002Fapi\u002Fcontent\u002Fv1\u002Frotd\u002Fcount\u002F1"},"env":"PROD","facebook":{"appId":"1636080783276430"},"https":"true","media":{"bp":{"xs":0,"s":600,"m":768,"l":1024,"xl":1360,"w":1710}},"newsletters":{"current":[{"description":"Become a better cook instantly with this weekly report of our ten most helpful tips, tricks, and kitchen secrets. Don't miss it!","id":"5","name":"The Top Ten"},{"description":"Love recipes, but hate searching? We do the work for you. You'll get our favorite seasonal recipe plus collections of our exclusive editors' picks.","id":"5117","name":"Cook This Now"},{"description":"Get a daily dose of the hottest recipes from Epicurious, Bon Appétit, and other great sites.","id":"195169","name":"Trending Recipes"},{"id":"248781","name":"Announcements"},{"id":"248789","name":"Cook 90"},{"id":"248818","name":"Diabetes Friendly"},{"id":"248842","name":"Small Plates"},{"id":"248886","name":"Well Equipped"}]},"server":"https:\u002F\u002Fwww.epicurious.com","services":{"endpoints":{"articles":{"latest":"\u002Fapi\u002Fsearch\u002Fv1\u002Fquery?size=20&content=article&sort=newest&q="},"branded":{"article":"\u002Fapi\u002Fbranded\u002Fv1\u002Farticle\u002F:brandCode\u002F:slug"},"content":{"channel":"\u002Fapi\u002Fcontent\u002Fv1\u002Fchannel\u002F","component":"\u002Fapi\u002Fcontent\u002Fv1\u002Fcomponent","contextual":"\u002Fapi\u002Fdataintelligence\u002Fv1\u002Fcontent\u002Frecommended","featuredIn":"\u002Fapi\u002Fcontent\u002Fv1\u002Ffeaturedin\u002F","homepage":"\u002Fapi\u002Fcontent\u002Fv1\u002Fhomepage","latestRecipes":"\u002Fapi\u002Fcontent\u002Fv1\u002Fcomponent\u002Flatestrecipes","memberLookup":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002F","navItems":"\u002Fapi\u002Fcontent\u002Fv1\u002Fcomponent\u002Fnavitems","nutritionalInfo":"\u002Fapi\u002Fnutritiondata\u002Fv2\u002F","reviews":"\u002Fapi\u002Frecipes\u002Fv2\u002F","reviewsFeed":"\u002Fapi\u002Frecipes\u002Fv3\u002F","reviewsSuffix":"\u002Freviews","reviewsFeedSuffix":"\u002Freviews\u002Ffeed","rotd":"\u002Fapi\u002Fcontent\u002Fv1\u002Frotd\u002Fcount\u002F1","search":"\u002Fapi\u002Fcontent\u002Fv1\u002Fsearch","videoSearchByKeywords":"\u002Fapi\u002Fvideo\u002Fv1\u002Fkeywords\u002F"},"contributors":{"details":"\u002Fapi\u002Fcontributors\u002Fv1\u002F:contributor\u002Fbundle","feed":"\u002Fapi\u002Fcontributors\u002Fv1\u002F:contributor\u002Ffeed"},"cookbooks":{"details":"\u002Fapi\u002Fcookbooks\u002Fv1\u002F:slug","index":"\u002Fapi\u002Fcookbooks\u002Fv1"},"menus":{"details":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Fmenus\u002F:menuId","index":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Fmenus"},"photos":{"instagramPosts":"\u002Fapi\u002Finstagram\u002Fv1","menuCover":"\u002Fapi\u002Fphotos\u002Fv1\u002Fmenu-cover","searchCard":"\u002Fapi\u002Fphotos\u002Fv1\u002Fsearch-card","searchUtility":"\u002Fapi\u002Fphotos\u002Fv1\u002Fsearch-utility"},"recipeBox":{"search":"\u002Fapi\u002Frecipe-box\u002Fv1\u002F:userId\u002Fsearch\u002F:term"},"recipes":{"byKeywords":"\u002Fapi\u002Frecipes\u002Fv2\u002Fkeywords\u002F","byKeywordsForMenus":"\u002Fapi\u002Fmenus\u002Fv1\u002Fkeywords\u002F","latest":"\u002Fapi\u002Frecipes\u002Fv2\u002Flatest"},"search":{"details":"\u002Fapi\u002Frecipes\u002Fv3\u002Fdetail","facets":"\u002Fapi\u002Fsearch\u002Fv1\u002Ffacets","query":"\u002Fapi\u002Fsearch\u002Fv1\u002Fquery","suggest":"\u002Fapi\u002Fsearch\u002Fv1\u002Fsuggest"},"users":{"authenticate":"\u002Fapi\u002Fusers\u002Fv2\u002Fauthenticate","info":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002F:uuid","newsletterSubscriptions":"\u002Fapi\u002Fnewsletters\u002Fv1\u002Fsubscription\u002F:email","recipeBoxSearch":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Frecipe-box\u002Fsearch\u002F:query","recipes":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Frecipes","reviews":"\u002Fapi\u002Fusers\u002Fv1\u002F:userId\u002Freviews","updateEmail":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002Femail","updatePassword":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002Fpassword","updateUsername":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser\u002Fdisplayname","updateSettings":"\u002Fapi\u002Fusers\u002Fv2\u002Fuser"}}},"servicesHost":"https:\u002F\u002Fservices.epicurious.com","simpleReach":{"pid":"570d6b7d736b79bf1d000d27"},"user":{"cookies":{"keys":{"id":"amg_user_partner","username":"amg_user_info"},"names":["amg_user_ext","amg_user_info","amg_user_partner","amg_user_update","cn_uid","CN_userAuth"]},"email":{"regExp":/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i},"password":{"regExp":/^[a-zA-Z0-9!"\#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~][a-zA-Z0-9 !"\#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]{4,253}[a-zA-Z0-9!"\#$%&'()*+,\-.\/:;<=>?@\[\\\]^_`{|}~]$/,"messages":{"requirements":"A password must be at least 6 characters long. It cannot begin or end with a space."}},"serviceKey":"NtibqP3y1qSJM\u002FGsy3blJgNWt\u002Fo=","serviceHost":"https:\u002F\u002Fuser-service.condenastdigital.com"},"userServiceHost":"https:\u002F\u002Fuser-service.condenastdigital.com","userServiceKey":"NtibqP3y1qSJM\u002FGsy3blJgNWt\u002Fo=","vulcan":{"host":"https:\u002F\u002Fassets.epicurious.com","path":"\u002Fphotos\u002F"}}};
root.__INITIAL_STATE__.contentType = "search";
}(this));

    window.copilot = window.copilot || window.__INITIAL_STATE__.copilotData;
  </script>
  <link as="style" href="/static/css/patch.css" onload="this.rel='stylesheet'" rel="preload"/>
  <noscript>
   <link href="/static/css/patch.css" rel="stylesheet"/>
  </noscript>
  <span data-react-checksum="-664854917" data-reactid="1" data-reactroot="" id="boomerang-beacon">
   <!-- react-empty: 2 -->
  </span>
  <div class="ad ad--out-of-page">
   <div class="ad__slot ad__slot--out-of-page">
   </div>
  </div>
 </body>
</html>

Plydata (dplyr for Python)

Sample Data

In [ ]:
n = 200
comp = ['C' + i for i in np.random.randint( 1,4, size  = n).astype(str)] # 3x Company
dept = ['D' + i for i in np.random.randint( 1,6, size  = n).astype(str)] # 5x Department
grp =  ['G' + i for i in np.random.randint( 1,3, size  = n).astype(str)] # 2x Groups
value1 = np.random.normal( loc=50 , scale=5 , size = n)
value2 = np.random.normal( loc=20 , scale=3 , size = n)
#value3 = np.random.normal( loc=5 , scale=30 , size = n)

mydf = pd.DataFrame({
    'comp':comp, 
    'dept':dept, 
    'grp': grp,
    'value1':value1, 
    'value2':value2
    #'value3':value3 
})
mydf.head()

Column Manipulation

Copy Column

In [ ]:
mydf >> define(newcol = 'value1')                 # simple method for one column
In [ ]:
mydf >> define (('newcol1', 'value1'), newcol2='value2')  # method for muiltiple new columns

New Column from existing Column

Without specify the new column name, it will be derived from expression

In [ ]:
mydf >> define ('value1*2')

Specify the new column name

In [ ]:
mydf >> define(value3 = 'value1*2')

Define multiple new columns in one go. Observe there are three ways to specify the new columns

In [ ]:
mydf >> define('value1*2',('newcol2','value2*2'),newcol3='value2*3')

Select Column(s)

In [ ]:
mydf2 = mydf >> define(newcol1='value1',newcol2='value2')
mydf2.info()

By Column Names

Exact Coumn Name

In [ ]:
mydf2 >> select ('comp','dept','value1')

Column Name Starts With ...

In [ ]:
mydf2 >> select ('comp', startswith='val')

Column Name Ends With ...

In [ ]:
mydf2 >> select ('comp',endswith=('1','2','3'))

Column Name Contains ...

In [ ]:
mydf2 >> select('comp', contains=('col','val'))

Specify Column Range

In [ ]:
mydf2 >> select ('comp', slice('value1','newcol2'))

Drop Column(s)

In [ ]:
mydf2 >> select('newcol1','newcol2',drop=True)

Rename Column

In [ ]:
mydf.head(80)

Assignment Method
Use when column name does not contain special character

In [ ]:
mydf >> rename( val1='value1', val2='value2' )

Dictionary Method
Use when column name contain special character

In [ ]:
mydf >> rename( {'val.1' : 'value1',
                 'val.2' : 'value2' })

Combined Method
Combine both assignment and dictionary method

In [ ]:
mydf >> rename( {'val.1' : 'value1',
                 'val.2' : 'value2'
              }, group = 'grp' )

Sorting (arrange)

Use '-colName' for decending

In [ ]:
mydf >> arrange('comp', '-value1')
In [ ]:
 
In [ ]:
 

Grouping

In [ ]:
mydf.info()
In [ ]:
gdf = mydf >> group_by('comp','dept')
type(gdf)

Summarization

Simple Method

Passing Multiple Expressions

In [ ]:
gdf >> summarize('n()','sum(value1)','mean(value2)')

Specify Summarized Column Name

Assignment Method

  • Passing colName='expression'**
  • Column name cannot contain special character
In [ ]:
gdf >> summarize(count='n()',v1sum='sum(value1)',v2_mean='mean(value2)')

Tuple Method ('colName','expression')
Use when the column name contain special character

In [ ]:
gdf >> summarize(('count','n()'),('v1.sum','sum(value1)'),('s2.sum','sum(value2)'),v2mean=np.mean(value2))

Number of Rows in Group

  • n() : total rows in group
  • n_unique() : total of rows with unique value
In [ ]:
gdf >> summarize(count='n()', va11_unique='n_unique(value1)')

numpy

  • Best array data manipulation, fast
  • numpy array allows only single data type, unlike list
  • Support matrix operation

Module Import

In [192]:
import numpy as np
np.__version__

## other modules
from datetime import datetime
from datetime import date
from datetime import time

Data Types

NumPy Data Types

NumPy supports a much greater variety of numerical types than Python does. This makes numpy much more powerful https://www.numpy.org/devdocs/user/basics.types.html

Integer: np.int8, np.int16, np.int32, np.uint8, np.uint16, np.uint32
Float: np.float32, np.float64

int32/64

np.int is actually python standard int

In [193]:
x = np.int(13)
y = int(13)
print( type(x) )
print( type(y) )
<class 'int'>
<class 'int'>

np.int32/64 are NumPy specific

In [194]:
x = np.int32(13)
y = np.int64(13)
print( type(x) )
print( type(y) )
<class 'numpy.int32'>
<class 'numpy.int64'>

float32/64

In [195]:
x = np.float(13)
y = float(13)
print( type(x) )
print( type(y) )
<class 'float'>
<class 'float'>
In [196]:
x = np.float32(13)
y = np.float64(13)
print( type(x) )
print( type(y) )
<class 'numpy.float32'>
<class 'numpy.float64'>

bool

np.bool is actually python standard bool

In [197]:
x = np.bool(True)
print( type(x) )
print( type(True) )
<class 'bool'>
<class 'bool'>

str

np.str is actually python standard str

In [198]:
x = np.str("ali")
print( type(x) )
<class 'str'>
In [199]:
x = np.str_("ali")
print( type(x) )
<class 'numpy.str_'>

datetime64

Unlike python standard datetime library, there is no seperation of date, datetime and time.
There is no time equivalent object
NumPy only has one object: datetime64 object .

Constructor

From String
Note that the input string cannot be ISO8601 compliance, meaning any timezone related information at the end of the string (such as Z or +8) will result in error.

In [286]:
np.datetime64('2005-02')
Out[286]:
numpy.datetime64('2005-02')
In [201]:
np.datetime64('2005-02-25')
Out[201]:
numpy.datetime64('2005-02-25')
In [202]:
np.datetime64('2005-02-25T03:30')
Out[202]:
numpy.datetime64('2005-02-25T03:30')

From datetime

In [203]:
np.datetime64( date.today() )
Out[203]:
numpy.datetime64('2019-02-05')
In [204]:
np.datetime64( datetime.now() )
Out[204]:
numpy.datetime64('2019-02-05T13:51:43.945110')

Instance Method

Convert to datetime using astype()

In [279]:
dt64 = np.datetime64("2019-01-31" )
dt64.astype(datetime)
Out[279]:
datetime.date(2019, 1, 31)

Numpy Array

Concept

Structure

  • NumPy provides an N-dimensional array type, the ndarray
  • ndarray is homogenous: every item takes up the same size block of memory, and all blocks
  • For each ndarray, there is a seperate dtype object, which describe ndarray data type
  • An item extracted from an array, e.g., by indexing, is represented by a Python object whose type is one of the array scalar types built in NumPy. The array scalars allow easy manipulation of also more complicated arrangements of data. numpy_concept

Constructor

By default, numpy.array autodetect its data types based on most common denominator

int, float

Notice example below auto detected as int32 data type

In [205]:
x = np.array( (1,2,3,4,5) )
x
Out[205]:
array([1, 2, 3, 4, 5])
In [206]:
x.dtype
Out[206]:
dtype('int32')

Notice example below auto detected as float64 data type

In [207]:
x = np.array( (1,2,3,4.5,5) )
x
Out[207]:
array([1. , 2. , 3. , 4.5, 5. ])
In [208]:
x.dtype
Out[208]:
dtype('float64')

You can specify dtype to specify desired data types.
NumPy will auto convert the data into specifeid types. Observe below that we convert float into integer

In [209]:
x = np.array( (1,2,3,4.5,5), dtype='int' )
x.dtype
print( x )
[1 2 3 4 5]

datetime64

Provide array of string in YYYY-MM-DD format will generate array of datetime64

In [310]:
ar = np.array(['2007-07-13', '2006-01-13', '2010-08-13'], dtype='datetime64')
ar
Out[310]:
array(['2007-07-13', '2006-01-13', '2010-08-13'], dtype='datetime64[D]')
In [315]:
ar.dtype  # array dtype
Out[315]:
dtype('<M8[D]')
In [319]:
type(ar[1]) # underlying date type
Out[319]:
numpy.datetime64
In [320]:
ar[1]
Out[320]:
numpy.datetime64('2006-01-13')

2D Array

In [210]:
x = np.array([range(10),np.arange(10)])
x
Out[210]:
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])

Dimensions

Differentiating Dimensions

1-D array is array of single list
2-D array is array made of list containing lists (each row is a list)
2-D single row array is array with list containing just one list

1-D Array

Observe that the shape of the array is (5,). It seems like an array with 5 rows, empty columns !
What it really means is 5 items single dimension.

In [241]:
arr = np.array(range(5))
print (arr)
print (arr.shape)
print (arr.ndim)
[0 1 2 3 4]
(5,)
1

2-D Array

In [242]:
arr = np.array([range(5),range(5,10),range(10,15)])
print (arr)
print (arr.shape)
print (arr.ndim)
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
(3, 5)
2

2-D Array - Single Row

In [243]:
arr = np.array([range(5)])
print (arr)
print (arr.shape)
print (arr.ndim)
[[0 1 2 3 4]]
(1, 5)
2

2-D Array : Single Column

Using array slicing method with newaxis at COLUMN, will turn 1D array into 2D of single column

In [244]:
arr = np.arange(5)[:, np.newaxis]
print (arr)
print (arr.shape)
print (arr.ndim)
[[0]
 [1]
 [2]
 [3]
 [4]]
(5, 1)
2

Using array slicing method with newaxis at ROW, will turn 1D array into 2D of single row

In [245]:
arr = np.arange(5)[np.newaxis,:]
print (arr)
print (arr.shape)
print (arr.ndim)
[[0 1 2 3 4]]
(1, 5)
2

Class Method

arange()

Generate array with a sequence of numbers

In [211]:
np.arange(10)
Out[211]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

ones()

In [212]:
np.ones(10)  # One dimension, default is float
Out[212]:
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
In [213]:
np.ones((2,5),'int')  #Two dimensions
Out[213]:
array([[1, 1, 1, 1, 1],
       [1, 1, 1, 1, 1]])

zeros()

In [214]:
np.zeros( 10 )    # One dimension, default is float
Out[214]:
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
In [215]:
np.zeros((2,5),'int')   # 2 rows, 5 columns of ZERO
Out[215]:
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])

where()

On 1D array numpy.where() returns the items matching the criteria

In [216]:
ar1 = np.array(range(10))
print( ar1 )
print( np.where(ar1>5) )
[0 1 2 3 4 5 6 7 8 9]
(array([6, 7, 8, 9], dtype=int64),)

On 2D array, where() return array of row index and col index for matching elements

In [217]:
ar = np.array([(1,2,3,4,5),(11,12,13,14,15),(21,22,23,24,25)])
print ('Data : \n', ar)
np.where(ar>13)
Data : 
 [[ 1  2  3  4  5]
 [11 12 13 14 15]
 [21 22 23 24 25]]
Out[217]:
(array([1, 1, 2, 2, 2, 2, 2], dtype=int64),
 array([3, 4, 0, 1, 2, 3, 4], dtype=int64))

Logical Methods

numpy.logical_or
Perform or operation on two boolean array, generate new resulting boolean arrays

In [218]:
ar = np.arange(10)
print( ar==3 )  # boolean array 1
print( ar==6 )  # boolean array 2
print( np.logical_or(ar==3,ar==6 ) ) # resulting boolean
[False False False  True False False False False False False]
[False False False False False False  True False False False]
[False False False  True False False  True False False False]

numpy.logical_and
Perform and operation on two boolean array, generate new resulting boolean arrays

In [285]:
ar = np.arange(10)
print( ar==3 ) # boolean array 1
print( ar==6 ) # boolean array 2
print( np.logical_and(ar==3,ar==6 ) )  # resulting boolean
[False False False  True False False False False False False]
[False False False False False False  True False False False]
[False False False False False False False False False False]

Instance Method

astype() conversion

Convert to from datetime64 to datetime

In [337]:
ar1 = np.array(['2007-07-13', '2006-01-13', '2010-08-13'], dtype='datetime64')
print( type(ar1) )  ## a numpy array
print( ar1.dtype )  ## dtype is a numpy data type
<class 'numpy.ndarray'>
datetime64[D]

After convert to datetime (non-numpy object, the dtype becomes generic 'object'.

In [340]:
ar2 = ar1.astype(datetime)
print( type(ar2) )  ## still a numpy array
print( ar2.dtype )  ## dtype becomes generic 'object'
<class 'numpy.ndarray'>
object

reshape()

reshape ( row numbers, col numbers )

Sample Data

In [220]:
a = np.array([range(5), range(10,15), range(20,25), range(30,35)])
a
Out[220]:
array([[ 0,  1,  2,  3,  4],
       [10, 11, 12, 13, 14],
       [20, 21, 22, 23, 24],
       [30, 31, 32, 33, 34]])

Resphepe 1-Dim to 2-Dim

In [221]:
np.arange(12) # 1-D Array
Out[221]:
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
In [222]:
np.arange(12).reshape(3,4)  # 2-D Array
Out[222]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

Respahe 2-Dim to 2-Dim

In [223]:
np.array([range(5), range(10,15)])  # 2-D Array
Out[223]:
array([[ 0,  1,  2,  3,  4],
       [10, 11, 12, 13, 14]])
In [224]:
np.array([range(5), range(10,15)]).reshape(5,2) # 2-D Array
Out[224]:
array([[ 0,  1],
       [ 2,  3],
       [ 4, 10],
       [11, 12],
       [13, 14]])

Reshape 2-Dimension to 2-Dim (of single row)

  • Change 2x10 to 1x10
  • Observe [[ ]], and the number of dimension is stll 2, don't be fooled
In [225]:
np.array( [range(0,5), range(5,10)])  # 2-D Array
Out[225]:
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])
In [226]:
np.array( [range(0,5), range(5,10)]).reshape(1,10) # 2-D Array
Out[226]:
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])

Reshape 1-Dim Array to 2-Dim Array (single column)

In [227]:
np.arange(8)
Out[227]:
array([0, 1, 2, 3, 4, 5, 6, 7])
In [228]:
np.arange(8).reshape(8,1)
Out[228]:
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7]])

A better method, use newaxis, easier because no need to input row number as parameter

In [229]:
np.arange(8)[:,np.newaxis]
Out[229]:
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7]])

Reshape 1-Dim Array to 2-Dim Array (single row)

In [230]:
np.arange(8)
Out[230]:
array([0, 1, 2, 3, 4, 5, 6, 7])
In [231]:
np.arange(8)[np.newaxis,:]
Out[231]:
array([[0, 1, 2, 3, 4, 5, 6, 7]])

Element Selection

Sample Data

In [232]:
x1 = np.array( (0,1,2,3,4,5,6,7,8))
x2 = np.array(( (1,2,3,4,5), 
      (11,12,13,14,15),
      (21,22,23,24,25)))
print(x1)
print(x2)
[0 1 2 3 4 5 6 7 8]
[[ 1  2  3  4  5]
 [11 12 13 14 15]
 [21 22 23 24 25]]

1-Dimension

All indexing starts from 0 (not 1)

Choosing Single Element does not return array

In [233]:
print( x1[0]   )  ## first element
print( x1[-1]  )  ## last element

print( x1[3]   )  ## third element from start 3
print( x1[-3]  )  ## third element from end
0
8
3
6

Selecting multiple elments return ndarray

In [234]:
print( x1[:3]  )  ## first 3 elements
print( x1[-3:])   ## last 3 elements

print( x1[3:]  )  ## all except first 3 elements
print( x1[:-3] )  ## all except last 3 elements

print( x1[1:4] )  ## elemnt 1 to 4 (not including 4)
[0 1 2]
[6 7 8]
[3 4 5 6 7 8]
[0 1 2 3 4 5]
[1 2 3]

2-Dimension

Indexing with [ row_positoins, row_positions ], index starts with 0

In [235]:
x[1:3, 1:4] # row 1 to 2 column 1 to 3
Out[235]:
array([[1, 2, 3]])

Attributes

dtype

ndarray contain a property called dtype, whcih tell us the type of underlying items

In [236]:
a = np.array( (1,2,3,4,5), dtype='float' )
a.dtype
Out[236]:
dtype('float64')
In [237]:
print(a.dtype)
print( type(a[1]))
float64
<class 'numpy.float64'>

dim

dim returns the number of dimensions of the NumPy array. Example below shows 2-D array

In [238]:
x = np.array(( (1,2,3,4,5), 
      (11,12,13,14,15),
      (21,22,23,24,25)))
x.ndim  
Out[238]:
2

shape

shape return a type of (rows, cols)

In [239]:
x = np.array(( (1,2,3,4,5), 
      (11,12,13,14,15),
      (21,22,23,24,25)))
x.shape  
Out[239]:
(3, 5)
In [240]:
np.identity(5)
Out[240]:
array([[1., 0., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1.]])

Operations

Arithmetic

Sample Date

In [341]:
ar = np.arange(10)
print( ar )
[0 1 2 3 4 5 6 7 8 9]

*

In [246]:
ar = np.arange(10)
print (ar)
print (ar*2)
[0 1 2 3 4 5 6 7 8 9]
[ 0  2  4  6  8 10 12 14 16 18]

**+ and -**

In [247]:
ar = np.arange(10)
print (ar+2)
print (ar-2)
[ 2  3  4  5  6  7  8  9 10 11]
[-2 -1  0  1  2  3  4  5  6  7]

Comparison

Sample Data

In [341]:
ar = np.arange(10)
print( ar )
[0 1 2 3 4 5 6 7 8 9]

==

In [251]:
print( ar==3 )
[False False False  True False False False False False False]

>, >=, <, <=

In [252]:
print( ar>3 )
print( ar<=3 )
[False False False False  True  True  True  True  True  True]
[ True  True  True  True False False False False False False]

Random Numbers

Uniform Distribution

Random Integer (with Replacement)

randint() Return random integers from low (inclusive) to high (exclusive)

np.random.randint( low )                  # generate an integer, i, which         i < low
np.random.randint( low, high )            # generate an integer, i, which  low <= i < high
np.random.randint( low, high, size=1)     # generate an ndarray of integer, single dimension
np.random.randint( low, high, size=(r,c)) # generate an ndarray of integer, two dimensions
In [253]:
np.random.randint( 10 )
Out[253]:
1
In [254]:
np.random.randint( 10, 20 )
Out[254]:
16
In [255]:
np.random.randint( 10, high=20, size=5)   # single dimension
Out[255]:
array([12, 10, 16, 14, 12])
In [256]:
np.random.randint( 10, 20, (3,5) )        # two dimensions
Out[256]:
array([[16, 19, 12, 19, 18],
       [15, 18, 10, 10, 17],
       [14, 12, 11, 11, 15]])

Random Integer (with or without replacement)

numpy.random .choice( a, size, replace=True)
 # sampling from a, 
 #   if a is integer, then it is assumed sampling from arange(a)
 #   if a is an 1-D array, then sampling from this array
In [257]:
np.random.choice(10,5, replace=False) # take 5 samples from 0:19, without replacement
Out[257]:
array([2, 4, 0, 9, 8])
In [258]:
np.random.choice( np.arange(10,20), 5, replace=False)
Out[258]:
array([12, 13, 18, 16, 10])

Random Float

randf() Generate float numbers in between 0.0 and 1.0

np.random.ranf(size=None)
In [259]:
np.random.ranf(4)
Out[259]:
array([0.94250048, 0.94960753, 0.29055676, 0.25391307])

uniform() Return random float from low (inclusive) to high (exclusive)

np.random.uniform( low )                  # generate an float, i, which         f < low
np.random.uniform( low, high )            # generate an float, i, which  low <= f < high
np.random.uniform( low, high, size=1)     # generate an array of float, single dimension
np.random.uniform( low, high, size=(r,c)) # generate an array of float, two dimensions
In [260]:
np.random.uniform( 2 )
Out[260]:
1.8839947654697506
In [261]:
np.random.uniform( 2,5, size=(4,4) )
Out[261]:
array([[3.53074707, 4.8318309 , 3.72637778, 3.91985394],
       [2.1729616 , 2.41428125, 3.09702137, 2.81555087],
       [4.95442552, 3.08758534, 4.04481284, 4.36283031],
       [2.98175957, 2.97723315, 3.46863149, 2.1131226 ]])

Normal Distribution

numpy. random.randn (n_items)       # 1-D standard normal (mean=0, stdev=1)
numpy. random.randn (nrows, ncols)  # 2-D standard normal (mean=0, stdev=1)
numpy. random.standard_normal( size=None )                # default to mean = 0, stdev = 1, non-configurable
numpy. random.normal         ( loc=0, scale=1, size=None) # loc = mean, scale = stdev, size = dimension

Standard Normal Distribution

Generate random normal numbers with gaussion distribution (mean=0, stdev=1)

One Dimension

In [262]:
np.random.standard_normal(3)
Out[262]:
array([-0.74560822, -2.31015733, -0.54510148])
In [263]:
np.random.randn(3)
Out[263]:
array([ 0.65124691,  0.14847405, -0.18527882])

Two Dimensions

In [264]:
np.random.randn(2,4)
Out[264]:
array([[ 0.43584434,  0.4222265 ,  0.532138  , -0.29037816],
       [-1.82357373,  0.97528663,  0.96177261,  1.38631561]])
In [265]:
np.random.standard_normal((2,4))
Out[265]:
array([[-0.1877177 , -1.62689842, -0.87913195, -0.37687932],
       [-0.25675386,  0.66879526, -0.19631951, -0.61547975]])

Observe: randn(), standard_normal() and normal() are able to generate standard normal numbers

In [266]:
np.random.seed(15)
print (np.random.randn(5))
np.random.seed(15)
print (np.random.normal ( size = 5 )) # stdev and mean not specified, default to standard normal
np.random.seed(15)
print (np.random.standard_normal (size=5))
[-0.31232848  0.33928471 -0.15590853 -0.50178967  0.23556889]
[-0.31232848  0.33928471 -0.15590853 -0.50178967  0.23556889]
[-0.31232848  0.33928471 -0.15590853 -0.50178967  0.23556889]

Normal Distribution (Non-Standard)

In [267]:
np.random.seed(125)
np.random.normal( loc = 12, scale=1.25, size=(3,3))
Out[267]:
array([[11.12645382, 12.01327885, 10.81651695],
       [12.41091248, 12.39383072, 11.49647195],
       [ 8.70837035, 12.25246312, 11.49084235]])

Linear Spacing

numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
# endpoint: If True, stop is the last sample, otherwise it is not included

Include Endpoint
Step = Gap divide by (number of elements minus 1) (2/(10-1))

In [268]:
np.linspace(1,3,10) #default endpont=True
Out[268]:
array([1.        , 1.22222222, 1.44444444, 1.66666667, 1.88888889,
       2.11111111, 2.33333333, 2.55555556, 2.77777778, 3.        ])

Does Not Include Endpoint
Step = Gap divide by (number of elements minus 1) (2/(101))

In [269]:
np.linspace(1,3,10,endpoint=False)
Out[269]:
array([1. , 1.2, 1.4, 1.6, 1.8, 2. , 2.2, 2.4, 2.6, 2.8])

Sampling (Integer)

random.choice( a, size=None, replace=True, p=None)  # a=integer, return <size> integers < a
random.choice( a, size=None, replace=True, p=None)  # a=array-like, return <size> integers picked from list a
In [270]:
np.random.choice (100, size=10)
Out[270]:
array([58,  0, 84, 50, 89, 32, 87, 30, 66, 92])
In [271]:
np.random.choice( [1,3,5,7,9,11,13,15,17,19,21,23], size=10, replace=False)
Out[271]:
array([ 5,  1, 23, 17,  3, 13, 15,  9, 21,  7])

NaN : Missing Numerical Data

  • You should be aware that NaN is a bit like a data virus–it infects any other object it touches
In [272]:
t = np.array([1, np.nan, 3, 4]) 
t.dtype
Out[272]:
dtype('float64')

Regardless of the operation, the result of arithmetic with NaN will be another NaN

In [273]:
1 + np.nan
Out[273]:
nan
In [274]:
t.sum(), t.mean(), t.max()
C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\_methods.py:28: RuntimeWarning: invalid value encountered in reduce
  return umr_maximum(a, axis, None, out, keepdims, initial)
Out[274]:
(nan, nan, nan)
In [275]:
np.nansum(t), np.nanmean(t), np.nanmax(t)
Out[275]:
(8.0, 2.6666666666666665, 4.0)

pandas

Modules Import

Display Setup

It is good idea to configure output setup as prefered

In [3]:
pd.set_option( 'display.notebook_repr_html', False)  # render Series and DataFrame as text, not HTML
pd.set_option( 'display.max_column', 10)    # number of columns
pd.set_option( 'display.max_rows', 10)     # number of rows
pd.set_option( 'display.width', 80)        # number of characters per row

Pandas Objects

Pandas Data Types

  • pandas.Timestamp
  • pandas.Timedelta
  • pandas.Period
  • pandas.Interval
  • pandas.DateTimeIndex

Pandas Data Structure

Type Dimension Size Value Constructor
Series 1 Immutable Mutable pandas.DataFrame( data, index, dtype, copy)
DataFrame 2 Mutable Mutable pandas.DataFrame( data, index, columns, dtype, copy)
Panel 3 Mutable Mutable

data can be ndarray, list, constants
index must be unique and same length as data. Can be integer or string dtype if none, it will be inferred
copy copy data. Default false

Class Method

Convert to Timestamp

Use to_datetime, resulting data structure depends on structure.
Source can be string, date, datetime object

From List to DateTimeIndex

In [4]:
dti = pd.to_datetime(['2011-01-03',      # from string
                date(2018,4,13),        # from date
                datetime(2018,3,1,7,30)]# from datetime
              )
dti
Out[4]:
DatetimeIndex(['2011-01-03 00:00:00', '2018-04-13 00:00:00',
               '2018-03-01 07:30:00'],
              dtype='datetime64[ns]', freq=None)

From Series to Series

In [5]:
sdt = pd.to_datetime(pd.Series(['2011-01-03',      # from string
                date(2018,4,13),        # from date
                datetime(2018,3,1,7,30)]# from datetime
              ))
In [6]:
sdt[1]
Out[6]:
Timestamp('2018-04-13 00:00:00')

From Scalar to Timestamp

In [7]:
print( pd.to_datetime('2011-01-03'))    # from string
print( pd.to_datetime(date(2011,1,3)))  # from date
print( pd.to_datetime(datetime(2011,1,3,5,30))) # from datetime
2011-01-03 00:00:00
2011-01-03 00:00:00
2011-01-03 05:30:00

Generate Timestamp Sequence

date_range()

Return DateTimeIndex object

Generate sequence of HOURS

In [8]:
## Specify start, Periods, Frequency
## Start from Date Only
pd.date_range('2018-01-01', periods=3, freq='H')
Out[8]:
DatetimeIndex(['2018-01-01 00:00:00', '2018-01-01 01:00:00',
               '2018-01-01 02:00:00'],
              dtype='datetime64[ns]', freq='H')
In [9]:
## Start from DateTime
dti = pd.date_range(datetime(2018,1,1,12,30), periods=3, freq='H')
In [10]:
## Specify start, End and Frequency
dti = pd.date_range(start='2018-01-03-1230', end='2018-01-03-18:30', freq='H')
print(dti)
DatetimeIndex(['2018-01-03 12:30:00', '2018-01-03 13:30:00',
               '2018-01-03 14:30:00', '2018-01-03 15:30:00',
               '2018-01-03 16:30:00', '2018-01-03 17:30:00',
               '2018-01-03 18:30:00'],
              dtype='datetime64[ns]', freq='H')

Generate sequence of DAYS

In [11]:
pd.date_range(date(2018,1,2), periods=3, freq='D')
Out[11]:
DatetimeIndex(['2018-01-02', '2018-01-03', '2018-01-04'], dtype='datetime64[ns]', freq='D')
In [12]:
pd.date_range('2018-01-01-1230', periods=4, freq='D')
Out[12]:
DatetimeIndex(['2018-01-01 12:30:00', '2018-01-02 12:30:00',
               '2018-01-03 12:30:00', '2018-01-04 12:30:00'],
              dtype='datetime64[ns]', freq='D')

Generate sequence of Start of Month

In [13]:
pd.date_range('2018-01', periods=4, freq='MS')
Out[13]:
DatetimeIndex(['2018-01-01', '2018-02-01', '2018-03-01', '2018-04-01'], dtype='datetime64[ns]', freq='MS')
In [14]:
pd.date_range(datetime(2018,1,3,12,30), periods=4, freq='MS')
Out[14]:
DatetimeIndex(['2018-02-01 12:30:00', '2018-03-01 12:30:00',
               '2018-04-01 12:30:00', '2018-05-01 12:30:00'],
              dtype='datetime64[ns]', freq='MS')

Generate sequence of End of Month

In [15]:
dti = pd.date_range('2018-02', periods=4, freq='M')
dti
Out[15]:
DatetimeIndex(['2018-02-28', '2018-03-31', '2018-04-30', '2018-05-31'], dtype='datetime64[ns]', freq='M')

Timestamp

This is an enhanced version to datetime standard library.
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Timestamp.html#pandas.Timestamp

Constructor

From Number

In [16]:
print( pd.Timestamp(year=2017, month=1, day=1) ) #date-like numbers
print( pd.Timestamp(2017,1,1) )                  # date-like numbers
print( pd.Timestamp(2017,12,11,5,45))            # datetime-like numbers
print( pd.Timestamp(2017,12,11,5,45,55,999))     # + microseconds
print( pd.Timestamp(2017,12,11,5,45,55,999,8))   # + nanoseconds
print( type(pd.Timestamp(2017,12,11,5,45,55,999,8)))
2017-01-01 00:00:00
2017-01-01 00:00:00
2017-12-11 05:45:00
2017-12-11 05:45:55.000999
2017-12-11 05:45:55.000999008
<class 'pandas._libs.tslibs.timestamps.Timestamp'>

From String

Observe that pandas support many string input format
Year Month Day, default no timezone

In [17]:
print( pd.Timestamp('2017-12-11'))      # date-like string: year-month-day
print( pd.Timestamp('2017 12 11'))      # date-like string: year-month-day
print( pd.Timestamp('2017 Dec 11'))      # date-like string: year-month-day
print( pd.Timestamp('Dec 11, 2017'))      # date-like string: year-month-day
2017-12-11 00:00:00
2017-12-11 00:00:00
2017-12-11 00:00:00
2017-12-11 00:00:00

YMD Hour Minute Second Ms

In [18]:
print( pd.Timestamp('2017-12-11 0545'))     ## hour minute
print( pd.Timestamp('2017-12-11-05:45'))
print( pd.Timestamp('2017-12-11T0545'))

print( pd.Timestamp('2017-12-11 054533'))   ## hour minute seconds
print( pd.Timestamp('2017-12-11 05:45:33'))
2017-12-11 05:45:00
2017-12-11 05:45:00
2017-12-11 05:45:00
2017-12-11 05:45:33
2017-12-11 05:45:33

Timezone

In [19]:
print( pd.Timestamp('2017-01-01T0545Z'))     # GMT 
print( pd.Timestamp('2017-01-01T0545+9'))    # GMT+9
print( pd.Timestamp('2017-01-01T0545+0800')) # GMT+0800
2017-01-01 05:45:00+00:00
2017-01-01 05:45:00+09:00
2017-01-01 05:45:00+08:00

From Standard Library datetime and date Object

In [20]:
print( pd.Timestamp(date(2017,3,5)) )           # from date
print( pd.Timestamp(datetime(2017,3,5,4,30)))   # from datetime
print( pd.Timestamp(datetime(2017,3,5,4,30), tz='Asia/Kuala_Lumpur'))   # from datetime, + tz
2017-03-05 00:00:00
2017-03-05 04:30:00
2017-03-05 04:30:00+08:00

Attributes

In [21]:
ts = pd.Timestamp('2017-01-01T054533+0800') # GMT+0800
print( ts.month )
print( ts.day   )
print( ts.year   )
print( ts.hour  )
print( ts.minute)
print( ts.second)
print( ts.microsecond)
print( ts.nanosecond)
print( ts.tz)
1
1
2017
5
45
33
0
0
pytz.FixedOffset(480)
In [22]:
ts1 = pd.Timestamp(datetime(2017,3,5,4,30), tz='Asia/Kuala_Lumpur')   # from datetime, + tz
ts2 = pd.Timestamp('2017-01-01T054533+0800') # GMT+0800
ts3 = pd.Timestamp('2017-01-01T0545')

print( ts1.tz )
print( ts2.tz )
print( ts3.tz )
Asia/Kuala_Lumpur
pytz.FixedOffset(480)
None

Operator

In [ ]:
 
In [ ]:
 

Instance Methods

Useful Methods

In [23]:
ts = pd.Timestamp(2017,1,1)
print( ts.weekday()  )
print( ts.isoweekday() )
6
7

Convert To datetime

Use to_pydatetime() to convert into standard library datetime.datetime, optionally to datetime.date

In [24]:
ts = pd.Timestamp(2017,1,10,7,30,52)  # to datetime.datetime
ts.to_pydatetime()
Out[24]:
datetime.datetime(2017, 1, 10, 7, 30, 52)
In [25]:
ts = pd.Timestamp(2017,1,10,7,30,52)  # to datetime.date
ts.to_pydatetime().date()
Out[25]:
datetime.date(2017, 1, 10)

Convert To numpy

Use to_datetime64() to convert into numpy.datetime64

In [26]:
ts = pd.Timestamp(2017,1,10,7,30,52)
ts.to_datetime64()
Out[26]:
numpy.datetime64('2017-01-10T07:30:52.000000000')

Formatting with strftime

Use strftime() to customize string format. For complete directive, see below:
https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior

In [27]:
ts = pd.Timestamp(2017,1,10,7,30,52)
ts.strftime("%m/%d")
Out[27]:
'01/10'

Add Timezone

Add timezone to tz-naive or tz-non-existance object. Clock will not be shifted as there is no original offset

In [28]:
ts = pd.Timestamp(2017,1,10,10,34)   ## No timezone
ts = ts.tz_localize('Asia/Kuala_Lumpur')  ## Add timezone
ts
Out[28]:
Timestamp('2017-01-10 10:34:00+0800', tz='Asia/Kuala_Lumpur')

Convert Timezone

Convert timezone to tz-aware object. The clock will be shifted according to the offset

In [29]:
ts = pd.Timestamp(2017,1,10,10,34)        ## No timezone
ts = ts.tz_localize('Asia/Kuala_Lumpur')  ## Add timezone
ts = ts.tz_convert('UTC')                 ## Convert timezone
ts
Out[29]:
Timestamp('2017-01-10 02:34:00+0000', tz='UTC')

Removing TImezone

In [30]:
ts = pd.Timestamp(2017,1,10,10,34)        ## No timezone
ts = ts.tz_localize('Asia/Kuala_Lumpur')  ## Add timezone
ts = ts.tz_localize(None)                 ## Convert timezone
ts
Out[30]:
Timestamp('2017-01-10 10:34:00')

Formatting with isoformat

Use isoformat() to format ISO string (without timezone)

In [31]:
ts.isoformat()
Out[31]:
'2017-01-10T10:34:00'

ceil

In [32]:
print( ts.ceil(freq='D') ) # ceiling to day
2017-01-11 00:00:00

replace()

In [33]:
ts.replace(year=2000, month=1,day=1)
Out[33]:
Timestamp('2000-01-01 10:34:00')

Series

Constructor

Empty Series

Passing empty parameter result in empty series

In [34]:
s = pd.Series()
print (s)
type(s)
Series([], dtype: float64)
Out[34]:
pandas.core.series.Series

From Scalar

If data is a scalar value, an index must be provided. The value will be repeated to match the length of index

In [35]:
pd.Series( 1, index = ['a','b','c','d'])
Out[35]:
a    1
b    1
c    1
d    1
dtype: int64

From array-like

From numpy.array
If index is not specified, default to 0 and continue incrementally

In [36]:
pd.Series(np.array(['a','b','c','d','e']))  # from np.array
Out[36]:
0    a
1    b
2    c
3    d
4    e
dtype: object

From list

In [37]:
pd.Series(['a','b','c','d','e'])           # from Python list
Out[37]:
0    a
1    b
2    c
3    d
4    e
dtype: object

From DateTimeIndex

In [38]:
dti = pd.date_range('2011-1-1','2011-1-3')
dti
Out[38]:
DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03'], dtype='datetime64[ns]', freq='D')
In [39]:
pd.Series(pd.date_range('2011-1-1','2011-1-3'))
Out[39]:
0   2011-01-01
1   2011-01-02
2   2011-01-03
dtype: datetime64[ns]

From Dictionary

The dictionary key will be the index

If index sequence is not specified, then the Series will be automatically sorted according to the key

In [40]:
pd.Series({'a' : 0., 'c' : 1., 'b' : 2.})  # from Python dict, autosort by default key
Out[40]:
a    0.0
c    1.0
b    2.0
dtype: float64

If index sequence is specifeid, then Series will forllow the index order
Objerve that missing data (index without value) will be marked as NaN

In [41]:
pd.Series({'a' : 0., 'c' : 1., 'b' : 2.},index = ['a','b','c','d'])  # from Python Dict, index specified, no auto sort
Out[41]:
a    0.0
b    2.0
c    1.0
d    NaN
dtype: float64

Specify Index During Creation

In [42]:
pd.Series(['a','b','c','d','e'], index=[10,20,30,40,50])
Out[42]:
10    a
20    b
30    c
40    d
50    e
dtype: object

Accessing Series

series     ( single/list/range_of_row_label/number ) # can cause confusion
series.loc ( single/list/range_of_row_label )
series.iloc( single/list/range_of_row_number )

Sample Data

In [43]:
s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e']) 
s
Out[43]:
a    1
b    2
c    3
d    4
e    5
dtype: int64

by Row Number(s)

Single Item

In [44]:
s.iloc[1]
Out[44]:
2

Multiple Items

In [45]:
s.iloc[[1,3]] 
Out[45]:
b    2
d    4
dtype: int64

Range (First 3)

In [46]:
s.iloc[:3]
Out[46]:
a    1
b    2
c    3
dtype: int64

Range (Last 3)

In [47]:
s.iloc[-3:]
Out[47]:
c    3
d    4
e    5
dtype: int64

Range (in between)

In [48]:
s.iloc[2:3]
Out[48]:
c    3
dtype: int64

by Index(es)

Single Label

In [49]:
s.loc['c'] 
# or  ... s[['c']]
Out[49]:
3

Multiple Labels

In [50]:
s.loc[['b','c']]
Out[50]:
b    2
c    3
dtype: int64

Range of Labels

In [51]:
s.loc['b':'d']
Out[51]:
b    2
c    3
d    4
dtype: int64

Filtering Criteria

Use logical array to filter

In [52]:
s = pd.Series(range(1,8))
s[s<5]
Out[52]:
0    1
1    2
2    3
3    4
dtype: int64

Use logical array with where

In [53]:
s.where(s>4)
Out[53]:
0    NaN
1    NaN
2    NaN
3    NaN
4    5.0
5    6.0
6    7.0
dtype: float64
In [54]:
s.where(s>4,None)
Out[54]:
0    None
1    None
2    None
3    None
4       5
5       6
6       7
dtype: object

Modifying Series

by Row Number(s)

In [55]:
s = pd.Series(range(1,7), index=['a','b','c','d','e','f'])
s[2] = 999
s[[3,4]] = 888,777
s
Out[55]:
a      1
b      2
c    999
d    888
e    777
f      6
dtype: int64

by Index(es)

In [56]:
s = pd.Series(range(1,7), index=['a','b','c','d','e','f'])
s['e'] = 888
s[['c','d']] = 777,888
s
Out[56]:
a      1
b      2
c    777
d    888
e    888
f      6
dtype: int64

Series Attributes

index

In [57]:
s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e']) 
s.index
Out[57]:
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')

dtype

In [58]:
s = pd.Series([1,2,3,4,5],index=['a','b','c','d','e']) 
s.dtype
Out[58]:
dtype('int64')

Dimensions

In [59]:
print(s)
print( s.size  )
a    1
b    2
c    3
d    4
e    5
dtype: int64
5
In [60]:
print( s.shape )
print( s.ndim  )
(5,)
1

Instance Methods

.reset_index ()

Resetting index will:

  • Convert index to a normal column
  • Index numbering became 0,1,2,3
In [61]:
s.reset_index()
Out[61]:
  index  0
0     a  1
1     b  2
2     c  3
3     d  4
4     e  5
In [62]:
s.index
Out[62]:
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')

Structure Conversion

Use to_numpy() to convert into numpy.ndarray

In [63]:
#npa = s.to_numpy()
#print( npa )
#print( type(npa) )

Use to_list() to convert into standard python list

In [64]:
#ll = s.to_list()
##print( ll )
#print( type(ll) )

DataType Conversion

Use astype() to convert to another numpy supproted datatypes

In [65]:
ser = pd.Series([1, 2], dtype='int32')
ser
Out[65]:
0    1
1    2
dtype: int32
In [66]:
ser.astype('int8')
Out[66]:
0    1
1    2
dtype: int8

Series Operators

The result of applying operator (arithmetic or logic) to Series object returns a new Series object

Arithmetic Operator

In [67]:
s1 = pd.Series( [100,200,300,400,500] )
s2 = pd.Series( [10, 20, 30, 40, 50] )

Apply To One Series Object

In [68]:
100 - s2
Out[68]:
0    90
1    80
2    70
3    60
4    50
dtype: int64

Apply To Two Series Objects

In [69]:
s1 - s2
Out[69]:
0     90
1    180
2    270
3    360
4    450
dtype: int64

Logic Operator

  • Apply logic operator to a Series return a new Series of boolean result
  • This can be used for Series or DataFrame filtering
In [70]:
bs = pd.Series(range(0,10))
bs
Out[70]:
0    0
1    1
2    2
3    3
4    4
5    5
6    6
7    7
8    8
9    9
dtype: int64
In [71]:
print (bs>3)
print (type (bs>3))
0    False
1    False
2    False
3    False
4     True
5     True
6     True
7     True
8     True
9     True
dtype: bool
<class 'pandas.core.series.Series'>
In [72]:
~((bs>3) & (bs<8))
Out[72]:
0     True
1     True
2     True
3     True
4    False
5    False
6    False
7    False
8     True
9     True
dtype: bool

Series String Accesor .str

If the underlying data is str type, then pandas exposed various properties and methos through str accessor.

  • This chapter focus on various functions that can be applied to entire Series data
    SeriesObj.str.operatorFunction()

Pandas str Method

Nearly all Python's built-in string methods are mirrored by a Pandas vectorized string method. Here is a list of Pandas str methods that mirror Python string methods:

len() lower() translate() islower() ljust() upper() startswith() isupper() rjust() find() endswith() isnumeric() center() rfind() isalnum() isdecimal() zfill() index() isalpha() split() strip() rindex() isdigit() rsplit() rstrip() capitalize() isspace() partition() lstrip() swapcase() istitle() rpartition()

Splitting

In [267]:
s = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h_i_j'])
s
Out[267]:
0        a_b_c
1        c_d_e
2          NaN
3    f_g_h_i_j
dtype: object

str.split() By default, split will split the string into array

In [268]:
s.str.split('_')
Out[268]:
0          [a, b, c]
1          [c, d, e]
2                NaN
3    [f, g, h, i, j]
dtype: object

After split, select rows to return

In [269]:
print( s.str.split('_').get(1) )
print( s.str.split('_')[1] )
['c', 'd', 'e']
['c', 'd', 'e']

str.split( expand=True, n= )

split and expand=True will return a dataframe instead of series

In [270]:
print( s.str.split('_', expand=True) )
     0    1    2     3     4
0    a    b    c  None  None
1    c    d    e  None  None
2  NaN  NaN  NaN   NaN   NaN
3    f    g    h     i     j

It is possible to limit the number of columns splitted

In [271]:
print( s.str.split('_', expand=True, n=1) )
     0        1
0    a      b_c
1    c      d_e
2  NaN      NaN
3    f  g_h_i_j

str.rsplit()

rsplit stands for reverse split, it works the same way, except it is reversed

In [272]:
print( s.str.rsplit('_', expand=True, n=1) )
         0    1
0      a_b    c
1      c_d    e
2      NaN  NaN
3  f_g_h_i    j

Matching

In [273]:
monte = pd.Series(['Graham Chapman', 'John Cleese', 'Terry Gilliam',
                   'Eric Idle', 'Terry Jones', 'Michael Palin'])
monte
Out[273]:
0    Graham Chapman
1       John Cleese
2     Terry Gilliam
3         Eric Idle
4       Terry Jones
5     Michael Palin
dtype: object

startwith

In [274]:
monte.str.startswith('T')
Out[274]:
0    False
1    False
2     True
3    False
4     True
5    False
dtype: bool
In [275]:
monte.str.split()
Out[275]:
0    [Graham, Chapman]
1       [John, Cleese]
2     [Terry, Gilliam]
3         [Eric, Idle]
4       [Terry, Jones]
5     [Michael, Palin]
dtype: object

Slicing

In [276]:
monte.str[0:3]
Out[276]:
0    Gra
1    Joh
2    Ter
3    Eri
4    Ter
5    Mic
dtype: object
In [277]:
monte.str[0:-1]
Out[277]:
0    Graham Chapma
1       John Clees
2     Terry Gillia
3         Eric Idl
4       Terry Jone
5     Michael Pali
dtype: object
In [73]:
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])

Case Conversion

SeriesObj.str.upper()
SeriesObj.str.lower()
In [74]:
s.str.upper()
Out[74]:
0       A
1       B
2       C
3    AABA
4    BACA
5     NaN
6    CABA
7     DOG
8     CAT
dtype: object

Number of Characters

In [75]:
s.str.len()
Out[75]:
0    1.0
1    1.0
2    1.0
3    4.0
4    4.0
5    NaN
6    4.0
7    3.0
8    3.0
dtype: float64
In [264]:
names = pd.Series(data)
names.str.capitalize()
Out[264]:
0    Peter
1     Paul
2     Yong
3     Mary
4    Guido
dtype: object

String Indexing

In [76]:
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan,'CABA', 'dog', 'cat'])
s
Out[76]:
0       A
1       B
2       C
3    Aaba
4    Baca
5     NaN
6    CABA
7     dog
8     cat
dtype: object
In [77]:
s.str[1]  # return char-1 (second char) of every item
Out[77]:
0    NaN
1    NaN
2    NaN
3      a
4      a
5    NaN
6      A
7      o
8      a
dtype: object

Splitting

Sample Data

In [78]:
s = pd.Series(['a_b_c', 'c_d_e', np.nan, 'f_g_h'])

Splitting base on a a delimieter Result is a SeriesObj with list of splitted characters

In [79]:
sp = s.str.split('_')
sp
Out[79]:
0    [a, b, c]
1    [c, d, e]
2          NaN
3    [f, g, h]
dtype: object

Retrieving Split Result
Use .str.get() to retrieve splitted elments

In [80]:
sp.str.get(-1) 
Out[80]:
0      c
1      e
2    NaN
3      h
dtype: object

Alternatively, use str[ ] for the same result

In [81]:
sp.str[-1]
Out[81]:
0      c
1      e
2    NaN
3      h
dtype: object

Split and Expand Into DataFrame

In [82]:
s.str.split('_',expand=True, n=5)  # limit expansion into n columns
Out[82]:
     0    1    2
0    a    b    c
1    c    d    e
2  NaN  NaN  NaN
3    f    g    h

Series Substring Extraction

Sample Data

In [83]:
s = pd.Series(['a1', 'b2', 'c3'])
s
Out[83]:
0    a1
1    b2
2    c3
dtype: object

Extract absed on regex matching
... to improve ...

In [84]:
type(s.str.extract('([ab])(\d)', expand=False))
Out[84]:
pandas.core.frame.DataFrame

Series DateTime Accessor .dt

If the underlying data is datetime64 type, then pandas exposed various properties and methos through dt accessor.

Sample Data

In [85]:
s = pd.Series([
    datetime(2000,1,1,0,0,0),
    datetime(1999,12,15,12,34,55),
    datetime(2020,3,8,5,7,12),
    datetime(2018,1,1,0,0,0),
    datetime(2003,3,4,5,6,7)
])
s
Out[85]:
0   2000-01-01 00:00:00
1   1999-12-15 12:34:55
2   2020-03-08 05:07:12
3   2018-01-01 00:00:00
4   2003-03-04 05:06:07
dtype: datetime64[ns]

Convert To

datetime.datetime
Use to_pydatetime() to convert into numpy.array of standard library datetime.datetime

In [86]:
pdt  = s.dt.to_pydatetime()
print( type(pdt) )
pdt
<class 'numpy.ndarray'>
Out[86]:
array([datetime.datetime(2000, 1, 1, 0, 0),
       datetime.datetime(1999, 12, 15, 12, 34, 55),
       datetime.datetime(2020, 3, 8, 5, 7, 12),
       datetime.datetime(2018, 1, 1, 0, 0),
       datetime.datetime(2003, 3, 4, 5, 6, 7)], dtype=object)

datetime.date
Use dt.date to convert into pandas.Series of standard library datetime.date
Is it possible to have a pandas.Series of datetime.datetime ? No, because Pandas want it as its own Timestamp.

In [87]:
sdt = s.dt.date
print( type(sdt[1] ))
print( type(sdt))
sdt
<class 'datetime.date'>
<class 'pandas.core.series.Series'>
Out[87]:
0    2000-01-01
1    1999-12-15
2    2020-03-08
3    2018-01-01
4    2003-03-04
dtype: object

Timestamp Attributes

A Series::DateTime object support below properties:

  • date
  • month
  • day
  • year
  • dayofweek
  • dayofyear
  • weekday
  • weekday_name
  • quarter
  • daysinmonth
  • hour
  • minute

Full list below:
https://pandas.pydata.org/pandas-docs/stable/reference/series.html#datetimelike-properties

In [88]:
s.dt.date
Out[88]:
0    2000-01-01
1    1999-12-15
2    2020-03-08
3    2018-01-01
4    2003-03-04
dtype: object
In [89]:
s.dt.month
Out[89]:
0     1
1    12
2     3
3     1
4     3
dtype: int64
In [90]:
s.dt.dayofweek
Out[90]:
0    5
1    2
2    6
3    0
4    1
dtype: int64
In [91]:
s.dt.weekday
Out[91]:
0    5
1    2
2    6
3    0
4    1
dtype: int64
In [92]:
s.dt.weekday_name
Out[92]:
0     Saturday
1    Wednesday
2       Sunday
3       Monday
4      Tuesday
dtype: object
In [93]:
s.dt.quarter
Out[93]:
0    1
1    4
2    1
3    1
4    1
dtype: int64
In [94]:
s.dt.daysinmonth
Out[94]:
0    31
1    31
2    31
3    31
4    31
dtype: int64
In [95]:
s.dt.time   # extract time as time Object
Out[95]:
0    00:00:00
1    12:34:55
2    05:07:12
3    00:00:00
4    05:06:07
dtype: object
In [96]:
s.dt.hour  # extract hour as integer
Out[96]:
0     0
1    12
2     5
3     0
4     5
dtype: int64
In [97]:
s.dt.minute # extract minute as integer
Out[97]:
0     0
1    34
2     7
3     0
4     6
dtype: int64

DataFrame

Constructor

From Row Oriented Data (List of Lists)

Create from List of Lists

DataFrame( [row_list1, row_list2, row_list3] )
DataFrame( [row_list1, row_list2, row_list3], column=columnName_list )
DataFrame( [row_list1, row_list2, row_list3], index=row_label_list )

Basic DataFrame with default Row Label and Column Header

In [98]:
pd.DataFrame ([[101,'Alice',40000,2017],
               [102,'Bob',  24000, 2017], 
               [103,'Charles',31000,2017]] )
Out[98]:
     0        1      2     3
0  101    Alice  40000  2017
1  102      Bob  24000  2017
2  103  Charles  31000  2017

Specify Column Header during Creation

In [99]:
pd.DataFrame ([[101,'Alice',40000,2017],
               [102,'Bob',  24000, 2017], 
               [103,'Charles',31000,2017]], columns = ['empID','name','salary','year'])
Out[99]:
   empID     name  salary  year
0    101    Alice   40000  2017
1    102      Bob   24000  2017
2    103  Charles   31000  2017

Specify Row Label during Creation

In [100]:
pd.DataFrame ([[101,'Alice',40000,2017],
               [102,'Bob',  24000, 2017], 
               [103,'Charles',31000,2017]], index   = ['r1','r2','r3'] )
Out[100]:
      0        1      2     3
r1  101    Alice  40000  2017
r2  102      Bob  24000  2017
r3  103  Charles  31000  2017

From Row Oriented Data (List of Dictionary)

DataFrame( [dict1, dict2, dict3] )
DataFrame( [row_list1, row_list2, row_list3], column=np.arrange )
DataFrame( [row_list1, row_list2, row_list3], index=row_label_list )

by default,keys will become collumn names, and autosorted

Default Column Name Follow Dictionary Key
Note missing info as NaN

In [101]:
pd.DataFrame ([{"name":"Yong", "id":1,"zkey":101},{"name":"Gan","id":2}])
Out[101]:
   id  name   zkey
0   1  Yong  101.0
1   2   Gan    NaN

Specify Index

In [102]:
pd.DataFrame ([{"name":"Yong", "id":'wd1'},{"name":"Gan","id":'wd2'}], 
             index = (1,2))
Out[102]:
    id  name
1  wd1  Yong
2  wd2   Gan

Specify Column Header during Creation, can acts as column filter and manual arrangement
Note missing info as NaN

In [103]:
pd.DataFrame ([{"name":"Yong", "id":1, "zkey":101},{"name":"Gan","id":2}], 
              columns=("name","id","zkey"))
Out[103]:
   name  id   zkey
0  Yong   1  101.0
1   Gan   2    NaN

From Column Oriented Data

Create from Dictrionary of List

DataFrame(  { 'column1': list1,
              'column2': list2,
              'column3': list3 } , 
              index    = row_label_list, 
              columns  = column_list)

By default, DataFrame will arrange the columns alphabetically, unless columns is specified

Default Row Label

In [104]:
data = {'empID':  [100,      101,    102,      103,     104],
        'year':   [2017,     2017,   2017,      2018,    2018],
        'salary': [40000,    24000,  31000,     20000,   30000],
        'name':   ['Alice', 'Bob',  'Charles', 'David', 'Eric']}
pd.DataFrame(data)
Out[104]:
   empID  year  salary     name
0    100  2017   40000    Alice
1    101  2017   24000      Bob
2    102  2017   31000  Charles
3    103  2018   20000    David
4    104  2018   30000     Eric

Specify Row Label during Creation

In [105]:
data = {'empID':  [100,      101,    102,      103,     104],
        'name':   ['Alice', 'Bob',  'Charles', 'David', 'Eric'],
        'year':   [2017,     2017,   2017,      2018,    2018],
        'salary': [40000,    24000,  31000,     20000,   30000] }
pd.DataFrame (data, index=['r1','r2','r3','r4','r5'])
Out[105]:
    empID     name  year  salary
r1    100    Alice  2017   40000
r2    101      Bob  2017   24000
r3    102  Charles  2017   31000
r4    103    David  2018   20000
r5    104     Eric  2018   30000

Manualy Choose Columns and Arrangement

In [106]:
data = {'empID':  [100,      101,    102,      103,     104],
        'name':   ['Alice', 'Bob',  'Charles', 'David', 'Eric'],
        'year':   [2017,     2017,   2017,      2018,    2018],
        'salary': [40000,    24000,  31000,     20000,   30000] }
pd.DataFrame (data, columns=('empID','name','salary'), index=['r1','r2','r3','r4','r5'])
Out[106]:
    empID     name  salary
r1    100    Alice   40000
r2    101      Bob   24000
r3    102  Charles   31000
r4    103    David   20000
r5    104     Eric   30000

Attributes

In [107]:
df = pd.DataFrame(
    { 'empID':  [100,      101,    102,      103,     104],
      'year1':   [2017,     2017,   2017,      2018,    2018],
      'name':   ['Alice',  'Bob',  'Charles','David', 'Eric'],
      'year2':   [2001,     1907,   2003,      1998,    2011],
      'salary': [40000,    24000,  31000,     20000,   30000]},
    columns = ['year1','salary','year2','empID','name'])

Dimensions

In [108]:
df.shape
Out[108]:
(5, 5)

Index

In [109]:
df.index
Out[109]:
RangeIndex(start=0, stop=5, step=1)

Underlying Index values are numpy object

In [110]:
df.index.values
Out[110]:
array([0, 1, 2, 3, 4], dtype=int64)

Columns

In [111]:
df.columns
Out[111]:
Index(['year1', 'salary', 'year2', 'empID', 'name'], dtype='object')

Underlying Index values are numpy object

In [112]:
df.columns.values
Out[112]:
array(['year1', 'salary', 'year2', 'empID', 'name'], dtype=object)

Values

Underlying Column values are numpy object

In [113]:
df.values
Out[113]:
array([[2017, 40000, 2001, 100, 'Alice'],
       [2017, 24000, 1907, 101, 'Bob'],
       [2017, 31000, 2003, 102, 'Charles'],
       [2018, 20000, 1998, 103, 'David'],
       [2018, 30000, 2011, 104, 'Eric']], dtype=object)

Index Manipulation

index and row label are used interchangeably in this book

Sample Data

Columns are intentionaly ordered in a messy way

In [114]:
df = pd.DataFrame(
    { 'empID':  [100,      101,    102,      103,     104],
      'year1':   [2017,     2017,   2017,      2018,    2018],
      'name':   ['Alice',  'Bob',  'Charles','David', 'Eric'],
      'year2':   [2001,     1907,   2003,      1998,    2011],
      'salary': [40000,    24000,  31000,     20000,   30000]},
    columns = ['year1','salary','year2','empID','name'])

print (df, '\n')
print (df.index)
   year1  salary  year2  empID     name
0   2017   40000   2001    100    Alice
1   2017   24000   1907    101      Bob
2   2017   31000   2003    102  Charles
3   2018   20000   1998    103    David
4   2018   30000   2011    104     Eric 

RangeIndex(start=0, stop=5, step=1)

Convert Column To Index

set_index('column_name', inplace=False)

inplace=True means don't create a new dataframe. Modify existing dataframe
inplace=False means return a new dataframe

In [115]:
print(df)
print(df.index,'\n')

df.set_index('empID',inplace=True) 
print(df)
print(df.index) # return new DataFrameObj
   year1  salary  year2  empID     name
0   2017   40000   2001    100    Alice
1   2017   24000   1907    101      Bob
2   2017   31000   2003    102  Charles
3   2018   20000   1998    103    David
4   2018   30000   2011    104     Eric
RangeIndex(start=0, stop=5, step=1) 

       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles
103     2018   20000   1998    David
104     2018   30000   2011     Eric
Int64Index([100, 101, 102, 103, 104], dtype='int64', name='empID')

Convert Index Back To Column

  • Reseting index will resequence the index as 0,1,2 etc
  • Old index column will be converted back as normal column
  • Operation support inplace** option
In [116]:
df.reset_index(inplace=True)
print(df)
   empID  year1  salary  year2     name
0    100   2017   40000   2001    Alice
1    101   2017   24000   1907      Bob
2    102   2017   31000   2003  Charles
3    103   2018   20000   1998    David
4    104   2018   30000   2011     Eric

Updating Index ( .index= )

Warning:

  • Updating index doesn't reorder the data sequence
  • Number of elements before and after reorder must match, otherwise error
  • Same label are allowed to repeat
  • Not reversable
In [117]:
df.index = [101, 101, 101, 102, 103]
print( df )
     empID  year1  salary  year2     name
101    100   2017   40000   2001    Alice
101    101   2017   24000   1907      Bob
101    102   2017   31000   2003  Charles
102    103   2018   20000   1998    David
103    104   2018   30000   2011     Eric

Reordering Index (. reindex )

  • Reindex will reorder the rows according to new index
  • The operation is not reversable

Start from this original dataframe

Change the order of Index, always return a new dataframe

In [118]:
df.index = [101,102,103,104,105]
print( df )                                ## original sequence
print( df.reindex([103,102,101,104,105]) ) ## new sequence, new dataframe
     empID  year1  salary  year2     name
101    100   2017   40000   2001    Alice
102    101   2017   24000   1907      Bob
103    102   2017   31000   2003  Charles
104    103   2018   20000   1998    David
105    104   2018   30000   2011     Eric
     empID  year1  salary  year2     name
103    102   2017   31000   2003  Charles
102    101   2017   24000   1907      Bob
101    100   2017   40000   2001    Alice
104    103   2018   20000   1998    David
105    104   2018   30000   2011     Eric

Subsetting Columns

Select Single Column Return Series

dataframe.columnName               # single column, name based, return Series object
dataframe[ single_col_name ]       # single column, name based, return Series object
dataframe[ [single_col_name] ]     # single column, name based, return DataFrame object

Select Single/Multiple Columns Return DataFrame

dataframe[ single/list_of_col_names ]                       # name based, return Dataframe object
dataframe.loc[ : , single_col_name  ]  # single column, series
dataframe.loc[ : , col_name_list    ]  # multiple columns, dataframe
dataframe.loc[ : , col_name_ranage  ]  # multiple columns, dataframe

dataframe.iloc[ : , col_number      ]  # single column, series
dataframe.iloc[ : , col_number_list ]  # multiple columns, dataframe
dataframe.iloc[ : , number_range    ]  # multiple columns, dataframe

Select Single Column

Selecting single column always return as panda::Series

In [119]:
df.name
Out[119]:
101      Alice
102        Bob
103    Charles
104      David
105       Eric
Name: name, dtype: object
In [120]:
df['name']
Out[120]:
101      Alice
102        Bob
103    Charles
104      David
105       Eric
Name: name, dtype: object
In [121]:
df.loc[:, 'name']
Out[121]:
101      Alice
102        Bob
103    Charles
104      David
105       Eric
Name: name, dtype: object
In [122]:
df.iloc[:, 3]
Out[122]:
101    2001
102    1907
103    2003
104    1998
105    2011
Name: year2, dtype: int64

Select Multiple Columns

Multiple columns return as panda::Dataframe object`

In [123]:
df[['name']]  # return one column dataframe
Out[123]:
        name
101    Alice
102      Bob
103  Charles
104    David
105     Eric
In [124]:
print(df.columns)
df[['name','year1']]
Index(['empID', 'year1', 'salary', 'year2', 'name'], dtype='object')
Out[124]:
        name  year1
101    Alice   2017
102      Bob   2017
103  Charles   2017
104    David   2018
105     Eric   2018
In [125]:
df.loc[:,['name','year1']]
Out[125]:
        name  year1
101    Alice   2017
102      Bob   2017
103  Charles   2017
104    David   2018
105     Eric   2018
In [126]:
df.loc[:,'year1':'year2']  # range of columns
Out[126]:
     year1  salary  year2
101   2017   40000   2001
102   2017   24000   1907
103   2017   31000   2003
104   2018   20000   1998
105   2018   30000   2011
In [127]:
df.iloc[:,[0,3]]
Out[127]:
     empID  year2
101    100   2001
102    101   1907
103    102   2003
104    103   1998
105    104   2011
In [128]:
df.iloc[:,0:3]
Out[128]:
     empID  year1  salary
101    100   2017   40000
102    101   2017   24000
103    102   2017   31000
104    103   2018   20000
105    104   2018   30000

Selection by Data Type

df.select_dtypes(include=None, exclude=None)

Always return panda::DataFrame, even though only single column matches.
Allowed types are:

  • number (integer and float)
  • integer / float
  • datetime
  • timedelta
  • category
In [129]:
df.get_dtype_counts()
Out[129]:
int64     4
object    1
dtype: int64
In [130]:
df.select_dtypes(exclude='number')
Out[130]:
        name
101    Alice
102      Bob
103  Charles
104    David
105     Eric
In [131]:
df.select_dtypes(exclude=('number','object'))
Out[131]:
Empty DataFrame
Columns: []
Index: [101, 102, 103, 104, 105]

Subset by filter()

.filter(items=None, like=None, regex=None, axis=1)

like = Substring Matches

In [132]:
df.filter( like='year',  axis='columns')  ## or axis = 1
Out[132]:
     year1  year2
101   2017   2001
102   2017   1907
103   2017   2003
104   2018   1998
105   2018   2011

items = list of column names

In [133]:
df.filter( items=('year1','year2'),  axis=1)  ## or axis = 1
Out[133]:
     year1  year2
101   2017   2001
102   2017   1907
103   2017   2003
104   2018   1998
105   2018   2011

regex = Regular Expression
Select column names that contain integer

In [134]:
df.filter(regex='\d')  ## default axis=1 if DataFrame
Out[134]:
     year1  year2
101   2017   2001
102   2017   1907
103   2017   2003
104   2018   1998
105   2018   2011

Column Manipulation

Sample Data

In [135]:
df
Out[135]:
     empID  year1  salary  year2     name
101    100   2017   40000   2001    Alice
102    101   2017   24000   1907      Bob
103    102   2017   31000   2003  Charles
104    103   2018   20000   1998    David
105    104   2018   30000   2011     Eric

Renaming Columns

Method 1 : Rename All Columns (.columns =)

  • Construct the new column names, check if there is no missing column names
  • Missing columns will return error
  • Direct Assignment to column property result in change to dataframe
In [136]:
new_columns = ['year.1','salary','year.2','empID','name']
df.columns = new_columns
df.head(2)
Out[136]:
     year.1  salary  year.2  empID   name
101     100    2017   40000   2001  Alice
102     101    2017   24000   1907    Bob

Method 2 : Renaming Specific Column (.rename (columns=) )

  • Change column name through rename function
  • Support inpalce option for original dataframe change
  • Missing column is OK
In [137]:
df.rename( columns={'year.1':'year1', 'year.2':'year2'}, inplace=True)
df.head(2)
Out[137]:
     year1  salary  year2  empID   name
101    100    2017  40000   2001  Alice
102    101    2017  24000   1907    Bob

Reordering Columns

Always return a new dataframe. There is no inplace option for reordering columns

Method 1 - reindex(columns = )

  • reindex may sounds like operation on row labels, but it works
  • Missmatch column names will result in NA for the unfound column
In [138]:
new_colorder = [ 'empID', 'name', 'salary', 'year1', 'year2']
df.reindex(columns = new_colorder).head(2)
Out[138]:
     empID   name  salary  year1  year2
101   2001  Alice    2017    100  40000
102   1907    Bob    2017    101  24000

Method 2 - [ ] notation

  • Missmatch column will result in ERROR
In [139]:
new_colorder = [ 'empID', 'name', 'salary', 'year1', 'year2']
df[new_colorder]
Out[139]:
     empID     name  salary  year1  year2
101   2001    Alice    2017    100  40000
102   1907      Bob    2017    101  24000
103   2003  Charles    2017    102  31000
104   1998    David    2018    103  20000
105   2011     Eric    2018    104  30000

Duplicating or Replacing Column

  • New Column will be created instantly using [] notation
  • DO NOT USE dot Notation because it is view only attribute
In [140]:
df['year3'] = df.year1
df
Out[140]:
     year1  salary  year2  empID     name  year3
101    100    2017  40000   2001    Alice    100
102    101    2017  24000   1907      Bob    101
103    102    2017  31000   2003  Charles    102
104    103    2018  20000   1998    David    103
105    104    2018  30000   2011     Eric    104

Dropping Columns (.drop)

dataframe.drop( columns='column_name',    inplace=True/False)   # delete single column
dataframe.drop( columns=list_of_colnames, inplace=True/False)   # delete multiple column

dataframe.drop( index='row_label',         inplace=True/False)   # delete single row
dataframe.drop( index= list_of_row_labels, inplace=True/False)   # delete multiple rows

inplace=True means column will be deleted from original dataframe. Default is False, which return a copy of dataframe

By Column Name(s)

In [141]:
df.drop( columns='year1') # drop single column
Out[141]:
     salary  year2  empID     name  year3
101    2017  40000   2001    Alice    100
102    2017  24000   1907      Bob    101
103    2017  31000   2003  Charles    102
104    2018  20000   1998    David    103
105    2018  30000   2011     Eric    104
In [142]:
df.drop(columns=['year2','year3'])  # drop multiple columns
Out[142]:
     year1  salary  empID     name
101    100    2017   2001    Alice
102    101    2017   1907      Bob
103    102    2017   2003  Charles
104    103    2018   1998    David
105    104    2018   2011     Eric

By Column Number(s)
Use dataframe.columns to produce interim list of column names

In [143]:
df.drop( columns=df.columns[[3,4,5]] )   # delete columns by list of column number
Out[143]:
     year1  salary  year2
101    100    2017  40000
102    101    2017  24000
103    102    2017  31000
104    103    2018  20000
105    104    2018  30000
In [144]:
df.drop( columns=df.columns[3:6] )       # delete columns by range of column number
Out[144]:
     year1  salary  year2
101    100    2017  40000
102    101    2017  24000
103    102    2017  31000
104    103    2018  20000
105    104    2018  30000

Subsetting Rows

dataframe.loc[ row_label       ]  # return series, single row
dataframe.loc[ row_label_list  ]  # multiple rows
dataframe.loc[ boolean_list    ]  # multiple rows

dataframe.iloc[ row_number       ]  # return series, single row
dataframe.iloc[ row_number_list  ]  # multiple rows
dataframe.iloc[ number_range     ]  # multiple rows

dataframe.sample(frac=)                                        # frac = 0.6 means sampling 60% of rows randomly

Sample Data

In [287]:
df = pd.DataFrame(
    { 'empID':  [100,      101,    102,      103,     104],
      'year1':   [2017,     2017,   2017,      2018,    2018],
      'name':   ['Alice',  'Bob',  'Charles','David', 'Eric'],
      'year2':   [2001,     1907,   2003,      1998,    2011],
      'salary': [40000,    24000,  31000,     20000,   30000]},
    columns = ['year1','salary','year2','empID','name']).set_index(['empID'])
df
Out[287]:
       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles
103     2018   20000   1998    David
104     2018   30000   2011     Eric

By Index or Boolean

Single Index return Series

In [146]:
df.loc[101]         # by single row label, return series
Out[146]:
year1      2017
salary    24000
year2      1907
name        Bob
Name: 101, dtype: object

List or Range of Indexes returns DataFrame

In [147]:
df.loc[ [100,103] ]  # by multiple row labels
Out[147]:
       year1  salary  year2   name
empID                             
100     2017   40000   2001  Alice
103     2018   20000   1998  David
In [148]:
df.loc[  100:103  ]  # by range of row labels
Out[148]:
       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles
103     2018   20000   1998    David

List of Boolean returns DataFrame

In [335]:
criteria = (df.salary > 30000) & (df.year1==2017)
print (criteria)
print (df.loc[criteria])
empID
100     True
101    False
102     True
103    False
104    False
dtype: bool
       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
102     2017   31000   2003  Charles

By Row Number

Single Row return Series

In [149]:
df.iloc[1]  # by single row number
Out[149]:
year1      2017
salary    24000
year2      1907
name        Bob
Name: 101, dtype: object

Multiple rows returned as dataframe object

In [150]:
df.iloc[ [0,3] ]    # by row numbers
Out[150]:
       year1  salary  year2   name
empID                             
100     2017   40000   2001  Alice
103     2018   20000   1998  David
In [151]:
df.iloc[  0:3  ]    # by row number range
Out[151]:
       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles

query()

.query(expr, inplace=False)

In [153]:
df.query('salary<=31000 and year1 == 2017')
Out[153]:
       year1  salary  year2     name
empID                               
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles

sample()

In [154]:
np.random.seed(15)
df.sample(frac=0.6) #randomly pick 60% of rows, without replacement
Out[154]:
       year1  salary  year2     name
empID                               
102     2017   31000   2003  Charles
103     2018   20000   1998    David
104     2018   30000   2011     Eric

Row Manipulation

Sample Data

Dropping Rows (.drop)

.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')

By Row Label(s)

In [155]:
df.drop(index=100)       # single row
Out[155]:
       year1  salary  year2     name
empID                               
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles
103     2018   20000   1998    David
104     2018   30000   2011     Eric
In [156]:
df.drop(index=[100,103])   # multiple rows
Out[156]:
       year1  salary  year2     name
empID                               
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles
104     2018   30000   2011     Eric

Slicing

Sample Data

In [336]:
df
Out[336]:
       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
101     1999   24000   1907      Bob
102     2017   31000   2003  Charles
103     2018   20000   1998    David
104     2018   30000   2011     Eric

Getting One Cell

By Row Label and Column Name (loc)

dataframe.loc [ row_label , col_name   ]    # by row label and column names
dataframe.loc [ bool_list , col_name   ]    # by row label and column names
dataframe.iloc[ row_number, col_number ]    # by row and column number
In [338]:
print (df.loc[100,'year1'])
2017

By Row Number and Column Number (iloc)

In [318]:
print (df.iloc[1,2])
1907

Getting Multiple Cells

Specify rows and columns (by individual or range)

dataframe.loc [ list/range_of_row_labels , list/range_col_names   ]    # by row label and column names
dataframe.iloc[ list/range_row_numbers,    list/range_col_numbers ]    # by row number

By Index and Column Name (loc)

In [327]:
print (df.loc[ [101,103], ['name','year1'] ], '\n')  # by list of row label and column names
print (df.loc[  101:104 ,  'year1':'year2'  ], '\n')  # by range of row label and column names
        name  year1
empID              
101      Bob   1999
103    David   2018 

       year1  salary  year2
empID                      
101     1999   24000   1907
102     2017   31000   2003
103     2018   20000   1998
104     2018   30000   2011 

By Boolean Row and Column Names (loc)

In [345]:
df.loc[df.year1==2017, 'year1':'year2']
Out[345]:
       year1  salary  year2
empID                      
100     2017   40000   2001
102     2017   31000   2003

By Row and Column Number (iloc)

In [344]:
print (df.iloc[ [1,4], [0,3]],'\n' )   # by individual rows/columns
print (df.iloc[  1:4 ,  0:3], '\n')    # by range
       year1  name
empID             
101     1999   Bob
104     2018  Eric 

       year1  salary  year2
empID                      
101     1999   24000   1907
102     2017   31000   2003
103     2018   20000   1998 

Chained Indexing

Chained Index Method creates a copy of dataframe, any modification of data on original dataframe does not affect the copy

dataframe.loc  [...]  [...]
dataframe.iloc [...]  [...]

Suggesting, never use chain indexing

In [382]:
df = pd.DataFrame(
    { 'empID':  [100,      101,    102,      103,     104],
      'year1':   [2017,     2017,   2017,      2018,    2018],
      'name':   ['Alice',  'Bob',  'Charles','David', 'Eric'],
      'year2':   [2001,     1907,   2003,      1998,    2011],
      'salary': [40000,    24000,  31000,     20000,   30000]},
    columns = ['year1','salary','year2','empID','name']).set_index(['empID'])
df
Out[382]:
       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles
103     2018   20000   1998    David
104     2018   30000   2011     Eric
In [384]:
df.loc[100]['year'] =2000
df  ## notice row label 100 had not been updated, because data was updated on a copy due to chain indexing
C:\ProgramData\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  """Entry point for launching an IPython kernel.
Out[384]:
       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles
103     2018   20000   1998    David
104     2018   30000   2011     Eric

Data Structure

Instance Methods - Structure

Find out the column names, data type in a summary. Output is for display only, not a data object

In [165]:
df.info()  # return text output
<class 'pandas.core.frame.DataFrame'>
Int64Index: 5 entries, 100 to 104
Data columns (total 4 columns):
year1     5 non-null int64
salary    5 non-null int64
year2     5 non-null int64
name      5 non-null object
dtypes: int64(3), object(1)
memory usage: 360.0+ bytes
In [166]:
df.get_dtype_counts() # return Series
Out[166]:
int64     3
object    1
dtype: int64

Conversion To Other Format

In [390]:
df.to_json()
Out[390]:
'{"year1":{"100":2017,"101":1999,"102":2017,"103":2018,"104":2018},"salary":{"100":40000,"101":24000,"102":31000,"103":20000,"104":30000},"year2":{"100":2001,"101":1907,"102":2003,"103":1998,"104":2011},"name":{"100":"Alice","101":"Bob","102":"Charles","103":"David","104":"Eric"}}'
In [391]:
df.to_records()
Out[391]:
rec.array([(100, 2017, 40000, 2001, 'Alice'),
           (101, 1999, 24000, 1907, 'Bob'),
           (102, 2017, 31000, 2003, 'Charles'),
           (103, 2018, 20000, 1998, 'David'),
           (104, 2018, 30000, 2011, 'Eric')],
          dtype=[('empID', '<i8'), ('year1', '<i8'), ('salary', '<i8'), ('year2', '<i8'), ('name', 'O')])
In [394]:
df.to_csv()
Out[394]:
'empID,year1,salary,year2,name\n100,2017,40000,2001,Alice\n101,1999,24000,1907,Bob\n102,2017,31000,2003,Charles\n103,2018,20000,1998,David\n104,2018,30000,2011,Eric\n'

Exploratory Analysis

Sample Data

In [167]:
df
Out[167]:
       year1  salary  year2     name
empID                               
100     2017   40000   2001    Alice
101     2017   24000   1907      Bob
102     2017   31000   2003  Charles
103     2018   20000   1998    David
104     2018   30000   2011     Eric

All Stats in One - .describe()

df.describe(include='number') # default
df.describe(include='object') # display for non-numeric columns
df.describe(include='all')    # display both numeric and non-numeric

When applied to DataFrame object, describe shows all basic statistic for all numeric columns:

  • Count (non-NA)
  • Unique (for string)
  • Top (for string)
  • Frequency (for string)
  • Percentile
  • Mean
  • Min / Max
  • Standard Deviation

For Numeric Columns only
You can customize the percentiles requred. Notice 0.5 percentile is always there although not specified

In [168]:
df.describe()
Out[168]:
             year1        salary        year2
count     5.000000      5.000000     5.000000
mean   2017.400000  29000.000000  1984.000000
std       0.547723   7615.773106    43.312816
min    2017.000000  20000.000000  1907.000000
25%    2017.000000  24000.000000  1998.000000
50%    2017.000000  30000.000000  2001.000000
75%    2018.000000  31000.000000  2003.000000
max    2018.000000  40000.000000  2011.000000
In [169]:
df.describe(percentiles=[0.9,0.3,0.2,0.1])
Out[169]:
             year1        salary        year2
count     5.000000      5.000000     5.000000
mean   2017.400000  29000.000000  1984.000000
std       0.547723   7615.773106    43.312816
min    2017.000000  20000.000000  1907.000000
10%    2017.000000  21600.000000  1943.400000
20%    2017.000000  23200.000000  1979.800000
30%    2017.000000  25200.000000  1998.600000
50%    2017.000000  30000.000000  2001.000000
90%    2018.000000  36400.000000  2007.800000
max    2018.000000  40000.000000  2011.000000

For both Numeric and Object

In [170]:
df.describe(include='all')
Out[170]:
         year1   salary   year2 name
count      5.0      5.0     5.0    5
unique     NaN      NaN     NaN    5
top        NaN      NaN     NaN  Bob
freq       NaN      NaN     NaN    1
mean    2017.4  29000.0  1984.0  NaN
...        ...      ...     ...  ...
min     2017.0  20000.0  1907.0  NaN
25%     2017.0  24000.0  1998.0  NaN
50%     2017.0  30000.0  2001.0  NaN
75%     2018.0  31000.0  2003.0  NaN
max     2018.0  40000.0  2011.0  NaN

[11 rows x 4 columns]

min/max/mean/median

In [171]:
df.min()  # default axis=0, column-wise
Out[171]:
year1      2017
salary    20000
year2      1907
name      Alice
dtype: object
In [172]:
df.min(axis=1) # axis=1, row-wise
Out[172]:
empID
100    2001
101    1907
102    2003
103    1998
104    2011
dtype: int64

Observe, sum on string will concatenate column-wise, whereas row-wise only sum up numeric fields

In [173]:
df.sum(0)
Out[173]:
year1                        10087
salary                      145000
year2                         9920
name      AliceBobCharlesDavidEric
dtype: object
In [174]:
df.sum(1)
Out[174]:
empID
100    44018
101    27924
102    35020
103    24016
104    34029
dtype: int64

Plotting

In [ ]:
 
In [ ]:
 

Categories

Creating

From List

Basic (Auto Category Mapping)
Basic syntax return categorical index with sequence with code 0,1,2,3... mapping to first found category
In this case, low(0), high(1), medium(2)

In [178]:
temp = ['low','high','medium','high','high','low','medium','medium','high']
temp_cat = pd.Categorical(temp)
temp_cat
Out[178]:
[low, high, medium, high, high, low, medium, medium, high]
Categories (3, object): [high, low, medium]
In [179]:
type( temp_cat )
Out[179]:
pandas.core.arrays.categorical.Categorical

Manual Category Mapping
During creation, we can specify mapping of codes to category: low(0), medium(1), high(2)

In [180]:
temp_cat = pd.Categorical(temp, categories=['low','medium','high'])
temp_cat
Out[180]:
[low, high, medium, high, high, low, medium, medium, high]
Categories (3, object): [low, medium, high]

From Series

  • We can 'add' categorical structure into a Series. With these methods, additional property (.cat) is added as a categorical accessor
  • Through this accessor, you gain access to various properties of the category such as .codes, .categories. But not .get_values() as the information is in the Series itself
  • Can we manual map category ?????
In [181]:
temp = ['low','high','medium','high','high','low','medium','medium','high']
temp_cat = pd.Series(temp, dtype='category')
print (type(temp_cat))       # Series object
print (type(temp_cat.cat))   # Categorical Accessor
<class 'pandas.core.series.Series'>
<class 'pandas.core.arrays.categorical.CategoricalAccessor'>
  • Method below has the same result as above by using .astype('category')
  • It is useful adding category structure into existing series.
In [182]:
temp_ser = pd.Series(temp)
temp_cat = pd.Series(temp).astype('category')
print (type(temp_cat))       # Series object
print (type(temp_cat.cat))   # Categorical Accessor
<class 'pandas.core.series.Series'>
<class 'pandas.core.arrays.categorical.CategoricalAccessor'>
In [183]:
temp_cat.cat.categories
Out[183]:
Index(['high', 'low', 'medium'], dtype='object')

Ordering Category

In [184]:
temp = ['low','high','medium','high','high','low','medium','medium','high']
temp_cat = pd.Categorical(temp, categories=['low','medium','high'], ordered=True)
temp_cat
Out[184]:
[low, high, medium, high, high, low, medium, medium, high]
Categories (3, object): [low < medium < high]
In [185]:
temp_cat.get_values()
Out[185]:
array(['low', 'high', 'medium', 'high', 'high', 'low', 'medium', 'medium',
       'high'], dtype=object)
In [186]:
temp_cat.codes
Out[186]:
array([0, 2, 1, 2, 2, 0, 1, 1, 2], dtype=int8)
In [187]:
temp_cat[0] < temp_cat[3]
Out[187]:
False

Properties

.categories

first element's code = 0
second element's code = 1
third element's code = 2

In [188]:
temp_cat.categories
Out[188]:
Index(['low', 'medium', 'high'], dtype='object')

.codes

Codes are actual integer value stored as array. 1 represent 'high',

In [189]:
temp_cat.codes
Out[189]:
array([0, 2, 1, 2, 2, 0, 1, 1, 2], dtype=int8)

Rename Category

Renamce To New Category Object

.rename_categories() method return a new category object with new changed categories

In [190]:
temp = ['low','high','medium','high','high','low','medium','medium','high']
new_temp_cat = temp_cat.rename_categories(['sejuk','sederhana','panas'])
new_temp_cat 
Out[190]:
[sejuk, panas, sederhana, panas, panas, sejuk, sederhana, sederhana, panas]
Categories (3, object): [sejuk < sederhana < panas]
In [191]:
temp_cat   # original category object categories not changed
Out[191]:
[low, high, medium, high, high, low, medium, medium, high]
Categories (3, object): [low < medium < high]

Rename Inplace

Observe the original categories had been changed using .rename()

In [192]:
temp_cat.categories = ['sejuk','sederhana','panas']
temp_cat   # original category object categories is changed
Out[192]:
[sejuk, panas, sederhana, panas, panas, sejuk, sederhana, sederhana, panas]
Categories (3, object): [sejuk < sederhana < panas]

Adding New Category

This return a new category object with added categories

In [193]:
temp_cat_more = temp_cat.add_categories(['susah','senang'])
temp_cat_more
Out[193]:
[sejuk, panas, sederhana, panas, panas, sejuk, sederhana, sederhana, panas]
Categories (5, object): [sejuk < sederhana < panas < susah < senang]

Removing Category

This is not in place, hence return a new categorical object

Remove Specific Categor(ies)

Elements with its category removed will become NaN

In [194]:
temp = ['low','high','medium','high','high','low','medium','medium','high']
temp_cat = pd.Categorical(temp)
temp_cat_removed = temp_cat.remove_categories('low')
temp_cat_removed
Out[194]:
[NaN, high, medium, high, high, NaN, medium, medium, high]
Categories (2, object): [high, medium]

Remove Unused Category

Since categories removed are not used, there is no impact to the element

In [195]:
print (temp_cat_more)
temp_cat_more.remove_unused_categories()
[sejuk, panas, sederhana, panas, panas, sejuk, sederhana, sederhana, panas]
Categories (5, object): [sejuk < sederhana < panas < susah < senang]
Out[195]:
[sejuk, panas, sederhana, panas, panas, sejuk, sederhana, sederhana, panas]
Categories (3, object): [sejuk < sederhana < panas]

Add and Remove Categories In One Step - Set()

In [196]:
temp = ['low','high','medium','high','high','low','medium','medium','high']
temp_cat = pd.Categorical(temp, ordered=True)
temp_cat
Out[196]:
[low, high, medium, high, high, low, medium, medium, high]
Categories (3, object): [high < low < medium]
In [197]:
temp_cat.set_categories(['low','medium','sederhana','susah','senang'])
Out[197]:
[low, NaN, medium, NaN, NaN, low, medium, medium, NaN]
Categories (5, object): [low < medium < sederhana < susah < senang]

Categorical Descriptive Analysis

At One Glance

In [198]:
temp_cat.describe()
Out[198]:
            counts     freqs
categories                  
high             4  0.444444
low              2  0.222222
medium           3  0.333333

Frequency Count

In [199]:
temp_cat.value_counts()
Out[199]:
high      4
low       2
medium    3
dtype: int64

Least Frequent Category, Most Frequent Category, and Most Frequent Category

In [200]:
( temp_cat.min(), temp_cat.max(), temp_cat.mode() )
Out[200]:
('high', 'medium', [high]
 Categories (3, object): [high < low < medium])

Other Methods

.get_values()

Since actual value stored by categorical object are integer codes, get_values() function return values translated from *.codes** property

In [201]:
temp_cat.get_values()  #array
Out[201]:
array(['low', 'high', 'medium', 'high', 'high', 'low', 'medium', 'medium',
       'high'], dtype=object)

Dummies

  • get_dummies creates columns for each categories
  • The underlying data can be string or pd.Categorical
  • It produces a new pd.DataFrame

Sample Data

In [202]:
df = pd.DataFrame (
    {'A': ['A1', 'A2', 'A3','A1','A3','A1'], 
     'B': ['B1','B2','B3','B1','B1','B3'],
     'C': ['C1','C2','C3','C1',np.nan,np.nan]})
df
Out[202]:
    A   B    C
0  A1  B1   C1
1  A2  B2   C2
2  A3  B3   C3
3  A1  B1   C1
4  A3  B1  NaN
5  A1  B3  NaN

Dummies on Array-Like Data

In [203]:
pd.get_dummies(df.A)
Out[203]:
   A1  A2  A3
0   1   0   0
1   0   1   0
2   0   0   1
3   1   0   0
4   0   0   1
5   1   0   0

Dummies on DataFrame (multiple columns)

All Columns

In [204]:
pd.get_dummies(df)
Out[204]:
   A_A1  A_A2  A_A3  B_B1  B_B2  B_B3  C_C1  C_C2  C_C3
0     1     0     0     1     0     0     1     0     0
1     0     1     0     0     1     0     0     1     0
2     0     0     1     0     0     1     0     0     1
3     1     0     0     1     0     0     1     0     0
4     0     0     1     1     0     0     0     0     0
5     1     0     0     0     0     1     0     0     0

Selected Columns

In [205]:
cols = ['A','B']
pd.get_dummies(df[cols])
Out[205]:
   A_A1  A_A2  A_A3  B_B1  B_B2  B_B3
0     1     0     0     1     0     0
1     0     1     0     0     1     0
2     0     0     1     0     0     1
3     1     0     0     1     0     0
4     0     0     1     1     0     0
5     1     0     0     0     0     1

Dummies with na

By default, nan values are ignored

In [206]:
pd.get_dummies(df.C)
Out[206]:
   C1  C2  C3
0   1   0   0
1   0   1   0
2   0   0   1
3   1   0   0
4   0   0   0
5   0   0   0

Make NaN as a dummy variable

In [207]:
pd.get_dummies(df.C,dummy_na=True)
Out[207]:
   C1  C2  C3  NaN
0   1   0   0    0
1   0   1   0    0
2   0   0   1    0
3   1   0   0    0
4   0   0   0    1
5   0   0   0    1

Specify Prefixes

In [208]:
pd.get_dummies(df.A, prefix='col')
Out[208]:
   col_A1  col_A2  col_A3
0       1       0       0
1       0       1       0
2       0       0       1
3       1       0       0
4       0       0       1
5       1       0       0
In [209]:
pd.get_dummies(df[cols], prefix=['colA','colB'])
Out[209]:
   colA_A1  colA_A2  colA_A3  colB_B1  colB_B2  colB_B3
0        1        0        0        1        0        0
1        0        1        0        0        1        0
2        0        0        1        0        0        1
3        1        0        0        1        0        0
4        0        0        1        1        0        0
5        1        0        0        0        0        1

Dropping First Column

  • Dummies cause colinearity issue for regression as it has redundant column.
  • Dropping a column does not loose any information technically
In [210]:
pd.get_dummies(df[cols],drop_first=True)
Out[210]:
   A_A2  A_A3  B_B2  B_B3
0     0     0     0     0
1     1     0     1     0
2     0     1     0     1
3     0     0     0     0
4     0     1     0     0
5     0     0     0     1

Getting External Data

html_table parser

  • Read the web page, create a list: which contain one or more dataframes that maps to each html table found
  • Auto detect column header
  • Auto create index using number starting from 0
    read_html(url)  # return list of dataframe(s) that maps to web table(s) structure
In [211]:
#df_list = pd.read_html('https://www.bloomberg.com/markets/currencies')
#print ('Total Table(s) Found : ', len(df_list))
#df = df_list[0]
#print (df)

CSV Import

Syntax

pandas.read_csv( 
    'url or filePath',                     # path to file or url 
    encoding    = 'utf_8',                 # optional: default is 'utf_8'
    index_col   = ['colName1', ...],       # optional: specify one or more index column
    parse_dates = ['dateCol1', ...],       # optional: specify multiple string column to convert to date
    na_values   = ['.','na','NA','N/A'],   # optional: values that is considered NA
    names       = ['newColName1', ... ],   # optional: overwrite column names
    thousands   = '.',                     # optional: thousand seperator symbol
    nrows       = n,                       # optional: load only first n rows
    skiprows    = 0                        # optional: don't load first n rows
)

Refer to full codec Python Codec.

Default Import

By default:

  • index is sequence of integer 0,1,2...
  • only two data type: number and string (auto detection)
  • date is not parsed, hence stayed as string
In [212]:
goo = pd.read_csv('data/goog.csv', encoding='utf_8')
In [213]:
goo.head()
Out[213]:
         Date        Open        High         Low       Close   Volume
0  12/19/2016  790.219971  797.659973  786.270020  794.200012  1225900
1  12/20/2016  796.760010  798.650024  793.270020  796.419983   925100
2  12/21/2016  795.840027  796.676025  787.099976  794.559998  1208700
3  12/22/2016  792.359985  793.320007  788.580017  791.260010   969100
4  12/23/2016  790.900024  792.739990  787.280029  789.909973   623400
In [214]:
goo.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 61 entries, 0 to 60
Data columns (total 6 columns):
Date      61 non-null object
Open      61 non-null float64
High      61 non-null float64
Low       61 non-null float64
Close     61 non-null float64
Volume    61 non-null int64
dtypes: float64(4), int64(1), object(1)
memory usage: 2.9+ KB

Specify Data Types

By default read_csv only import data types of float64 and object(str). This is done through auto detection.
To customize the data type, use dtype parameter with a dict of definition.

In [215]:
d_types = {'Volume': str}
pd.read_csv('data/goog.csv', dtype=d_types).head()
Out[215]:
         Date        Open        High         Low       Close   Volume
0  12/19/2016  790.219971  797.659973  786.270020  794.200012  1225900
1  12/20/2016  796.760010  798.650024  793.270020  796.419983   925100
2  12/21/2016  795.840027  796.676025  787.099976  794.559998  1208700
3  12/22/2016  792.359985  793.320007  788.580017  791.260010   969100
4  12/23/2016  790.900024  792.739990  787.280029  789.909973   623400
In [216]:
pd.read_csv('data/goog.csv', dtype=d_types).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 61 entries, 0 to 60
Data columns (total 6 columns):
Date      61 non-null object
Open      61 non-null float64
High      61 non-null float64
Low       61 non-null float64
Close     61 non-null float64
Volume    61 non-null object
dtypes: float64(4), object(2)
memory usage: 2.9+ KB

On The Fly Date Parsing and Indexing

You can specify multiple date-alike column for parsing

In [217]:
pd.read_csv('data/goog.csv', parse_dates=['Date']).head()
Out[217]:
        Date        Open        High         Low       Close   Volume
0 2016-12-19  790.219971  797.659973  786.270020  794.200012  1225900
1 2016-12-20  796.760010  798.650024  793.270020  796.419983   925100
2 2016-12-21  795.840027  796.676025  787.099976  794.559998  1208700
3 2016-12-22  792.359985  793.320007  788.580017  791.260010   969100
4 2016-12-23  790.900024  792.739990  787.280029  789.909973   623400
In [218]:
pd.read_csv('data/goog.csv', parse_dates=['Date']).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 61 entries, 0 to 60
Data columns (total 6 columns):
Date      61 non-null datetime64[ns]
Open      61 non-null float64
High      61 non-null float64
Low       61 non-null float64
Close     61 non-null float64
Volume    61 non-null int64
dtypes: datetime64[ns](1), float64(4), int64(1)
memory usage: 2.9 KB

Parse Date, Then Set as Index

When date is set as index, the type is DateTimeIndex

In [219]:
goo3 = pd.read_csv('data/goog.csv',index_col='Date', parse_dates=['Date'])
In [220]:
goo3.head()
Out[220]:
                  Open        High         Low       Close   Volume
Date                                                               
2016-12-19  790.219971  797.659973  786.270020  794.200012  1225900
2016-12-20  796.760010  798.650024  793.270020  796.419983   925100
2016-12-21  795.840027  796.676025  787.099976  794.559998  1208700
2016-12-22  792.359985  793.320007  788.580017  791.260010   969100
2016-12-23  790.900024  792.739990  787.280029  789.909973   623400

Observe index is now DateTime data type

In [221]:
type(goo3.index)
Out[221]:
pandas.core.indexes.datetimes.DatetimeIndex

Frequency Table (crosstab)

crosstab returns Dataframe Object

crosstab( index = <SeriesObj>, columns = <colName> )                    # one dimension table
crosstab( index = <SeriesObj>, columns = <SeriesObj> )                  # two dimension table
crosstab( index = <SeriesObj>, columns = [<SeriesObj1>, <SeriesObj2>] ) # multi dimension table   
crosstab( index = <SeriesObj>, columns = <SeriesObj>, margines=True )   # add column and row margins

Sample Data

In [222]:
n = 200
comp = ['C' + i for i in np.random.randint( 1,4, size  = n).astype(str)] # 3x Company
dept = ['D' + i for i in np.random.randint( 1,6, size  = n).astype(str)] # 5x Department
grp =  ['G' + i for i in np.random.randint( 1,3, size  = n).astype(str)] # 2x Groups
value1 = np.random.normal( loc=50 , scale=5 , size = n)
value2 = np.random.normal( loc=20 , scale=3 , size = n)
value3 = np.random.normal( loc=5 , scale=30 , size = n)

mydf = pd.DataFrame({
    'comp':comp, 
    'dept':dept, 
    'grp': grp,
    'value1':value1, 
    'value2':value2,
    'value3':value3 })
mydf.head()
Out[222]:
  comp dept grp     value1     value2     value3
0   C1   D3  G2  45.132603  20.170157   6.740557
1   C1   D3  G2  46.180146  19.885813  -7.651088
2   C2   D2  G2  54.856648  17.716647 -22.138893
3   C3   D4  G1  56.956977  20.149642  33.682010
4   C2   D2  G1  50.188809  22.869554  64.539563

One DimensionTable

In [223]:
pd.crosstab(index=mydf.comp, columns='counter')
Out[223]:
col_0  counter
comp          
C1          78
C2          62
C3          60
In [224]:
type(pd.crosstab(index=mydf.comp, columns='counter'))
Out[224]:
pandas.core.frame.DataFrame

Two Dimension Table

In [225]:
pd.crosstab(index=mydf.comp, columns=mydf.dept)
Out[225]:
dept  D1  D2  D3  D4  D5
comp                    
C1    13  13  17  21  14
C2     9  13  13  17  10
C3    12  13  10  13  12

Higher Dimension Table

In [226]:
tb = pd.crosstab(index=mydf.comp, columns=[mydf.dept, mydf.grp])
tb
Out[226]:
dept D1    D2    D3      D4     D5   
grp  G1 G2 G1 G2 G1  G2  G1  G2 G1 G2
comp                                 
C1    7  6  6  7  7  10   9  12  7  7
C2    5  4  6  7  6   7  10   7  3  7
C3    4  8  8  5  3   7   4   9  4  8

Get the subtable under D2

In [227]:
tb['D2']
Out[227]:
grp   G1  G2
comp        
C1     6   7
C2     6   7
C3     8   5

Getting Margin

New column and row labeled 'All' will be created

In [228]:
tb = pd.crosstab(index=mydf.dept, columns=mydf.grp, margins=True)
tb
Out[228]:
grp   G1   G2  All
dept              
D1    16   18   34
D2    20   19   39
D3    16   24   40
D4    23   28   51
D5    14   22   36
All   89  111  200
In [229]:
tb['All']   # row total, return a Series
Out[229]:
dept
D1      34
D2      39
D3      40
D4      51
D5      36
All    200
Name: All, dtype: int64
In [230]:
tb.loc['All'] # column total, return a Series
Out[230]:
grp
G1      89
G2     111
All    200
Name: All, dtype: int64

Getting Proportion

Use matrix operation divide for each cells over the margin

In [231]:
tb/tb.loc['All']
Out[231]:
grp         G1        G2    All
dept                           
D1    0.179775  0.162162  0.170
D2    0.224719  0.171171  0.195
D3    0.179775  0.216216  0.200
D4    0.258427  0.252252  0.255
D5    0.157303  0.198198  0.180
All   1.000000  1.000000  1.000

Reseting Index

  • When creating a crosstab, column specified by index will become index
  • To convert it to normal column, use reset_index()
    DataFrameObj.reset_index( inpalce=False )
In [232]:
tb.reset_index()
Out[232]:
grp dept  G1   G2  All
0     D1  16   18   34
1     D2  20   19   39
2     D3  16   24   40
3     D4  23   28   51
4     D5  14   22   36
5    All  89  111  200

GroupBy

  • Aggretation and summarization require creating DataFrameGroupBy object from existing DataFrame
  • The GroupBy object is a very flexible abstraction. In many ways, you can simply treat it as if it's a collection of DataFrames, and it does the difficult things under the hood
In [386]:
company = pd.read_csv('data/company.csv')
company.head()
Out[386]:
  Company Department      Name  Age  Salary  Birthdate
0      C1         D1      Yong   45   15000   1/1/1970
1      C1         D1      Chew   35   12000   2/1/1980
2      C1         D2       Lim   34    8000  2/19/1977
3      C1         D3     Jessy   23    2500  3/15/1990
4      C1         D3  Hoi Ming   55   25000  4/15/1987

Creating Groups

In [389]:
com_grp = company.groupby(['Company','Department'])
com_grp
Out[389]:
<pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000028FAE43BE10>

Properties

Number of Groups Created

In [236]:
com_grp.ngroups
Out[236]:
9

Row Numbers Associated For Each Group

In [237]:
com_grp.groups  # return Dictionary
Out[237]:
{('C1', 'D1'): Int64Index([0, 1], dtype='int64'),
 ('C1', 'D2'): Int64Index([2], dtype='int64'),
 ('C1', 'D3'): Int64Index([3, 4, 5], dtype='int64'),
 ('C2', 'D1'): Int64Index([6], dtype='int64'),
 ('C2', 'D2'): Int64Index([7, 8, 9], dtype='int64'),
 ('C2', 'D3'): Int64Index([10, 11, 12], dtype='int64'),
 ('C3', 'D1'): Int64Index([14], dtype='int64'),
 ('C3', 'D2'): Int64Index([15], dtype='int64'),
 ('C3', 'D3'): Int64Index([13, 16, 17], dtype='int64')}

Methods

Number of Rows In Each Group

In [238]:
com_grp.size()  # return panda Series object
Out[238]:
Company  Department
C1       D1            2
         D2            1
         D3            3
C2       D1            1
         D2            3
         D3            3
C3       D1            1
         D2            1
         D3            3
dtype: int64

Valid (not Null) Data Count For Each Fields In The Group

In [239]:
com_grp.count()  # return panda DataFrame object
Out[239]:
                    Name  Age  Salary  Birthdate
Company Department                              
C1      D1             2    2       2          2
        D2             1    1       1          1
        D3             3    3       3          3
C2      D1             1    1       1          1
        D2             3    3       3          3
        D3             3    3       3          3
C3      D1             1    1       1          1
        D2             1    1       1          1
        D3             3    3       3          3

Retrieve Rows

All row retrieval operations return a dataframe

Retrieve N Rows For Each Groups

Example below retrieve 2 rows from each group

In [240]:
com_grp.head(2)
Out[240]:
   Company Department      Name  Age  Salary   Birthdate
0       C1         D1      Yong   45   15000    1/1/1970
1       C1         D1      Chew   35   12000    2/1/1980
2       C1         D2       Lim   34    8000   2/19/1977
3       C1         D3     Jessy   23    2500   3/15/1990
4       C1         D3  Hoi Ming   55   25000   4/15/1987
..     ...        ...       ...  ...     ...         ...
11      C2         D3   Jeannie   30   12500  12/31/1980
13      C3         D3     Chang   32    7900   7/26/1973
14      C3         D1       Ong   44   17500   8/21/1980
15      C3         D2      Lily   41   15300   7/17/1990
16      C3         D3     Sally   54   21000   7/19/1968

[14 rows x 6 columns]

Retrieve Rows In One Specific Group

In [241]:
com_grp.get_group(('C1','D3'))
Out[241]:
  Company Department      Name  Age  Salary  Birthdate
3      C1         D3     Jessy   23    2500  3/15/1990
4      C1         D3  Hoi Ming   55   25000  4/15/1987
5      C1         D3   Sui Wei   56    3000  6/15/1990

Retrieve n-th Row From Each Group

Row number is 0-based

In [242]:
com_grp.nth(-1)    # retireve last row from each group
Out[242]:
                    Age   Birthdate     Name  Salary
Company Department                                  
C1      D1           35    2/1/1980     Chew   12000
        D2           34   2/19/1977      Lim    8000
        D3           56   6/15/1990  Sui Wei    3000
C2      D1           18   7/15/1997     Anne     400
        D2           46  10/31/1988    Jimmy   14000
        D3           29   12/1/1963  Bernard    9800
C3      D1           44   8/21/1980      Ong   17500
        D2           41   7/17/1990     Lily   15300
        D3           37   3/16/1969   Esther   13500

Iteration

DataFrameGroupBy object can be thought as a collection of named groups

In [243]:
def print_groups (g):
    for name,group in g:
        print (name)
        print (group[:2])
        
print_groups (com_grp)
('C1', 'D1')
  Company Department  Name  Age  Salary Birthdate
0      C1         D1  Yong   45   15000  1/1/1970
1      C1         D1  Chew   35   12000  2/1/1980
('C1', 'D2')
  Company Department Name  Age  Salary  Birthdate
2      C1         D2  Lim   34    8000  2/19/1977
('C1', 'D3')
  Company Department      Name  Age  Salary  Birthdate
3      C1         D3     Jessy   23    2500  3/15/1990
4      C1         D3  Hoi Ming   55   25000  4/15/1987
('C2', 'D1')
  Company Department  Name  Age  Salary  Birthdate
6      C2         D1  Anne   18     400  7/15/1997
('C2', 'D2')
  Company Department     Name  Age  Salary  Birthdate
7      C2         D2  Deborah   30    8600  8/15/1984
8      C2         D2  Nikalus   51   12000  9/18/2000
('C2', 'D3')
   Company Department     Name  Age  Salary   Birthdate
10      C2         D3  Michael   38   17000  11/30/1997
11      C2         D3  Jeannie   30   12500  12/31/1980
('C3', 'D1')
   Company Department Name  Age  Salary  Birthdate
14      C3         D1  Ong   44   17500  8/21/1980
('C3', 'D2')
   Company Department  Name  Age  Salary  Birthdate
15      C3         D2  Lily   41   15300  7/17/1990
('C3', 'D3')
   Company Department   Name  Age  Salary  Birthdate
13      C3         D3  Chang   32    7900  7/26/1973
16      C3         D3  Sally   54   21000  7/19/1968
In [244]:
com_grp
Out[244]:
<pandas.core.groupby.groupby.DataFrameGroupBy object at 0x0000028FADC90B70>

Apply Aggregate Functions to Groups

Aggregate apply functions to columns in every groups, and return a summary data for each group

Apply One Function to One or More Columns

In [245]:
com_grp['Age'].sum()
Out[245]:
Company  Department
C1       D1             80
         D2             34
         D3            134
C2       D1             18
         D2            127
         D3             97
C3       D1             44
         D2             41
         D3            123
Name: Age, dtype: int64
In [246]:
com_grp[['Age','Salary']].sum()
Out[246]:
                    Age  Salary
Company Department             
C1      D1           80   27000
        D2           34    8000
        D3          134   30500
C2      D1           18     400
        D2          127   34600
        D3           97   39300
C3      D1           44   17500
        D2           41   15300
        D3          123   42400

Apply One or More Functions To All Columns

In [247]:
com_grp.agg(np.mean)
Out[247]:
                          Age        Salary
Company Department                         
C1      D1          40.000000  13500.000000
        D2          34.000000   8000.000000
        D3          44.666667  10166.666667
C2      D1          18.000000    400.000000
        D2          42.333333  11533.333333
        D3          32.333333  13100.000000
C3      D1          44.000000  17500.000000
        D2          41.000000  15300.000000
        D3          41.000000  14133.333333
In [248]:
com_grp.agg([np.mean,np.sum])
Out[248]:
                          Age             Salary       
                         mean  sum          mean    sum
Company Department                                     
C1      D1          40.000000   80  13500.000000  27000
        D2          34.000000   34   8000.000000   8000
        D3          44.666667  134  10166.666667  30500
C2      D1          18.000000   18    400.000000    400
        D2          42.333333  127  11533.333333  34600
        D3          32.333333   97  13100.000000  39300
C3      D1          44.000000   44  17500.000000  17500
        D2          41.000000   41  15300.000000  15300
        D3          41.000000  123  14133.333333  42400

Apply Different Functions To Different Columns

In [249]:
com_grp.agg({'Age':np.mean, 'Salary': [np.min,np.max]})
Out[249]:
                          Age Salary       
                         mean   amin   amax
Company Department                         
C1      D1          40.000000  12000  15000
        D2          34.000000   8000   8000
        D3          44.666667   2500  25000
C2      D1          18.000000    400    400
        D2          42.333333   8600  14000
        D3          32.333333   9800  17000
C3      D1          44.000000  17500  17500
        D2          41.000000  15300  15300
        D3          41.000000   7900  21000

Transform

  • Transform is an operation used combined with DataFrameGroupBy object
  • transform() return a new DataFrame object
In [250]:
grp = company.groupby('Company')
grp.size()
Out[250]:
Company
C1    6
C2    7
C3    5
dtype: int64

transform() perform a function to a group, and expands and replicate it to multiple rows according to original DataFrame

In [251]:
grp[['Age','Salary']].transform('sum')
Out[251]:
    Age  Salary
0   248   65500
1   248   65500
2   248   65500
3   248   65500
4   248   65500
..  ...     ...
13  208   75200
14  208   75200
15  208   75200
16  208   75200
17  208   75200

[18 rows x 2 columns]
In [252]:
grp.transform( lambda x:x+10 )
Out[252]:
    Age  Salary
0    55   15010
1    45   12010
2    44    8010
3    33    2510
4    65   25010
..  ...     ...
13   42    7910
14   54   17510
15   51   15310
16   64   21010
17   47   13510

[18 rows x 2 columns]

Concat

Sample Data

In [253]:
s1 = pd.Series(['A1','A2','A3','A4'])
s2 = pd.Series(['B1','B2','B3','B4'])
s3 = pd.Series(['C1','C2','C3','C4'])
df = pd.DataFrame({ 'A': s1, 'B': s2})
df
Out[253]:
    A   B
0  A1  B1
1  A2  B2
2  A3  B3
3  A4  B4

Column-Wise

Multiple Arrays/Series

  • Added series will have 0,1,2,... column names
In [254]:
pd.concat([s1,s2,s3],axis=1)
Out[254]:
    0   1   2
0  A1  B1  C1
1  A2  B2  C2
2  A3  B3  C3
3  A4  B4  C4

DataFrame and Series

  • No change to original data frame column name
  • Added columns from series will have 0,1,2,3,.. column name
In [255]:
pd.concat([df,s3,s1],axis=1)
Out[255]:
    A   B   0   1
0  A1  B1  C1  A1
1  A2  B2  C2  A2
2  A3  B3  C3  A3
3  A4  B4  C4  A4

Row-Wise

In [ ]:
 
In [ ]:
 
In [ ]:
 

Fundamental Analysis

Structure of the Dataframe (.info())

info() is a function that print information to screen. It doesn't return any object

dataframe.info()  # display columns and number of rows (that has no missing data)
In [256]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 2 columns):
A    4 non-null object
B    4 non-null object
dtypes: object(2)
memory usage: 144.0+ bytes

First Few Rows (.head())

dataframe.head (n) # return dataframe of first n rows, default n = 5
In [257]:
df.head()
Out[257]:
    A   B
0  A1  B1
1  A2  B2
2  A3  B3
3  A4  B4

Missing Data

What Is Considered Missing Data ?

Sample Data

In [258]:
df = pd.DataFrame( np.random.randn(5, 3), 
                   index   =['a', 'c', 'e', 'f', 'h'],
                   columns =['one', 'two', 'three'])
df['four'] = 'bar'
df['five'] = df['one'] > 0
df
df.reindex(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
Out[258]:
        one       two     three four   five
a  0.366083 -0.690501 -0.736248  bar   True
b       NaN       NaN       NaN  NaN    NaN
c -0.607350  0.800183 -0.412550  bar  False
d       NaN       NaN       NaN  NaN    NaN
e  0.684213 -0.148327 -1.432006  bar   True
f  0.469932  0.420283  0.586002  bar   True
g       NaN       NaN       NaN  NaN    NaN
h -1.700706 -0.289902 -1.803585  bar  False

How Missing Data For Each Column ?

In [259]:
df.count()
Out[259]:
one      5
two      5
three    5
four     5
five     5
dtype: int64
In [260]:
len(df.index) - df.count()
Out[260]:
one      0
two      0
three    0
four     0
five     0
dtype: int64
In [261]:
df.isnull()
Out[261]:
     one    two  three   four   five
a  False  False  False  False  False
c  False  False  False  False  False
e  False  False  False  False  False
f  False  False  False  False  False
h  False  False  False  False  False
In [262]:
df.describe()
Out[262]:
            one       two     three
count  5.000000  5.000000  5.000000
mean  -0.157566  0.018347 -0.759677
std    0.995005  0.591203  0.931889
min   -1.700706 -0.690501 -1.803585
25%   -0.607350 -0.289902 -1.432006
50%    0.366083 -0.148327 -0.736248
75%    0.469932  0.420283 -0.412550
max    0.684213  0.800183  0.586002

Pandas DateTime

pandas contains extensive capabilities and features for working with time series data for all domains. Using the NumPy datetime64 and timedelta64 dtypes

panda.Timestamp, a subclass of datetime.datetime, is pandas’ scalar type for timezone-naive or timezone-aware datetime data. It mimics datetime.datime

DatetimeIndex

Creating

Source can be string, date, datetime object

Convert From

When the input is list-like, to_datetime convert to DateTimeIndex

In [278]:
dti = pd.to_datetime(['2011-01-03',      # from string
                date(2018,4,13),        # from date
                datetime(2018,3,1,7,30)]# from datetime
              )
dti
Out[278]:
DatetimeIndex(['2011-01-03 00:00:00', '2018-04-13 00:00:00',
               '2018-03-01 07:30:00'],
              dtype='datetime64[ns]', freq=None)
In [279]:
dti[1]
Out[279]:
Timestamp('2018-04-13 00:00:00')

Instance Method

Convert to datetime.datetime

Use to_pydatetime to convert into python standard datetime object

In [280]:
dti.to_pydatetime()
Out[280]:
array([datetime.datetime(2011, 1, 3, 0, 0),
       datetime.datetime(2018, 4, 13, 0, 0),
       datetime.datetime(2018, 3, 1, 7, 30)], dtype=object)

Convert to Series to_series

This creates index and data with the same value

In [281]:
dti = pd.date_range('2018-02', periods=4, freq='M')
dts = dti.to_series()
print( dts)
2018-02-28   2018-02-28
2018-03-31   2018-03-31
2018-04-30   2018-04-30
2018-05-31   2018-05-31
Freq: M, dtype: datetime64[ns]
In [ ]:
 

Convert to DataFrame to_frame()

This convert to single column dataframe with index as the same value

In [282]:
dtf = dti.to_frame()
dtf
Out[282]:
                    0
2018-02-28 2018-02-28
2018-03-31 2018-03-31
2018-04-30 2018-04-30
2018-05-31 2018-05-31
In [283]:
dtf.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 4 entries, 2018-02-28 to 2018-05-31
Freq: M
Data columns (total 1 columns):
0    4 non-null datetime64[ns]
dtypes: datetime64[ns](1)
memory usage: 64.0 bytes
In [ ]:
 

Properties

In [284]:
dti = pd.date_range('2018-02', periods=4, freq='D')
In [285]:
print( dti.weekday )
print( dti.month   )
Int64Index([3, 4, 5, 6], dtype='int64')
Int64Index([2, 2, 2, 2], dtype='int64')
In [ ]:
 
In [ ]:
 

matplotlib

Library

In [176]:
import matplotlib
import matplotlib.pyplot as plt

from plydata import define, query, select, group_by, summarize, arrange, head, rename
import plotnine
from plotnine import *

Sample Data

This chapter uses the sample data generate with below code. The idea is to simulate two categorical-alike feature, and two numeric value feature:

  • com is random character between ‘C1’, ‘C2’ and ‘C3’
  • dept is random character between ‘D1’, ‘D2’, ‘D3’, ‘D4’ and ‘D5’
  • grp is random character with randomly generated ‘G1’, ‘G2’
  • value1 represents numeric value, normally distributed at mean 50
  • value2 is numeric value, normally distributed at mean 25
In [177]:
n = 200
comp = ['C' + i for i in np.random.randint( 1,4, size  = n).astype(str)] # 3x Company
dept = ['D' + i for i in np.random.randint( 1,6, size  = n).astype(str)] # 5x Department
grp =  ['G' + i for i in np.random.randint( 1,3, size  = n).astype(str)] # 2x Groups
value1 = np.random.normal( loc=50 , scale=5 , size = n)
value2 = np.random.normal( loc=20 , scale=3 , size = n)
value3 = np.random.normal( loc=5 , scale=30 , size = n)

mydf = pd.DataFrame({
    'comp':comp, 
    'dept':dept, 
    'grp': grp,
    'value1':value1, 
    'value2':value2,
    'value3':value3 })
mydf.head()
Out[177]:
  comp dept grp     value1     value2     value3
0   C3   D4  G2  49.259153  17.587988  19.092745
1   C2   D5  G1  52.631445  20.660326   8.084155
2   C3   D5  G2  58.203905  20.580107  -4.092313
3   C1   D1  G1  43.757573  17.453912 -25.390765
4   C3   D2  G2  45.935129  24.022889   9.566659
In [178]:
mydf.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 6 columns):
comp      200 non-null object
dept      200 non-null object
grp       200 non-null object
value1    200 non-null float64
value2    200 non-null float64
value3    200 non-null float64
dtypes: float64(3), object(3)
memory usage: 9.5+ KB

MATLAB-like API

  • The good thing about the pylab MATLAB-style API is that it is easy to get started with if you are familiar with MATLAB, and it has a minumum of coding overhead for simple plots.
  • However, I'd encourrage not using the MATLAB compatible API for anything but the simplest figures.
  • Instead, I recommend learning and using matplotlib's object-oriented plotting API. It is remarkably powerful. For advanced figures with subplots, insets and other components it is very nice to work with.

Sample Data

In [179]:
# Sample Data
x = np.linspace(0,5,10)
y = x ** 2

Single Plot

In [180]:
plt.figure()
plt.xlabel('x')
plt.ylabel('y')
plt.plot(x,y,'red')
plt.title('My Good Data');

Multiple Subplots

Each call lto subplot() will create a new container for subsequent plot command

In [181]:
plt.figure()
plt.subplot(1,2,1) # 1 row, 2 cols, at first box
plt.plot(x,y,'r--')
plt.subplot(1,2,2) # 1 row, 2 cols, at second box
plt.plot(y,x,'g*-');

Object-Oriented API

Sample Data

In [182]:
# Sample Data
x = np.linspace(0,5,10)
y = x ** 2

Single Plot

One figure, one axes

In [183]:
fig = plt.figure()
axes = fig.add_axes([0,0,1,1]) # left, bottom, width, height (range 0 to 1)
axes.plot(x, y, 'r')
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('title');

Multiple Axes In One Plot

  • This is still considered a single plot, but with multiple axes
In [184]:
fig = plt.figure()
ax1 = fig.add_axes([0, 0, 1, 1])         # main axes
ax2 = fig.add_axes([0.2, 0.5, 0.4, 0.3]) # inset axes

ax1.plot(x,y,'r')
ax1.set_xlabel('x')
ax1.set_ylabel('y')

ax2.plot(y, x, 'g')
ax2.set_xlabel('y')
ax2.set_ylabel('x')
ax2.set_title('insert title');

Multiple Subplots

  • One figure can contain multiple subplots
  • Each subplot has one axes

Simple Subplots - all same size

  • subplots() function return axes object that is iterable.

Single Row Grid
Single row grid means axes is an 1-D array. Hence can use for to iterate through axes

In [185]:
fig, axes = plt.subplots( nrows=1,ncols=3 )
print (axes.shape)
for ax in axes:
    ax.plot(x, y, 'r')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title('title')
    ax.text(0.2,0.5,'One')
(3,)

Multiple Row Grid
Multile row grid means axes is an 2-D array. Hence can use two levels of for loop to iterate through each row and column

In [186]:
fig, axes = plt.subplots(2, 3, sharex='col', sharey='row')
print (axes.shape)
for i in range(axes.shape[0]):
    for j in range(axes.shape[1]):
        axes[i, j].text(0.5, 0.5, str((i, j)),
                      fontsize=18, ha='center')
(2, 3)

Complicated Subplots - different size

  • GridSpec specify grid size of the figure
  • Manually specify each subplot and their relevant grid position and size
In [187]:
plt.figure(figsize=(5,5))
grid = plt.GridSpec(2, 3, hspace=0.4, wspace=0.4)
plt.subplot(grid[0, 0])  #row 0, col 0
plt.subplot(grid[0, 1:]) #row 0, col 1 to :
plt.subplot(grid[1, :2]) #row 1, col 0:2 
plt.subplot(grid[1, 2]); #row 1, col 2
In [188]:
plt.figure(figsize=(5,5))
grid = plt.GridSpec(4, 4, hspace=0.8, wspace=0.4)
plt.subplot(grid[:3, 0])    # row 0:3, col 0
plt.subplot(grid[:3, 1: ])  # row 0:3, col 1:
plt.subplot(grid[3, 1: ]);  # row 3,   col 1:

-1 means last row or column

In [189]:
plt.figure(figsize=(6,6))
grid = plt.GridSpec(4, 4, hspace=0.4, wspace=1.2)
plt.subplot(grid[:-1, 0 ])  # row 0 till last row (not including last row), col 0
plt.subplot(grid[:-1, 1:])  # row 0 till last row (not including last row), col 1 till end
plt.subplot(grid[-1, 1: ]); # row last row, col 1 till end

Figure Customization

Avoid Overlap - Use tight_layout()

Sometimes when the figure size is too small, plots will overlap each other.

  • tight_layout() will introduce extra white space in between the subplots to avoid overlap.
  • The figure became wider.
In [190]:
fig, axes = plt.subplots( nrows=1,ncols=2)
for ax in axes:
    ax.plot(x, y, 'r')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title('title')
fig.tight_layout() # adjust the positions of axes so that there is no overlap

Avoid Overlap - Change Figure Size

In [191]:
fig, axes = plt.subplots( nrows=1,ncols=2,figsize=(12,3))
for ax in axes:
    ax.plot(x, y, 'r')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title('title')

Text Within Figure

In [192]:
fig = plt.figure()
fig.text(0.5, 0.5, 'This Is A Sample',fontsize=18, ha='center');
axes = fig.add_axes([0,0,1,1]) # left, bottom, width, height (range 0 to 1)

Axes Customization

Y-Axis Limit

In [193]:
fig = plt.figure()
fig.add_axes([0,0,1,1], ylim=(-2,5));

Text Within Axes

In [194]:
fig, ax = plt.subplots(2, 3, sharex='col', sharey='row')
for i in range(2):
    for j in range(3):
        ax[i, j].text(0.5, 0.5, str((i, j)),
                      fontsize=18, ha='center')
In [195]:
plt.text(0.5, 0.5, 'one',fontsize=18, ha='center')
Out[195]:
Text(0.5,0.5,'one')

Share Y Axis Label

In [196]:
fig, ax = plt.subplots(2, 3, sharex='col', sharey='row') # removed inner label
In [ ]:
 

Create Subplot Individually

Each call lto subplot() will create a new container for subsequent plot command

In [197]:
plt.subplot(2,4,1)
plt.text(0.5, 0.5, 'one',fontsize=18, ha='center')

plt.subplot(2,4,8)
plt.text(0.5, 0.5, 'eight',fontsize=18, ha='center')
Out[197]:
Text(0.5,0.5,'eight')

Iterate through subplots (ax) to populate them

In [198]:
fig, ax = plt.subplots(2, 3, sharex='col', sharey='row')
for i in range(2):
    for j in range(3):
        ax[i, j].text(0.5, 0.5, str((i, j)),
                      fontsize=18, ha='center')

Histogram

In [271]:
plt.hist(mydf.value1, bins=12);

Scatter Plot

In [276]:
plt.scatter(mydf.value1, mydf.value2);

Bar Chart

In [315]:
com_grp = mydf.groupby('comp')
grpdf = com_grp['value1'].sum().reset_index()
grpdf
Out[315]:
  comp       value1
0   C1  1412.606519
1   C2  2088.746830
2   C3  1532.740700
In [290]:
plt.bar(grpdf.comp, grpdf.value1);
plt.xlabel('Company')
plt.ylabel('Sum of Value 1')
Out[290]:
Text(0,0.5,'Sum of Value 1')

seaborn

Seaborn and Matplotlib

  • seaborn returns a matplotlib object that can be modified by the options in the pyplot module
  • Often, these options are wrapped by seaborn and .plot() in pandas and available as arguments

Sample Data

In [199]:
n = 100
comp = ['C' + i for i in np.random.randint( 1,4, size  = n).astype(str)] # 3x Company
dept = ['D' + i for i in np.random.randint( 1,4, size  = n).astype(str)] # 5x Department
grp =  ['G' + i for i in np.random.randint( 1,4, size  = n).astype(str)] # 2x Groups
value1 = np.random.normal( loc=50 , scale=5 , size = n)
value2 = np.random.normal( loc=20 , scale=3 , size = n)
value3 = np.random.normal( loc=5 , scale=30 , size = n)

mydf = pd.DataFrame({
    'comp':comp, 
    'dept':dept, 
    'grp': grp,
    'value1':value1, 
    'value2':value2,
    'value3':value3 
})
mydf.head()
Out[199]:
  comp dept grp     value1     value2     value3
0   C1   D2  G2  47.432744  18.323433  42.768271
1   C2   D1  G3  46.153260  20.852176  17.194632
2   C2   D2  G3  46.309545  26.438398  31.674028
3   C2   D3  G2  34.668435  17.262189  18.806680
4   C3   D3  G2  46.021468  20.394564  48.391633

Scatter Plot

2x Numeric

In [200]:
sns.lmplot(x='value1', y='value2', data=mydf);
In [201]:
sns.lmplot(x='value1', y='value2', fit_reg=False, data=mydf);  #hide regresion line

2xNumeric + 1x Categorical

Use hue to represent additional categorical feature

In [202]:
sns.lmplot(x='value1', y='value2', data=mydf, hue='comp', fit_reg=False);

2xNumeric + 2x Categorical

Use col and hue to represent two categorical features

In [203]:
sns.lmplot(x='value1', y='value2', col='comp',hue='grp', fit_reg=False, data=mydf);

2xNumeric + 3x Categorical

Use row, col and hue to represent three categorical features

In [204]:
sns.lmplot(x='value1', y='value2', row='dept',col='comp', hue='grp', fit_reg=False, data=mydf);

Customization

size

size: height in inch for each facet

In [205]:
sns.lmplot(x='value1', y='value2', col='comp',hue='grp', size=3,fit_reg=False, data=mydf);

Observe that even size is very large, lmplot will fit (shrink) everything into one row by deafult. See example below.

In [206]:
sns.lmplot(x='value1', y='value2', col='comp',hue='grp', size=5,fit_reg=False, data=mydf);

col_wrap

To avoid lmplot from shrinking the chart, we use col_wrap=<col_number to wrap the output.
Compare the size (height of each facet) with the above without col_wrap. Below chart is larger.

In [207]:
sns.lmplot(x='value1', y='value2', col='comp',hue='grp', size=5, col_wrap=2, fit_reg=False, data=mydf);

Histogram

seaborn.distplot(
  a,               # Series, 1D Array or List
  bins=None,
  hist=True,
  rug = False,
  vertical=False
)

1x Numeric

In [208]:
sns.distplot(mydf.value1)
Out[208]:
<matplotlib.axes._subplots.AxesSubplot at 0x1d576f3a860>
In [209]:
sns.distplot(mydf.value1,hist=True,rug=True,vertical=True, bins=30,color='g')
Out[209]:
<matplotlib.axes._subplots.AxesSubplot at 0x1d576f83ac8>

Bar Chart

In [316]:
com_grp = mydf.groupby('comp')
grpdf = com_grp['value1'].sum().reset_index()
grpdf
Out[316]:
  comp       value1
0   C1  1412.606519
1   C2  2088.746830
2   C3  1532.740700

1x Categorical, 1x Numeric

In [317]:
sns.barplot(x='comp',y='value1',data=grpdf)
C:\ProgramData\Anaconda3\lib\site-packages\seaborn\categorical.py:1460: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  stat_data = remove_na(group_data)
Out[317]:
<matplotlib.axes._subplots.AxesSubplot at 0x1d5017b59e8>

Customization

Ordering

In [237]:
sns.barplot(x='comp',y='value2', hue='grp',
            order=['C3','C2','C1'],
            hue_order=['G1','G2','G3'],
            data=mydf
)
C:\ProgramData\Anaconda3\lib\site-packages\seaborn\categorical.py:1508: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  stat_data = remove_na(group_data[hue_mask])
Out[237]:
<matplotlib.axes._subplots.AxesSubplot at 0x1d5760eceb8>

Flipping X/Y Axis

In [238]:
sns.barplot(x='value2',y='comp', hue='grp',data=mydf)
C:\ProgramData\Anaconda3\lib\site-packages\seaborn\categorical.py:1508: FutureWarning: remove_na is deprecated and is a private function. Do not use.
  stat_data = remove_na(group_data[hue_mask])
Out[238]:
<matplotlib.axes._subplots.AxesSubplot at 0x1d57298bfd0>

Faceting

Faceting in Seaborn is a generic function that works with matplotlib various plot utility.
It support matplotlib as well as seaborn plotting utility.

Faceting Histogram

In [256]:
g = sns.FacetGrid(mydf, col="comp", row='dept')
g.map(plt.hist, "value1");
In [258]:
g = sns.FacetGrid(mydf, col="comp", row='dept')
g.map(plt.hist, "value1");

Faceting Scatter Plot

In [296]:
g = sns.FacetGrid(mydf, col="comp", row='dept',hue='grp')
g.map(plt.scatter, "value1","value2",alpha=0.7);
g.add_legend()
Out[296]:
<seaborn.axisgrid.FacetGrid at 0x1d57a58ca58>

Pair Grid

Simple Pair Grid

In [304]:
g = sns.PairGrid(mydf, hue='comp')
g.map(plt.scatter);
g.add_legend()
Out[304]:
<seaborn.axisgrid.PairGrid at 0x1d500027320>

Different Diag and OffDiag

In [306]:
g = sns.PairGrid(mydf, hue='comp')
g.map_diag(plt.hist, bins=15)
g.map_offdiag(plt.scatter);
g.add_legend();

plotnine

Histogram

1xNumeric

plotnine.ggplot( dataframe, aex(x='colName')) + geom_histogram( bins=10 )
plotnine.ggplot( dataframe, aex(x='colName')) + geom_histogram( binwidth=? )
In [211]:
plotnine.options.figure_size = (3, 3)
ggplot(mydf, aes(x='value1')) + geom_histogram()  # default bins = 10
C:\ProgramData\Anaconda3\lib\site-packages\plotnine\stats\stat_bin.py:90: UserWarning: 'stat_bin()' using 'bins = 9'. Pick better value with 'binwidth'.
  warn(msg.format(params['bins']))
Out[211]:
<ggplot: (-9223371910833822292)>
In [212]:
ggplot(mydf, aes(x='value1')) + geom_histogram(bins = 15)
Out[212]:
<ggplot: (126021179582)>
In [213]:
ggplot(mydf, aes(x='value1')) + geom_histogram(binwidth = 3)
Out[213]:
<ggplot: (-9223371910833576518)>

1xNumeric + 1xCategorical

plotnine.ggplot( dataframe, 
                    aes(x='colName'), 
                    fill='categorical-alike-colName') 
+ geom_histogram()
In [214]:
ggplot(mydf, aes(x='value1', fill='grp')) + geom_histogram(bins=15)
Out[214]:
<ggplot: (126021224228)>

Scatter Plot

2x Numeric

In [215]:
ggplot(mydf, aes(x='value1',y='value2')) + geom_point()
Out[215]:
<ggplot: (126021263052)>

2x Numeric + 1x Categorical

ggplot( DataFrame, aes(x='colName1',y='colName2')) 
    + geom_point( aes(
        color='categorical-alike-colName',
        size='numberColName'
    ))
In [216]:
ggplot(mydf, aes(x='value1',y='value2')) + geom_point(aes(color='grp'))
Out[216]:
<ggplot: (-9223371910833254221)>
In [217]:
ggplot(mydf, aes(x='value1',y='value2',color='grp')) + geom_point()
Out[217]:
<ggplot: (126021563554)>
In [218]:
ggplot(mydf, aes(x='value1',y='value2')) + \
    geom_point(aes(
        color='grp'
    ))
Out[218]:
<ggplot: (-9223371910831519905)>

2x Numeric + 1x Numeric + 1x Categorical

In [219]:
ggplot(mydf, aes(x='value1',y='value2')) + \
    geom_point(aes( 
        color='grp', size='value3'
    ))
Out[219]:
<ggplot: (126021524039)>

Overlay Smooth Line

In [220]:
ggplot(mydf, aes(x='value1', y='value2')) + \
    geom_point() + \
    geom_smooth()          # default method='loess'
C:\ProgramData\Anaconda3\lib\site-packages\plotnine\stats\smoothers.py:150: UserWarning: Confidence intervals are not yet implementedfor lowess smoothings.
  warnings.warn("Confidence intervals are not yet implemented"
Out[220]:
<ggplot: (-9223371910831489469)>
In [221]:
ggplot(mydf, aes(x='value1', y='value2',fill='grp')) + \
    geom_point() + \
    geom_smooth(
        se=True,
        color='red',
        method='lm', 
        level=0.75)
Out[221]:
<ggplot: (-9223371910831435674)>

Line Chart

2x Numeric Data

In [222]:
ggplot (mydf.head(15), aes(x='value1', y='value2')) + geom_line()
Out[222]:
<ggplot: (126023819184)>

1x Numeric, 1x Categorical

In [223]:
ggplot (mydf.head(15), aes(x='dept', y='value1')) + geom_line()
Out[223]:
<ggplot: (-9223371910831255748)>
In [224]:
ggplot (mydf.head(30), aes(x='dept', y='value1')) + geom_line( aes(group=1))
Out[224]:
<ggplot: (-9223371910830920360)>

2x Numeric, 1x Categorical

In [225]:
ggplot (mydf.head(15), aes(x='value1', y='value2')) + geom_line( aes(color='grp'),size=2)
Out[225]:
<ggplot: (-9223371910830909678)>

Bar Chart

1x Categorical

Single categorical variable produces frequency chart.

In [226]:
tmpdf = mydf.groupby(['comp'],as_index=False).count()
tmpdf
Out[226]:
  comp  dept  grp  value1  value2  value3
0   C1    28   28      28      28      28
1   C2    41   41      41      41      41
2   C3    31   31      31      31      31
In [227]:
tmpdf.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3 entries, 0 to 2
Data columns (total 6 columns):
comp      3 non-null object
dept      3 non-null int64
grp       3 non-null int64
value1    3 non-null int64
value2    3 non-null int64
value3    3 non-null int64
dtypes: int64(5), object(1)
memory usage: 168.0+ bytes
In [228]:
ggplot (tmpdf, aes(x='comp', y='grp')) +geom_col()
Out[228]:
<ggplot: (-9223371910831421454)>

sklearn

This is a machine learning library.

The Library

sklearn does not automatically import its subpackages. Therefore all subpakcages must be specifically loaded before use.

In [93]:
# Sample Data
from sklearn                 import datasets

# Model Selection
from sklearn.model_selection import train_test_split
from sklearn.model_selection import KFold
from sklearn.model_selection import LeaveOneOut
from sklearn.model_selection import cross_validate

# Preprocessing
from sklearn.preprocessing   import Imputer
from sklearn.preprocessing   import MinMaxScaler
from sklearn.preprocessing   import StandardScaler
from sklearn.preprocessing   import Normalizer
from sklearn.preprocessing   import PolynomialFeatures

# Model and Pipeline
from sklearn.linear_model    import LinearRegression,Lasso
from sklearn.pipeline        import make_pipeline

# Measurement
from sklearn.metrics         import *

import statsmodels.formula.api as smf

Model Fitting

split

Underfitting

  • The model does not fit the training data and therefore misses the trends in the data
  • The model cannot be generalized to new data, this is usually the result of a very simple model (not enough predictors/independent variables)
  • The model will have poor predictive ability
  • For example, we fit a linear model (like linear regression) to data that is not linear

Overfitting

  • The model has trained “too well” and is now, well, fit too closely to the training dataset
  • The model is too complex (i.e. too many features/variables compared to the number of observations)
  • The model will be very accurate on the training data but will probably be very not accurate on untrained or new data
  • The model is not generalized (or not AS generalized), meaning you can generalize the results
  • The model learns or describes the “noise” in the training data instead of the actual relationships between variables in the data

Just Right

  • It is worth noting the underfitting is not as prevalent as overfitting
  • Nevertheless, we want to avoid both of those problems in data analysis
  • We want to find the middle ground between under and overfitting our model

Model Tuning

  • A highly complex model tend to overfit
  • A too flexible model tend to underfit

Complexity can be reduced by:

  • Less features
  • Less degree of polynomial features
  • Apply generalization (tuning hyperparameters)

split

High Level ML Process

split

Built-in Datasets

sklearn included some popular datasets to play with
Each dataset is of type Bunch.
It has useful data (array) in the form of properties:

  • keys (display all data availabe within the dataset)
  • data (common)
  • target (common)
  • DESCR (common)
  • feature_names (some dataset)
  • target_names (some dataset)
  • images (some dataset)

diabetes (regression)

Load Dataset

In [37]:
diabetes = datasets.load_diabetes()
print (type(diabetes))
<class 'sklearn.utils.Bunch'>

keys

In [34]:
diabetes.keys()
Out[34]:
dict_keys(['data', 'target', 'DESCR', 'feature_names'])

Features and Target

.data = features - two dimension array
.target = target - one dimension array

In [25]:
print (type(diabetes.data))
print (type(diabetes.target))
print (diabetes.data.shape)
print (diabetes.target.shape)
<class 'numpy.ndarray'>
<class 'numpy.ndarray'>
(442, 10)
(442,)

Load with X,y (Convenient Method)

using return_X_y = True, data is loaded into X, target is loaded into y

In [38]:
X,y      = datasets.load_diabetes(return_X_y=True)
In [36]:
print (X.shape)
print (y.shape)
(442, 10)
(442,)

digits (Classification)

This is a copy of the test set of the UCI ML hand-written digits datasets

In [47]:
digits = datasets.load_digits()
print (type(digits))
print (type(digits.data))
<class 'sklearn.utils.Bunch'>
<class 'numpy.ndarray'>
In [49]:
digits.keys()
Out[49]:
dict_keys(['data', 'target', 'target_names', 'images', 'DESCR'])
In [91]:
digits.target_names
Out[91]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

data

In [41]:
digits.data.shape  # features
Out[41]:
(1797, 64)
In [43]:
digits.target.shape # target
Out[43]:
(1797,)

Images

  • images is 3 dimensional array
  • There are 1797 samples, each sample is 8x8 pixels
In [68]:
digits.images.shape
Out[68]:
(1797, 8, 8)
In [70]:
type(digits.images)
Out[70]:
numpy.ndarray

Each element represent the data that make its target

In [84]:
print (digits.target[100])
print (digits.images[100])
plt.matshow(digits.images[100]) 
4
[[  0.   0.   0.   2.  13.   0.   0.   0.]
 [  0.   0.   0.   8.  15.   0.   0.   0.]
 [  0.   0.   5.  16.   5.   2.   0.   0.]
 [  0.   0.  15.  12.   1.  16.   4.   0.]
 [  0.   4.  16.   2.   9.  16.   8.   0.]
 [  0.   0.  10.  14.  16.  16.   4.   0.]
 [  0.   0.   0.   0.  13.   8.   0.   0.]
 [  0.   0.   0.   0.  13.   6.   0.   0.]]
Out[84]:
<matplotlib.image.AxesImage at 0x1a4a03a9b38>

Loading Into X,y (Convenient Method)

In [44]:
X,y = datasets.load_digits(return_X_y=True)
In [45]:
X.shape
Out[45]:
(1797, 64)
In [46]:
y.shape
Out[46]:
(1797,)

iris (Classification)

In [85]:
iris = datasets.load_iris()
In [86]:
iris.keys()
Out[86]:
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])

Feature Names

In [87]:
iris.feature_names
Out[87]:
['sepal length (cm)',
 'sepal width (cm)',
 'petal length (cm)',
 'petal width (cm)']

target

In [88]:
iris.target_names
Out[88]:
array(['setosa', 'versicolor', 'virginica'],
      dtype='<U10')
In [89]:
iris.target
Out[89]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

Train Test Data Splitting

Sample Data

Generate 100 rows of data, with 3x features (X1,X2,X3), and one dependant variable (Y)

In [265]:
n = 21  # number of samples
I = 5  # intercept value
E = np.random.randint( 1,20, n)  # Error
x1 = np.random.randint( 1,n+1, n)
x2 = np.random.randint( 1,n+1, n)
x3 = np.random.randint( 1,n+1, n)
y = 0.1*x1 + 0.2*x2 + 0.3*x3 + E + I
mydf = pd.DataFrame({
    'y':y,
    'x1':x1,
    'x2':x2,
    'x3':x3
})
mydf.shape
Out[265]:
(21, 4)

One Time Split

sklearn::train_test_split() has two forms:

  • Take one DF, split into 2 DF (most of sklearn modeling use this method
  • Take two DFs, split into 4 DF
In [266]:
mydf.head()
Out[266]:
   x1  x2  x3     y
0  10  17  12  21.0
1  12   5   9  16.9
2  18  13   2  27.0
3  11  19  17  22.0
4  18  13  10  24.4

Method 1: Split One Dataframe Into Two (Train & Test)

traindf, testdf = train_test_split( df, test_size=, random_state= ) 
 # random_state : seed number (integer), optional
 # test_size    : fraction of 1, 0.2 means 20%

split

In [267]:
traindf, testdf = train_test_split(mydf,test_size=0.2, random_state=25)
In [268]:
print (len(traindf))
print (len(testdf))
16
5

Method 2: Split Two DataFrame (X,Y) into Four x_train/test, y_train/test

x_train, x_test, y_train, y_test = train_test_split( X,Y, test_size=, random_state= )
 # random_state : seed number (integer), optional
 # test_size    : fraction of 1, 0.2 means 20%

split

Split DataFrame into X and Y First

In [269]:
feature_cols = ['x1','x2','x3']
X = mydf[feature_cols]
Y = mydf.y

Then Split X/Y into x_train/test, y_train/test

In [270]:
x_train, x_test, y_train, y_test = train_test_split( X,Y, test_size=0.2, random_state=25)
print (len(x_train))
print (len(x_test))
16
5

K-Fold

KFold(n_splits=3, shuffle=False, random_state=None)

split

suffle=False (default), meaning index number is taken continously

In [271]:
kf = KFold(n_splits=7)
In [272]:
for train_index, test_index in kf.split(X):
  print (train_index, test_index)
[ 3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [0 1 2]
[ 0  1  2  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [3 4 5]
[ 0  1  2  3  4  5  9 10 11 12 13 14 15 16 17 18 19 20] [6 7 8]
[ 0  1  2  3  4  5  6  7  8 12 13 14 15 16 17 18 19 20] [ 9 10 11]
[ 0  1  2  3  4  5  6  7  8  9 10 11 15 16 17 18 19 20] [12 13 14]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 18 19 20] [15 16 17]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17] [18 19 20]

shuffle=True

In [273]:
kf = KFold(n_splits=7, shuffle=True)
In [274]:
for train_index, test_index in kf.split(X):
  print (train_index, test_index)
[ 0  2  4  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [1 3 5]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 15 17 18 19 20] [13 14 16]
[ 0  1  2  3  4  5  6  9 10 11 12 13 14 15 16 17 19 20] [ 7  8 18]
[ 0  1  2  3  4  5  6  7  8  9 10 12 13 14 16 17 18 20] [11 15 19]
[ 1  2  3  4  5  6  7  8  9 11 13 14 15 16 17 18 19 20] [ 0 10 12]
[ 0  1  2  3  5  6  7  8  9 10 11 12 13 14 15 16 18 19] [ 4 17 20]
[ 0  1  3  4  5  7  8 10 11 12 13 14 15 16 17 18 19 20] [2 6 9]

Leave One Out

  • For a dataset of N rows, Leave One Out will split N-1 times, each time leaving one row as test, remaning as training set.
  • Due to the high number of test sets (which is the same as the number of samples-1) this cross-validation method can be very costly. For large datasets one should favor KFold.
In [275]:
loo = LeaveOneOut()
In [276]:
for train_index, test_index in loo.split(X):
  print (train_index, test_index)
[ 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [0]
[ 0  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [1]
[ 0  1  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [2]
[ 0  1  2  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [3]
[ 0  1  2  3  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [4]
[ 0  1  2  3  4  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [5]
[ 0  1  2  3  4  5  7  8  9 10 11 12 13 14 15 16 17 18 19 20] [6]
[ 0  1  2  3  4  5  6  8  9 10 11 12 13 14 15 16 17 18 19 20] [7]
[ 0  1  2  3  4  5  6  7  9 10 11 12 13 14 15 16 17 18 19 20] [8]
[ 0  1  2  3  4  5  6  7  8 10 11 12 13 14 15 16 17 18 19 20] [9]
[ 0  1  2  3  4  5  6  7  8  9 11 12 13 14 15 16 17 18 19 20] [10]
[ 0  1  2  3  4  5  6  7  8  9 10 12 13 14 15 16 17 18 19 20] [11]
[ 0  1  2  3  4  5  6  7  8  9 10 11 13 14 15 16 17 18 19 20] [12]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 14 15 16 17 18 19 20] [13]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 15 16 17 18 19 20] [14]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 16 17 18 19 20] [15]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 17 18 19 20] [16]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 18 19 20] [17]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 19 20] [18]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 20] [19]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19] [20]
In [277]:
X
Out[277]:
    x1  x2  x3
0   10  17  12
1   12   5   9
2   18  13   2
3   11  19  17
4   18  13  10
..  ..  ..  ..
16  20  13  18
17   1  17   1
18  13  20  18
19  11   4  15
20   6   2  10

[21 rows x 3 columns]

Polynomial Transform

This can be used as part of feature engineering, to introduce new features for data that seems to fit with quadradic model.

Single Variable

Sample Data

Data must be 2-D before polynomial features can be applied. Code below convert 1D array into 2D array.

In [278]:
x = np.array([1, 2, 3, 4, 5])
X = x[:,np.newaxis]
X
Out[278]:
array([[1],
       [2],
       [3],
       [4],
       [5]])

Degree 1

One Degree means maintain original features. No new features is created.

In [279]:
PolynomialFeatures(degree=1, include_bias=False).fit_transform(X)
Out[279]:
array([[ 1.],
       [ 2.],
       [ 3.],
       [ 4.],
       [ 5.]])

Degree 2

Degree-1 original feature: x
Degree-2 additional features: x^2

In [280]:
PolynomialFeatures(degree=2, include_bias=False).fit_transform(X)
Out[280]:
array([[  1.,   1.],
       [  2.,   4.],
       [  3.,   9.],
       [  4.,  16.],
       [  5.,  25.]])

Degree 3

Degree-1 original feature: x
Degree-2 additional features: x^2
Degree-3 additional features: x^3

In [281]:
PolynomialFeatures(degree=3, include_bias=False).fit_transform(X)
Out[281]:
array([[   1.,    1.,    1.],
       [   2.,    4.,    8.],
       [   3.,    9.,   27.],
       [   4.,   16.,   64.],
       [   5.,   25.,  125.]])

Degree 4

Degree-1 original feature: x
Degree-2 additional features: x^2
Degree-3 additional features: x^3
Degree-3 additional features: x^4

In [282]:
PolynomialFeatures(degree=4, include_bias=False).fit_transform(X)
Out[282]:
array([[   1.,    1.,    1.,    1.],
       [   2.,    4.,    8.,   16.],
       [   3.,    9.,   27.,   81.],
       [   4.,   16.,   64.,  256.],
       [   5.,   25.,  125.,  625.]])

Two Variables

Sample Data

In [283]:
X = pd.DataFrame( {'x1': [1, 2, 3, 4, 5 ],
                   'x2': [6, 7, 8, 9, 10]})
X
Out[283]:
   x1  x2
0   1   6
1   2   7
2   3   8
3   4   9
4   5  10

Degree 2

Degree-1 original   features:  x1,     x2  
Degree-2 additional features:  x1^2,   x2^2,   x1:x2
In [284]:
PolynomialFeatures(degree=2, include_bias=False).fit_transform(X)
Out[284]:
array([[   1.,    6.,    1.,    6.,   36.],
       [   2.,    7.,    4.,   14.,   49.],
       [   3.,    8.,    9.,   24.,   64.],
       [   4.,    9.,   16.,   36.,   81.],
       [   5.,   10.,   25.,   50.,  100.]])

Degree 3

Degree-1 original   features:  x1,       x2  
Degree-2 additional features:  x1^2,     x2^2,   x1:x2 
Degree-3 additional features:  x1^3,     x2^3    x1:x2^2    x2:x1^2
In [285]:
PolynomialFeatures(degree=3, include_bias=False).fit_transform(X)
Out[285]:
array([[    1.,     6.,     1.,     6.,    36.,     1.,     6.,    36.,
          216.],
       [    2.,     7.,     4.,    14.,    49.,     8.,    28.,    98.,
          343.],
       [    3.,     8.,     9.,    24.,    64.,    27.,    72.,   192.,
          512.],
       [    4.,     9.,    16.,    36.,    81.,    64.,   144.,   324.,
          729.],
       [    5.,    10.,    25.,    50.,   100.,   125.,   250.,   500.,
         1000.]])

Imputation of Missing Data

Sample Data

In [158]:
from numpy import nan
X = np.array([[ nan, 0,   3  ],
              [ 3,   7,   9  ],
              [ 3,   5,   2  ],
              [ 4,   nan, 6  ],
              [ 8,   8,   1  ]])

y = np.array([14, 16, -1,  8, -5])

Imputer

mean strategy

In [159]:
imp = Imputer(strategy='mean')
X2 = imp.fit_transform(X)
X2
Out[159]:
array([[ 4.5,  0. ,  3. ],
       [ 3. ,  7. ,  9. ],
       [ 3. ,  5. ,  2. ],
       [ 4. ,  5. ,  6. ],
       [ 8. ,  8. ,  1. ]])

Scaling

It is possible that some insignificant variable with larger range will be dominating the objective function.
We can remove this problem by scaling down all the features to a same range.

Sample Data

In [288]:
X=mydf.filter(like='x')[:5]
X
Out[288]:
   x1  x2  x3
0  10  17  12
1  12   5   9
2  18  13   2
3  11  19  17
4  18  13  10

MinMax Scaler

MinMaxScaler( feature_range(0,1), copy=True )
# default feature range (output result) from 0 to 1
# default return a copy of new array, copy=False will inplace original array

Define Scaler Object

In [289]:
scaler = MinMaxScaler()

Transform Data

In [290]:
scaler.fit_transform(X)
Out[290]:
array([[ 0.        ,  0.85714286,  0.66666667],
       [ 0.25      ,  0.        ,  0.46666667],
       [ 1.        ,  0.57142857,  0.        ],
       [ 0.125     ,  1.        ,  1.        ],
       [ 1.        ,  0.57142857,  0.53333333]])

Scaler Attributes

data_min_: minimum value of the feature (before scaling)  
data_max_: maximum value of the feature (before scaling)
In [291]:
pd.DataFrame(list(zip(scaler.data_min_, scaler.data_max_)), 
             columns=['data_min','data_max'], 
             index=X.columns)
Out[291]:
    data_min  data_max
x1      10.0      18.0
x2       5.0      19.0
x3       2.0      17.0

Standard Scaler

It is most suitable for techniques that assume a Gaussian distribution in the input variables and work better with rescaled data, such as linear regression, logistic regression and linear discriminate analysis.

StandardScaler(copy=True, with_mean=True, with_std=True)
# copy=True : return a copy of data, instead of inplace
# with_mean=True : centre all features by substracting with its mean
# with_std=True  : centre all features by dividing with its std

Define Scaler Object

In [292]:
scaler = StandardScaler()

Transform Data

In [293]:
scaler.fit_transform(X)
Out[293]:
array([[-1.08972474,  0.75      ,  0.41169348],
       [-0.5161854 , -1.75      , -0.20584674],
       [ 1.2044326 , -0.08333333, -1.64677394],
       [-0.80295507,  1.16666667,  1.4409272 ],
       [ 1.2044326 , -0.08333333,  0.        ]])

Scaler Attributes
After the data transformation step above, scaler will have the mean and variance information for each feature.

In [294]:
pd.DataFrame(list(zip(scaler.mean_, scaler.var_)), 
             columns=['mean','variance'], 
             index=X.columns)
Out[294]:
    mean  variance
x1  13.8     12.16
x2  13.4     23.04
x3  10.0     23.60

Pipeline

With any of the preceding examples, it can quickly become tedious to do the transformations by hand, especially if you wish to string together multiple steps. For example, we might want a processing pipeline that looks something like this:

  • Impute missing values using the mean
  • Transform features to quadratic
  • Fit a linear regression

make_pipeline takes list of functions as parameters. When calling fit() on a pipeline object, these functions will be performed in sequential with data flow from one function to another.

make_pipeline (
    function_1 (),
    function_2 (),
    function_3 ()
 )

Sample Data

In [295]:
X
Out[295]:
   x1  x2  x3
0  10  17  12
1  12   5   9
2  18  13   2
3  11  19  17
4  18  13  10
In [296]:
y
Out[296]:
array([14, 16, -1,  8, -5])

Create Pipeline

In [297]:
my_pipe = make_pipeline (
    Imputer            (strategy='mean'),
    PolynomialFeatures (degree=2),
    LinearRegression   ()
)
type(my_pipe)
Out[297]:
sklearn.pipeline.Pipeline
In [298]:
my_pipe
Out[298]:
Pipeline(memory=None,
     steps=[('imputer', Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)), ('polynomialfeatures', PolynomialFeatures(degree=2, include_bias=True, interaction_only=False)), ('linearregression', LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False))])

Executing Pipeline

In [299]:
my_pipe.fit( X, y) # execute the pipeline
print (y)
print (my_pipe.predict(X))
[14 16 -1  8 -5]
[ 14.  16.  -1.   8.  -5.]
In [300]:
type(my_pipe)
Out[300]:
sklearn.pipeline.Pipeline

Cross Validation

Load Data

In [146]:
X,y = datasets.load_diabetes(return_X_y=True)

Choose An Cross Validator

In [147]:
kf = KFold(n_splits=5)

Run Cross Validation

Single Scorer
Use default scorer of the estimator (if available)

In [148]:
lasso = Lasso()
cv_results1 = cross_validate(lasso, X,y,cv=kf,
    return_train_score=False)
In [149]:
cv_results2 = cross_validate(lasso, X,y,cv=kf,
    scoring=("neg_mean_absolute_error","neg_mean_squared_error","r2"),
    return_train_score=False)

The Result

Result is a dictionary

In [150]:
cv_results1.keys()
Out[150]:
dict_keys(['fit_time', 'score_time', 'test_score'])
In [151]:
cv_results2.keys()
Out[151]:
dict_keys(['fit_time', 'score_time', 'test_neg_mean_absolute_error', 'test_neg_mean_squared_error', 'test_r2'])
In [152]:
cv_results1
Out[152]:
{'fit_time': array([ 0.0009973 ,  0.        ,  0.        ,  0.00099802,  0.        ]),
 'score_time': array([ 0.        ,  0.        ,  0.00100255,  0.        ,  0.0010004 ]),
 'test_score': array([ 0.28349047,  0.35157959,  0.3533813 ,  0.33481474,  0.36453281])}
In [153]:
cv_results2
Out[153]:
{'fit_time': array([ 0.00099897,  0.        ,  0.        ,  0.00099826,  0.0010004 ]),
 'score_time': array([ 0.00100064,  0.00100303,  0.00099969,  0.00099945,  0.        ]),
 'test_neg_mean_absolute_error': array([-50.09003423, -52.54110842, -55.02813846, -50.81121806, -55.60471593]),
 'test_neg_mean_squared_error': array([-3491.74009759, -4113.86002091, -4046.91780932, -3489.74018715,
        -4111.92401769]),
 'test_r2': array([ 0.28349047,  0.35157959,  0.3533813 ,  0.33481474,  0.36453281])}

Regression

Linear Regression

The Concept

Linear Regression establishes a relationship between dependent variable (Y) and one or more independent variables (X) using a best fit straight line (also known as regression line).

  • The objective of linear regression modeling is to find the most optimum equation that best explain the data
  • Optimum equation is defined as the one that has the least cost (error)

Once we had derived the optimum equation, we can use the model to predict target $Y'$ base on new variables $X$.

Assumptions

Below are conditions for the least-squares estimator - used by linear regression to possess desirable properties; in particular, these assumptions imply that the parameter estimates will be unbiased, consistent, and efficient in the class of linear unbiased estimators.

Classical Assumptions

  • The sample is representative of the population for the inference prediction
    Question how is the data being gathered, is it convincing that it represents the population ?

  • Number of observations must be larger than number of independent variables
    Check the length of observations >= column length of data

Assumptions On Dependent Variable

  • Must not be a categorical data type

Assumptions On Independent Variable

  • The independent variables are measured with no error, that is observations must be a set of known constants. (Note: If this is not so, modeling may be done instead using errors-in-variables model techniques)

  • Each independent variable are linearly correclated with outcome, when other independent variables are held constant. Matrix scatter plot and correlation calculation can validate this. Generally correlation of 0.7 and above are considered good.

  • NO Multicollinearity amont predictors - Meaning little or not linear correlationamong the predictors, i.e. it is not possible to express any predictor as a linear combination of the others, if so, we wouldn't know which predictor actually influene the outcome.

Assumptions On Errors (residuals)

  • The errors are random numbers, with means of zero

    • There should not be a pattern in the residuals distribution
    • If the residuals are normally distributed with mean of zero, then it is considered a bonus which we can perform statistical significant testing. $e = N(0,\sigma^2)$
    • Normality on redisuals implies that the dependent variable are also normally distributed (if and only if dependent variable is not stochastic)
  • The errors are uncorrelated - that is, the variance–covariance matrix of the errors is diagonal and each non-zero element is the variance of the error

  • Homoscedasticity - The variance of the error is constant across observations. If heteroscedasticity exist, scatter plot of response and predictor will look like below Heteroscedasticity

    • The Goldfeld-Quandt Test can test for heteroscedasticity
    • If homoscedasticity is present, a non-linear correction might fix the problem
    • Otherwise, weighted least squares or other methods might instead be used.

Are These Assumptions to be followed strictly ?

In real life, actual data rarely satisfies the assumptions, that is:

  • Method is used even though the assumptions are not true
  • Variation from the assumptions can sometimes be used as a measure of how far the model is from being useful
  • Many of these assumptions may be relaxed in more advanced treatments

Reports of statistical analyses usually include analyses of tests on the sample data and methodology for the fit and usefulness of the model.

Additional Notes On Independent variables

  • Adding more variables to a regression procedure may overfit the model and make things worse. The idea is to pick the best variables
  • Some independent variable(s) are better at predicting the outocme, some contribute little or nothing

    Because of multicollinearity and overfitting, there is a fair amount of prep-work to be performed BEFORE conducting multiple regression analysis - if one is to do it properly.

Equations

Terminology

Simple Linear Regression (classical) consists of just on predictor. aka Single Variable Linear Regression.
Multiple Linear Regression (classical) consists of multiple predictors. aka. Multiple Variable Linear Regression.

Multivariate Regression (aka. General Linear Regression) is linear regression where the outocme is a vector (not scalar). Not the same as multiple variable linear regression.

Ordinary Least Square Estimatation

Regression Model - Actual Outcome

$\quad y_i = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + ... \beta_k x_k + e_i$
$\quad$where:
$\quad \quad y_i$ = actual outcome value
$\quad \quad \beta_0$ = intercept, when all independent variables are 0
$\quad \quad \beta_k$ = parameter for independent variable k $\quad \quad e_i$ = error for observation i

Regression Equation - Predicted Outcome

$\quad E(y_i) = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + ... \beta_k x_k$

$\quad h_\theta(X)~=~\theta_0~+~\theta_1 \cdot X$ , error terms assumed to be zero
$\quad$where:
$\quad \quad h_\theta(x)$ = hypothesis target (dependant variable)
$\quad \quad \theta_0$ = intercept
$\quad \quad \theta_1$ = slopes or coefficients
$\quad \quad X$ = independant variables (predictors)

$\quad$Take note that each $\theta_0$ and $\theta_1$ represents multi-variate data in matrix form.

Cost Function

  • The goal is to find some values of θ (known as coefficients), so we can minimize the difference between real values $y$ and predicted values ($h(x)$)
  • Mathematically, this means finding the minimum value of cost function $J$ and derive the optimum value of $\theta_0$ and $\theta_1$
  • Linear regression uses Total Sum Of Square calculation on Error as Cost Function, denoted by $J$ below:

$\quad \quad J(\theta_0,\theta_1) = \frac{1}{2m}\sum_{i=1}^m ((h_\theta(x^i)-y^i)^2$

OLS Performance

Fundamental

OLS performance is mainly on error analysis.

SST (total sample variability) = SSR (explained variability) + SSE (unexplained variability) :

SST Explained

Root Mean Square Error (RMSE)

  • RMSE = The square root of the average of the total sum of square error
    $RMSE = \sqrt{\frac{SSE}{n}} = \sqrt \frac{\sum^n_{i=1}{(y_i - \hat y_i)^2}}{n}$
  • It measure how close observed data points are to the model’s predicted values
  • It has a unit of Y, therefore cannot used for comparison models with different outcome
  • It can be used to compare different model with the similar outcome but different predictors, however, adjusted $R^2$ is better in this
  • Low RMSE value indicates better fit
  • Compared to the similar Mean Absolute Error, RMSE amplifies and severely punishes large errors
  • SSE is not usable for performance measurement becuase it increases with number of datapoints. RMSE does not suffer this as it is divided by number of datapoints
  • Residual Standard Errror (RSE) is very similar to RMSE, except that RSE use division by degree of freedom

RMSE is excellent general measurement to assess the accuracy of a model

$r$, $R^2$ and $R^2_{adj}$

r - Correlation Coeeficient

  • Correlation, often measured as a correlation coefficient - indicates the strength and direction of a linear relationship between two variables (for example model output and observed values)
  • The best known is the Pearson product-moment correlation coefficient (also called Pearson correlation coefficient or the sample correlation coefficient)
  • It is a ratio (has no unit)
    $Pearson Correlation, r = \frac{{}\sum_{i=1}^{n} (x_i - \overline{x})(y_i - \overline{y})} {\sqrt{\sum_{i=1}^{n} (x_i - \overline{x})^2(y_i - \overline{y})^2}} \quad, \quad 0=<r<=1$

Scatter plot predicted and actual outcome reveal visually the good-fit of the model, good correlation also means tigther the scatter plots with less variability

R-Squared - Coefficient Determination

$R^2 = r^2 = \frac{SSR}{SST} = 1-\frac{SSE}{SST}, \quad 0 <= R^2 <= 1$

  • $R^2$ is a ratio (unit-less) indicating how much variations are explained by regression model
  • $R^2$ compares the fit model to a 'baseline' model (SST)
  • High $R^2$ value indicates high SSR and low SSE, which means the model is more precise

    • Perfect Case - no errors (SSE=0), $R^2$ will be 1.
    • Worst Case - no improvement over baseline, (coefficient=0, SSR=0, aka horizontally flat line), $R^2$ will be 0.
  • One pitfall of $R^2$ is that it always increases when additional variables are added to the model. The increase can be artificial as it doesn't improve the model fit - which is called over-fitting. A remediation to this is $R^2_{adj}$

Adjusted R-Squared

  • Adjusted $R^2$ incorporates the number of coefficients and observations into the calculation
    $R_{adj}^2 = 1- \bigg( \frac{n-1}{n-p}\bigg) \frac{SSE}{SST}$
    $\quad$ p = number of coefficients (including intercept)
    $\quad$ n = number of observations

  • Adjusted $R^2$ will decrease when adding predictors that doesn't increase the model fit that make up for the loss of degrees of freedom

  • Likewise, it will increase as predictors are added if the increase in model fit is worthwhile

$R^2_{adj}$ is useful to compare models with a different number of predictors, hence good for feature selection

Training Data and Test Data (out of sample)

  • A built model based on training data always has $R^2$ between 0 <= $R^2$ <= 1
  • However, if the model is underfit, test data may reveal $R^2$ <= 0

Feature Selection

  1. The strength and importance of an independent variable is not measured by its correlation or coefficient with the dependent variable - It only hold true if there is only single independent variable

  2. Multicolinearity has below independent variable diversion and therefore must be removed:

    • It increases the p-value to make it insignificant
    • It divert a coef direction (eg. positive becomes negative)
  3. Perform transformation (such as log, quadradric) if the plot of independet vs dependent variables shows Heteroscedasticity

Run The Code

Sample Data

In [3]:
n = 200  # number of samples
I = 250  # intercept value
E = np.random.randint( 1,20, n)  # Error
x1 = np.random.randint( 1,n+1, n)
x2 = np.random.randint( 1,n+1, n)
x3 = np.random.randint( 1,n+1, n)
x4 = x3 + np.random.randint(1,n+1,n)
Y = 0.1*x1 + 0.2*x2 + 0.3*x3 + E + I

Put All Data In pandas DataFrame

In [4]:
mydf = pd.DataFrame({
    'Y':Y,
    'x1':x1,
    'x2':x2,
    'x3':x3,
    'x4':x4
})
mydf.head()
X = mydf.filter(like='x')

Data Validation

Colleration Check

Ensure there is no col-linearity among the features used

Correlation Text Output

In [5]:
my_corr = X.corr()
my_corr
Out[5]:
          x1        x2        x3        x4
x1  1.000000  0.089132 -0.003379 -0.030738
x2  0.089132  1.000000  0.054852  0.089682
x3 -0.003379  0.054852  1.000000  0.717366
x4 -0.030738  0.089682  0.717366  1.000000

Correlation HTML Output

In [6]:
my_corr.style.background_gradient().set_precision(2)
Out[6]:
x1 x2 x3 x4
x1 1 0.089 -0.0034 -0.031
x2 0.089 1 0.055 0.09
x3 -0.0034 0.055 1 0.72
x4 -0.031 0.09 0.72 1

Correlation HTML Output without Annotation

In [7]:
my_corr.style.background_gradient().set_properties(**{'font-size': '0pt'})
Out[7]:
x1 x2 x3 x4
x1 1 0.0891317 -0.00337879 -0.0307377
x2 0.0891317 1 0.0548518 0.0896824
x3 -0.00337879 0.0548518 1 0.717366
x4 -0.0307377 0.0896824 0.717366 1
Matrix Scatter Plot
In [8]:
pd.plotting.scatter_matrix(X, alpha=0.2, figsize=(6, 6), diagonal='hist');
In [9]:
plt.matshow(X.corr())
plt.xticks(range(len(X.columns)), X.columns)
plt.yticks(range(len(X.columns)), X.columns)
plt.colorbar()
plt.show()

Data Preparation

Preparing Features and Dependent Value
In [10]:
feature_cols = ['x1','x2','x3']
X = mydf[feature_cols]
Y = mydf.Y 
Splitting Data Into Training and Test Sets
In [11]:
trainX,testX,trainY,testY = train_test_split(X,Y,test_size=0.2)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-18935983abcd> in <module>()
----> 1 trainX,testX,trainY,testY = train_test_split(X,Y,test_size=0.2)

NameError: name 'train_test_split' is not defined

Create The Model

In [ ]:
lm = LinearRegression()   # create linear regression object
lm.fit( trainX, trainY )  # train the model using training set

Analyze The Model

Intercept
In [ ]:
lm.intercept_
Coef
In [ ]:
lm.coef_
In [ ]:
pd.DataFrame(list(zip(X.columns, lm.coef_)), columns=['features','coef'] )
R-Squared
In [ ]:
trainPred = lm.predict( trainX )
In [ ]:
r2_score( trainY, trainPred )

Model Performance

Prediction on Train Data
In [ ]:
trainY_ = lm.predict( trainX )

Mean Absolute Error (MAE)

In [ ]:
mean_absolute_error( trainY, trainY_ )

Mean Squared Error (MSE)

In [ ]:
mean_squared_error( trainY, trainY_ )

Root Mean Squared Error (RMSE)

In [ ]:
math.sqrt( mean_squared_error( trainY, trainY_ ) )
Prediction on Test Data
In [ ]:
testY_ = lm.predict( testX )
In [ ]:
mean_absolute_error( testY, testY_ )
In [ ]:
mean_squared_error( testY, testY_ )
In [331]:
math.sqrt( mean_squared_error( testY, testY_ ) )
Out[331]:
6.4844871580983785

Modeling (statsmodel)

Data Preparation

Splitting data into training set and testing set.

In [332]:
traindf, testdf = train_test_split(mydf, test_size=0.2)
trainX,testX,trainY,testY = train_test_split(X,Y,test_size=0.2)

Create The Model - Equation Method

This method assume all data (dependend and independent variables) are in single dataframe

In [335]:
fit = smf.ols(formula='Y ~ x1 + x2 + x3', data=traindf).fit()

Analyze The Model

In [336]:
print (fit.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      Y   R-squared:                       0.947
Model:                            OLS   Adj. R-squared:                  0.946
Method:                 Least Squares   F-statistic:                     936.2
Date:                Fri, 15 Jun 2018   Prob (F-statistic):           1.74e-99
Time:                        10:32:45   Log-Likelihood:                -492.05
No. Observations:                 160   AIC:                             992.1
Df Residuals:                     156   BIC:                             1004.
Df Model:                           3                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept    260.2819      1.375    189.257      0.000     257.565     262.999
x1             0.0922      0.008     12.155      0.000       0.077       0.107
x2             0.1943      0.007     27.428      0.000       0.180       0.208
x3             0.3013      0.007     43.734      0.000       0.288       0.315
==============================================================================
Omnibus:                       21.242   Durbin-Watson:                   2.038
Prob(Omnibus):                  0.000   Jarque-Bera (JB):                8.749
Skew:                           0.341   Prob(JB):                       0.0126
Kurtosis:                       2.080   Cond. No.                         613.
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

Create The Model - Array Method

This method assume independent and dependent variables are in seperate dataframe
intercept is not included in OLS modeling by default. Hence need to use add_constant() to training dataset in order to display intercept estimate.

In [337]:
trainX = sm.add_constant(trainX)     # this add new column of all value 1
fit2 = smf.OLS(trainY, trainX).fit()

Analyze The Model

In [338]:
print (fit2.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      Y   R-squared:                       0.943
Model:                            OLS   Adj. R-squared:                  0.942
Method:                 Least Squares   F-statistic:                     862.1
Date:                Fri, 15 Jun 2018   Prob (F-statistic):           7.58e-97
Time:                        10:32:45   Log-Likelihood:                -493.22
No. Observations:                 160   AIC:                             994.4
Df Residuals:                     156   BIC:                             1007.
Df Model:                           3                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const        259.8796      1.386    187.517      0.000     257.142     262.617
x1             0.0980      0.008     12.885      0.000       0.083       0.113
x2             0.1898      0.007     26.031      0.000       0.175       0.204
x3             0.3026      0.007     41.776      0.000       0.288       0.317
==============================================================================
Omnibus:                       27.839   Durbin-Watson:                   1.976
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               10.915
Skew:                           0.413   Prob(JB):                      0.00426
Kurtosis:                       2.023   Cond. No.                         609.
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

Examples

Example 1 - Linear Regression

Sample Data

Plot looks like polynomial.

In [340]:
x = np.array([1, 2, 3, 4, 5])
y = np.array([4, 2, 1, 3, 7])
plt.scatter(x, y);

Built The Model

Prepare The Data
X needs to be at least 2D. Increase the dimension with newaxis

In [341]:
X = x[:, np.newaxis]
X
Out[341]:
array([[1],
       [2],
       [3],
       [4],
       [5]])

Fit and Predict

In [342]:
fit = LinearRegression().fit(X, y)
pred = fit.predict(X)
plt.scatter(x, y)
plt.plot(x,pred)
Out[342]:
[<matplotlib.lines.Line2D at 0x20c40764588>]

Example 2 - Linear Regression with Polynomial Basic Functions

Sample Data

In [343]:
x = np.array([1, 2, 3, 4, 5])
y = np.array([4, 2, 1, 3, 7])
plt.scatter(x, y);

Clean Method - Use Pipeline

This method avoid manually creating engineered features.

In [344]:
poly_model = make_pipeline( PolynomialFeatures(3), LinearRegression())
poly_model.fit( X,y)
pred2 = poly_model.predict(X)
## plot
plt.scatter(x, y)
plt.plot(x,pred2)
Out[344]:
[<matplotlib.lines.Line2D at 0x20c411f2278>]

Alternative Method - Use Transform

This method involve create a PolynomialFeatures object, transform original data (X) with more engineered features according to degree chosen.

In [345]:
poly = PolynomialFeatures(degree=3, include_bias=False)
X2 = poly.fit_transform(X)
fit2 = LinearRegression().fit(X2, y)
pred2 = fit2.predict(X2)
## plot
plt.scatter(x, y)
plt.plot(x,pred2)
Out[345]:
[<matplotlib.lines.Line2D at 0x20c41105668>]

Logistic Regression

In [ ]:
 
In [ ]:
 
In [ ]:
 

Feature Selection

The advantage of using skcikit-learn package is that it has this particular method selection, works more or less like backward selection (not exactly), and is called Recursive Feature. How it works:

  • Model run with all variables, weight is assigned to each variable
  • Variable with smallest weight will be pruned from next iteration
  • Run the model again till the number of desired features is left

The Library

In [346]:
from sklearn.feature_selection import RFE
from sklearn.svm import SVR
In [347]:
estimator = SVR(kernel='linear')       # we are using linear model
selector = RFE (estimator, 2, step=1)  # we want just 2 features
selector = selector.fit(X,Y)           # execute
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-347-0c48fa9d44fe> in <module>()
      1 estimator = SVR(kernel='linear')       # we are using linear model
      2 selector = RFE (estimator, 2, step=1)  # we want just 2 features
----> 3 selector = selector.fit(X,Y)           # execute

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\feature_selection\rfe.py in fit(self, X, y)
    132             The target values.
    133         """
--> 134         return self._fit(X, y)
    135 
    136     def _fit(self, X, y, step_score=None):

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\feature_selection\rfe.py in _fit(self, X, y, step_score)
    140         # self.scores_ will not be calculated when calling _fit through fit
    141 
--> 142         X, y = check_X_y(X, y, "csc")
    143         # Initialization
    144         n_features = X.shape[1]

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\utils\validation.py in check_X_y(X, y, accept_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, multi_output, ensure_min_samples, ensure_min_features, y_numeric, warn_on_dtype, estimator)
    581         y = y.astype(np.float64)
    582 
--> 583     check_consistent_length(X, y)
    584 
    585     return X, y

C:\ProgramData\Anaconda3\lib\site-packages\sklearn\utils\validation.py in check_consistent_length(*arrays)
    202     if len(uniques) > 1:
    203         raise ValueError("Found input variables with inconsistent numbers of"
--> 204                          " samples: %r" % [int(l) for l in lengths])
    205 
    206 

ValueError: Found input variables with inconsistent numbers of samples: [5, 200]
In [ ]:
selector.support_
In [ ]:
selector.ranking_
In [ ]:
selector.estimator_
In [ ]:
 
In [ ]: