Skip to content

Instantly share code, notes, and snippets.

@ogrisel
Last active December 14, 2015 16:29
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ogrisel/5115540 to your computer and use it in GitHub Desktop.
Save ogrisel/5115540 to your computer and use it in GitHub Desktop.
Demo Notebook + Helper For Distributed Model Selection with IPython.parallel and scikit-learn
*.pyc
*.npy
*.pkl
*.mmap
import os
from IPython.parallel import interactive
@interactive
def persist_cv_splits(name, X, y, n_cv_iter=5, suffix="_cv_%03d.pkl",
test_size=0.25, random_state=None):
"""Materialize randomized train test splits of a dataset."""
from sklearn.externals import joblib
from sklearn.cross_validation import ShuffleSplit
import os
cv = ShuffleSplit(X.shape[0], n_iter=n_cv_iter,
test_size=test_size, random_state=random_state)
cv_split_filenames = []
for i, (train, test) in enumerate(cv):
cv_fold = (X[train], y[train], X[test], y[test])
cv_split_filename = os.path.abspath(name + suffix % i)
joblib.dump(cv_fold, cv_split_filename)
cv_split_filenames.append(cv_split_filename)
return cv_split_filenames
import os
def warm_mmap_on_cv_splits(client, cv_split_filenames):
"""Trigger a disk load on all the arrays of the CV splits
Assume the files are shared on all the hosts using NFS.
"""
# First step: query cluster to fetch one engine id per host
all_engines = client[:]
@interactive
def hostname():
import socket
return socket.gethostname()
hostnames = all_engines.apply(hostname).get_dict()
one_engine_per_host = dict((hostname, engine_id)
for engine_id, hostname
in hostnames.items())
hosts_view = client[one_engine_per_host.values()]
# Second step: for each data file and host, mmap the arrays of the file
# and trigger a sequential read of all the arrays' data
@interactive
def load_in_memory(filenames):
from sklearn.externals import joblib
for filename in filenames:
arrays = joblib.load(filename, mmap_mode='r')
for array in arrays:
array.sum() # trigger the disk read
cv_split_filenames = [os.path.abspath(f) for f in cv_split_filenames]
hosts_view.apply_sync(load_in_memory, cv_split_filenames)
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": "Model Selection for the Nystroem Method"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "code",
"collapsed": false,
"input": [
"%pylab inline\n",
"import pylab as pl\n",
"import numpy as np\n",
"\n",
"# Some nice default configuration for plots\n",
"pl.rcParams['figure.figsize'] = 10, 7.5\n",
"pl.rcParams['axes.grid'] = True\n",
"pl.gray()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.kernel.zmq.pylab.backend_inline].\n",
"For more information, type 'help(pylab)'.\n"
]
},
{
"output_type": "display_data",
"text": [
"<matplotlib.figure.Figure at 0x10da00fd0>"
]
}
],
"prompt_number": 1
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"IPython.parallel"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.parallel import Client\n",
"client = Client()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"len(client)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 3,
"text": [
"2"
]
}
],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%px print(\"Hello from the cluster engines!\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[stdout:0] Hello from the cluster engines!\n",
"[stdout:1] Hello from the cluster engines!\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def where_am_i():\n",
" import os\n",
" import socket\n",
" \n",
" return \"In process with pid {0} on host: '{1}'\".format(\n",
" os.getpid(), socket.gethostname())\n"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"where_am_i()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 6,
"text": [
"\"In process with pid 60954 on host: 'iamapc.local'\""
]
}
],
"prompt_number": 6
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Direct View"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"direct_view = client.direct_view()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"where_am_i_direct_results = direct_view.apply(where_am_i)\n",
"where_am_i_direct_results"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 8,
"text": [
"<AsyncResult: where_am_i>"
]
}
],
"prompt_number": 8
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"where_am_i_direct_results.get()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 9,
"text": [
"[\"In process with pid 56581 on host: 'iamapc.local'\",\n",
" \"In process with pid 56582 on host: 'iamapc.local'\"]"
]
}
],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"where_am_i_direct_results.get_dict()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 10,
"text": [
"{0: \"In process with pid 56581 on host: 'iamapc.local'\",\n",
" 1: \"In process with pid 56582 on host: 'iamapc.local'\"}"
]
}
],
"prompt_number": 10
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Load Balanced View"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"lb_view = client.load_balanced_view()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 11
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"where_am_i_lb_result = lb_view.apply(where_am_i)\n",
"where_am_i_lb_result"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 12,
"text": [
"<AsyncResult: where_am_i>"
]
}
],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"where_am_i_lb_result.get()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 13,
"text": [
"\"In process with pid 56581 on host: 'iamapc.local'\""
]
}
],
"prompt_number": 13
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Distributed Grid Search for a Linear Support Vector Machine"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import mmap_utils, model_selection\n",
"_ = reload(mmap_utils), reload(model_selection)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from sklearn.datasets import load_digits\n",
"from sklearn.preprocessing import MinMaxScaler\n",
"\n",
"digits = load_digits()\n",
"\n",
"X = MinMaxScaler().fit_transform(digits.data)\n",
"y = digits.target\n",
"\n",
"digits_cv_split_filenames = mmap_utils.persist_cv_splits('digits_10', X, y, 10)\n",
"digits_cv_split_filenames"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 15,
"text": [
"['/Users/ogrisel/coding/dsl-demo/digits_10_cv_000.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_001.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_002.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_003.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_004.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_005.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_006.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_007.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_008.pkl',\n",
" '/Users/ogrisel/coding/dsl-demo/digits_10_cv_009.pkl']"
]
}
],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"mmap_utils.warm_mmap_on_cv_splits(client, digits_cv_split_filenames)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 16
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from sklearn.svm import LinearSVC\n",
"from collections import OrderedDict\n",
"import numpy as np\n",
"\n",
"linear_svc_params = OrderedDict((\n",
" ('C', np.logspace(-2, 2, 5)),\n",
"))\n",
"linear_svc = LinearSVC()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 17
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"linear_svc_search = model_selection.RandomizedGridSeach(lb_view)\n",
"\n",
"linear_svc_search.launch_for_splits(linear_svc, linear_svc_params, digits_cv_split_filenames)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 18,
"text": [
"Progress: 00% (000/050)\n"
]
}
],
"prompt_number": 18
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"linear_svc_search"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 23,
"text": [
"Progress: 72% (036/050)\n",
"\n",
"Rank 1: validation: 0.96267 (+/-0.00307) train: 0.99154 (+/-0.00047):\n",
" {'C': 1.0}\n",
"Rank 2: validation: 0.96089 (+/-0.00302) train: 0.97669 (+/-0.00104):\n",
" {'C': 0.10000000000000001}\n",
"Rank 3: validation: 0.94667 (+/-0.00344) train: 0.99765 (+/-0.00035):\n",
" {'C': 10.0}\n",
"Rank 4: validation: 0.94200 (+/-0.00295) train: 0.95442 (+/-0.00092):\n",
" {'C': 0.01}"
]
}
],
"prompt_number": 23
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"linear_svc_search.boxplot_parameters(display_train=False)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"png": "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\n2mm6gNMFOIZGDOjH+PGX/oU23IcU3+eNH+/sz+slZGcn9po0m817vTIjBvQj1W+T2/y2fKKRnZ3I\nAW7FfcQAAABcikbMZZhzMBv5mYvsTBdwugCMgM3XH40YAACAQ5gRA/rBnJG5yM5O5AC3YkYMAOB5\n7DVpNpv3eqURcxmb18m9gPzMRXZmY69Js9m81yuNGAAAgEOYEQP6wZyRucgOMI+XryNmxAAAAFyK\nRsxlmFMxG/mZi+zMRn6mCzhdgGNoxAAAxmOvSbOx16RBmBFDKjBnZC6ysxM5wK2YEQMAAHApGjGX\nYc7BbORnLrIzXcDpAjACNl9/NGIAAAAOYUYM6AdzRgbz+VL/PQnPcVxDcCtmxABYxafopb+RU/Tw\nib/93YC9Js3GXpNwDZvXyb2A/MxFdmZjr0mzsdckAAAAUo4ZMaAfzIiZi+wA83j5OmJGDAAAwKVo\nxFyGORWzkZ+5yM5s5Ge6gNMFOIZGDABgPPaaNBt7TRqEGTGkAnNG5iI7O5ED3IoZMQAAAJeiEXMZ\n5hzMRn7mIjvTBZwuACNg8/VHIwYAAOAQZsSAfjBnZC6ysxM5wK2YEQMAGGP8+EtN1XAfUnyfN368\nsz8vLmGvSbiGzevkXkB+5iI7d+jujm//9UOHAnF9Xne30z8xJPaaBAAAgAOYEQP6wZyRucjObORn\nJy/n4MiMmN/v14wZMzR9+nRt2LChz/Pd3d2qqKhQYWGhSkpK1NraGnvu3LlzWrx4sfLy8jRz5kwd\nPXo0GSUCAAA4LuGNWCQS0cqVK+X3+9XW1qbdu3crGAz2OmfdunWaO3euWlpa1NDQoNra2thztbW1\n+sIXvqBgMKhXXnlFeXl5iS7R1ZhTMRv5mYvszEZ+pgs4XYBjEt6INTU1KScnR9nZ2UpPT1dlZaX2\n79/f65xgMKgFCxZIknJzcxUKhdTV1aWenh4dPnxYy5cvlySlpaVpzJgxiS4RAAC4iM17TaYl+gt2\ndnZq8uTJseOsrCw1Njb2OqewsFD79u3T/Pnz1dTUpNOnT+vMmTPy+XyaMGGCli1bppaWFs2bN0+b\nNm3SDTfc0Ovzq6qqlJ2dLUkaO3as5syZo7KyMklX/lVk6vHlj7mlHluPo1og+a78G63s4/8e7Pjy\nx4Z6/uXj6Mf/6Zaf3/Tjy/8LD+fzy8rKUvr9OCY/jq8c79gRf35uO77851AopKFI+LD+008/Lb/f\n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\n",
"text": [
"<matplotlib.figure.Figure at 0x10ef2d990>"
]
}
],
"prompt_number": 44
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Scaling Non-Linear SVM: Kernel Approximations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Motivation: traditional kernel SVM as in SVC has almost cubic complexity w.r.t. `n_samples`"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = np.linspace(0, int(1e3), 100)\n",
"\n",
"pl.plot(x, x ** 3 / 1e9)\n",
"pl.xlabel(\"Number of training samples\")\n",
"pl.ylabel(\"Estimated Convergence Time of SMO (in seconds)\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 25,
"text": [
"<matplotlib.text.Text at 0x1108ea1d0>"
]
},
{
"output_type": "display_data",
"png": "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\nt8LHH0Me1sCJOMrtdOf5tm7dyqhRo5g1axbp6enejCuHpjtFRMQTZs+G556DtWu1UEC8x9bpzu3b\ntxMTE0PNmjXp27cvjRs35sCBAx65uYiIiB3WroWnn4YFC1SgiTncFmk9e/YkNDSUpUuX8sUXX/DU\nU09x44032hGb+AH1VphLuTOb8ndOSgq0bw8ffQSRkU5H455yJ9nc7pP2zTff2BGHiIiIxx0/Dm3a\nwJAh1rOISdz2pH399dcMHz6clJQUMjIyrB8KCsrT0VAeCVA9aSIikg8ZGXDvvVC5srUfmo58Ejt4\nsm5xW6TdeuutjB07lnr16lGwYMGc18PCwjwSgDsq0kRE5Eq5XPDkk/Djj7BoERRyO28k4hm2LhwI\nDQ2ldevWlC5dmrCwsJyHSF6ot8Jcyp3ZAj1/r70G69bBp5+aV6AFeu7kHLd/dZs3b87gwYNp3749\nRYoUyXndyVMIREREcjNtGkyYAN98AyEhTkcjkn9upzujo6MJusRE/qpVq7wW1Pk03SkiInm1ahV0\n7Gg916jhdDQSiGztSXOaijQREcmL776zzuScNQuaN3c6GglUtvakHTt2jAEDBhAVFUVUVBSDBg3i\n+PHjHrm5+D/1VphLuTNboOXvp5+slZxvvWV+gRZouZPcuS3SevToQfHixfn000+ZPXs2ISEhdO/e\n3Y7YRERE3DpxwirQeveGRx5xOhoRz3E73VmnTh02b97s9jVv0XSniIjk5syZc3uh/fe/2gtNnGfr\ndOe1117LV199lXP99ddfU7RoUY/cXEREJL+ysqBrVyheHN55RwWa+B+3Rdp7773H008/Tfny5Slf\nvjx9+/blvffesyM28QPqrTCXcmc2f8+fywUDB1q9aDNmwHl7rRvP33Mneed2n7TIyEi2bNmSs1ig\nRIkSXg9KRETkcv7zH1ixAr76Cq65xuloRLwj1560N954gxIlSvD4449f8PqkSZNIS0ujf//+9gSo\nnjQRETnPxx/DsGGwejWEhzsdjciFbNknrV69eqxdu5bChQtf8PrZs2eJiopi69atHgnAbYAq0kRE\n5E+LF0OPHpCQAFWrOh2NyMVsWTiQkZFxUYEGULhwYRVNkmfqrTCXcmc2f8zf6tXWQoG5c/27QPPH\n3En+5FqkuVwufvnll4teP3jw4CWPiRIREfGWzZuhfXvrXM5GjZyORsQeuU53Tpkyhbfffps33niD\n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\n",
"text": [
"<matplotlib.figure.Figure at 0x1105ebfd0>"
]
}
],
"prompt_number": 25
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"1e6 ** 3 / 1e9 / 60 / 60 / 24 / 365"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 26,
"text": [
"31.709791983764582"
]
}
],
"prompt_number": 26
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Solution: Approximate Kernel SVM with a non-linear Kernel Expansion on a Small Basis + Linear SVC"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from sklearn.kernel_approximation import Nystroem\n",
"from sklearn.pipeline import Pipeline\n",
"\n",
"nystroem_pipeline = Pipeline([\n",
" ('nystroem', Nystroem()),\n",
" ('clf', LinearSVC()),\n",
"])"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 27
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"nystroem_pipeline_params = OrderedDict((\n",
" ('nystroem__n_components', [50, 100, 200]),\n",
" ('nystroem__gamma', np.logspace(-2, 2, 5)),\n",
" ('clf__C', np.logspace(-2, 2, 5)),\n",
"))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 28
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"nystroem_search = model_selection.RandomizedGridSeach(lb_view)\n",
"nystroem_search.launch_for_splits(nystroem_pipeline, nystroem_pipeline_params, digits_cv_split_filenames)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 29,
"text": [
"Progress: 00% (000/750)\n"
]
}
],
"prompt_number": 29
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"nystroem_search"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 41,
"text": [
"Progress: 32% (240/750)\n",
"\n",
"Rank 1: validation: 0.98556 (+/-0.00142) train: 0.99933 (+/-0.00021):\n",
" {'nystroem__n_components': 200, 'clf__C': 10.0, 'nystroem__gamma': 0.10000000000000001}\n",
"Rank 2: validation: 0.98156 (+/-0.00159) train: 0.99852 (+/-0.00027):\n",
" {'nystroem__n_components': 100, 'clf__C': 10.0, 'nystroem__gamma': 0.10000000000000001}\n",
"Rank 3: validation: 0.97178 (+/-0.00175) train: 0.98827 (+/-0.00044):\n",
" {'nystroem__n_components': 100, 'clf__C': 1.0, 'nystroem__gamma': 0.10000000000000001}\n",
"Rank 4: validation: 0.96578 (+/-0.00263) train: 0.99436 (+/-0.00039):\n",
" {'nystroem__n_components': 50, 'clf__C': 100.0, 'nystroem__gamma': 0.01}\n",
"Rank 5: validation: 0.96578 (+/-0.00137) train: 0.98337 (+/-0.00169):\n",
" {'nystroem__n_components': 200, 'clf__C': 100.0, 'nystroem__gamma': 1.0}"
]
}
],
"prompt_number": 41
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"nystroem_search.boxplot_parameters()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"png": "iVBORw0KGgoAAAANSUhEUgAAAlwAAAHQCAYAAAB0hrSOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3X9cVGXeP/7X2CCZmWgl2Qy7mCBgCCiga61JGgu2hZlm\n6G4BokuWt9vPrfb+7CNs+6FtbXbDZkgbahRaWouVjT40px8qP1YFTQyRnLuR0jtS0/VHwHB9//DL\nJDLDwHAOZ645r+fjcWou5pqZ9/i+DrznXNecYxBCCBARERGRavpoHQARERGRv2PBRURERKQyFlxE\nREREKmPBRURERKQyFlxEREREKmPBRURERKQyxQuuOXPmIDg4GKNGjXLbZ+HChQgPD0dsbCx2796t\ndAhEREREPkXxgisrKwsWi8Xt/Rs2bMDBgwdRV1eH5cuXY/78+UqHQERERORTjEo/4YQJE2Cz2dze\nv379emRkZAAAxo0bhxMnTuDo0aMIDg5u189gMCgdGhEREZFqOjuXvOIFlycNDQ0ICQlxts1mMw4f\nPtyh4AI6D5yUl5ubi9zcXK3DIFIVxznJqDcOQvBvbs94ylGvF1xAx6TyaJZv6OzIJJGv8ub3x6JF\ni7rVn3+ISGvdHYMGQyaEWKFOMOSVXv+Woslkgt1ud7YPHz4Mk8nU22HogsFg6Na2cuXKbj+GSGtC\niG5tsbEZ3X4MEVFP9XrBlZaWhlWrVgEAysrKEBQU5HI6kXqu+39UtvIPEfm96upMrUMgAgAMHgwY\nDOpsQKZqzz14sNb/cnIyCIX/as6aNQuffvopGhsbERwcjEWLFqG5uRkAkJOTAwBYsGABLBYL+vfv\nj6KiIowZM6ZjYAYD/6D3MoMB4D85+TuOc/IVso5FWeNWm6e6RfGCSyksuFwbPBg4flytZ7cCSFLl\nmQcNAo4dU+WpibrFYLBCiCStwyBStXCxWq1ISkpS5blZcLnmqW7hmeYlc/z4+YGuxrZ1q3rPrV6R\nSERE5Pt4hEsysn6ykDVu8j8ci+QrZB2LssatNk91iyanhSAi6oy6U+dti4qVx6lzInKHU4rkZLVa\ntQ6BCIDaU+dWTp2T3+Pvc9/DgouIiIhIZVzDJRlZ585ljZu0Iet4kTVu0oas40XWuNXGbykSERER\naYwFFzlxzp/0gOOc9IDj3Pew4CIiIiJSGddwSUbWuXNZ4yZtyDpeZI2btCHreJE1brVxDRcRERGR\nxlhwkRPn/EkPOM5JDzjOfQ8LLiIiIiKVcQ2XZGSdO5c1btKIWtfe6Q0c6NRFsv5elDVutfFaikQk\nHQOElL/QDQZAwrCJqBeoMqVosVgQGRmJ8PBwLFmypMP9jY2NSE1NRVxcHKKjo7FixQo1wqBu4pw/\n6QHHOekBx7nvUbzgcjgcWLBgASwWC2pqalBSUoL9+/e365Ofn4/Ro0ejqqoKVqsVjzzyCFpaWpQO\nhYiIiMgnKF5wVVRUICwsDKGhoQgICEB6ejpKS0vb9Rk6dChOnjwJADh58iSuvPJKGI2c3dRaUlKS\n1iEQqY7jnPSA49z3KF7lNDQ0ICQkxNk2m80oLy9v12fevHmYNGkSrr32Wpw6dQrvvPOOy+fKzMxE\naGgoACAoKAhxcXHOQdR2uFRvbcC34ulqG7DCavWdeNj27bas40XW/ZNtbdqyjhdZ90/l83f+ts1m\nQ1co/i3FdevWwWKxoLCwEABQXFyM8vJy5OXlOfs888wzaGxsxNKlS1FfX4/k5GRUV1djwIABPwfG\nbym6pOa3Q6xW6wU7lLL4rRbqDo5z0gOOc//S62eaN5lMsNvtzrbdbofZbG7XZ/v27bjrrrsAAMOH\nD8ewYcNQW1urdChEREREPkHxgishIQF1dXWw2WxoamrCmjVrkJaW1q5PZGQkNm/eDAA4evQoamtr\ncd111ykdCnWTWp+GiHwJxznpAce571F8DZfRaER+fj5SUlLgcDiQnZ2NqKgoFBQUAABycnLw5z//\nGVlZWYiNjUVrayteeOEFDB48WOlQiIiIiHwCzzQvGc75kx5wnJMecJz7l15fw0VERERE7fEIl2Rk\n/WQha9ykDVnHi6xxkzZkHS+yxq02HuEiIiIi0hgLLnK68GRuRP6K45z0gOPc97DgIiIiIlIZ13BJ\nRta5c1njJm3IOl5kjZu0Iet4kTVutXENFxEREZHGWHCRE+f8SQ84zkkPOM59DwsuIiIiIpV5XMN1\n+vRp/P3vf8c333yDwsJC1NXVoba2Frfddpu6gXENl0uyzp3LGjdpQ9bxImvcpA1Zx4uscautx2u4\nsrKy0LdvX2zfvh0AcO211+K///u/lYuQiIiIyM95LLjq6+vx+OOPo2/fvgCA/v37qx4UaYNz/qQH\nHOekBxznvsdjwRUYGIizZ8862/X19QgMDFQ1KCIiIiJ/4nEN16ZNm/Dss8+ipqYGycnJ2LZtG1as\nWIGbb75Z3cC4hsslWefOZY2btCHreJE1btKGrONF1rjV5qluMXb24NbWVhw/fhzr1q1DWVkZAOCV\nV17B1VdfrWyURERERH7M4xGu+Ph47Ny5s7ficeIRLtfU/GRhtVqRlJSkynPzExF1B8c56QHHuX/p\n8bcUk5OT8eKLL8Jut+PYsWPOrTMWiwWRkZEIDw/HkiVLXPaxWq0YPXo0oqOjVRsURERERL7A4xGu\n0NBQGAyG9g8yGPD111+77O9wOBAREYHNmzfDZDIhMTERJSUliIqKcvY5ceIEbrzxRmzcuBFmsxmN\njY246qqrOrwGj3B1JOsnC1njJm3IOl5kjZu0Iet4kTVutfVoDRcA2Gy2br1gRUUFwsLCEBoaCgBI\nT09HaWlpu4Lr7bffxvTp02E2mwGgQ7FFRERE5E88FlxNTU1YtmwZPvvsMxgMBkycOBH33XcfAgIC\nXPZvaGhASEiIs202m1FeXt6uT11dHZqbm3HzzTfj1KlT+OMf/4h77rmnw3NlZmY6C7egoCDExcU5\npx/bzjGitzag3vNXVVXhwQcfVOX5ASusVu3//diWo63mePl5X5Jr/2Tb/9r8fS53u+12Vw9MeZxS\nzM7ORktLCzIyMiCEwJtvvgmj0YjXX3/dZf9169bBYrGgsLAQAFBcXIzy8nLk5eU5+yxYsAC7du3C\nli1bcObMGYwfPx4fffQRwsPDfw6MU4oucZEl6QHHOekBx7l/6fGUYmVlJfbs2eNsT548GTExMW77\nm0wm2O12Z9tutzunDtuEhITgqquuQr9+/dCvXz/cdNNNqK6ubldwUe9Ta+ck8iUc56QHHOe+p4+n\nDkajEQcPHnS26+vrYTS6r9MSEhJQV1cHm82GpqYmrFmzBmlpae36TJ06FV988QUcDgfOnDmD8vJy\njBw5sgdvg4iIiMh3eTzC9be//Q2TJk3CsGHDAJxfRF9UVOT+CY1G5OfnIyUlBQ6HA9nZ2YiKikJB\nQQEAICcnB5GRkUhNTUVMTAz69OmDefPmseDyAWoegibyFRznpAcc577H4xouADh37hxqa2thMBgw\nYsQIXHrppeoHxjVcrl10ig4lWdG2hFMlzCd1Ede2kB5wnPsXT3WLx4IrPz8fv/vd7zBo0CAAwPHj\nx1FSUoL7779f2UgvDowFl0uyDnRZ4yZtyDpeZI2btCHreJE1brX1uOCKjY1FdXV1u5/FxcWhqqpK\nmQjdBcaCyyVZB7qscZM2ZB0vssZN2pB1vMgat9p6fGmf1tZWtLa2OtsOhwPNzc3KREc+5cJzixD5\nK45z0gOOc9/jcdF8SkoK0tPTkZOTAyEECgoKkJqa2huxEREREfkFj1OKDocDy5cvx5YtWwCcv5j1\n3Llzcckll6gbGKcUXZL1UK6scZM2ZB0vssZN2pB1vMgat9p6vIarTVNTE7788kuYzWYMGTJEsQDd\nYcHlmqwDXda4SRuyjhdZ4yZtyDpeZI1bbV6v4crJycGXX34JAPjxxx8RGxuLjIwMxMXF4e2331Y+\nUtIc5/xJDzjOSQ84zn2P24Lr888/R3R0NACgqKgIERER2Lt3L3bt2oUXXnih1wIkIiIikp3bgisw\nMNB5e9OmTZg6dSoA4JprrlE/KtIEz0pMesBxTnrAce573BZcAwcOxAcffIBdu3Zh+/btzm8mNjc3\n49y5c70WIBEREZHs3BZcBQUFyM/PR1ZWFpYuXYqhQ4cCAD755BP89re/7bUAqfdwzp/0gOOc9IDj\n3Pe4PQ9XREQENm7c2OHnKSkpSElJUTUoIiIiIn/S5dNC9DaeFsI1Wb+OK2vcpA1Zx4uscZM2ZB0v\nssatth5f2oeIiIiIeoYFFzlxzp/0gOOc9IDj3Pd4VXDt3LlT6TiIiIiI/JZXBddrr73W6f0WiwWR\nkZEIDw/HkiVL3ParrKyE0WjEe++9500YpDCet4X0gOOc9IDj3Pcovmje4XAgIiICmzdvhslkQmJi\nIkpKShAVFdWhX3JyMi677DJkZWVh+vTp7QPjonmXZF2sKGvcpA1Zx4uscZM2ZB0vssatNk91i9vT\nQuzcuRMGg8HtA8eMGePy5xUVFQgLC0NoaCgAID09HaWlpR0Krry8PMyYMQOVlZVuXyMzM9P5PEFB\nQYiLi3NW7W3z03prA+o9f1VVFR588EFVnh+wwmrV/t+PbTnaao6Xn/clufZPtv2vzd/ncrfbbtts\nNnSF2yNcSUlJnRZcW7dudfnztWvXYuPGjSgsLAQAFBcXo7y8HHl5ec4+DQ0N+P3vf49PPvkEc+bM\nwe23344777yzfWA8wuWSmp8srFbrBTuUsviJiLqD45z0gOPcv3h9hOvCCq67L+jJgw8+iMWLFzuD\nY2HlG9TaOYl8Ccc56QHHue9xW3BdaO/evdi/f3+7ayjee++9LvuaTCbY7XZn2263w2w2t+uzc+dO\npKenAwAaGxvx8ccfIyAgAGlpad1+A0RERES+ro+nDrm5uVi4cCEWLFiArVu34k9/+hPWr1/vtn9C\nQgLq6upgs9nQ1NSENWvWdCikvv76axw6dAiHDh3CjBkzsGzZMhZbPsDbo5pEMuE4Jz3gOPc9Hguu\ntWvXYvPmzRg6dCiKiopQXV2NEydOuO1vNBqRn5+PlJQUjBw5EnfffTeioqJQUFCAgoICRYMnIiIi\nkoHH00IkJiaisrIS8fHx+OSTT3DFFVcgMjIStbW16gbGRfMuybpYUda4SRuyjhdZ4yZtyDpeZI1b\nbV4vmm+TkJCA48ePY968eUhISED//v1xww03KBokERERkT9ze4Tr/vvvx+zZs/HrX//a+bNDhw7h\n5MmTiI2NVT8wHuFyiV8jJj3gOCc94Dj3L14f4RoxYgQee+wxfPvtt7j77rsxa9YsjB49WpUgiYiI\niPyZxzVcNpsNq1evxpo1a3DmzBnMnj0bs2bNwogRI9QNjEe4XJL1k4WscZM2ZB0vssZN2pB1vMga\nt9o81S3dupbi7t27kZWVhb1798LhcCgSoDssuFyTdaDLGjdpQ9bxImvcpA1Zx4uscavNU93i8bQQ\nLS0tWL9+PWbPno3U1FRERkbivffeUzRI8g08bwvpAcc56QHHue9xu4Zr06ZNWL16NT766COMHTsW\ns2bNwvLly3H55Zf3ZnxERERE0nM7pThp0iTMmjUL06dPx+DBg3s7Lk4puiHroVxZ4yZtyDpeZI2b\ntCHreJE1brUpuoarN7Hgck3WgS5r3KQNWceLrHGTNmQdL7LGrbYer+Ei/eCcP+kBxznpAce572HB\nRURERKQyTilKRtZDubLGTdqQdbzIGjdpQ9bxImvcauOUIhEREZHGWHCRE+f8SQ84zkkPOM59Dwsu\nIiIiIpWpUnBZLBZERkYiPDwcS5Ys6XD/W2+9hdjYWMTExODGG2/Enj171AiDukmtK8sT+RKOc9ID\njnPfo/iieYfDgYiICGzevBkmkwmJiYkoKSlBVFSUs8+OHTswcuRIDBw4EBaLBbm5uSgrK2sfGBfN\nuyTrYkVZ4yZtyDpeZI2btCHreJE1brX1+qL5iooKhIWFITQ0FAEBAUhPT0dpaWm7PuPHj8fAgQMB\nAOPGjcPhw4eVDoO8wDl/0gOOc9IDjnPf4/Zait5qaGhASEiIs202m1FeXu62/z//+U/ceuutLu/L\nzMxEaGgoACAoKAhxcXHOw6Rtg0lvbUC956+qqlItfsAKq1X7fz+25WjLOl7U3D/Z9r82f5/L3W67\nbbPZ0BWKTymuW7cOFosFhYWFAIDi4mKUl5cjLy+vQ9+tW7figQcewLZt2zBo0KD2gXFK0SVZD+XK\nGjdpQ9bxImvcpA1Zx4uscavNU92i+BEuk8kEu93ubNvtdpjN5g799uzZg3nz5sFisXQotoiIiIj8\nSR+lnzAhIQF1dXWw2WxoamrCmjVrkJaW1q7PN998gzvvvBPFxcUICwtTOgTy0oWHSYn8Fcc56QHH\nue9R/AiX0WhEfn4+UlJS4HA4kJ2djaioKBQUFAAAcnJy8PTTT+P48eOYP38+ACAgIAAVFRVKh0JE\nRETkE3gtRcnIOncua9ykDVnHi6xxkzZkHS+yxq02XkuRiIiISGMsuMiJc/6kBxznpAcc576HBRcR\nERGRyriGSzKyzp3LGjdpQ9bxImvcpA1Zx4uscauNa7iIiIiINMaCi5w45096wHFOesBx7nsUPw8X\nEREReSZgAAxaR9F94oL/UtdxDZdkZJ07lzVu0oas40XWuEkbso4XWeNWW69fS5GISAkGCT/587Kw\n1F0c5/rBgktC6u2gVgBJqjwzd1DqDjU/PRsMVgiRpN4LEHURx7m+sOCSjLo7KA8TExERqYEFlx8z\neHEorLsP4To70hrHOekBx7n8WHD5Me48pAcc56QHHOfy43m4yInnbSE94DgnPeA49z0suMipqqpK\n6xCIVMdxTnrAce57WHCR04kTJ7QOgUh1HOekBxznvkeVgstisSAyMhLh4eFYsmSJyz4LFy5EeHg4\nYmNjsXv3bjXCICIiIvIJihdcDocDCxYsgMViQU1NDUpKSrB///52fTZs2ICDBw+irq4Oy5cvx/z5\n85UOg7xgs9m0DoFIdRznpAcc5z5IKGz79u0iJSXF2X7++efF888/365PTk6OWL16tbMdEREhjhw5\n0q4Pzl+oiRs3bty4cePGTYqtM4qfFqKhoQEhISHOttlsRnl5ucc+hw8fRnBwsPNngl+BJSIiIj+h\n+JRiV0/OdnFB5c1J3YiIiIhkoHjBZTKZYLfbnW273Q6z2dxpn8OHD8NkMikdChEREZFPULzgSkhI\nQF1dHWw2G5qamrBmzRqkpaW165OWloZVq1YBAMrKyhAUFNRuOpGIiIjInyi+hstoNCI/Px8pKSlw\nOBzIzs5GVFQUCgoKAAA5OTm49dZbsWHDBoSFhaF///4oKipSOgwiIiIin2EQXJ2uW6Ghobjiiitw\nySWXICAgABUVFTh27Bjuvvtu/O///i9CQ0PxzjvvICgoSOtQibpszpw5+OijjzBkyBDs3bsXADod\n188//zzeeOMNXHLJJfif//kf/OY3v9EyfKIusdvtuPfee/F///d/MBgM+MMf/oCFCxdyrPswnmle\nxwwGA6xWK3bv3o2KigoAwOLFi5GcnIwDBw5g8uTJWLx4scZREnVPVlYWLBZLu5+5G9c1NTVYs2YN\nampqYLFYcP/996O1tVWLsIm6JSAgAC+//DL27duHsrIy/OMf/8D+/fs51n0YCy6du/gA5/r165GR\nkQEAyMjIwL/+9S8twiLy2oQJEzBo0KB2P3M3rktLSzFr1iwEBAQgNDQUYWFhzg8fRL7smmuuQVxc\nHADg8ssvR1RUFBoaGjjWfRgLLh0zGAy45ZZbkJCQgMLCQgDA0aNHnV9gCA4OxtGjR7UMkUgR7sb1\nt99+2+5b1GazGQ0NDZrESOQtm82G3bt3Y9y4cRzrPkzxRfMkj23btmHo0KH4/vvvkZycjMjIyHb3\nGwwGnh+N/I6ncc0xTzL5z3/+g+nTp+OVV17BgAED2t3Hse5beIRLx4YOHQoAuPrqqzFt2jRUVFQg\nODgYR44cAQB89913GDJkiJYhEinC3bjmOQFJZs3NzZg+fTruuece3HHHHQA41n0ZCy6dOnPmDE6d\nOgUAOH36NDZt2oRRo0YhLS0NK1euBACsXLnSuRMTyczduE5LS8Pq1avR1NSEQ4cOoa6uDmPHjtUy\nVKIuEUIgOzsbI0eOxIMPPuj8Oce67+JpIXTq0KFDmDZtGgCgpaUFv/vd7/Dkk0/i2LFjmDlzJr75\n5hueFoKkNGvWLHz66adobGxEcHAwnn76aUydOtXtuH7uuefwxhtvwGg04pVXXkFKSorG74DIsy++\n+AI33XQTYmJinFODzz//PMaOHcux7qNYcBERERGpjFOKRERERCpjwUVERESkMhZcRERERCpjwUVE\n3VZaWor9+/drHQa58Omnn2LHjh1ah0FEF2HBRUTd9v7776OmpsblfQ6Ho5ejoQtt3boV27dv1zoM\nIroICy4inbHZbIiKisIf/vAHREdHIyUlBTU1NYiPj3f2qaurc7afeOIJXH/99YiNjcVjjz2GHTt2\n4IMPPsBjjz2GMWPG4Ouvv0ZSUhIeeughJCYm4pVXXsGWLVswZswYxMTEIDs7G01NTQCAnTt3Iikp\nCQkJCUhNTXWeoDEpKQkPP/wwEhMTERUVhcrKSkybNg0jRozAX/7ylx6/v3Pnzrntf/DgQdxyyy2I\ni4tDfHw8Dh06BAB47LHHMGrUKMTExOCdd94BAFitVkycOBF33HEHhg8fjieeeAJvvvkmxo4di5iY\nGHz99dcAgMzMTNx3331ITExEREQEPvroIwDAuXPnkJWVhZiYGIwZMwZWqxUAsGLFCtx5552YMmUK\nRowYgccff9wZ36ZNm3DDDTcgPj4eM2fOxOnTpwEAoaGhyM3NRXx8PGJiYlBbWwubzYaCggK8/PLL\nGD16NL744gu8++67GDVqFOLi4jBx4sRu/VsSkYIEEenKoUOHhNFoFNXV1UIIIWbOnCmKi4vFzTff\nLKqqqoQQQjz55JMiPz9f/PDDDyIiIsL52B9//FEIIURmZqZYt26d8+dJSUnigQceEEIIcfbsWRES\nEiLq6uqEEELce++9YunSpaK5uVmMHz9eNDY2CiGEWL16tZgzZ47z8U888YQQQohXXnlFDB06VBw5\nckT89NNPwmw2i2PHjvX4/bkzduxY8a9//UsIIcRPP/0kzpw5I9auXSuSk5NFa2urOHr0qPjFL34h\nvvvuO7F161YRFBTkjO3aa68VTz31lDPuBx98UAghREZGhpgyZYoQQoi6ujphNpvFuXPnxIsvviiy\ns7OFEEJ89dVX4he/+IU4d+6cKCoqEtddd504efKkOHfunPjlL38pDh8+LL7//ntx0003iTNnzggh\nhFi8eLF4+umnhRBChIaGivz8fCGEEK+++qqYO3euEEKI3Nxc8dJLLznf36hRo8S3337bLn9E1PsU\nP8I1Z84cBAcHY9SoUW77LFy4EOHh4YiNjcXu3buVDoGIPBg2bBhiYmIAAPHx8bDZbJg7dy6KiorQ\n2tqKd955B7Nnz8YVV1yBSy+9FNnZ2Xj//ffRr18/53OIi07hd/fddwMAamtrMWzYMISFhQEAMjIy\n8Nlnn6G2thb79u3DLbfcgtGjR+PZZ59td/HctLQ0AEB0dDSio6MRHByMvn374rrrrsM333zT4/fn\nyqlTp/Dtt99i6tSpAIC+ffuiX79+2LZtG2bPng2DwYAhQ4Zg4sSJqKyshMFgQGJiojO2sLAw58kj\no6Ojna9jMBgwc+ZMAEBYWBiuu+46fPXVV9i2bRt+//vfAwAiIiLwy1/+EgcOHIDBYMDkyZMxYMAA\nBAYGYuTIkbDZbCgrK0NNTQ1uuOEGjB49GqtWrWr3b3HnnXcCAMaMGdPuPV6YmxtvvBEZGRl4/fXX\n0dLS0q1/RyJSjuIFV1ZWFiwWi9v7N2zYgIMHD6Kurg7Lly/H/PnzlQ6BiDwIDAx03r7kkkvgcDgw\nffp0fPzxx/jwww+RkJCAQYMGwWg0oqKiAjNmzMCHH36I1NRU5+MuvvBt//79Xb5W2x9/IQSuv/56\n7N69G7t378aePXva/a5oi6lPnz7t4uvTp0+314Vd/P68KTQuLijb3u/FsV0Yd2ev0/b4i5/XU8zJ\nycnOf7N9+/ahsLCww2M6e4/Lli3DM888A7vdjvj4eBw7dsxtjESkHsULrgkTJmDQoEFu71+/fj0y\nMjIAAOPGjcOJEydw9OhRpcMgom4QQiAwMBApKSmYP38+srKyAJy/zuaJEycwZcoU/P3vf0d1dTUA\nYMCAATh58mSH5wDOH7mx2Wyor68HALz55ptISkpCREQEvv/+e5SVlQE4f+Fddwvve8uAAQNgNptR\nWloKAPjpp59w9uxZTJgwAWvWrEFrayu+//57fPbZZxg7dqzbYuliQgi8++67EEKgvr4eX3/9NSIj\nIzFhwgS89dZbAIADBw7gm2++QWRkpMvnNRgM+NWvfoVt27Y5/y1Pnz6Nuro6j++p7TqpAFBfX4+x\nY8di0aJFuPrqq3H48OEuvQciUpga85SHDh0S0dHRLu+77bbbxLZt25ztyZMni3//+98d+gHgxo0b\nN27cuHGTZuuMERoQbg7Ve+rnT3Jzc5Gbm6t1GOSGuzHZFf48bv0B9z25MX/y8vfcefq70eunhTCZ\nTLDb7c724cOHYTKZejuMXmEwGNxuixYt6vR+Ut/gwYDB4Hrr/ENMRqf3u3vOwYN7/z1SR+4W0JMc\nmD956T13vV5wpaWlYdWqVQCAsrIyBAUFITg4uLfD6BVCCLcbkOHhflLbseMGCHR/y8BKrx537DgL\n6d7S2YeZlStX8sMOEfU6xacUZ82ahU8//RSNjY0ICQnBokWL0NzcDADIycnBrbfeig0bNiAsLAz9\n+/dHUVGR0iH0Li9/QW8FAMNK716TBZkiDBBe/VNmWq1AUlL3X89w/hgYqa+zDy0GgxVCJPVeMKSo\nzMxMrUMgL+k9dwbho4dTDAaDFEd6evsD8aBBAL/VrQzmTp8MBn5mISLleapbeGmfHhLC/QYYvN7c\nPSf/YCtXOcJSAAAgAElEQVSns9x1nlerV49j7nyFVesAqAfaLodE8tF77lhwqaizNVpbt27lGi4i\nIiKd4JQiUTdxSkpuzB8RqcFT3aLJebiIfF3n31b7CQZDoNt7+UGhdwweDBw/7t1jvVm/xzV4RNQT\nnFLUiN7nsn3dxVO8L78sMHHi+Q3Y7rz98sucDtbK8ePercHbutW7NXjeFnekLP7ulJfec8cjXERd\ncPAgcOE5+9puHzyoRTRERCQbruEi6gKr9fwGAIsWAU89df52UpJXp+QiBfT2Wiyu/SKizniqW1hw\nEXVTQADw/5/Ll7SkxVnh+TuJiNzgebh8lN7nsmVjtQK5uee3lhar8zbTqB0DvDuRmnXrVq8eZ+B1\nAnwCf3fKS++54xouoi64cOqwrOx8sUVERNRVnFIk6qa2o1ukLa7hIiJfwilFIoVxkTwREXUXCy6N\n6H0uW25WrQOgHuC+JzfmT156zx0LLiIiIiKVcQ0XEUmJa7iIyJdwDRcRERGRxlQpuCwWCyIjIxEe\nHo4lS5Z0uL+xsRGpqamIi4tDdHQ0VqxYoUYYPk3vc9kyY+7kxvzJjfmTl95zp3jB5XA4sGDBAlgs\nFtTU1KCkpAT79+9v1yc/Px+jR49GVVUVrFYrHnnkEbS0tCgdChEREZFPULzgqqioQFhYGEJDQxEQ\nEID09HSUlpa26zN06FCcPHkSAHDy5ElceeWVMBr1dQ7WJJ5bQFrMndyYP7kxf/LSe+4Ur3IaGhoQ\nEhLibJvNZpSXl7frM2/ePEyaNAnXXnstTp06hXfeecflc2VmZiI0NBQAEBQUhLi4OGfC2g5Nss02\n2/ptA/79emyzzbbvtttu22w2dIXi31Jct24dLBYLCgsLAQDFxcUoLy9HXl6es88zzzyDxsZGLF26\nFPX19UhOTkZ1dTUGDBjwc2B+/i1Fq9XqTB7JhbnzDd5+a9Db/PFbir6B+5+8/D13vf4tRZPJBLvd\n7mzb7XaYzeZ2fbZv34677roLADB8+HAMGzYMtbW1SodCRERE5BMUP8LV0tKCiIgIbNmyBddeey3G\njh2LkpISREVFOfs8/PDDGDhwIJ566ikcPXoU8fHx2LNnDwYPHvxzYH5+hIuIesZg6N3XGzQIOHas\nd1+TiOThqW5RfA2X0WhEfn4+UlJS4HA4kJ2djaioKBQUFAAAcnJy8Oc//xlZWVmIjY1Fa2srXnjh\nhXbFFhGRJ95+HuPUIBFpgWea14i/z2X7M+ZObgaDFUIkaR0GeYn7n7z8PXc80zwRERGRxniEi4h0\nhVOKRKQGHuEiIiIi0hgLLo1ceOI0kgtzJ7eMDKvWIVAPcP+Tl95zx4KLiHQlM1PrCIhIj7iGi4iI\niKiHuIaLiIiISGMsuDSi97lsmTF3cmP+5Mb8yUvvufNYcJ0+fRp//etfMW/ePABAXV0dPvzwQ9UD\nIyIiIvIXHtdwzZw5E/Hx8Vi1ahX27duH06dP44YbbkB1dbW6gXENFxGpIDf3/EZEpKQer+Gqr6/H\n448/jr59+wIA+vfvr1x0RES9bNEirSMgIj3yWHAFBgbi7NmzznZ9fT0CAwNVDUoP9D6XLTPmTnZW\nrQOgHuD+Jy+9587oqUNubi5SU1Nx+PBhzJ49G9u2bcOKFSt6ITQiIiIi/9DpGq7W1la8++67mDx5\nMsrKygAA48aNw9VXX61+YFzDRUQq4LUUiUgNnuoWj4vm4+PjsXPnTsUD84QFFxGpgQUXEamhx4vm\nk5OT8eKLL8Jut+PYsWPOjXpG73PZMmPu5MZrKcqN+5+89J47jwXX6tWr8Y9//AM33XQT4uPjER8f\nj4SEhE4fY7FYEBkZifDwcCxZssRlH6vVitGjRyM6OhpJSUleBU9E1F28liIRaUHxayk6HA5ERERg\n8+bNMJlMSExMRElJCaKiopx9Tpw4gRtvvBEbN26E2WxGY2MjrrrqqvaBcUqRiIiIJOGpbvH4LcWm\npiYsW7YMn332GQwGAyZOnIj77rsPAQEBLvtXVFQgLCwMoaGhAID09HSUlpa2K7jefvttTJ8+HWaz\nGQA6FFttMjMznc8TFBSEuLg459GwtkOTbLPNNttss802273dbrtts9nQFR6PcGVnZ6OlpQUZGRkQ\nQuDNN9+E0WjE66+/7rL/2rVrsXHjRhQWFgIAiouLUV5ejry8PGefhx56CM3Nzdi3bx9OnTqFP/7x\nj7jnnnvaB+bnR7isVqszeSQX5k5uzJ/cmD95+XvuenyEq7KyEnv27HG2J0+ejJiYmE5f0JPm5mbs\n2rULW7ZswZkzZzB+/Hj86le/Qnh4uMfHEhEREcmmj6cORqMRBw8edLbr6+thNLqv00wmE+x2u7Nt\nt9udU4dtQkJC8Jvf/Ab9+vXDlVdeiZtuukn1azP6Gn+u8v0dcyc3qzVJ6xCoB7j/yUvvufNYcP3t\nb3/DpEmTMHHiREycOBGTJk3Ciy++6LZ/QkIC6urqYLPZ0NTUhDVr1iAtLa1dn6lTp+KLL76Aw+HA\nmTNnUF5ejpEjR/b83RARecBrKRKRFjxOKU6ePBkHDhxAbW0tDAYDRowYgUsvvdT9ExqNyM/PR0pK\nChwOB7KzsxEVFYWCggIAQE5ODiIjI5GamoqYmBj06dMH8+bN013B5e9z2f6MuZOdFUCSxjGQt7j/\nyUvvufNYcOXn5+N3v/sdYmNjAQDHjx/HG2+8gfvvv9/tY6ZMmYIpU6a0+1lOTk679qOPPopHH33U\nm5iJiIiIpOLxW4qxsbEd1lfFxcWhqqpK3cD8/FuKRKSernx5xx3+3iEib/T40j6tra1obW11th0O\nB5qbm5WJjohIBUIIt9vWre7vY7FFRGrxWHClpKQgPT0dW7ZswebNm5Geno7U1NTeiM2vXXjiNJIL\ncye3FSusWodAPcD9T156z53HNVxLlizB8uXLsWzZMgDnL2Y9d+5c1QMjIiIi8hddvpZiU1MTvvzy\nS5jNZgwZMkTtuLiGi4gUY7We34Dzp4V46qnzt5OSzm9ERD3lqW5xW3Dl5OTgv/7rvxAdHY0ff/wR\nv/rVr2A0GvHDDz/gxRdfxOzZs1ULGmDBRUTqiIsDVP7ODxHpkNeL5j///HNER0cDAIqKihAREYG9\ne/di165deOGFF5SPVGf0PpctM+ZObkeOWLUOgXqA+5+89J47t2u4AgMDnbc3bdqEu+66CwBwzTXX\nqB8VEZGCLpxSPHoUyM09f5tTikTUW9we4Ro4cCA++OAD7Nq1C9u3b3d+M7G5uRnnzp3rtQD9lZ7P\ntis75k52SVoHQD3A/U9ees+d2zVctbW1WLhwIY4cOYKHHnoImZmZAICNGzdi06ZNeOmll9QNjGu4\niEgFXMNFRGrwetG81vy94NL7NaVkxtzJLSzMioMHk7QOg7zE/U9e/p67Hp9pnojIn4SFaR0BEekR\nj3ARkd/jebiISG2e6haPZ5onIpLdxYVV27cUiYh6i1dTijt37lQ6Dt3R+/lIZMbcyc1ms2odAvUA\n9z956T13XhVcr732Wqf3WywWREZGIjw8HEuWLHHbr7KyEkajEe+99543YRARdVtcnNYREJEeKb6G\ny+FwICIiAps3b4bJZEJiYiJKSkoQFRXVoV9ycjIuu+wyZGVlYfr06e0D4xouIiIikoTXa7h27twJ\ng8Hg9oFjxoxx+fOKigqEhYUhNDQUAJCeno7S0tIOBVdeXh5mzJiBysrKzuInIiIikp7bguuRRx7p\ntODaunWry583NDQgJCTE2TabzSgvL+/Qp7S0FJ988gkqKyvdvk5mZqazcAsKCkJcXJzzHB5tc8Gy\ntpcuXepX70dP7QvXIfhCPGwzf3pqM3/yttt+5ivxKPF+rFYrbDYbukLxKcV169bBYrGgsLAQAFBc\nXIzy8nLk5eU5+9x111149NFHMW7cOGRmZuL222/X3ZSi1Wp1Jo/kwtzJjfmTG/MnL3/PnSJnmt+7\ndy/279/f7hqK9957r8u+ZWVlyM3NhcViAQA8//zz6NOnDx5//HFnn+uuu84ZVGNjIy677DIUFhYi\nLS2ty4ETERER+YoeF1y5ubn49NNPsW/fPvz2t7/Fxx9/jF//+tdYu3aty/4tLS2IiIjAli1bcO21\n12Ls2LEuF823ycrKwu23344777yzW4ETERER+YoeX9pn7dq12Lx5M4YOHYqioiJUV1fjxIkTbvsb\njUbk5+cjJSUFI0eOxN13342oqCgUFBSgoKDAu3fhhy6cAya5MHdyY/7kxvzJS++583im+X79+uGS\nSy6B0WjEjz/+iCFDhsBut3f6mClTpmDKlCntfpaTk+Oyb1FRUTfCJSIiIpKPxynF+fPn47nnnsOa\nNWvw0ksvoX///hg9erTqhRKnFImIiEgWXq/huv/++zF79mz8+te/dv7s0KFDOHnyJGJjY5WP9OLA\nWHARERGRJLxewzVixAg89thj+OUvf4k//elP2L17N4YNG9YrxZYe6H0uW2bMndyYP7kxf/LSe+7c\nFlwPPvggduzYgU8//RSDBw/GnDlzEBERgUWLFuHAgQO9GSMRERGR1Lp14tPdu3cjKysLe/fuhcPh\nUDMuTikSERGRNHp8WoiWlhasX78es2fPRmpqKiIjI/Hee+8pGiQRERGRP3NbcG3atAlz5syByWRC\nYWEhbrvtNtTX12P16tWYOnVqb8bol/Q+ly0z5k5uzJ/cmD956T13bs/DtXjxYsyaNQsvvvgiBg8e\n3JsxEREREfkVxS9erRSu4SIiIiJZ9HgNFxERERH1DAsujeh9LltmzJ3cmD+5MX/y0nvuWHARERER\nqYxruIiIiIh6iGu4iIiIiDTGgksjep/LlhlzJzfmT27Mn7z0njsWXEREREQqU2UNl8ViwYMPPgiH\nw4G5c+fi8ccfb3f/W2+9hRdeeAFCCAwYMADLli1DTExM+8C4houIiIgk4aluUbzgcjgciIiIwObN\nm2EymZCYmIiSkhJERUU5++zYsQMjR47EwIEDYbFYkJubi7Kysm4FTkREROQren3RfEVFBcLCwhAa\nGoqAgACkp6ejtLS0XZ/x48dj4MCBAIBx48bh8OHDSofh8/Q+ly0z5k5uzJ/cmD956T13bq+l6K2G\nhgaEhIQ422azGeXl5W77//Of/8Stt97q8r7MzEyEhoYCAIKCghAXF4ekpCQAPydO1nZVVZVPxcM2\n22yzzTbbarbb+Eo8Srwfq9UKm82GrlB8SnHdunWwWCwoLCwEABQXF6O8vBx5eXkd+m7duhUPPPAA\ntm3bhkGDBrUPjFOKREREJAlPdYviR7hMJhPsdruzbbfbYTabO/Tbs2cP5s2bB4vF0qHYIiIiIvIn\nfZR+woSEBNTV1cFms6GpqQlr1qxBWlpauz7ffPMN7rzzThQXFyMsLEzpEKRw8SFWkgdzJzfmT27M\nn7z0njvFj3AZjUbk5+cjJSUFDocD2dnZiIqKQkFBAQAgJycHTz/9NI4fP4758+cDAAICAlBRUaF0\nKEREREQ+gddSJCIiIuohXkuRiIiISGMsuDSi97lsmTF3cmP+5Mb8yUvvuWPBRURERKQyruEiIiIi\n1U2bBrz/vtZRqKfXr6WoFBZcRET6ZDAYvH4s/274rqAg4MQJraNQDxfN+yi9z2XLjLmTG/Pn+4QQ\nbjdgq4f7yVe1tFi1DkFTLLiIiKjXDR4MGAzd3wDvHjd4sLbvV6+mTTt/ZCsoCDh9+ufb06ZpHVnv\n45QiERH1vh5MG3qNf1NU1/l08HEA7i/lJ/vf/F6/liIREZEnBvTuH9dBg4BjvfqKfqyToqqzrBrR\nHy1ePq8/FMucUtQI15HIi7mTG/PnG4TwbgOsXj3uGKstxRggvNoc2ObV4wYPkr/YAniEi4iIiLrB\n24NNffsCTU3KxiITruEiIiKfwtNC+I8JE4DKyvO3f/oJCAw8fzsxEfj8c+3iUgPPw0VERESau/RS\n4Nw5raNQD8/D5aO4jkRezJ3cmD+5MX/yam21ah2CplhwaaSqqkrrEMhLzJ3cmD+5MX/yMpv1nTtV\nCi6LxYLIyEiEh4djyZIlLvssXLgQ4eHhiI2Nxe7du9UIw6ed8OfrG/g55k5uzJ/cmD953XuvvnOn\neMHlcDiwYMECWCwW1NTUoKSkBPv372/XZ8OGDTh48CDq6uqwfPlyzJ8/X+kwiIiIiHyG4gVXRUUF\nwsLCEBoaioCAAKSnp6O0tLRdn/Xr1yMjIwMAMG7cOJw4cQJHjx5VOhSfZrPZtA6BvMTcyY35kxvz\nJy+9507x83A1NDQgJCTE2TabzSgvL/fY5/DhwwgODm7XrydfDZbBypUrtQ6BvMTcyY35kxvzJy89\n507xgqurRdLFX528+HE8JQQRERH5C8WnFE0mE+x2u7Ntt9thNps77XP48GGYTCalQyEiIiLyCYoX\nXAkJCairq4PNZkNTUxPWrFmDtLS0dn3S0tKwatUqAEBZWRmCgoI6TCcSERER+QvFpxSNRiPy8/OR\nkpICh8OB7OxsREVFoaCgAACQk5ODW2+9FRs2bEBYWBj69++PoqIipcMgIiIi8hmqnIdrypQpqK2t\nxcGDB/Hkk08COF9o5eTkOPvk5+fj4MGDqK6uxpgxY9QIQzM9OQ/ZnDlzEBwcjFGjRvVWuNQJT7n8\n6quvMH78eFx66aV46aWXNIiQXOnKfqT3cwH6Glc5O3bsGJKTkzFixAj85je/cXsOrq78ziVldTdf\nzz//PMLDwxEZGYlNmza5fM6u5ltWPNO8wnp6HrKsrCxYLJbeDptc6Eour7zySuTl5eHRRx/VKEpy\nxdN+xHMB+h5XOVu8eDGSk5Nx4MABTJ48GYsXL+7wuK7sp6S87uSrpqYGa9asQU1NDSwWC+6//360\ntrZ2eM6u5FtmLLgU5u15yI4cOQIAmDBhAgYNGtTrcVNHXcnl1VdfjYSEBAQEBGgUJbniaT/iuQB9\nj6ucXZinjIwM/Otf/+rwuK7sp6S87uSrtLQUs2bNQkBAAEJDQxEWFoaKiooOz9mVfMuMBZfCXJ1j\nrKGhodt9SHvMk/9ydy5A8i1Hjx51fqEqODjYZVHM/dR3uMvXt99+2+5sBe5y1JV8y4wFl8KUOg8Z\naY858W/cB+ViMBhc5oh5803u8nXh/T15vIxYcCmM5yHzH13JJcmJ+6AcgoODncstvvvuOwwZMqRD\nH+6nvsNdvrq6v3Ul3zJjwaUwnofMf3Qll214ZQS5cB+UQ1pamvNSMCtXrsQdd9zRoU939lNSl7t8\npaWlYfXq1WhqasKhQ4dQV1eHsWPHdvnxfkOQ4jZs2CBGjBghhg8fLp577jkhhBCvvfaaeO2115x9\nHnjgATF8+HARExMjdu7c6fx5enq6GDp0qOjbt68wm83ijTfe6PX46Weecvndd98Js9ksrrjiChEU\nFCRCQkLEqVOntAyZxM/7UUBAgDCbzeKf//xnl/dB0sbFOXvjjTfEDz/8ICZPnizCw8NFcnKyOH78\nuBBCiIaGBnHrrbc6H+tqPyV1dSdfQgjx7LPPiuHDh4uIiAhhsVicP587d67497//LYQQnT7eHxiE\n4EdzIiIiIjVxSpGIiIhIZSy4iIiIiFTGgouIiIhIZSy4iIiIiFTGgouINFNaWsrr3hGRLrDgIiLN\nvP/++6ipqXF5n8Ph6OVoiIjUw4KLiLxis9kQFRWFP/zhD4iOjkZKSgpqamoQHx/v7FNXV+dsP/HE\nE7j++usRGxuLxx57DDt27MAHH3yAxx57DGPGjMHXX3+NpKQkPPTQQ0hMTMQrr7yCLVu2YMyYMYiJ\niUF2djaampoAADt37kRSUhISEhKQmprqPDt1UlISHn74YSQmJiIqKgqVlZWYNm0aRowYgb/85S/d\nfo9//etfERkZiQkTJmD27Nl46aWXAACFhYUYO3Ys4uLiMGPGDJw9exYAkJmZifvvvx/jx4/H8OHD\nYbVakZGRgZEjRyIrK8v5vJdffjn+9Kc/ITo6GsnJySgrK8PEiRMxfPhwfPDBB85/35tuugnx8fGI\nj4/Hjh07vMgSEfkMrU8ERkRyOnTokDAajaK6uloIIcTMmTNFcXGxuPnmm0VVVZUQQognn3xS5Ofn\nix9++EFEREQ4H/vjjz8KIYTIzMwU69atc/48KSlJPPDAA0IIIc6ePStCQkJEXV2dEEKIe++9Vyxd\nulQ0NzeL8ePHi8bGRiGEEKtXrxZz5sxxPv6JJ54QQgjxyiuviKFDh4ojR46In376SZjNZnHs2LEu\nv7+KigoRFxcnfvrpJ3Hq1CkRHh4uXnrpJSHE+RM0tvl//+//iby8POf7mTVrlhBCiNLSUjFgwADx\n5ZdfitbWVhEfH+/8tzIYDM6TP06bNk0kJyeLlpYWUV1dLeLi4oQQQpw5c0acO3dOCCHEgQMHREJC\nQpdjJyLfo/gRrjlz5iA4OBijRo1y22fhwoUIDw9HbGwsdu/erXQIRNRLhg0bhpiYGABAfHw8bDYb\n5s6di6KiIrS2tuKdd97B7NmzccUVV+DSSy9FdnY23n//ffTr18/5HOKicy/ffffdAIDa2loMGzYM\nYWFhAICMjAx89tlnqK2txb59+3DLLbdg9OjRePbZZ9HQ0OB8fNtlXaKjoxEdHY3g4GD07dsX1113\nHb755psuv7dt27bhjjvuQN++fXH55Zfj9ttvd8a6d+9eTJgwATExMXjrrbfaTYvefvvtzte/5ppr\ncP3118NgMOD666+HzWYDAPTt2xcpKSkAgFGjRuHmm2/GJZdcgujoaGefpqYmzJ07FzExMZg5c6bb\nqVcikoPiBVdWVhYsFovb+zds2ICDBw+irq4Oy5cvx/z585UOgYh6SWBgoPP2JZdcAofDgenTp+Pj\njz/Ghx9+iISEBAwaNAhGoxEVFRWYMWMGPvzwQ6SmpjofZzAY2j1n//79Xb5WW7EjhMD111+P3bt3\nY/fu3dizZ0+73zltMfXp06ddfH369OnWujCDwdCuGBRCOGPNzMzEq6++ij179uCpp55yTikC54sp\nd6/f0tICAAgICGj38wsf09bn5ZdfxtChQ7Fnzx78+9//dk6nEpGcFC+4JkyYgEGDBrm9f/369cjI\nyAAAjBs3DidOnMDRo0eVDoOINCCEQGBgIFJSUjB//nznuqXTp0/jxIkTmDJlCv7+97+juroaADBg\nwACcPHmyw3MAQEREBGw2G+rr6wEAb775JpKSkhAREYHvv/8eZWVlAIDm5mZVjv7ceOON+OCDD/DT\nTz/hP//5Dz766CPnff/5z39wzTXXoLm5GcXFxR2KRiWcPHkS11xzDQBg1apV/BIBkezUmKc8dOiQ\niI6OdnnfbbfdJrZt2+ZsT5482XnhygsB4MaNGzdu3Lhxk2brjBEaEBet2XD36fDifv4kNzcXubm5\nWodBXmDu5Mb8+b6eHDH0578bMtBz7jy9914/LYTJZILdbne2Dx8+DJPJ1NthaK5tYSzJh7nzfQaD\nwe22aNGiTu8n7Qkh3G5Ahof7SUvMnXu9XnClpaVh1apVAICysjIEBQUhODi4t8MgIj/GX/q+b/Bg\nwGDo/gZ497jBg7V9v0SKTynOmjULn376KRobGxESEoJFixahubkZAJCTk4Nbb70VGzZsQFhYGPr3\n74+ioiKlQ5BCZmam1iGQl5g73zB4MHD8uDePzIQ3B7IGDQKOHfPm9ciV48cBb+pbqzUTSUndfxwP\nXiqH+553DMJHP9Jd/JVsIqILGQze/cGW5fX8HfMnL+bONU91Cy/toxGr1ap1COQl5k5uzJ/cmD95\n6T13mnxLUS/0/G0Nf1ZVBa+mNIiISL84pagRWQ6RUke5uec30hanNeTG/MmLuXONU4pECuNZIYiI\nqLs4pagZK4AkjWOgrrJaz28AsHKlFaGhSQDOTy1yelEuVqsVSUyatJg/7QkYAC9WzFjh3V89ccF/\nZcaCq4e8/3qsd19T9pevx8rmwsLqmWc4pUhE+mWA8G6Kz2r16hOqweAP5RbXcPUY57L14cIjXIsW\nAU89df42j3Bph/ue3Jg/eTF3rnmqW3iEi6gL1q4FPvzw5/aKFef/39jIgouIiDzjonmN6P18JLKZ\nMQPIzDy/AVbn7RkztIyKvMF9T27Mn7z0njse4SLqgqqqn6cUgZ9vBwXxCBcREXnGI1wa4bdsZJak\ndQDUA9z35Mb8yUvvueOi+R7i4kH9ufxy4D//0ToK4r4nN+ZPXsydazzxqY/S+1y2zAYOtGodAvUA\n9z25MX/y0nvuWHARddO0aVpHQEREsuGUYg/x0CqRNrjvyY35kxdz5xqnFImIiIg0pkrBZbFYEBkZ\nifDwcCxZsqTD/Y2NjUhNTUVcXByio6Oxou0skjqi97lsmTF3cmP+5Mb8yUvvuVO84HI4HFiwYAEs\nFgtqampQUlKC/fv3t+uTn5+P0aNHo6qqClarFY888ghaWlqUDoWIiIjIJyh+4tOKigqEhYUhNDQU\nAJCeno7S0lJERUU5+wwdOhR79uwBAJw8eRJXXnkljMaOoWRmZjqfJygoCHFxcc7zeLRVylq3287J\n1N3Ht/2st16PbeXaSUlJPhWPntve7A89yR/3P2XbzJ+cbcAKq9V/X6/r4+n8bZvNhq5QfNH82rVr\nsXHjRhQWFgIAiouLUV5ejry8PGef1tZWTJo0CQcOHMCpU6fwzjvvYMqUKe0D46J5n3g9Il/FfU9u\nzJ+8mDvXen3RvMFg8NjnueeeQ1xcHL799ltUVVXhgQcewKlTp5QOxaddWCGTXJg7uTF/cmP+5KX3\n3ClecJlMJtjtdmfbbrfDbDa367N9+3bcddddAIDhw4dj2LBhqK2tVToUIiIiIp+g+JRiS0sLIiIi\nsGXLFlx77bUYO3YsSkpK2q3hevjhhzFw4EA89dRTOHr0KOLj47Fnzx4MHjz458AkmVJEF47oKU6G\nfxcilXFaQ27Mn7yYO9c81S2KL5o3Go3Iz89HSkoKHA4HsrOzERUVhYKCAgBATk4O/vznPyMrKwux\nsTLP1WEAABVWSURBVLFobW3FCy+80K7YkokBovcHXu+9HBERESmAZ5rvIW8rb6vVesE3MNR/PVKO\nt7kjZXHfkxvzJy/mzjWeaZ6IiIhIYzzC1UOcyybSBvc9uTF/8mLuXOMRLiIiIiKNseDSiN7PRyIz\n5k5uzJ/cmD956T13LLiIiIiIVMY1XD3EuWwibXDfkxvzJy/mzjWu4SIiIiLSGAsujeh9LltmzJ3c\nmD+5MX/y0nvuPBZcp0+fxl//+lfMmzcPAFBXV4cPP/xQ9cCIiIiI/IXHNVwzZ85EfHw8Vq1ahX37\n9uH06dO44YYbUF1drW5gXMPlE69H5Ku478mN+ZMXc+daj9dw1dfX4/HHH0ffvn0BAP3791cuOiIi\nIiId8FhwBQYG4uzZs852fX09AgMDVQ1KD/Q+ly0z5k5uzJ/cmD956T13Rk8dcnNzkZqaisOHD2P2\n7NnYtm0bVqxY0QuhEREREfmHTtdwtba24t1338XkyZNRVlYGABg3bhyuvvpq9QPjGi6feD0iX8V9\nT27Mn7yYO9c81S0eF83Hx8dj586digfmCQsu33g9Il/FfU9uzJ+8mDvXerxoPjk5GS+++CLsdjuO\nHTvm3DpjsVgQGRmJ8PBwLFmyxGUfq9WK0aNHIzo6GklJSZ7C8Dt6n8uWGXMnN+ZPbsyfvPSeO49r\nuFavXg2DwYB//OMfzp8ZDAZ8/fXXLvs7HA4sWLAAmzdvhslkQmJiItLS0hAVFeXsc+LECTzwwAPY\nuHEjzGYzGhsbFXgrRERERL5J8Wsp7tixA4sWLYLFYgEALF68GADwxBNPOPu8+uqrOHLkCJ5++mn3\ngUk0pdibBg0CPBxgJNIFTmvIjfmTF3Pnmqe6xeMRrqamJixbtgyfffYZDAYDJk6ciPvuuw8BAQEu\n+zc0NCAkJMTZNpvNKC8vb9enrq4Ozc3NuPnmm3Hq1Cn88Y9/xD333NPhuTIzMxEaGgoACAoKQlxc\nnHP6se3QpNZtIbx7vMFgxdat2sfPNtsytwH/fj1/bzN/crYBK6xW/329ro+n87dtNhu6wuMRruzs\nbLS0tCAjIwNCCLz55pswGo14/fXXXfZft24dLBYLCgsLAQDFxcUoLy9HXl6es8+CBQuwa9cubNmy\nBWfOnMH48ePx0UcfITw8/OfAJDnC5S2Dweos1kguVqv1gl8EpBVvP/V6mz9ZPmXLgvmTF3PnWo+P\ncFVWVmLPnj3O9uTJkxETE+O2v8lkgt1ud7btdjvMZnO7PiEhIbjqqqvQr18/9OvXDzfddBOqq6vb\nFVxERERE/qKPpw5GoxEHDx50tuvr62E0uq/TEhISUFdXB5vNhqamJqxZswZpaWnt+kydOhVffPEF\nHA4Hzpw5g/LycowcObIHb0NGSVoHQF7i0S25MX9yY/7kpffceTzC9be//Q2TJk3CsGHDAAA2mw1F\nRUXun9BoRH5+PlJSUuBwOJCdnY2oqCgUFBQAAHJychAZGYnU1FTExMSgT58+mDdvng4LLiIiItKL\nLn1L8dy5c6itrYXBYMCIESNw6aWXqh+Yn6/hysy0YsWKJK3DIC9wDZdv4DoSuTF/8mLuXOvxiU/z\n8/Nx9uxZxMbGIiYmBmfPnsWrr76qaJB6lJmpdQRERETUWzwe4YqNjUV1dXW7n8XFxaGqqkrdwPz8\nCBcR9QzPBSQ35k9ezJ1rPT7C1draitbWVmfb4XCgublZmeiIiIiIdMBjwZWSkoL09HRs2bIFmzdv\nRnp6OlJTU3sjNr924YnTSC7MndyYP7kxf/LSe+48fktxyZIlWL58OZYtWwbg/MWs586dq3pgRERE\nRP6iy9dSbGpqwpdffgmz2YwhQ4aoHZffr+HKzT2/EZF3uI5EbsyfvJg717xew5WTk4Mvv/wSAPDj\njz8iNjYWGRkZiIuLw9tvv618pDqzaJHWERAREVFvcVtwff7554iOjgYAFBUVISIiAnv37sWuXbvw\nwgsv9FqA/suqdQDkJb2vQ5Ad8yc35k9ees+d24IrMDDQeXvTpk2YOnUqAOCaa65RPyoiIiIiP+J2\nDVdSUhIeeeQRmEwmTJo0Cfv378fQoUPR3NyMUaNG4auvvlI3MD9fwyXLnDSRr+I6Erkxf/Ji7lzz\nVLe4/ZZiQUEBFi5ciCNHjmDp0qUYOnQoAOCTTz7Bb3/7W+UjJSIiIvJTXf6WYm/z9yNcvJaivHgt\nRd/A67nJjfmTF3PnWo/PNE/q4LUUiYiI9INHuFRkMBi8fqzs751IbVxHIjfmT17MnWter+GinmPR\nRERERICXU4o7d+5UOg7d0fv5SGTG3MmN+ZMb8ycvvefOq4Lrtdde6/R+i8WCyMhIhIeHY8mSJW77\nVVZWwmg04r333vMmDCIiIiIpKL6Gy+FwICIiAps3b4bJZEJiYiJKSkoQFRXVoV9ycjIuu+wyZGVl\nYfr06e0D84M1XESkHq4jkRvzJy/mzjWv13Dt3Lmz00XfY8aMcfnziooKhIWFITQ0FACQnp6O0tLS\nDgVXXl4eZsyYgcrKys7iJyIiIpKe24LrkUce6bTg2rp1q8ufNzQ0ICQkxNk2m80oLy/v0Ke0tBSf\nfPIJKisr3b5OZmams3ALCgpCXFyc8xwebXPBsraXLl3qV+9HT+0L1yH4Qjx6bgPdf3xP8ufN67HN\n/PlbG7DC+v+1d/8xVdV/HMdfd0KrmQW0ZMR14biAUCkl6dxsOY0MTSo3C/0jFW2ktebKas0/0jYV\nm2wt2BJZ+tXRlGUl/oE3hwRbm8pkpOaPgAYLTd0SrP4p5u18/3DdvHKRy+Vc7v3c83xsFvfyOfe+\n8cXBN/fzuZ/THM7ff2CGkX6+yH//3vy4p6dHobB9SvGrr76S1+tVTU2NJKm2tlYnTpxQZWWlf8yS\nJUu0fv16zZw5UytWrNCiRYscN6XY3Nx8yzcTTEJ2sYHNF81GfuYiu+Bs2RbizJkzOn/+vP766y//\nfa+++mrQsenp6ert7fXf7u3tldvtDhjT1tamkpISSdJvv/2mw4cPKzExUcXFxaGUExf4B9tcZGc2\n8jMb+ZnL6dkN+wrXxo0b1dLSorNnz2rhwoU6fPiwZs+erQMHDgQdf+PGDeXk5Ojo0aN66KGHNGPG\njKCL5v+1cuVKLVq0SIsXLw4sLM5f4QIwOizcNRv5mYvsghv1pX0OHDigxsZGpaWlaffu3Tp16pSu\nX78+5PiEhARVVVVp/vz5ysvL0yuvvKLc3FxVV1eruro6vK8iDt06BwyzkJ3ZyM9s5Gcup2c37JTi\nPffco3HjxikhIUG///67Jk6cGDBlGExRUZGKiooC7isrKws6dvfu3SMoFwAAwDzDTimuWbNGW7Zs\nUV1dnSoqKjR+/Hg9/vjjEW+UmFIEcCdMa5iN/MxFdsEN17cM2XCtXbtWy5Yt0+zZs/33dXd3648/\n/tC0adPsr/T2wmi4ANwBP/TNRn7mIrvgwl7DlZ2drXfffVcPP/yw3nvvPbW3t2vy5Mlj0mw5gdPn\nsk1GdmYjP7ORn7mcnt2QDde6det07NgxtbS0KCUlRaWlpcrJydGmTZvU0dExljUCAAAYbUQbn7a3\nt2vlypU6c+aMfD5fJOtiShHAHTGtYTbyMxfZBTfqbSFu3LihQ4cOadmyZXruuec0ZcoUff3117YW\nCQAAEM+GbLiOHDmi0tJSpaenq6amRs8//7x+/vln7d+/Xy+88MJY1hiXnD6XbTKyMxv5mY38zOX0\n7Ibch6u8vFxLly7V9u3blZKSMpY1AWMiJUXq7x+750tOlvr6xu75AACxw/aLV9uFNVyItHDXBYz1\ncQiOdSRmIz9zkV1wo17DBQAAgNGh4YoSp89lm6052gVgFDj3zEZ+5nJ6djRcAAAAEcYaLjgWa7jM\nxjoSs5GfucguONZwATb78MNoVwAAMA0NV5Q4fS7bZHPmNEe7BIwC557ZyM9cTs+OhgsAACDCIrKG\ny+v1at26dfL5fFq9erXef//9gM9/8cUX+vjjj2VZliZMmKDPPvtMU6dODSyMNVyIMNYhmI38zEZ+\n5iK74IbrW2xvuHw+n3JyctTY2Kj09HQ9+eST2rdvn3Jzc/1jjh07pry8PN1///3yer3auHGjjh8/\nPqLCgdHih4bZyM9s5GcusgtuuL5lyEv7hKu1tVUej0cZGRmSpJKSEtXX1wc0XLNmzfJ/PHPmTF28\neDHoY61YscL/OElJScrPz9ecOXMk/TcXbOrtTz75JK6+HlNvSyM//tZ1CGPxfNwmv3i9TX5m3paa\n1dwczt9/YIaRfr7If//e/Linp0ehsP0VrgMHDujbb79VTU2NJKm2tlYnTpxQZWVl0PHbt29XR0eH\ndu7cGVhYnL/C1dzcfMs3E6Ih3N+aVqxo1v/+N2fMng/Bhfv3Ge65R372Ij9zkV1wY74thMvlCnns\nd999p127dmnbtm12lxHzaLbMtWfPnGiXgFHg3DMb+ZnL6dnZPqWYnp6u3t5e/+3e3l653e5B406f\nPq3XXntNXq9XycnJdpcBAAAQM2x/haugoECdnZ3q6enRwMCA6urqVFxcHDDml19+0eLFi1VbWyuP\nx2N3CUa4dQ4YpmmOdgEYBc49s5GfuZyene2vcCUkJKiqqkrz58+Xz+fTqlWrlJubq+rqaklSWVmZ\nPvroI/X392vNmjWSpMTERLW2ttpdCgAAQEzgWopwLK6laDbemm428jMX2QXHtRQBm3EtRQDASNFw\nRYnT57JNxrUUzca5ZzbyM5fTs6PhAgAAiDDWcMGxWIdgNvIzG/mZi+yCYw0XAABAlNFwRYnT57JN\nRnZmI7/YYMl186WLEf5pDuMYuVw3nw9R5fRzz/Z9uIB4MJJLVN2OqfCxcfMf7LF8vv/+i9FzyQpv\nmujmVYxH/nwu0rPTKH5Ejli8XIyGNVxwLNYhmI38zEZ+zhPvGQzXt/AKFxyLV0jMx2/ZZiM/OAlr\nuKLE6XPZMcGywvrj0ndhHwv7hB9Bc1jH9fVF+yuOL+TnRM3RLiCqeIULAADYYrj1r3f6dLwvI2IN\nFxAEi+bNRn5mIz+YiDVcQBj4oW028jMb+SEesYYrSljDZS6yMxv5mY38zOX07Gi4ouSHH36IdgkI\nE9mZjfzMRn7mcnp2EWm4vF6vpkyZoqysLG3bti3omLfeektZWVmaNm2a2tvbI1FGTLt+/Xq0S0CY\nyM5s5Gc28jOX07OzveHy+Xx688035fV6de7cOe3bt0/nz58PGNPQ0KCuri51dnZq586dWrNmjd1l\nAAAAxAzbG67W1lZ5PB5lZGQoMTFRJSUlqq+vDxhz6NAhLV++XJI0c+ZMXb9+XVevXrW7lJjW09MT\n7RIQJrIzG/mZjfzM5fTsbH+X4qVLlzRp0iT/bbfbrRMnTgw75uLFi0pNTQ0YN5q3Bptgz5490S4B\nYSI7s5Gf2cjPXE7OzvaGK9Qm6fa3/d5+HG8LBgAA8cL2KcX09HT19vb6b/f29srtdt9xzMWLF5We\nnm53KQAAADHB9oaroKBAnZ2d6unp0cDAgOrq6lRcXBwwpri4WHv37pUkHT9+XElJSYOmEwEAAOKF\n7VOKCQkJqqqq0vz58+Xz+bRq1Srl5uaqurpaklRWVqYFCxaooaFBHo9H48eP1+7du+0uAwAAIGZE\nZB+uoqIi/fTTT+rq6tIHH3wg6WajVVZW5h9TVVWlrq4unTp1Sk888UQkyoia0exDVlpaqtTUVD32\n2GNjVS7uYLgsL1y4oFmzZunuu+9WRUVFFCpEMKGcR07fCzDWBMusr69PhYWFys7O1rPPPjvkPk6h\n/MyFvUaa19atW5WVlaUpU6boyJEjQR8z1LxNxU7zNhvtPmQrV66U1+sd67IRRChZPvDAA6qsrNT6\n9eujVCWCGe48Yi/A2BMss/LychUWFqqjo0Pz5s1TeXn5oONCOU9hv5Hkde7cOdXV1encuXPyer1a\nu3at/vnnn0GPGUreJqPhslm4+5BduXJFkvTUU08pOTl5zOvGYKFk+eCDD6qgoECJiYlRqhLBDHce\nsRdg7AmW2a05LV++XAcPHhx0XCjnKew3krzq6+u1dOlSJSYmKiMjQx6PR62trYMeM5S8TUbDZbNg\ne4xdunRpxGMQfeQUv4baCxCx5erVq/43VKWmpgZtijlPY8dQef36668BuxUMlVEoeZuMhstmdu1D\nhugjk/jGOWgWl8sVNCNyi01D5XXr50dzvIlouGzGPmTxI5QsYSbOQTOkpqb6l1tcvnxZEydOHDSG\n8zR2DJVXqOdbKHmbjIbLZuxDFj9CyfJfXBnBLJyDZiguLvZfCmbPnj168cUXB40ZyXmKyBoqr+Li\nYu3fv18DAwPq7u5WZ2enZsyYEfLxccOC7RoaGqzs7GwrMzPT2rJli2VZlrVjxw5rx44d/jFvvPGG\nlZmZaU2dOtVqa2vz319SUmKlpaVZd911l+V2u61du3aNef34z3BZXr582XK73dZ9991nJSUlWZMm\nTbL+/PPPaJYM67/zKDEx0XK73dbnn38e8jmI6Lg9s127dlnXrl2z5s2bZ2VlZVmFhYVWf3+/ZVmW\ndenSJWvBggX+Y4Odp4iskeRlWZa1efNmKzMz08rJybG8Xq///tWrV1snT560LMu64/HxwGVZ/GoO\nAAAQSUwpAgAARBgNFwAAQITRcAEAAEQYDRcAAECE0XABAABEGA0XgLiyceNGVVRUSJIuXLig/Px8\nTZ8+Xd3d3SE/xpUrV1RSUiKPx6OCggItXLhQnZ2dkSoZgAPQcAGIK7deEuTgwYNasmSJ2traNHny\n5JCOtyxLL730kubOnauuri6dPHlSW7dujbvrugEYW+zDBcBoe/fuVUVFhVwul6ZOnarMzEzde++9\nysvLU2lpqcaNG6fs7Gw1NTWF9HhNTU3atGmTWlpaIlw5ACdJiHYBABCus2fPavPmzTp27JhSUlLU\n39+vTz/9VJJUVFSk119/XRMmTNDbb78d8mP++OOPmj59eqRKBuBQTCkCMFZTU5NefvllpaSkSJKS\nk5MHjRnpi/j/TkcCgJ1ouAAYy+Vy2X7h8EceeURtbW22PiYA0HABMNbcuXP15Zdfqq+vT5L8/x/t\nY/7999+qqanx33f69Gl9//33o35sAM5FwwXAWHl5edqwYYOefvpp5efn65133pEUOC0YzhThN998\no8bGRnk8Hj366KPasGGD0tLSbKsbgPPwLkUAAIAI4xUuAACACGNbCABx79q1a3rmmWcC7vP5fJKk\ncePGBdx/9OhR/7seAcAuTCkCAABEGFOKAAAAEUbDBQAAEGE0XAAAABFGwwUAABBhNFwAAAAR9n9U\nfWddTRaQFwAAAABJRU5ErkJggg==\n",
"text": [
"<matplotlib.figure.Figure at 0x1108ef710>"
]
}
],
"prompt_number": 42
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"client.abort()"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"A Word of Caution on the Scalability of this Implementation Nystroem method"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this example we used LinearSVC that does not provide a `partial_fit` method hence require to put the Nystroem expansion of complet dataset in memory. Furthermore the `Pipeline` object does not optimize the memory usage.\n",
"\n",
"To make this example really scalable we would need to:\n",
" \n",
"- Replace LinearSVC with an incremental linear model: Perceptron, PassiveAggressiveClassifier, SGDClassifier\n",
"- Add support for memory efficient `partial_fit` to `sklearn.pipeline.Pipeline`\n",
"- Change our IPython.parallel based model evaluator to use the `partial_fit` method with small minibatches in the inner model evaluation function."
]
}
],
"metadata": {}
}
]
}
from collections import namedtuple
from collections import defaultdict
from IPython.parallel import interactive
from IPython.parallel import TaskAborted
from scipy.stats import sem
import numpy as np
from sklearn.utils import check_random_state
try:
# sklearn 0.14+
from sklearn.grid_search import ParameterGrid
except ImportError:
# sklearn 0.13
from sklearn.grid_search import IterGrid as ParameterGrid
from mmap_utils import warm_mmap_on_cv_splits
def is_aborted(task):
return isinstance(getattr(task, '_exception', None), TaskAborted)
@interactive
def compute_evaluation(model, cv_split_filename, params=None,
train_fraction=1.0, mmap_mode='r'):
"""Function executed on a worker to evaluate a model on a given CV split"""
# All module imports should be executed in the worker namespace
from time import time
from sklearn.externals import joblib
X_train, y_train, X_test, y_test = joblib.load(
cv_split_filename, mmap_mode=mmap_mode)
# Slice a subset of the training set for plotting learning curves
n_samples_train = int(train_fraction * X_train.shape[0])
X_train = X_train[:n_samples_train]
y_train = y_train[:n_samples_train]
# Configure the model
if model is not None:
model.set_params(**params)
# Fit model and measure training time
t0 = time()
model.fit(X_train, y_train)
train_time = time() - t0
# Compute score on training set
train_score = model.score(X_train, y_train)
# Compute score on test set
test_score = model.score(X_test, y_test)
# Wrap evaluation results in a simple tuple datastructure
return (test_score, train_score, train_time,
train_fraction, params)
# Named tuple to collect evaluation results
Evaluation = namedtuple('Evaluation', (
'validation_score',
'train_score',
'train_time',
'train_fraction',
'parameters'))
class RandomizedGridSeach(object):
""""Async Randomized Parameter search."""
def __init__(self, load_balanced_view, random_state=0):
self.task_groups = []
self.lb_view = load_balanced_view
self.random_state = random_state
def map_tasks(self, f):
return [f(task) for task_group in self.task_groups
for task in task_group]
def abort(self):
for task_group in self.task_groups:
for task in task_group:
if not task.ready():
try:
task.abort()
except AssertionError:
pass
return self
def wait(self):
self.map_tasks(lambda t: t.wait())
return self
def completed(self):
return sum(self.map_tasks(lambda t: t.ready() and not is_aborted(t)))
def total(self):
return sum(self.map_tasks(lambda t: 1))
def progress(self):
c = self.completed()
if c == 0:
return 0.0
else:
return float(c) / self.total()
def reset(self):
# Abort any other previously scheduled tasks
self.map_tasks(lambda t: t.abort())
# Schedule a new batch of evalutation tasks
self.task_groups, self.all_parameters = [], []
def launch_for_splits(self, model, parameter_grid, cv_split_filenames,
pre_warm=True):
"""Launch a Grid Search on precomputed CV splits."""
# Abort any existing processing and erase previous state
self.reset()
self.parameter_grid = parameter_grid
# Warm the OS disk cache on each host with sequential reads
# XXX: fix me: interactive namespace issues to resolve
# if pre_warm:
# warm_mmap_on_cv_splits(self.lb_view.client, cv_split_filenames)
# Randomize the grid order
random_state = check_random_state(self.random_state)
self.all_parameters = list(ParameterGrid(parameter_grid))
random_state.shuffle(self.all_parameters)
for params in self.all_parameters:
task_group = []
for cv_split_filename in cv_split_filenames:
task = self.lb_view.apply(compute_evaluation,
model, cv_split_filename, params=params)
task_group.append(task)
self.task_groups.append(task_group)
# Make it possible to chain method calls
return self
def find_bests(self, n_top=5):
"""Compute the mean score of the completed tasks"""
mean_scores = []
for params, task_group in zip(self.all_parameters, self.task_groups):
evaluations = [Evaluation(*t.get())
for t in task_group
if t.ready() and not is_aborted(t)]
if len(evaluations) == 0:
continue
val_scores = [e.validation_score for e in evaluations]
train_scores = [e.train_score for e in evaluations]
mean_scores.append((np.mean(val_scores), sem(val_scores),
np.mean(train_scores), sem(train_scores),
params))
return sorted(mean_scores, reverse=True)[:n_top]
def report(self, n_top=5):
bests = self.find_bests(n_top=n_top)
output = "Progress: {0:02d}% ({1:03d}/{2:03d})\n".format(
int(100 * self.progress()), self.completed(), self.total())
for i, best in enumerate(bests):
output += ("\nRank {0}: validation: {1:.5f} (+/-{2:.5f})"
" train: {3:.5f} (+/-{4:.5f}):\n {5}".format(
i + 1, *best))
return output
def __repr__(self):
return self.report()
def boxplot_parameters(self, display_train=False):
"""Plot boxplot for each parameters independently"""
import pylab as pl
results = [Evaluation(*task.get())
for task_group in self.task_groups
for task in task_group
if task.ready() and not is_aborted(task)]
n_rows = len(self.parameter_grid)
pl.figure()
for i, (param_name, param_values) in enumerate(self.parameter_grid.items()):
pl.subplot(n_rows, 1, i + 1)
val_scores_per_value = []
train_scores_per_value = []
for param_value in param_values:
train_scores = [r.train_score for r in results
if r.parameters[param_name] == param_value]
train_scores_per_value.append(train_scores)
val_scores = [r.validation_score for r in results
if r.parameters[param_name] == param_value]
val_scores_per_value.append(val_scores)
widths = 0.25
positions = np.arange(len(param_values)) + 1
offset = 0
if display_train:
offset = 0.175
pl.boxplot(train_scores_per_value, widths=widths,
positions=positions - offset)
pl.boxplot(val_scores_per_value, widths=widths,
positions=positions + offset)
pl.xticks(np.arange(len(param_values)) + 1, param_values)
pl.xlabel(param_name)
pl.ylabel("Val. Score")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment