diff --git a/lenses.ipynb b/lenses.ipynb
new file mode 100644
index 0000000..548ab00
--- /dev/null
+++ b/lenses.ipynb
@@ -0,0 +1,2007 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- Each type of **Optic** comes with a set of compatible **actions**.\n",
+ "\n",
+ "Lenses have the following concrete gaurantees.\n",
+ "\n",
+ "* A Lens focuses (i.e selects) a single piece of data within a larger structure.\n",
+ "* A Lens must **never fail** to **get** or **modify** that focus.\n",
+ "\n",
+ "These constraints unlock a few **actions** we can perform on lenses.\n",
+ "\n",
+ "* We can use a lens to **view** the **focus** within a structure.\n",
+ "* We can use a lens to **set** the **focus** within a structure.\n",
+ "* We can use a lens to **modify** the **focus** within a structure."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "\"hello\""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "{-# LANGUAGE TemplateHaskell #-}\n",
+ "{-# LANGUAGE FlexibleInstances #-}\n",
+ "{-# LANGUAGE FlexibleContexts #-}\n",
+ "{-# LANGUAGE RankNTypes #-}\n",
+ "{-# LANGUAGE ScopedTypeVariables #-}\n",
+ "{-# LANGUAGE TypeApplications #-}\n",
+ "{-# LANGUAGE TypeFamilies #-}\n",
+ "{-# LANGUAGE InstanceSigs #-}\n",
+ "\n",
+ "import Control.Lens\n",
+ "import Numeric.Lens\n",
+ "import Data.Bits.Lens\n",
+ "import Data.Data.Lens\n",
+ "\n",
+ "import Control.Applicative\n",
+ "import Data.Char as C\n",
+ "import qualified Data.Map as M\n",
+ "import qualified Data.Set as S\n",
+ "import qualified Data.Text as T\n",
+ "import qualified Data.List as L\n",
+ "\n",
+ "view (_2 . _1) (42, (\"hello\", False))\n",
+ "\n",
+ "-- view is the action\n",
+ "-- (_2 . _1) is the path\n",
+ "-- (42, (\"hello\", False)) is the structure\n",
+ "-- \"hello\" is the focus"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Exercises - Optic Anatomy"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "2"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "(False,Left \"new\")"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\"TESTING ONE two three\""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\"supercalifragilisticexpialidocious\""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "view (_1 . _2) ((1, 2), 3)\n",
+ "\n",
+ "-- view is the action\n",
+ "-- (_1 . _2) is the path. Focus on the 1st member of tuple and then the 2nd member of 1st member\n",
+ "-- ((1, 2), 3) is the structure\n",
+ "-- 2 is the focus\n",
+ "\n",
+ "set (_2 . _Left) \"new\" (False, Left \"old\")\n",
+ "\n",
+ "-- set is the action\n",
+ "-- (_2 . _Left) is the path\n",
+ "-- (False, Left \"Old\") is the structure\n",
+ "-- \"old\" is the focus\n",
+ "\n",
+ "over (taking 2 worded . traversed) C.toUpper \"testing one two three\"\n",
+ "\n",
+ "-- over is the action\n",
+ "-- (taking 2 worded . traversed) is the path\n",
+ "-- \"testing one two three\"\n",
+ "-- \"testing one\" is the focus\n",
+ "\n",
+ "foldOf (both . each) ([\"super\", \"cali\"],[\"fragilistic\", \"expialidocious\"])\n",
+ "\n",
+ "-- foldOf is the action\n",
+ "-- (both . each) is the path\n",
+ "-- The rest is the structure"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Lens Actions\n",
+ "\n",
+ "### Viewing through lenses"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "_1 :: forall s t a b (f :: * -> *). (Field1 s t a b, Functor f) => (a -> f b) -> s -> f t"
+ ],
+ "text/plain": [
+ "_1 :: forall s t a b (f :: * -> *). (Field1 s t a b, Functor f) => (a -> f b) -> s -> f t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Lens' :: * -> * -> *"
+ ],
+ "text/plain": [
+ "Lens' :: * -> * -> *"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Lens :: * -> * -> * -> * -> *"
+ ],
+ "text/plain": [
+ "Lens :: * -> * -> * -> * -> *"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "_2 :: forall s t a b (f :: * -> *). (Field2 s t a b, Functor f) => (a -> f b) -> s -> f t"
+ ],
+ "text/plain": [
+ "_2 :: forall s t a b (f :: * -> *). (Field2 s t a b, Functor f) => (a -> f b) -> s -> f t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "view :: forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a"
+ ],
+ "text/plain": [
+ "view :: forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "'a'"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "'b'"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ ":t _1\n",
+ "\n",
+ ":k Lens'\n",
+ ":k Lens\n",
+ "\n",
+ "-- _1 :: Lens' (a, b) a\n",
+ "-- (a, b) --> Type of structure\n",
+ "-- a --> Focus within it\n",
+ "\n",
+ ":t _2\n",
+ "\n",
+ ":t view\n",
+ "\n",
+ "-- A lens on it's own isn't enough. We need an action to perform on it.\n",
+ "\n",
+ "-- view :: Lens' s a -> s -> a\n",
+ "-- Get the path's focus from within the structure\n",
+ "\n",
+ "view _1 ('a', 'b')\n",
+ "\n",
+ "view _2 ('a', 'b')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Setting through a lens"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "set :: forall s t a b. ASetter s t a b -> b -> s -> t"
+ ],
+ "text/plain": [
+ "set :: forall s t a b. ASetter s t a b -> b -> s -> t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "over :: forall s t a b. ASetter s t a b -> (a -> b) -> s -> t"
+ ],
+ "text/plain": [
+ "over :: forall s t a b. ASetter s t a b -> (a -> b) -> s -> t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "('x','b')"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "(100,2)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "-- set :: Lens' s a -> a -> s -> s\n",
+ "-- Set a new value at the path’s focus, leaving the rest of the structure unaltered.\n",
+ "\n",
+ "-- over :: Lens' s a -> (a -> a) -> s -> s\n",
+ "-- Modify the focus of a path by running a function over it, altering it in-place and leaving the\n",
+ "-- rest of the structure unaltered.\n",
+ "\n",
+ ":t set\n",
+ ":t over\n",
+ "\n",
+ "set _1 'x' ('a', 'b')\n",
+ "\n",
+ "over _1 (*100) (1, 2)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Exercises - Lens Actions"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'c'"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "(False,20)"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "-- 1. Find structure & focus in the following lens\n",
+ "\n",
+ "-- Lens' (Bool, (Int, String)) Int\n",
+ "\n",
+ "-- (Bool, (Int, String)) is the structure\n",
+ "-- Focus is Int, the 1st member of the 2nd member of the complete structure\n",
+ "\n",
+ "-- 2. Write the type signature of a Lens with the structure (Char, Int) and the focus Char\n",
+ "\n",
+ "-- Lens' (Char, Int) Char\n",
+ "\n",
+ "-- 3. Name three actions we can use on a Lens\n",
+ "\n",
+ "-- set\n",
+ "-- view\n",
+ "-- over\n",
+ "\n",
+ "-- 4\n",
+ "\n",
+ "view _3 ('a', 'b', 'c')\n",
+ "\n",
+ "over _2 (*10) (False, 2)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Lenses and records\n",
+ "\n",
+ "* Lenses subsume the accessor pattern in other languages."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "lens :: forall (f :: * -> *) s a b t. Functor f => (s -> a) -> (s -> b -> t) -> (a -> f b) -> s -> f t"
+ ],
+ "text/plain": [
+ "lens :: forall (f :: * -> *) s a b t. Functor f => (s -> a) -> (s -> b -> t) -> (a -> f b) -> s -> f t"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Lens :: * -> * -> * -> * -> *"
+ ],
+ "text/plain": [
+ "Lens :: * -> * -> * -> * -> *"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "Lens' :: * -> * -> *"
+ ],
+ "text/plain": [
+ "Lens' :: * -> * -> *"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "-- Just changed the names from the example in the book\n",
+ "data Name = \n",
+ " Name { _name :: String\n",
+ " , _age :: Int\n",
+ " } deriving (Show)\n",
+ " \n",
+ "-- lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b\n",
+ "-- lens :: (s -> a) -> (s -> a -> s) -> Lens' s a\n",
+ "\n",
+ ":t lens\n",
+ ":k Lens\n",
+ ":k Lens'\n",
+ "\n",
+ "-- Whenever you see 's' in a Lens thing 'structure' and when you see 'a', think 'focus'.\n",
+ "\n",
+ "-- getAge :: s -> a\n",
+ "getAge :: Name -> Int\n",
+ "getAge = _age\n",
+ "\n",
+ "-- setAge :: s -> a -> s\n",
+ "setAge :: Name -> Int -> Name\n",
+ "setAge name newAge = name { _age = newAge }\n",
+ "\n",
+ "numAge :: Lens' Name Int\n",
+ "numAge = lens getAge setAge"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Exercises - Records Part One"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "31"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Name {_name = \"Sanchayan Maity\", _age = 32}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Name {_name = \"Sanchayan Maity\", _age = 34}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Name {_name = \"Sanchayan Maity\", _age = 34}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "\"Sanchayan Maity\""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Name {_name = \"Foo\", _age = 31}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Name {_name = \"Boo Sanchayan Maity\", _age = 31}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "-- 1. The structure and focus of a lens are typically represented by which letters in type signature\n",
+ "-- s and a respectively\n",
+ "\n",
+ "-- 2. Which two components are required to create a lens\n",
+ "-- getter and setter\n",
+ "\n",
+ "-- Implement the following Lens\n",
+ "\n",
+ "-- name :: Lens' Name String\n",
+ "\n",
+ "getName :: Name -> String\n",
+ "getName = _name\n",
+ "\n",
+ "setName :: Name -> String -> Name\n",
+ "setName name newName = name { _name = newName }\n",
+ "\n",
+ "name :: Lens' Name String\n",
+ "name = lens getName setName\n",
+ "\n",
+ "myName :: Name\n",
+ "myName = Name { _name = \"Sanchayan Maity\"\n",
+ " , _age = 31 } \n",
+ " \n",
+ "-- Getting, setting & modifying with a field lens\n",
+ "\n",
+ "-- For Age field\n",
+ "view numAge myName\n",
+ "set numAge 32 myName\n",
+ "over numAge (+3) myName\n",
+ "set numAge (view numAge myName + 3) myName\n",
+ "\n",
+ "-- For Name field\n",
+ "view name myName\n",
+ "set name \"Foo\" myName\n",
+ "over name (\"Boo \" ++) myName"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Automatically generating field names"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "name :: forall (f :: * -> *). Functor f => (String -> f String) -> Ship -> f Ship"
+ ],
+ "text/plain": [
+ "name :: forall (f :: * -> *). Functor f => (String -> f String) -> Ship -> f Ship"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "numCrew :: forall (f :: * -> *). Functor f => (Int -> f Int) -> Ship -> f Ship"
+ ],
+ "text/plain": [
+ "numCrew :: forall (f :: * -> *). Functor f => (Int -> f Int) -> Ship -> f Ship"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "getNumCrew :: Ship -> Int"
+ ],
+ "text/plain": [
+ "getNumCrew :: Ship -> Int"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "data Ship = \n",
+ " Ship { _name :: String\n",
+ " , _numCrew :: Int \n",
+ " } deriving (Show)\n",
+ "\n",
+ "makeLenses ''Ship\n",
+ "\n",
+ ":t name\n",
+ ":t numCrew\n",
+ ":t getNumCrew"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Exercises - Records Part Two"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 72,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "-- data Inventory = \n",
+ "-- Inventory { _wand :: Wand\n",
+ "-- , _book :: Book\n",
+ "-- , _potions :: [Potion] }\n",
+ "\n",
+ "-- makeLenses ''Inventory\n",
+ "\n",
+ "-- Lenses generated would be\n",
+ "\n",
+ "-- wand\n",
+ "-- book\n",
+ "-- potions\n",
+ "-- getWand\n",
+ "-- getBook\n",
+ "-- getPotions\n",
+ "-- setWand\n",
+ "-- setBook\n",
+ "-- setPotions\n",
+ "\n",
+ "-- gazork :: Functor f => (Spuzz -> f Spuzz) -> Chumble -> f Chumble\n",
+ "-- gazork :: Lens' Chumble Spuzz\n",
+ "\n",
+ "data Pet = Pet \n",
+ " { _petName :: String\n",
+ " , _petType :: String\n",
+ " }\n",
+ " \n",
+ "makeLenses ''Pet\n",
+ "\n",
+ "getPetName :: Pet -> String\n",
+ "getPetName = view petName"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Lens is an optic which **always** accesses **exactly** one focus"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Is it a Lens?\n",
+ "\n",
+ "* second :: Lens' (a, b, c) b\n",
+ "\n",
+ "* inMaybe :: Lens' (Maybe a) a\n",
+ "\n",
+ "* left :: Lens' (Either a b) a\n",
+ "\n",
+ "* listThird :: Lens' [a] a\n",
+ "\n",
+ "* Can you write a lens which focuses the second element of a tuple if the Bool in the first slot is True and focuses the third element if it’s False ? conditional :: Lens' (Bool, a, a) a\n",
+ "\n",
+ "* Consider the below data type. Is it possible to have a lens msg :: Lens' Err String"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "data Err = \n",
+ " ReallyBadError { _msg :: String }\n",
+ " | ExitCode { _code :: Int }\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Lens Laws\n",
+ "\n",
+ "1. You get back what you set\n",
+ "2. Setting back what you got doesn't do anything\n",
+ "3. Setting twice is the same as setting once"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Virtual Fields"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "celsius :: forall (f :: * -> *). Functor f => (Float -> f Float) -> Temperature -> f Temperature"
+ ],
+ "text/plain": [
+ "celsius :: forall (f :: * -> *). Functor f => (Float -> f Float) -> Temperature -> f Temperature"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "7.0"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Temperature {_location = \"Bangalore\", _celsius = 13.5}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Temperature {_location = \"Bangalore\", _celsius = 17.0}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "44.6"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Temperature {_location = \"Bangalore\", _celsius = 13.5}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/plain": [
+ "Temperature {_location = \"Bangalore\", _celsius = 17.0}"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "data Temperature = \n",
+ " Temperature { _location :: String\n",
+ " , _celsius :: Float\n",
+ " } deriving (Show)\n",
+ " \n",
+ "makeLenses ''Temperature\n",
+ "\n",
+ ":t celsius\n",
+ "\n",
+ "let temp = Temperature \"Bangalore\" 7.0\n",
+ "\n",
+ "view celsius temp\n",
+ "set celsius 13.5 temp\n",
+ "over celsius (+10) temp\n",
+ "\n",
+ "celsiusToFahrenheit :: Float -> Float\n",
+ "celsiusToFahrenheit c = (c * (9/5)) + 32\n",
+ "\n",
+ "fahrenheitToCelsius :: Float -> Float\n",
+ "fahrenheitToCelsius f = (f - 32) * (5/9)\n",
+ "\n",
+ "fahrenheit :: Lens' Temperature Float\n",
+ "fahrenheit = lens getter setter\n",
+ " where\n",
+ " getter = celsiusToFahrenheit . view celsius\n",
+ " setter temp f = set celsius (fahrenheitToCelsius f) temp\n",
+ " \n",
+ "view fahrenheit temp\n",
+ "set fahrenheit 56.3 temp\n",
+ "over fahrenheit (+18) temp"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Note: TODO: The exercises on laws & virtual fields"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Haskell",
+ "language": "haskell",
+ "name": "haskell"
+ },
+ "language_info": {
+ "codemirror_mode": "ihaskell",
+ "file_extension": ".hs",
+ "name": "haskell",
+ "pygments_lexer": "Haskell",
+ "version": "8.6.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}