├── .gitignore ├── .ipynb_checkpoints └── demo-checkpoint.ipynb ├── .python-version ├── README.md ├── __main__.py ├── demo.ipynb └── mgeval ├── __init__.py ├── core.py ├── documentation.md └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | data/ 2 | start.sh 3 | *.pyc 4 | -------------------------------------------------------------------------------- /.ipynb_checkpoints/demo-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "deletable": true, 7 | "editable": true 8 | }, 9 | "source": [ 10 | "# Usage Demo : \n" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": { 17 | "collapsed": false, 18 | "deletable": true, 19 | "editable": true 20 | }, 21 | "outputs": [], 22 | "source": [ 23 | "import midi\n", 24 | "import glob\n", 25 | "import numpy as np\n", 26 | "import pretty_midi\n", 27 | "import seaborn as sns\n", 28 | "import matplotlib.pyplot as plt\n", 29 | "from mgeval import core, utils\n", 30 | "from sklearn.model_selection import LeaveOneOut" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": { 36 | "deletable": true, 37 | "editable": true 38 | }, 39 | "source": [ 40 | "## Absolute measurement: statistic analysis\n" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "deletable": true, 47 | "editable": true 48 | }, 49 | "source": [ 50 | "Assign dataset path" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 2, 56 | "metadata": { 57 | "collapsed": false, 58 | "deletable": true, 59 | "editable": true 60 | }, 61 | "outputs": [], 62 | "source": [ 63 | "set1 = glob.glob('../data/set1/*.mid')" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": { 69 | "deletable": true, 70 | "editable": true 71 | }, 72 | "source": [ 73 | "construct empty dictionary to fill in measurement across samples" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 3, 79 | "metadata": { 80 | "collapsed": true, 81 | "deletable": true, 82 | "editable": true 83 | }, 84 | "outputs": [], 85 | "source": [ 86 | "num_samples = 100" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 4, 92 | "metadata": { 93 | "collapsed": false, 94 | "deletable": true, 95 | "editable": true 96 | }, 97 | "outputs": [], 98 | "source": [ 99 | "set1_eval = {'total_used_pitch':np.zeros((num_samples,1))}\n", 100 | "metrics_list = set1_eval.keys()\n", 101 | "for i in range(0, num_samples):\n", 102 | " pm_midi = pretty_midi.PrettyMIDI(set1[i])\n", 103 | " piano_roll = pm_midi.instruments[0].get_piano_roll(fs=100)\n", 104 | " set1_eval[metrics_list[0]][i] = getattr(core.metrics(), metrics_list[0])(piano_roll)" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": { 110 | "deletable": true, 111 | "editable": true 112 | }, 113 | "source": [ 114 | "repeat for second dataset" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": 5, 120 | "metadata": { 121 | "collapsed": false, 122 | "deletable": true, 123 | "editable": true 124 | }, 125 | "outputs": [], 126 | "source": [ 127 | "set2 = glob.glob('../data/set2/*.mid')\n", 128 | "set2_eval = {'total_used_pitch':np.zeros((num_samples,1))}\n", 129 | "for i in range(0, num_samples):\n", 130 | " pm_midi = pretty_midi.PrettyMIDI(set2[i])\n", 131 | " piano_roll = pm_midi.instruments[0].get_piano_roll(fs=100)\n", 132 | " set2_eval[metrics_list[0]][i] = getattr(core.metrics(), metrics_list[0])(piano_roll)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": { 138 | "deletable": true, 139 | "editable": true 140 | }, 141 | "source": [ 142 | "statistic analysis: absolute measurement" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 6, 148 | "metadata": { 149 | "collapsed": false, 150 | "deletable": true, 151 | "editable": true 152 | }, 153 | "outputs": [ 154 | { 155 | "name": "stdout", 156 | "output_type": "stream", 157 | "text": [ 158 | "total_used_pitch:\n", 159 | "------------------------\n", 160 | " demo_set\n", 161 | " mean: [6.87]\n", 162 | " std: [2.10549282]\n", 163 | "------------------------\n", 164 | " demo_set\n", 165 | " mean: [11.3]\n", 166 | " std: [1.96723156]\n" 167 | ] 168 | } 169 | ], 170 | "source": [ 171 | "for i in range(0, len(metrics_list)):\n", 172 | " print metrics_list[i] + ':'\n", 173 | " print '------------------------'\n", 174 | " print ' demo_set'\n", 175 | " print ' mean: ', np.mean(set1_eval[metrics_list[i]], axis=0)\n", 176 | " print ' std: ', np.std(set1_eval[metrics_list[i]], axis=0)\n", 177 | "\n", 178 | " print '------------------------'\n", 179 | " print ' demo_set'\n", 180 | " print ' mean: ', np.mean(set2_eval[metrics_list[i]], axis=0)\n", 181 | " print ' std: ', np.std(set2_eval[metrics_list[i]], axis=0)\n" 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "metadata": { 187 | "deletable": true, 188 | "editable": true 189 | }, 190 | "source": [ 191 | "## Relative measurement: generalizes the result among features with various dimensions\n" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": {}, 197 | "source": [ 198 | "the features are sum- marized to \n", 199 | "- the intra-set distances\n", 200 | "- the difference of intra-set and inter-set distances." 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "metadata": { 206 | "deletable": true, 207 | "editable": true 208 | }, 209 | "source": [ 210 | "exhaustive cross-validation for intra-set distances measurement" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 7, 216 | "metadata": { 217 | "collapsed": false, 218 | "deletable": true, 219 | "editable": true 220 | }, 221 | "outputs": [], 222 | "source": [ 223 | "loo = LeaveOneOut()\n", 224 | "loo.get_n_splits(np.arange(num_samples))\n", 225 | "set1_intra = np.zeros((num_samples, len(metrics_list), num_samples-1))\n", 226 | "set2_intra = np.zeros((num_samples, len(metrics_list), num_samples-1))\n", 227 | "for metric in metrics_list:\n", 228 | " for train_index, test_index in loo.split(np.arange(num_samples)):\n", 229 | " set1_intra[test_index[0]][0] = utils.c_dist(set1_eval[metric][test_index], set1_eval[metric][train_index])\n", 230 | " set2_intra[test_index[0]][0] = utils.c_dist(set2_eval[metric][test_index], set2_eval[metric][train_index])\n" 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": { 236 | "deletable": true, 237 | "editable": true 238 | }, 239 | "source": [ 240 | "exhaustive cross-validation for inter-set distances measurement" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": 8, 246 | "metadata": { 247 | "collapsed": false, 248 | "deletable": true, 249 | "editable": true 250 | }, 251 | "outputs": [], 252 | "source": [ 253 | "loo = LeaveOneOut()\n", 254 | "loo.get_n_splits(np.arange(num_samples))\n", 255 | "sets_inter = np.zeros((num_samples, len(metrics_list), num_samples))\n", 256 | "\n", 257 | "for metric in metrics_list:\n", 258 | " for train_index, test_index in loo.split(np.arange(num_samples)):\n", 259 | " sets_inter[test_index[0]][0] = utils.c_dist(set1_eval[metric][test_index], set2_eval[metric])" 260 | ] 261 | }, 262 | { 263 | "cell_type": "markdown", 264 | "metadata": { 265 | "deletable": true, 266 | "editable": true 267 | }, 268 | "source": [ 269 | "visualization of intra-set and inter-set distances" 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": null, 275 | "metadata": { 276 | "collapsed": false, 277 | "deletable": true, 278 | "editable": true 279 | }, 280 | "outputs": [ 281 | { 282 | "data": { 283 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAecAAAFlCAYAAADRdSCHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzs3XmcVNWZ8PHfXWqv6r1BQEFFcVcE\nTNxAM4ozkozRxCgYSSbO4DsfgzGJwSUuMcQo+hkTI0aMMdEkbsQkakw0C2pEUVZFBQUFZIfet1pv\nVd37/nHrVnfTS1V1N03R/Xz/ka67HkCeOuc85zmKZVkWQgghhCga6oF+ASGEEEJ0JsFZCCGEKDIS\nnIUQQogiI8FZCCGEKDISnIUQQogiI8FZCCGEKDISnIXYD6666ioaGxv7fc6KFSv4whe+MJCvVrD5\n8+ezcOHCPl//s5/9jOeffx6ABx98kCVLlvR6/k033cSvfvWrPj9PiKFAP9AvIMRQtGzZsgE5Zyi4\n7rrrsr9esWIFRx111AF8GyEODhKchRhgN998MwBf//rXue2221i4cCHNzc0oisJVV13FxRdf3Omc\nRx55hA0bNvCLX/wCwzBobGzk4osv5tvf/nbezzzmmGN4++23qaio6PSzx+Ph5ptvZtu2baiqygkn\nnMD8+fNRVZVXX32VRYsWkUwm8Xq93HjjjZx66qmEw2FuueUWNmzYwIgRI9A0jcmTJ/f6/BUrVnDv\nvfcycuRIduzYgdfrZcGCBYwfP56bbrqJo48+Gq/Xy7p167j33nvRNI0zzzyTO++8k3feeQdN0zj/\n/PP5zne+A8C7777LzJkzqa+v5+ijj+a+++7D7/f35Y9DiIOTJYQYcBMmTLAaGhqs8847z/r73/9u\nWZZl7d2715o6dar1zjvvdDrHNE3ryiuvtD799NPseccdd5zV0NBgLV++3Pr85z+f9/P2/fm5556z\nrrrqKsuyLCuVSlm33HKLtXXrVuvTTz+1vvCFL1iNjY2WZVnWxx9/bJ111llWJBKxfvzjH1s33HCD\nZZqm1dDQYE2bNs164IEHen3+8uXLrWOPPdZatWqVZVmW9dRTT1mXXHKJZVmWdeONN1qPPvqoZVmW\ndeWVV1ovv/yyZVmWddddd1nf+c53rFQqZSUSCeurX/2qtXz5cuvGG2+0Lr30UisajVqpVMq65JJL\nrOeeey6v33chhgqZcxZiP9m8eTOJRIILLrgAgJEjR3LBBRfwxhtvdDpPURQefvhh1q9fz4MPPsiC\nBQuwLItYLNbvd5g8eTKbNm1i9uzZPPLII3z9619n3LhxLFu2jNraWv7rv/6LL37xi3zve99DURS2\nb9/O22+/zcUXX4yiKFRUVDB9+vS8nnXssccyZcoUAL785S/z0Ucf0dTU1OP5b731FpdeeimapuF2\nu3niiSf47Gc/C8D555+Pz+dD0zSOPvronHPzQgw1MqwtxH6iKEqXzyzLIpVKdfosGo1yySWXcP75\n5zNlyhS+/OUvs2TJEqw+lr03DCP768MOO4x//vOfrFixguXLl/ONb3yDW2+9FdM0OeOMM7j//vuz\n5+7Zs4cRI0Zk39OhaVpez933PMuyer1W1/VOv0d79uzB6/VmjzkURenz74UQByvpOQuxH2iaxpgx\nY3C5XPzjH/8AoKamhr///e+ceeaZ2XNSqRTbtm0jHA7z7W9/m3/7t39j5cqVGIaBaZp5P6+iooIP\nPvgAgH/+85/Zz5966iluvvlmzj77bObNm8fZZ5/NJ598wumnn86yZcvYvHkzAK+//joXXXQRiUSC\nqVOn8oc//AHTNGlpaeGVV17J6x02bNjAhg0bAFi8eDGTJk2ipKSky++L8+XkjDPO4LnnnsM0TQzD\n4Fvf+harVq3Ku81CDGXScxZiP5g+fTqzZ8/moYce4s4772ThwoWk02m++c1vcvrpp2fPueKKK3jw\nwQc599xzufDCCykpKWHs2LEcddRRbNu2Dbfbndfzbr31VubPn09JSQlnnnkm1dXVAFx88cWsXLmS\nGTNm4PP5GD16NF/72tcoLS1l/vz5fPe738WyLHRdZ9GiRfj9fq699lp+8IMfcOGFF1JRUcGECRPy\neoeqqiruv/9+du3aRUVFBffee2+Xcz73uc9xzz33kEwmmTt3Lj/+8Y/54he/SDqdZsaMGVxwwQW8\n+uqref4uCzF0KZaMFwkh+mnFihX86Ec/4i9/+cuBfhUhhgTpOQtxEHj00Ud58cUXuz323//931x0\n0UX7/R2+/e1v8+mnn3Z7bNasWfv9+UIMJ9JzFkIIIYqMJIQJIYQQRUaCsxBCCFFkJDgLIYQQRaZo\nEsLq6toO9CsMiPJyP01N0QP9GoNuOLZ7OLYZpN3DzXBs92C1ubo61OMx6TkPMF3Pr5rSUDMc2z0c\n2wzS7uFmOLa7GNoswVkIIYQoMhKchRBCiCKTMzibpsntt9/O5ZdfzuzZs9m2bVu35/zP//wPTz/9\nNADxeJxrr72WK664gjlz5siOMkIIIUQBcgbnJUuWYBgGixcv5vrrr2fBggVdzrn//vtpbW3N/vz0\n008zYcIEnnrqKS6++GIeeuihgX1rIYQQYgjLGZzXrFnD1KlTAZg4cSLr1q3rdPxvf/sbiqJkz9n3\nmmnTpvH2228P5DsLIYQQQ1rOpVThcJhgMJj92dnyTdd1Pv74Y/7yl7/wwAMP8POf/7zTNaGQnSIe\nCARoa8u9TKq83F8UGXIDobf0+KFsOLZ7OLYZpN3DzXBs94Fuc87gHAwGiUQi2Z9N08xuhP78889T\nU1PD17/+dXbt2oXL5WLMmDGdrolEIl32dO3OUFlHV10dGjJrtgsxHNs9HNsM0u7hZji2e7Da3NsX\ngJzBedKkSbz22mvMmDGDtWvXdtrb9YYbbsj+euHChVRVVTFt2jQ2bdrE66+/zsknn8zSpUuZPHly\nP5sghBBCDB8555ynT5+O2+1m5syZ3H333dx888089thjvPLKKz1eM2vWLD755BNmzZrF4sWLmTt3\n7oC+tBBCiOFl+fK3eOGFP3V7rLW1hX/842+D9i6JRIIXX3y+02evv/4ad9xxy4A9I2fPWVVV5s+f\n3+mz8ePHdznv2muvzf7a5/PxwAMPDMDrCSGEKCa/f3UTqzbUDug9Tzt2BJf921G9nnP66Wf2eGzT\npk9Ytux1LrjgPwb0vXrS2NjAiy8+z3/+58UA3H///7Fy5dscffSEHFfmr2hqa4vepdvaiKz7gNBp\nn0HR5Y9NCDG8vPTSi6xY8RZ79+5lxIiR7Nq1k+OPP4Hvfe9mfvvbX7Np0ye88MKfWLfufVpaWmht\nbeGee37CokULqa2toaGhnrPOmsbVV1/T4zPuuuuH7Ny5g3Q6ySWXXMZ//MfneffdNTzyyENomsbo\n0WO44YZb+O1vf83WrZ/y2GO/5BvfmMNJJ53MtGnn8sILfxyw9sq/8geJpleX0PjiC7StWsGo//0m\nqtt9oF9JCDEMXfZvR+Xs5e5PO3Zs56c/fRCPx8tll32RhoZ6vva1q3jhhT/yxS9+iXXr3mfy5Clc\nfvlX2bNnNyeccBI33XQbiUSCL31pRo/BORqNsHbtO/ziF49TVRXk5ZdfwbIs7rnnxyxa9Cjl5RX8\n8peLeOmlF/na165i8+ZNfOMbcwA477wLeOed1QPaTgnOB4l0awsAkfffY9cDP2XM3G+hen0H+K2E\nEGJwjRlzKH5/AIDKyioMw+hyztix4wAoKSnho4/W8847qwkEAhhGssf7+v0BvvWt67n33h+TTMb5\n3OcuoLm5iYaGem677SbAnms+7bTP7odWdSXB+SCRjthLzXzHHkdsw0fs/Ol9HHbj91FUKY8uhBg+\nFEXp8pmqqpim1eEc+9/Fl176C8FgiBtuuIWdO3fw5z8/h2VZ3d6jvr6ejRs/4u67/4+SEjfTpk3j\nggsuZMSIESxY8BOCwSBvvvk6Pp8fRVGxLHP/NRIJzgcNM2qvGx8z9zp2/3wh0Y/Wk6zZi3vU6AP8\nZkIIcWCNGXMoW7Zs4ve/f6rT55Mnn8YPf3gr69d/gMvl4tBDD6O+vo7q6hFd7lFZWUljYwP/+79X\n4fG4mDnzSlwuF9dd9z3mzbsOy7Lw+wPcdtsP8fsDJJMpHnroAa655lv7pU2KZVlW7tP2v6GyyH1/\nLV7fducPMXbv4uiHHqHuD7+n6W8vcdjNt+Ibf+DmfjqSQgXDh7R7eBmO7T4oipCI4mBGwqh+PwBa\n5r9mbGhUVRNCiMHy5puv88wzT3b5/CtfmcU553zuALxR9yQ4HyTSkSh6WRlANkinoxKchRCiEGef\nfQ5nn33OgX6NnCSb6CBgmSZmLIoWsDMUVV+m5yzBWQghhiQJzgcBMxYDy0LNBOfssLYEZyGEGJIk\nOB8E0plMbScoy7C2EEIMbRKcDwJmZo2z6t9nWFsSwoQQw0QxbXwxGCQh7CCQ7TnLsLYQYpgqpo0v\nBoME54OAGbGDszPnLMPaQogD5U+b/sK7tR8M6D1PHXESXzrqC72ek+/GF6effib33nsXiUQcj8fL\nDTd8H9M0ufHG71BSUsoZZ5zFV7/69QF9//1BgvNBYN85Z8XlQtF1GdYWQgw7uTa+uP32m7n00ss5\n44yzWL16JQ8//CBXX30NjY0N/OpXT+ByuQ50E/IiwfkgkO05Z+acFUVB9fml5yyEGHRfOuoLOXu5\n+1OujS+2bNnE7373GE8++RsANM0Oc6NGjT5oAjNIcD4oOEHYmXMGe2jbjMUO1CsJIcQBkWvji7Fj\nD2fWrCs56aRT2LZtK+++uyZz3cGV/yzB+SCQjoSBzsFZ8/tJNTYcqFcSQoii0XHji29+8zruu28B\nhmGQSMS57rrvHejX6xMJzgcBJyvbGda2f+3HSiYxkwaqy32gXk0IIQbFjBn/yYwZ/9nps0ceeTz7\n6yef/EP21z/5yYNdru947sHg4OrnD1PpSOeEMOhYwlOGtoUQYqiR4HwQMKNRFI8HRW8f6JCdqYQQ\nYuiS4HwQSEfCneabAVSfzz4mGdtCCDHkSHA+CJjRaKf5ZmgvRCJVwoQQYuiR4Fzk7O0iY53mm0FK\neAohxFAmwbnIZTO19x3Wdkp4ypyzEEIMORKci1x3a5yhY7a2BGchhBhqJDgXuXRmu0htnzlnTTa/\nEEIMI8W0ZWQikeDFF58HIBwOc8MN32Hu3Kv5f//vG6xb9/6APCNnERLTNLnjjjvYuHEjbrebO++8\nk3HjxmWPP/nkk/zpT39CURSuuuoqZsyYgWVZTJs2jcMPPxyAiRMncv311w/ICw83ZtSpq915zlkS\nwoQQB0Lds8/QtnrVgN4zNOU0qr8ys9dzimnLyMbGBl588Xn+8z8vZvHiJ5ky5TQuu+wKtm/fyh13\n3MKvf/1kv5+RMzgvWbIEwzBYvHgxa9euZcGCBSxatCjzgo08/fTTPPfccyQSCT7/+c9z4YUXsn37\ndk444QQefvjhfr/gcLfvXs4OWecshBhO8t0yct2692lpaaG1tYV77vkJixYtpLa2hoaGes46axpX\nX31Nj8+4664fsnPnDtLpJJdcchn/8R+f59131/DIIw+haRqjR4/hhhtu4be//TVbt37KY4/9kssu\nuwK3295QI5VK43Z7BqS9OYPzmjVrmDp1KmD3gNetW5c9VlFRwfPPP4+u6+zatQuPx4OiKKxfv56a\nmhpmz56N1+vl5ptv5sgjjxyQFx5u9t2RyuHMOcuwthBiMFV/ZWbOXu7+lGvLyHXr3mfy5ClcfvlX\n2bNnNyeccBI33XQbiUSCL31pRo/BORqNsHbtO/ziF49TVRXk5ZdfwbIs7rnnxyxa9Cjl5RX88peL\neOmlF/na165i8+ZNfOMbc7LXNzTU86Mf3ca3vjUwo8Q5g3M4HCYYDGZ/1jSNVCqFnqlWpes6Tzzx\nBAsXLmT27NkAVFdXc/XVV3PhhReyevVq5s2bxx//+Mden1Ne7kfXtf60pWhUV4cG7F5xUgBUjK6i\nvMN9LSvIZl1HSyYG9Hn9USzvMZiGY5tB2j3cFEO7QyEvHo+Lww8fx7hxhwBwyCEjCQZdlJX58Xhc\nVFeH8HpdnHTScVRXh/D5xvCHP3zCggV3EAwGSSaTvbQlxG233crPfnYP4XCYiy66CE1L0thYz49+\ndCsA8XicM888k4qKAC6Xlr3Xxo0buf7673LDDTdwzjnnDEh7cwbnYDBIJNN7A3sOWtc7X3bllVdy\n2WWXMWfOHJYvX84pp5yCptmBdsqUKdTW1mJZVrdbfTmamoZGD7C6OkRdXduA3a+trsn+b1Iltc99\nVZ+PREvbgD6vrwa63QeD4dhmkHYPN8XS7ra2OIlEklTKzL5PMpmmsTFCa2ucWMygrq6NeDxJa2uc\nuro2nn32GTTNw003zWPnzh38/ve/p7a2tdtYVF9fz8qV73DHHQsoKXEzbdo0zjjjc1RXj2D+/HsJ\nBoO8+ebr+Hx+mppiGEaSuro2Pv10C7fcMo8f/vBujj56QkG/V7196ckZnCdNmsRrr73GjBkzWLt2\nLRMmTMge27JlCz/5yU9YuHAhLpcLt9uNqqo8+OCDlJWVMWfOHDZs2MCoUaN6DcyiZ+1zzv4ux1S/\nX9Y5CyGGvY5bRnY0efJp/PCHt7J+/Qe4XC4OPfQw6uvrqK4e0eUelZWVNDY28L//exUej4uZM6/E\n5XJx3XXfY96867AsC78/wG23/RC/P0AymeKhhx5g+/atGIbBz372f4DdoV2w4Cf9bpNiWZbV2wlO\ntvbHH3+MZVncddddLF26lLFjx3Leeefx4IMPsnTpUhRFYerUqcydO5eWlhbmzZtHNBpF0zRuv/12\nxo8f3+uLFMM3s4Ew0N8yd/38ASLvvsP4ny5EC3X+lrXtzh9i7NrJ0Yt+OWDP66ti+XY9mIZjm0Ha\nPdwMx3YPVpv71XNWVZX58+d3+qxjoJ07dy5z587tdLy0tJRHHnmk0PcU3WhPCOvac9ZkT2chhCjI\nm2++zjPPdF3q9JWvzOKccz53AN6oezmDsziw0tEoqs+HonVNlnN2pjKjMdRSCc5CCJHL2Wefw9ln\nD0zS1v4kFcKKnBmNdOo1p9Imyz/cSyptthcikXlnIYQYUqTnXOTSkQjuESOzP/9z1Q6e/ddmlIsU\njpQSnkIIMSRJz7mIWakUViLRaUeqlR/VAlDbFG3f/CIWOyDvJ4QQYv+Q4FzEnB6xU7qztjnGtho7\ng7ChNSF7OgshxBAlwbmImZntIp255dUbarPHGtvi7Xs6S3AWQoghReaci1i255ypq71qQy2aqqBp\nCo2tCdmZSgghhijpORexdKR9R6ra5hjb9rZx3LhyRpT5aWyNo/nsoC3Z2kIIMbRIcC5i2b2cAwHW\nZIa0pxw7gooSD3EjjaHba5tlWFsIIYYWCc5FzBmu1nx+Vm2oRVUUJk2oprLEC0BLSut0nhBCiKFB\ngnMRMxMJANpSClv3tnHc4eUEfS4qSuzNvJtT9mYiA9lztiwLo6ZmwO4nhBCicBKci5gTnD+usdcx\nn3asvZNKRcjuOTfELNC0AZ1zblu1gq233Eh0w0cDdk8hhBCFkeBcxJzgvDecAuDYsWUA2Z5zY1sC\nzecf0GHt+KZP7P9u/XTA7imEEKIwEpyLmNVhWBsg5LcTwCoyc87OcqqBHNZO7N4NQLKuNseZQggh\n9hcJzkUsO+ecVNBUBa/bTgArD3lQgMbWOKrPN6DD2sYeJzjXDdg9hRBCFEaCcxEzDTs4tyQh6HOh\nKHYPWtdUSoJuGtvi9p7OhoGZTPb7eelwmHRLCyA9ZyGEOJAkOBcxZ1i7OW4R9Ls6HasIeWlsTaB4\nvJ3O7Q9jz57sr5MNDVjpdL/vKYQQonASnIuYmUiAqtJmWAS9nYNzZYmHtGmR1vT2c/spsWcXAIqu\ng2mSbGzo9z2FEEIUToJzETMTCRS3GxSla885kxRmqK7suf1lZJLBfMceB8i8sxBCHCgSnIuYlUiA\ny142FfR1H5xjppo5N97v5znJYMGTTwFk3lkIIQ4UCc5FzDQSWC47KHcJziE7aMesTAnPAeo56+UV\neA4bB0jPWQghDhQJzkXMSiRI6z0E50zPOZK2/wj7G5zTsRippkbco0fjGlENSM9ZCCEOFAnORcqy\nLMxEgrRmFx7ZNzhXZqqEOQVK+put7Qxpu0eNRispRXG7SdZKcBZCiANBgnORspJJsCxSqp2NvW9w\nDgXcaKpCS2Z5s9nPOWcnGcw9ajSKouCqHkGyvg7Lsvp1XyGEEIWT4FyknJ6woXQfnFVFoaLEQ7Nh\n/2wmjH49z8gso/KMHg2Aq7oaMxbDDIf7dV8hhBCFk+BcpJzqYNngvM9SKrALkbRkRrMto5/D2h16\nzgCuansHLEOSwoQQYtDlDM6maXL77bdz+eWXM3v2bLZt29bp+JNPPsmXv/xlLr30Ul566SUA4vE4\n1157LVdccQVz5syhsbFx/7z9EOYkeMWxs7H37TmDvTuVkRn2NuP9G9ZO7NmNVlKCFgwCds8ZJClM\nCCEOhJzBecmSJRiGweLFi7n++utZsGBB9lhjYyNPP/00zzzzDI8//jj33HMPlmXx9NNPM2HCBJ56\n6ikuvvhiHnroof3aiKHIGdaOWxqqouDz6F3OqSjxknSCcz96zmYiQaq+HvfoMdnP3JmeswRnIYQY\nfDmD85o1a5g6dSoAEydOZN26ddljFRUVPP/887hcLurr6/F4PCiK0umaadOm8fbbb++n1x+6nJ5z\n1FQJ+HTUzKYXHVWUeDGUTIWweN+Ds7HXrqntDGlD+7C2rHUWQojBlzM4h8NhgpmhTgBN00ilUtmf\ndV3niSee4PLLL+eiiy7KXhMKhQAIBAK0tbUN9HsPeU5wjphqt0PaYC+ncnrO/ZlzdnrH7pEjs5/p\nlZWgKNJzFkKIA6DrWOk+gsEgkUgk+7Npmuh658uuvPJKLrvsMubMmcPy5cs7XROJRCgpKcn5IuXl\nfnRdK/T9i1J1daj/N/HY35uiaYXyEm+39zzCMElmEsZ0K9Xn56ZVe/epslFVne6xo6qSdEN93vcd\nkHYfZIZjm0HaPdwMx3Yf6DbnDM6TJk3itddeY8aMGaxdu5YJEyZkj23ZsoWf/OQnLFy4EJfLhdvt\nRlVVJk2axOuvv87JJ5/M0qVLmTx5cs4XaWqK9q8lRaK6OkRdXf9HClrqmwE7W9ujq93e04gZ2YSw\neFu0z89tqWkCIJLq/By1oorYxxup2d2A6nL3eo+BavfBZDi2GaTdw81wbPdgtbm3LwA5g/P06dNZ\ntmwZM2fOxLIs7rrrLh577DHGjh3Leeedx7HHHsvll1+OoihMnTqVz3zmM5x00knceOONzJo1C5fL\nxX333TegDRoOnGFtQ3VR1sOwtt+rYykqaVXrV7a2GbO/GGl+f6fPXdUjiG3cYCeLdZiPFkIIsX/l\nDM6qqjJ//vxOn40fPz7767lz5zJ37txOx30+Hw888MAAveLw5GRrJxW92zXOAF63ncmdUl39mnNO\nR+3grO4TnPXycgBSLS0SnIUQYhBJEZIi5fSck6reY0KYoij4vTpJVe9XtraZDc6BTp9rPjtYOz1r\nIYQQg0OCc5EyO5Tv7Ck4AwS8Ooai92uds9Nz3ndYW/X7Oh0XQggxOCQ4FylnmLq3njOA3+sioWj9\n2pXKjEVB01DcnZO+VJ8vczzW53sLIYQonATnItVxWDvk6zlT2u45u7CSSSzT7NuzolE0nx9ln0In\nWmaYW4KzEEIMLgnORarjsHbA13Pent+rZ9c6m33sPaejkS7JYNCh5yzD2kIIMagkOBcpq2PP2d9b\nz9mVXets9XFPZzMa7TU4p6XnLIQQg0qCc5EyEwlMRcVSNPzdbHrhCPj09s0v+tBzNpMGVjKZzczu\nSJVsbSGEOCAkOBcpM5Egper4vTqq2nXTC4ff4+rXsLYZtXvFTmZ2R+3D2tJzFkKIwSTBuUhZRgJD\n1Qn2MqQNmYQw1c7m7kvGdrY6WCDQ5ZjqcqHoOmnpOQshxKCS4FykzHgCA51gL8lgYC+lau85Fz7n\nnK0O1s2wtvO5ZGsLIcTgkuBcpMyE3XPubRkVOD3n/gxrd1+606H6/TLnLIQQg0yCcxGyLAsraZDM\nsYwKyJbvBLASRsHPMjtUB4vEkySS6U7HVZ9Pes5CCDHIcm58IQafZRhgWTkLkEBmKVV/hrWdXrHX\nx62PriCdtrh46hGcM3E0mqqi+fx2gZNUCkWXvy5CCDEYpOdchJw62bkKkIDTc7YTwvo0rB2JABDF\nRUvYIBxL8sQ/Pub2X63k4x3N7fW1ZWhbCCEGjQTnImTF8ytAAva2kal+BGcnIawlrQFwzsTRnDtx\nNHsboyx6YZ1UCRNCiANAximLkNNzTio6AW/Pm16AvW2k5vUA/VtK1Zyyg/MRo0qYdspo6lvirPu0\nEavCmzlP5p2FEGKwSM+5CHXa9MLfe3AG0H2ZANqHOWenR9xo2IVOKkvse5WF7IBvaPZ/JTgLIcTg\nkeBchLJ1tRWdQC/bRTpcztBzP4a16zJxvbLUDs7lQTsoxzLJZrKnsxBCDB4JzkUouyOV6iKUR3B2\nB+3gnIr1oecci6LoOnXhFACVJXZQLs/8N2JlMsGl5yyEEINGgnMR6jisnStbG8Dj73twTkejqD4/\n9a1xSgNuXLo99+z0nNtM+2cpRCKEEINHgnMRyiZ2ud1oau4/Ip/fQxqFdLxvc86q309jayI7pA1Q\nnplzbs0kismwthBCDB4JzkXIydZW3Z68zg/4XCRVnXQfy3daHi9p08omg0F7cG5K2oliMqwthBCD\nR4JzEXKGtTWvN8eZNmfbyEKXUpmGgZVKkXLZz+nYcw76XOiaSoMhwVkIIQabBOciZGaKkOh5Bmdn\n20jLKDA4Z4aqE5pd6KSqQ3BWFIXykDubxS1zzkIIMXgkOBchI9NLddYv5+L32sPaSrKwjS+ceeR4\npsJYx2FtsJPC6rPBWXrOQggxWCQ4F6Fk1A6Ebn/+PeekYgdny7Lyfo7TGw5bmeBc2vl5ZSEPaVRw\nuUhLcBZCiEEjwbkIOUuiXJklUrn4M3s6K2R2tMqTM6zdmlkutW/PuSKU+dnjk9raQggxiHIuojVN\nkzvuuIONGzfidru58847GTeaEyYEAAAgAElEQVRuXPb4448/zl//+lcAzjnnHObOnYtlWUybNo3D\nDz8cgIkTJ3L99dfvnxYMQel4AgXwBPILzgGvi6TSvvmF6skvy9sZ1m5OqgSCOj5P578OTgnPtNuD\nJnPOQggxaHIG5yVLlmAYBosXL2bt2rUsWLCARYsWAbBjxw7+/Oc/8+yzz6KqKrNmzeL888/H5/Nx\nwgkn8PDDD+/3BgxF6UQCHfAG/Hmdb28baf9RFpKx3bGu9r5D2tC+nCqle9Bbm/K+rxBCiP7JOay9\nZs0apk6dCtg94HXr1mWPHXLIITz66KNomoaiKKRSKTweD+vXr6empobZs2czZ84ctmzZsv9aMASZ\niQQpVPz+/HrAXreWDc6FbH7Rcc553yFtaA/OCc2NlUphFphwJoQQom9y9pzD4TDBYDD7s6ZppFIp\ndF3H5XJRUVGBZVnce++9HH/88RxxxBHU19dz9dVXc+GFF7J69WrmzZvHH//4x16fU17uR8+UjjzY\nVVeH+nW9mjJIqjqHjAjlf69MwZJSv04oz2siVhKwg+9hh5R0eZaV+fMwMkutyv0a7rKe793fdh+M\nhmObQdo93AzHdh/oNucMzsFgkEgkkv3ZNE10vf2yRCLB97//fQKBAD/4wQ8AOPHEE9E0+x/2KVOm\nUFtbi2VZKIrS43OamobGnGZ1dYi6urZ+3cNMJEiqOqlEMv97ZYJzY00T8Yr8rgk3NAMQV934XWqX\nZ6XTJgrQltaoAup21OFOdv8FaiDafbAZjm0GafdwMxzbPVht7u0LQM5h7UmTJrF06VIA1q5dy4QJ\nE7LHLMvimmuu4ZhjjmH+/PnZgPzggw/ym9/8BoANGzYwatSoXgOz6ExJGiQVHb8396YXDtVj927T\n8fyXPLWvc3ZTWdo1+UzXVEoCbsKy+YUQQgyqnP/6T58+nWXLljFz5kwsy+Kuu+7iscceY+zYsZim\nycqVKzEMgzfeeAOA7373u1x99dXMmzeP119/HU3TuPvuu/d7Q4YSNZXE0H34PQUE50w1sWS0gDln\np0KY6u5UHayjspCH1l2y+YUQQgymnP/6q6rK/PnzO302fvz47K8/+OCDbq975JFH+vlqw5Nlmmjp\nJElXYT1np9RnPJx/AE1Ho6RVjbSqdZutDVAR8hBF9nQWQojBJEVIioxTRCSp6ngL6Dk7pT4TkfwD\nqBmLYmgePC6NQA9fBMpCHhKqO3u+EEKI/U+Cc5FxdqQydRdqAfP0rkxwNqIFBOdolJjiorLU22NO\nQHnQQyJTe1t6zkIIMTgkOBcZZy9nS3cXdJ07U+ozGctvztmyLNKZ4NzTfDPYa52dnrPU1xZCiMEh\nwbnIZCt8uQsLzk41sVSeAdQyDEiniWuebguQOMpDHhKa03OWYW0hhBgMEpyLTDruBOf8qoM5PEF/\n5+tzPafDdpFlwZ6/CJSHPMSdOecByNZONjZKpTEhhMgh/4wjMShiYbvgi1pgz9kfsoNzvuU7Oy6j\nqgj0/KyyDnPO/R3WNmr2svXWm1F9PkKfPZ3Ss6bhzWyOIoQQop30nItMPGwHwHx3lnL4MsHZSuTX\nK+0YnEt6Cc4+j47qs+ez+5sQlti5AywLM5Gg5bVX2X7nHbStWd2vewohxFAkwbnIJDLrlFVfz/PA\n3QkE/VgAyTyHtTPzx3Gt9+AMUFbix1D1fg9rpxoaARj131dTfcWVACR2bOvXPYUQYiiS4FxkjEwA\n1H357eXsCPjdJBUdxciz5xxr7zmX+nsPzuVBNwnF1e9h7WSTHZz1qioCx58IQKqpuV/3FEKIoUjm\nnIuMEYnhBVz+/PZydjjbRiqpfIe17UCbUF25e85BezlVf8t3phobAHBVVGaHylPNsk+0EELsS4Jz\nkXGWQjnrlvOlKAopzYWeSuZ1vtNzNj1e3K7et+oM+d0kVBdWrC3n7mK9STU1gqahlZSgqCqqz0eq\nWXrOQgixLxnWLjLO0LGzNKoQpu5GT+cXnJ1esB7I/Zyg30VCc4NpZsuL9kWysRG9vBxFtf/a6WXl\npJqk5yyEEPuS4FxkzMw6ZW8wUPi1Lg8uM0kylc55rhOc3YFgznODPle/S3haqRTplhZc5RXZz/Sy\ncsxoBLMfAV8IIYYiCc5Fxlmn7CyNKoTl8aJi0doUznmukVlP7S3JHZxDfld7IZI+VglLtTSDZaFX\ndAjO5WX2Mek9CyFEJxKci02mfKe/pPCes5LZNjLS3JbzXCc4+0pDOc8N+dwY2UIk+e8X3VGqMZOp\nvU/PGTKBWwghRJYkhBUZxeh7cHYyoMPNrTnPTUejmCgEQ7kTz4J+V7+3jUxmgrOrU885E5yl5yyE\nEJ1Iz7nIKMkEhqLj8xVWvhNAyyy/irXmHtY2o1F7jXMwdyWyTnPO8b7NOWd7zhWV2c/0ssywtiyn\nEkKITiQ4FxktlSSpFbaXs8OVybyOt0ZynmvFYyTyqA4G4PfqGJrTc+7jsHaTvca505xzmfSchRCi\nOxKci4yWNkhltmgslCeT4Z0I5+45K4l4XgVIAFRFyc5n93tYu7ybYW1Z6yyEEJ1IcC4yrrRBWi98\nSBvAG7Izr41I7wHUSqXQ0kniOTa96EjzZXa9ivc9IUxxuVCD7dnhWkkpKIoMawshxD4kOBeRdCqN\ny0xh9jE4+0rtwJfOEZydtcoJ1U1JjrraDmfIvK8lPFNNjegVFZ2qiymqilZaKsFZCCH2IcG5iEQj\nURTAKnAvZ4c/s2Y51wYVzvGk7sbr7r10p6N9yDz3fPa+TMMg3daGq0MymEMvKyfd3IxlWQXfVwgh\nhioJzkUk2pIJfO7C9nJ2uDIB1MqRUe1s/Wh5vHnXyfaE7Hsn+xCcU01d1zg79PJyrFQKM495ciGE\nGC4kOBeRqJNl7SlsL2eHs85ZSfQ+L5yO2s9RvPlXIXMqiaWihS+lal9G1U1wdjK2ZWhbCCGyJDgX\nkXimV6r2MThrXjs4q8lEr8PEsTa7l6oVsC1lMOAljdqnOedkh+D80dZGbnr4bXbX2211ZTK2k7Kc\nSgghsiQ4F5FE2O6Var7+9ZzdaYNYItXjedEmu7xnPjtSOYIBe9tIM0evvDvOsLarooK3P6yhtjnG\nP1btAEArlUIkQgixLwnOAyixYwf1b73d9+sjdm9S9xa2l7ND0XXSqo7bTNIW63nrSKeCmDuUf4lQ\nZ09n+lAhrL2udiWbd7UAsOLDGmKJVHatc1rWOgshRFbO2tqmaXLHHXewceNG3G43d955J+PGjcse\nf/zxx/nrX/8KwDnnnMPcuXOJx+PMmzePhoYGAoEA99xzDxXdzDcONTt+/SvMHVs58v/uz5amLEQq\nYgc+PdC34Axguj140knaoklGlnd/TqItjBfwhHLvSOUI+lw0aW5KjMITt5xhbcMfYk+DPSyeSKZZ\n8WENZ4yUOWchhNhXzp7zkiVLMAyDxYsXc/3117NgwYLssR07dvDnP/+ZZ555ht///ve8+eabbNiw\ngaeffpoJEybw1FNPcfHFF/PQQw/t10YUAyMcJrVjGwCxLZv7dI9kZomT29/34Gx5vHhMg3C0555z\nMrMOOpDHjlSOkM+FobjQUgaWaRb0TqmmRlSfj61N9judfdIoVEXh9bW7ZfMLIYToRs7gvGbNGqZO\nnQrAxIkTWbduXfbYIYccwqOPPoqmaSiKQiqVwuPxdLpm2rRpvP1234d6DxbbVqxFxU7Cql33UZ/u\n4WzH6ClgLnhfiseLx0zSFjV6PCeVGT4PlOUfnIN+FwnN2fyisHnnVGMDenlFdkh78jHVnHJUJdtq\n2tjenETxeKXnLIQQHeQc1g6HwwQ7llzUNFKpFLqu43K5qKiowLIs7r33Xo4//niOOOIIwuEwoZD9\nD38gEKCtLff+wuXlfnQ9v4IYxejdjz7CmcFt+2QT1dX5B76slB1Qq0dX9u16wB0KYtWmsSyrx3so\nhh1cDztyVN7PsSyLZGbzi3K/iqeb67q7Vyoaw4zF8B83gu119peCz5w8hrIyP+9+Us/KjXWcUVlB\nurWlz20+kA7Gdx4I0u7hZTi2+0C3OWdwDgaDRCLthSdM00TX2y9LJBJ8//vfJxAI8IMf/KDLNZFI\nhJKSkpwv0tTUt7KQxcLctIGkotHmChCq2UnNniZUvbDtsp3h5iQqdXW5v9B0x8oUMKnb29DjPZzy\nnqaqF/Qc021nkdftqsdD54zy6upQt/cy9u61r/UH2bC1kZEVfhLRBIdV+Kgs8fKvNTs5PVhCcvdu\nanY3orr6tunHgdBTm4c6affwMhzbPVht7u0LQM5h7UmTJrF06VIA1q5dy4QJE7LHLMvimmuu4Zhj\njmH+/Plompa95vXXXwdg6dKlTJ48uV8NKHZGczOhcAO1oUNIHXokLjPFlrUbC79RZpmSN5h/FvW+\n3NltI3tO3FKMOIaiEwwUWIkss/7aLKAQSTozahLVvMSNNEeNtr+oqarCtFNGkUimaVbs+6ZbJGNb\nCCEgj57z9OnTWbZsGTNnzsSyLO666y4ee+wxxo4di2marFy5EsMweOONNwD47ne/y6xZs7jxxhuZ\nNWsWLpeL++67b7835EDatWotAMnDjmLcsYeR2rKWT1d9wFFTTijsRoY9rK37+p4Q5g4GMQCjrecy\nm7oRx9A9eZfudDjrqI1IhHzfMB22g3NDyv6rNn5MafbYyeOreO6NT2lWfPiAVFMzrqrqgt5JCCGG\nopzBWVVV5s+f3+mz8ePHZ3/9wQcfdHvdAw880M9XO3g0vr+OEFB64gkcd+ZRfPDHJ4ht2YxpWqhq\n/gFQTSbs/3r7VoQEwB20e869bRvpShsY7sKTzrRMcI62hCnNca7DCc57Y/bvw1EdgnNlqd3OZjyM\nAlItkhQmhBAgRUgGhLZtE3HVxRGTjic09jBSuofqcA0btxcWbNSk3XNWPX3b+ALae7epHspsxhJJ\nPGmDdB9KhOp+e7g93pb/Wud0ZkOL7WELr1tjdFX7kH3Aq+NxaTSm7e+I6Ujhm2oIIcRQJMG5n4z6\nOvzRZvaGRlNdEbD3KB47jspkK2vWbsv7Pqm0iZ5OklY1lAITyTpygnNP20a2NoftJV+ewofOnV55\noqDgbPecd0cVjhxd0mkkQVEUKku91CfUzLmyM5UQQoAE537bu/o9AIzDxmfncCuOO9Y+9sGHee9T\n3BoxcJtJ0nrf9nJ2aD47gKqJOKl012IhrQ2tACh9KBHqziSq9TZkvq90JpBHNQ/jR3cdDK8o8dBk\n2l9GZNtIIYSwSXDup8YPNwBQesLx2c98mTn5itYamsM9FwPpqCVi4LKSWK7+BWen52wXIulaJSyc\n2fSikB2pHL6SzJ7OhQTnTM85pnk6JYM5qkq8xDR7GF+GtYUQwibBuZ9iDXbd6COOPyL7me9IOziP\njtdRm+f67ZaIgcdMgbvvyWDQYWcq0yDczeYX0Wa75+zqw3Itf6bcZ7qQpVThNkxFxVBcHD6q65q+\nylIvcdUJztJzFkIIkODcb1ZrC4aqM2Z0+8YeWjBIqrSSUYkGapvyC2St4QRuM4nq7XsyGOzbc+7a\na29ptEto+kvz3/TCEcyU+7QK2Jkq3RYmrnvxeHRCvq4FRipLvCRUF5aiypyzEEJkSHDuh8bWOB4j\nSsob6LJmWKuswmca1NW35nWv1tYoKhZaP5ZRAaje9uDcXc+5rdF+n9LKfBdDtcsG5wL2dE6H24io\nHqpKvd2uq64o8YKikHJ7MWVYWwghAAnO/VLfFCWQjmMFupYn9VbZPemWvfV53SvSYvca9T7MBXek\n+Z3gbHQ75xxpseeAvSWF140NBb0Yio6aZ3C2UinMWMwOziXdf+moyqx1NnSvDGsLIUSGBOd+aKlv\nQsVCCXUNzv6qSgCidfkF52ir3Wvsz3aRYO9KZaF0O6xtJNPZHan6khDm0lUMzZUtlpKLE2xjmoeq\n0u7bVRb0oKkKMc1NOhLJO7tdCCGGMgnO/dBW2wCAXtp1iNhVVgaA0dSUV8CJhe3EMWctcV8pioLi\nzWwbuc+wdk1TDE/a/kztY4nQlOZGT+WXgd6xrrZTDWxfqqpQHvIQxg2midnD+mwhhBhOJDj3QzyT\nqe0pL+tyTC8vB8Abj9DazfDyvoxwpkfbzzlnsAOvxzQI7/PcPQ0RPGamClkfh8/Tbg+utJHXFw4n\nwSuWmXPuSUWJlzbLThaToW0hhJDg3C9Gs72LUiAzhN2RVmoH52A6mtdyqkRmeVJ/6mpnn+3z4e5m\nWHtvQ7Q9OPv6FpwttxeXlSYeyz203XGNc089Z7Aztp21zlKIRAghJDj3i9lqZz4HR1R0OaZnhrWD\nqWjO5VTJVBoS/d/0wqH5/Xa29j7BeU9jFK9p96a1Pg5rW5ma3G1Nufc6ba8O5u2151xZ6iWmSiES\nIYRwSHDuj4gdoNxl5V0O6SUlWCiEUjFqcvScWzKlOwHUPmxIsS/N50PFIhbu/KVgT0MEr5UEVUXp\n4+YaSub9ws25l4g5Peekx0ewmzXOjqpSLzHNrowmw9pCCCHBuc8sy0KP2oFE6yYhTNF11FAoM6zd\ne8+5NZJsD84DNOcMkAhHaGqze+SmZbG3MUqAFKrPV/Bezg4nyzvSnDuIOnPOntLSXp9XUeJpL+Ep\nw9pCCCHBua9iiRS+lN0j1kPdrxl2l5fZPefGXD3nBG4zBQxscPaYBh9ssTPKm1oTGEkTr2X0aRmV\nwxVwgnPuYe1Es12NLFDRe8GTypIOJTwlOAshhATnvmpqSxBMxUi6fT1u8aiXleOyUjQ3tPaa3dw6\nwMPaTpUwt5nk/c12cN7TaM/lulJGn5PBAHwldtnPaEvuIJpoyczJV3bNZu+oU0KYzDkLIYQE575q\nDhsE0jHS/p4rbemZuWg92tptKU1HS8TAbQ38sPZIv8L6rY2k0iZ7GqIolomWMvq8jArAnwnOsdbc\nwTnZ1oah6FRW9l6NzO3S0AP2Rhwy5yyEEBKc+6ypKYzXTHZbHczRnrEdo6aXeWe75zyAw9qZ4Ht0\nlYeEkeaTHc2ZZVT9K0ACECy325sI5+7hWpGwXYCkh9KdHfnK7aFvGdYWQggJzn0Wruu5OphD67Sc\nqud555aIgSsTOJV+7koFoGWGtceV2RnS721uYE9DhEDaromtBQrfLtLhDTl7OucOzmos0mvpzo7K\nyoOkFBWjTYKzEEJ0P1kqcoo1NgHgKe+6jMqR7TmnY71mbLdGDDz7YVh7hB/cLpUPtjQQTaQ43GM/\nw1VZ1e97p3OU2TQTCdR0iqin9+pgjspSHzHVg96WO9FMCCGGOuk595HRZFcH81X2FpztY6EchUha\nIgY+0vb6Y73n9cD5yg5bJxIcP66CPQ1RWsIGY1z2sqqBCM6qkSBupHo8z1njnNC9hPy521RZaieF\nWVFJCBNCCAnOfZRusZcJ+atyB+eSdO45Zw8pVG/3ex4XygmgZizGSePbS4tWY7+DXtWf4GzPZ3vM\nZHYNdXec6mD4u+513R1nOZWSiGOl031+PyGEGApkWLuPlEx1MFdpz8uEtGAQNI0y4j3OOSeSaeJG\nGo+ZQvX3f0gb2gOoGY9x8pHtwbk0mVlOVdm1Fni+NJ/9jk5wHlXZ/fx1NDOyoAbz2ze6ssTLLqcQ\nSTSC3kuiXW/e2r2KzS2fkjbTpK00aTPNEaXjmD7u3D7dTwghDgQJzn1gmhZatjpYz8FZUVX00lKC\n0RiReIpwLNmljGVrxK5/7TKTqJ7ggLyfmgmgZixGZamXMdUBdtVF8MVaQFWzPfq+aN8v2ui159xa\nZ8/Ju0vzC7LOsDZkNr/oQ3DeE6nhqQ1/wKLzmvL36tdzZOnhjC87vOB7CiHEgSDD2n3QGjUIpDPV\nwXrJ1gY7KcxrhMGy2NvQtffsBGctZQxIMhi0FyExMztd/dukQxlTHUAPt6BXVKBoWp/vrSgKeDy4\nzSSNvQTncENmTr6s998fR8CrY+j92/zib1tfwcJi9nGXceeZ3+fus2/jWxOvBuAPn/wZ0zL7dN99\ntSRaB+xeQgjRHek590FzOEEgFcdUtZwFPfTSclRzCz4zwfbaNo46tHOwaokYqJaJaqYHLji7XCi6\njhm3g/PnTh3DOSeOYNM1D+ObcEz/7+/z4QknaWqN93hOrKkZNxCs6r06mENRFPAHoLFva51rIrWs\nqXmPQ4Oj+ewhk7Pz3CUVIaaMnMjqmrWs2vsunx01ueB7d/TW7lU8ueFZyjylnDVuCseFjuXwkrED\nkisghBCOnD1n0zS5/fbbufzyy5k9ezbbtm3rck5jYyP//u//TiKz7aFlWUydOpXZs2cze/Zs7rvv\nvoF/8wOoqS2RqQ4WzPmPsrPWOZSKsr2ma9Bp7bjGuY87RXX73FCIVEtz9udUYyNYVr/mm7P39vnx\nmEavPedkZjvN0uqu22n2eN+APayfDBe+nOrlra9iYXHhEed3+TP54vgLcak6L2x+mXgq9z7UPamN\n1vHsx8/j0dwk0gZ//fgV/m/Nz7ntrbvZ0rK1z/cVQoh95QzOS5YswTAMFi9ezPXXX8+CBQs6HX/j\njTe46qqrqKury362fft2TjjhBH73u9/xu9/9juuvv37g3/wAam5LEEjFIJh7XtSVWQddasbYUds1\n6LREjPbKXQPUcwZwjzmUVGNjtheabKgHQO/HMiqHHrD3i+6t5+w8t3Jk/sHZFcrU7W7MvR1lRzXR\nOlbXvMvowCGcXHU8AK0rl5PM/J2s8JZz/thzaDFaWbL9XwXd25E20zz+4TMYZpIrjr2UBWffxk1T\nv8lnD5lMc6KFZz9+odf66UIIUYicwXnNmjVMnToVgIkTJ7Ju3brON1BVHnvsMcrK2ocv169fT01N\nDbNnz2bOnDls2bJlgF/7wGptaEHHRC/JPZ/qJIwd6jPZWRchbXaeq+xcurPvZTX35TlsLACJHdsB\nSGWCs6sfy6gcmt+PikW4t80vohEsoLQ6/+QzTyZ5LJrHXtEd/b1Dr1lVVGKbN7H3kYepffqJ7Dnn\njz2XUncJS7a/TmO8qaD7gz2fva11B6eNPJUpIyeiqzqTRp/I146/nInVJ7K9bRcbmj4p+L5CCNGd\nnHPO4XCYYLA9i1jTNFKpFHpmJ6azzjqryzXV1dVcffXVXHjhhaxevZp58+bxxz/+sdfnlJf70fW+\nJyoNJjNsB4/QIVVUV3ddKtTxM9fho6nBDs7JmEnCUhjX4Xg8ZWZ3pApWlHR7v75QTjyGppf/it5U\nQ3X1Z4nG7F571ZGHUdbPZzSPqCICEG6jpMyPx2X/uTnvbpoWWiKKoXsYOSr/4Fx9aDUAViyS9+/D\n3nAdq2re5bCSUUw//gxURWXLC+8CENvwERUhF5rXC4S4cuIl/Hzlb3h55z/59hn/nfd7fVy/hZe3\nvUKVv4JrzrySgLs9z6C6OsTlE7/Au//8gNd2L2XaMf2b0z5YDNTf04ONtHv4ONBtzhmcg8EgkQ7Z\ns6ZpZgNzT0488US0TEbwlClTqK2txbKsXudnm3qpPV1sWvfavVA1GKKurvNQdXV1588S2PPIJZns\n7vc21ODX2n8f6hqjBE17eNjQvV3u11dG6QgAGj76BPeZbbRs3wVAVA+Q7OczUh47OAXSMT75tJ6R\n5f5O7a5rjuFNxUl5/QW1R8usz442tuR93VMf2VnY0w/7HA31ESzTpPaNZQCYhsH2pSsInjoJgGMD\nxzE2dChvbV/NGdWf4cjSw3PeP56Kc//KX4EFVx7zFaItaaLY7+a0OUQ5x1VMYH3tx6zctJ4jSsfm\n3eaD0b5/x4cLaffwMVht7u0LQM5h7UmTJrF06VIA1q5dy4QJE3I+8MEHH+Q3v/kNABs2bGDUqFFD\nKps1nUm08lbk7hU69bVDaTtzesc+SWEtkQRVmp2kpOVYllUI14gRKB4Pie3OsHYDKAp6L7XA8+W8\nZzAVo7G1a4LVrtow/nQCNVDYuu3STGa3mee2kc2JFlbufYdD/CM4dcTJAMQ2fUK6uTk7rB9+793s\n+aqicunRFwHw7Mf5La16bvNL1McbmT7uXI4uH9/jeReM+xwA/9j2Wl7vLoQQvckZnKdPn47b7Wbm\nzJncfffd3HzzzTz22GO88sorPV5z9dVXs2rVKq688kruvvtu7r777gF96QMuk02ca40z2Ns3Ki4X\nrsyw8raazt/GWiNJyhUjc7/8lh3lQ1FVPIcehrF3D2bSINlQj15egZJj1CMfzlx7IB2jqa1rUtie\nHbWoWLjyXOPsKCsLkFBcEM1vFOXt3asxLZNzDzsbVbH/KretWgFA1Ze/glZSQuS9tVgd5vnHlx3O\n5BGnsL1tJyv3vtPr/T9u2sSbu5YzKjCSGUdM7/Xco8uO5PCSsbxfv549kZq83l8IIXqS819qVVWZ\nP39+p8/Gj+/ag3j11Vezvy4tLeWRRx4ZgNcrPslUGj1uD/NreVSxUhQFvbwCs7mJERN87KgNZ4f4\n40aKRDJNaWZYW8sjwawQnrFjiW/eRGL7dlJNTfiOOnpA7ut8ibCDc9eec8OuvYwHAiMKSz4rC7jZ\nprlxJ3IHZ9MyWbZ7BR7NzWkjJwJgpdOEV69GC4XwH3c8gZMn0vrmUuKfbsE3/qjstRcfNYP36z/k\nhc0vM7H6RLx61yz5RNrgyY/+gILC7OMuw6X2/r+KoihcMO5zPPLBb/jntn/xteMvL6jtQgjRkVQI\nK1Bz2MDv7Iscyi9hQK+oIN3ayrgqL+FY+4YRzn8DmSFvvcCeZi7O0G7kvbVgWf3a8KKjTsPa3QTn\nSI09Jx8cWV3Qfd0ujYTuRU/2vETL8WHDRpoSzUwZeWo2uMY+3ki6rZXgpCkomkZw4qkAhNe+2+na\nCm8508eeQ6vRxt97GIZ+ccvfqI83ct7YaYwrOSyv9z+p6jgOCYxkVc27NMQKzwgXQgiHBOcCNbUl\n8KUzc8R5BmdXhV3444iAPby6vdaeU33jvT0AhMw4iq5nN6wYKF5n3jUTnPqzVWRHeok9YhBIx2ja\nZ845lTZJNTXaz6vIf9lGGTsAACAASURBVI1z9nqPD5eZwkwavZ735m57+Prs0Z/NfuYMaYdO+wwA\n/uOOR3G5iLz3bpfrp487lzJPKa/ueIP6WEOnY1tatvKvHcsY4avi80dckPe7q4rKBWPPxbRMXt2x\nNO/rhBBiXxKcC9QcTuAzE1iKmncw1TNVuUa77ICzvaaNlnCCV9/ZSXnIgy8ZRSstHfCkOfeYQ0FV\nMXbbmdoDUR0M7GIpisdLKB3vMqy9tzFKIJmpO15eeHC2vJmM7aaWHs9pijezrv4jxobGMLbkUPs6\n06TtnTVopaXZEqWqx4P/+BMwdu/GqK3tdA+35uaS8TNImSme2fgc6+o/YkvLNvZEanjio2cB+Opx\nX8GtFba/9pSREynzlPL2nlXEUrlHAIQQojsSnAvUErGHtS2fP+9g6gRFZz/lHTVhXl6xHSNl8oUz\nxpJubR3QZDCH6nbjPmRU+3tUFTbM3Bu9rJSgGe+SELazLkwoZc/J9yUzXAnYW1C21DX3eM5be1Zh\nYXH26NOzn6WaGjHDYfzHHIuitv+1Dp5iD21H3l/b5T6TR07kyNLD+ajxYxa9/xj3rfk5d664j5po\nHdMOPZOjyo4o+P01VWPamDNIpA2W71ld8PVCCAGy8UXBWiMGI9MJlPL8e6F6ZljbFWkh6Kvik53N\nvL8lTWWJhzPHl7AtnR7QZVQdeQ4bm+05D0TpTodeUoqvppa2SIJkqj0belddhFAq03MuK/wLh57Z\n/7m1rokx3RxPm2ne2r0Sr+ZhciYRDCCZ6Rm7RozodL43kwSX2Lmzy70UReGaU67i3dr3iSSjRJJR\noqkomqJx0ZH/UfC7O84a/Vle2rqE13cu45xDz8xmkgshRL4kOBeorS2G1zTQgvmv4XXmnFNNjYwd\neTgfbrWThT5/5uEdlmUNfM8Z7IztthVvg6L0aQ64J1ppKQoW/nSCpnCC0ZnPd9VFOC0VRQ2GUF3u\nXu/RnGihzQgzJjgqG8DcmaS4aGP3CVUfNm6kOdHC2WNOx6u3bxRi1GWCc3Xn4OyUK3XKl+7Lp3s5\nc/Rnem9sgYLuAKeNPJW396ziw4aNnFh13IDeXwgx9ElwLlAsU/fZXZp7GZVDzwTFVEMjY08N8eHW\nJqpKvZx90igSGz60z9mPPWewe7EDscbZ0Wmtc4cNMHbWtnFeOoqromu/N56Ks2z3Sj5t2canrdtp\nTtjzyqcfMoUrjv0ymqrhK7e/pCQaux/WfnPXcoBOQ9rQ3nN2jxjZ6XPV7UYrLSVZX8dgOvfQs3h7\nzyr+tXOZBGchRMFkvK1AzlaIhQRn1e1GC4VINjZw3OH2POwlU49E11TSrXaA2l/D2k7G9kDON0P7\nkHUg1b7WOZZI0dbUhstMdTuk/dsPF/OnTX/h3boPSJtpTq46gUODo1m+dzW/Wv8kSTNFoMr+/TFa\nuyaEbW7eyvqGjYwrOYzDQqM7HUv20HMGO0s92djYqRjJ/nZoaDRHlx3JR40fs7fAoiSmZWKkk/vp\nzYQQBwPpORco1WYPQ2vBwoqi6xWVGLt3ceIRFdx/7dmUBOwh31SzHYTy2eGqL7RQiEOumoNr5Mjc\nJxdy38z7BtMxaprsRLfd9ZEOyWCdh9A/aviY9+rXc2TpOP7r+FlUeMvtQiypOL94/ze8V7eOh997\njEsrz6UNsNo6V1KrizbwyAe/QVEUvnjkhV3eJ1lbi5LpJe/LVVVNfMtmUk1NA5axno9zDz2LT5q3\n8K+dbzHzmEvyuqY50cLD7z/O3kgtnznkVM459CzGBEflvlAIMaRIz7kAlmVhZjYBKTQ4uyoqsZJJ\n0uG2bGAGSGV6iH1JnspXyZlndaqQNRCcYfhSEvxt5XZ214UzmdrOMqr2TO2UmeLZT15AQeGyCZdQ\n6avIZrp7dS/XnHIVJ1Udz4amT1hc91f7omh7fe1oMsqi939NOBlh5oRLOKaic1ssy8KorcVVPaLb\nDHpn3nmwh7ZPqjqeCm85K/asJpqM5Tx/e9tO7l21kB1tu3BrLpbtXsldK3/Kz975BR82bByENxZC\nFAsJzgWIJdJ4Mv/I5luAxKFXts87d+RsojHQpTv3N6eHOmW0h4SR5p7frmbr3rYOwbm95/yvncuo\nidZx9pjTuwxHA7g0F3NOnM1pI0/lk/gu0ipoqTrajDApM8UvP/gdNdE6zh97DmeN+WyX69NtbViJ\neJdMbYd+gIKzs6zKMJPZufKevFe3np+uWUSr0cYlR32eBWffzv876escU34UHzdv5ufv/YpPW7YN\n0psLIQ40Cc4FaI0a7dXBCsjWhvaM7WRj52pUqRZnWDv/Oexi4PScq/Qk004ZxZbdLSxdu5tQZmtM\nJzO8JdHKy58uIaD7+cKRPVfb0lSNrx1/OV897jJiHg1fKsrtby/gZ+/+f/bOOz6O6lr835md7bvq\nvbvJvcndxgZjjCEUJ4RiQyhxCiHJjxQIJHkvCQl+AVJ47/FekgcJIYkTMA69OTZgsI1xQ7bc5SZZ\ntnpfbW8zvz9Wki0XNavrfv3RR/LOnTvn7J3dM/fcc895lmONJ5maOInloy50Z8PZ9WbDOca54Hgt\nB4si73XLenuw9uIR273JgrTZmBUTbxX9i60XMdCqprLh1Cb+eOBvAHxt8j1ck3UlsiQzJXEiD07/\nOt+aGqk9/cbJ99A0rU/lFwgE/YMwzl2gyd31vNottOx1Dl1gnBvR2ew9GkndF+jsUSBJhB0OVl6T\nS3aKHQ1IkiMPLy1u7TdPrscX9nPjyGXY9NZ2+5Qlmflpswjr4zB7wSgbKHKUkGXP4L4JKy65XzhY\nHQm4agkGK6l08r+vHeB3bxzEHwi3GudQPxhni97C/5v2Nax6C2uPvsa7RRtbDWylu4qn83/PW0X/\nIspg53szHmBq4sQL+pgQP5ZJ8eM50VjMobrCvlZBIBD0A4PLIvQzTe4A5hbj3I2AMGiuq3wOYYej\n9dhgQpJldHY7oSYHRr2OR++ZxUP/vZnE5trUSkwsRY4Sdlbmk2FL44qLuKMvicWOoamGr2Z9DYep\nmnFxYzDoLr1nuiU1pz4xibCq8sL6I6iahj8QJv9YNfPGJYIk9blbu4XsqEwemvFN/rfged479QGO\nQBMJ5njeLX6fkBpiRtJUbstdjt1waW/M8lHXc6iukDdPrmdC/FiR2EQgGOKIT3gXiKTu7KZbu3nN\n+Vy3thoIoHq9vbbHubdRomMIN7vlM5Pt/OqB+STrAshmM5LRyBsn3gPgttzlXTImUvODj6emiRnJ\nU7Hq289hftatncyGXWc4XeVi4ojI+73tQCWSoqDExhK8RCKSviDJkshDM75Fpi2NbeW7ePPkesyK\nia9NvodVk+5q1zADpNlSmJMyg3J3JbsrLyzkIRAIhhbCOHeBJncgUvRCb0A2tJ/96nx09igkRSF4\nzsy5xbD11h7n3kYXHY3q86H6m0tfmvSEGxtQYuM41nCSk45iJsWP63KO6pb1d2dtfQctIwSrq0Gn\noxYTb35STJTVwP03TyQ3M4YjJQ3UOrzoExIJNTSghUJdU7IHiTba+W7eN5iZPI35qbP59zkPMS1x\nUqfPv2HkUhRZ4e2iDQTFPmiBYEgjjHMXaPJE1pzlLrq0IeIGVuLi26w5t26j6qXUnb1Ny97slqA2\n1edD9XhQYmN579T7AHxuxNIu92tszhLmrbt08YtzCdZUo49P4G8bjxMMqXxpaS42s54Fk1IA2H6w\nMlIuU9PaPBz1BybFxJcn3sld42/tcA3+fOJMsVyVsYAGfyNbyrb3koQCgWAgIIxzF2hyRWo5K/au\nubRbUOLiCDc1tdYqDjVGjE9vJSDpbVpm/C0egFBjJB+2x6pworGYCfFjyY7K7HK/lrjmLGGOjo1z\n2Osl7HSixsRz9Ewjk0fGM2NsJABs5rgkDHqZbQcqz26n6kfXdk9wbfZizIqZDac2dWrvtEAgGJwI\n49wF3C4Pei2MvpvbnloLYDQXdWhN3RkzOI1zy4w/1GxEQw0RvY6rkcCrz+V0fdYMYE+KrBeHm5wd\ntDy73txkjHgzpo9JaE1EYjYqzMhNorrRS70cmaX2V1BYT2HVW7g26yrcIQ+bS7f1tzgCgaCXEMa5\nCwQdkbzaXd1G1YIS33Y7VYtRG6gzZ0/Q0+6+2pZAthb3fItxLpGbmBA3lhHRWd26rjkuYvQ1VyeM\nc3OkdqUWMb6jM9q+l1dMjri2D9RH9OiP7VQ9zaKMeVgVCx+d+QRfyNfxCQKBYNAhtlJ1gbAzklKy\nq9uoWmhJzBFsNc69n7qzs2iaxv7aQxxtOEmFq5JydyWuoJtMezr3T76XWNOFMp7v1g42RAK4XBaZ\n20Zc021Z9M39Sh4XmqZdNCVnCy17nIt8eixGhbSEtuu4Y7NjiY8ysqvSy2T6JxFJT2NSTCzOXMg7\nxRvYUrada7MX97dIAoGghxEz507iD4TR+SPZr7q6jaqFs4lIIkasNVp7AMyc91Tv57kDf2Nz6TaO\nNxZh0hkZEZXFGWcZv/7sfznjLLvgnPMDwuoqI+klk1JHMiI6u9uytDz8mIIeHO5Au21b6jifChgZ\nnRGNfJ4hlyWJyaMSqFWNIMuD3q3dwlWZ8zErJj48vQV/uP33SCAQDD7EzLmTODwBLGrzHuduurVb\nKiK1RAyHHA4kgwHZbO4ZIbuJM+Bi3bE30MsKD0xZRU50FkadAU3T+PDMFt448R5P7/kDqybeyeSE\nCa3nKTEtM+dG6jwNlJUdJR1YOOHSaTo7g6QohAwmLGEf5bVuYmzGS7YN1tSgIdGo2Lky/eIPOZlJ\nNjRJJmyPGTLG2ayYuSpjAetPfcgnZTtYkrWov0USCAQ9iJg5d5I2qTu76dZWYuNAp8NdsBfPsaOE\nHI0oUdHtum37gn8eexNX0M1NI69jbNxojM3ZuCRJ4pqsK/nq5LvRNI1n9/+V9cUfEGieqUlGE5LB\ngLeumide/yUmhwdVr2NkyrjLF8pmxxryUVHnabdZsLqKoMVGWNYxJuMSxjkx4ulwm6Ii0fKBoTHT\nXJy5EKPOwAenN4v6zwLBEEMY504SSd3ZvexgLchGI0kr7iLscVP6m6cIOxz9noBkX81B8qv3MSIq\ni8WZV1y0zbTESXwv7xvYDTbeKd7IY9ufYkvpp4S1MJrdilpeyRfWFRHvCGNKSO6Rhw19VDQW1U95\nzaWDwtRggFBDAw36KHSyxIjUi0fRpydG1qEbdC0R24N/3RkikduL0ufTFHDyacWu/hZHIBD0IMI4\nd5Jz82or3XRrA8QsvpqMhx+NuMY1rV9Td7qDHtYefR1FVvjS+NvaTbGZHZXJT+Y8xLLsq/GG/bx8\n7A1+vuPXfDxKpSTVgDpzArHXXkfyPff1iGwtEdv1FZc2pMGaGtA0KrGQnWLHoNddvC+jQkK0iYqw\nKXLeEHFtAyzJWoRe1vN+yccE1c5lPytylPDHA2t448R7NPodvSyhQCDoDmLNuZM0tcmr3X3jDGDJ\nHUv2T35O7Wv/xD57bk+I1y1ePf42TQEny0deT4o1ucP2Fr2Fm0ddx1WZC9h46iO2lm3nyFg7C774\nTRaOm0lNO7PcrtISse2suXQKz5ZtVPWK/ZIu7RYyk2xUl0bW9kNDyDjbDTYWps9l05mtPH9wDasm\n3nXJIiFNASdvnHiPnZX5ra99dGYrs1PyuCbrSpKtF6+HLRAI+p4OjbOqqjz22GMcPXoUg8HA6tWr\nyc5uG4lbX1/PypUreeuttzAajfh8Pn7wgx9QV1eH1WrlqaeeIq55G9FgxeEJkBb2gSQhW7uWdvFi\nKDExpKz6Wg9I1j2ONZxkZ2U+Wfb0LgcTRRns3Jp7M0uzF6OhEmPs+dl/S35t1eXE7QtiNekvaNOy\njapBb2dmevvb0TKTbOQrkeWIYH3ncnYPFm4YcS3lrkoO1B7hmb1/5BtT72uTGjQQDrCtfBfvFm/E\nG/KRbkvl1jE3UeOp44PTm/m0YjfbKz7jxpHLuC7n6n7URCAQtNChW/uDDz4gEAjw8ssv89BDD/Hk\nk0+2Ob5161ZWrVpFTc3Z2chLL71Ebm4uL774Ip///Of5/e9/3/OS9zEta86SxYIkD+7VAE3TeOvk\negBWjL0FnXxxd3BHRBvtvWKYAXTNxtka9lFRe/GgsJZSkQ36qAuSj5xPRqKNJiVisM6vqT3YMSlG\nHpj6ZWYlT6e4qYSn839PnbeBCncV/zz2Jj/e9h+8cvwtIFIh7NGZD5IbO5oF6XP4ydyH+eqku4k2\nRvFu8UYq3dX9rI1AIIBOGOf8/HwWLlwIwLRp0zh48GDbDmSZF154gZhzEmmce86iRYvYvn3wJ+lv\nqUil2LuXunMgcbDuCMVNp5mWOKlbua/7gpaZszXkpbzOfdE2garIzNmQmEi0tf0qYZlJNlyKGU2S\n+r34RW+gyAr3TLiDJVmLqPLUsHrXb1m987d8XLoNRdaxLPtqfjb3Ea7KWNDmYUyWZKYnTeb23OWo\nmsprJ97pRy0EAkELHbq1XS4XtnOik3U6HaFQCEWJnLpgwYKLnmNvDpqyWq04nR2vRcbGWlCU7s3g\n+gK3N4g57MccF0NiYvtrzh0d709UTeW9/PeRkLhnxi0kRvecrD2ptzEzhXLAEvbR6AletO+T1VU4\ndWbGjU3t8Npx8TYMRj0egw1jY0OPyTrQxvr+pJWkxyXxj/2vMzl5LEtHLWJm+lSUDrwjSxLmsq1q\nB4eqCykLnWZa6sR22w80vfsKoffwob917tA422w23O6zMxdVVVsNc2fOcbvdRHWiUERDQ/v7Wfsb\nb6MDGY2w0dxu4FNior1HA6N6mt2VezntKGNOygyMAVuPydrTegfCkXvMEvZRVNp4Qd9qMEiovo5G\nYyJZidZOXTs9wUp9sRlrfQ3VFQ1IHdzHHTFQx3pO3GxmLprROkNu6GCveAvLc27gcPVx/vzZOn48\n+3uXXO4YqHr3NkLv4UNf6dzeA0CHbu28vDy2bNkCQEFBAbm5uR1eMC8vj82bNwOwZcsWZsyY0VlZ\nByTBUBjJG/mCu5xtVP1NWA3zTvFGdJKuW3WW+xIlOvJAF42f8toL3dqhulokTaNeH8XkkfGd6jMj\n0YZDZwVNay1vOVTpThxBui2VBWmzqfRUs7VsRy9IJRAIOkuHxnnp0qUYDAZWrFjBE088wY9+9CNe\neOEFPvzww0ues3LlSo4fP87KlSt5+eWX+fa3v92jQvc1jh7IDjYQ+LRiN7XeOhakzSHBPLCj5yWj\nCUmvJ4oAdQ4f/mC4zXF3WQUAWmx8u+k9zyUzyUZTcxTzUIvY7iluHLkMk87Eu8UbcQcHtjdLIBjK\ndOjXk2WZX/ziF21eGzVq1AXtNm3a1Pq32WzmmWee6QHxBgZN7uBlZwfrbwLhIOuLP0Av67kuZ0l/\ni9MhkiShi4rC4vGiAZV1HrJTzj4YlR8vQQ/EZmd0us+MRCuHWiK2h2BQWE9gN9i4fsQSXj/xLu8V\nv89tucv7WySBYFgyuPcE9RFtU3cOvplzWA3zt8NrcQSaWJx5BdHGwaGDzh6Fwe8BTaPivIjt+lOl\nAGSNy+l0f5lJZ7dTBYfYdqqe5KqMBSSY4vikbAcOf1N/iyMQDEuEce4ETZ4AtrAXoN9zYUMk4rqw\n/jiflu/CE/R22PYfha+wt+YAo2NGcP0gmDW3oERFIalhjGqQ8vOCmloSkIyYOLLT/VlMeuSYWGDo\n7XXuSRRZ4drsxYS0MB+e3tLf4ggEwxKRvrMTONwBrM3GWenH2st13gZ2VH7GjorPqPdFAppeOf4W\nC9LmcHXmQmJNbbNkaZrGP4+9yc7KfLKjMnlgypcvmdpxIKLERgxpTMhJxTlBYdUNHqxeB36DBYOt\na9naotOS4Qh4q4dOCs/eYHbqDN4tfp+t5Tu4Nmdxm4xjAoGg9xHGuRM4XH6iQ80z55j+Mc5vF21g\nw6lNaGgYdQbmp84izhTH1rLtbDqzlY9LtzE1cRIZtjTiTbHEm+MoqD7AlrLtpNtS+dbUr2BSTP0i\ne3cxZuUAkBlqoOwct/aB4zWkB10EU7O63GdKWjw+2YBWMzQqU/UWelnhmqxFvHriHTaf2cYNIy+v\nRrdAIOgawjh3ggann7SwF2QdOmvfB4QVO06z4dQm4kwxXJ9zDdOTpmBSIhHKS7OvZHdVAR+e3sze\n6v3srd7f5txkSyLfnvZVrHpLn8t9uZhGjABghNbI3gYvtQ4vCdFmig4Xk4mGPT21y322rDsnOBrQ\nNK3fa2kPZBakz+VfJZv4uHQbS7IWDbqHO4FgMCOMcyeod/qxh72RNdA+zqsdVsO8fPQ1NDTuHn8H\nY2LbrrEqssK81JnMScmj2lNLrbeOOl8Ddb56wmqYpdlXEWUYHAFg52NMS0fS60kP1BNWNX72512s\nXJJLXUkkGMyekdblPjOTbOxVrCR5GlA9HnQ9UMRkqGLUGVicsZB3ijfwSflOrsm6sr9FEgiGDcI4\nd4IGhxdryIsuJrHPr721bAdnXOXMSZlxgWE+F1mSSbEmkTKEyv5JioIxMwvtVDFfXjGKFz86xZ/f\nO8IMb6QGsT6p67omx1pwGWzgiQSFdcc4N3z4Pr6ikzhi7ATQYZ81F1NOTpf7GQxcmTGPD05/zIen\nt3Bl+nz0ugurgwkEgp5HRGt3QDCk4nd5ULQwSh9Hajv8TbxdtAGLYuYLo2/o02sPFEw5I0BVmRkd\n5LFVsxiRGkVsMJJWz5DUcQ3q85FlCSkmkoDFV9P1oLBQUxM1a1/EuXMHVRvep2HDv6j62wtd7mew\nYNFbWJg+j6aAkx2Vn/W3OALBsEEY5w5odPmxhZtTd/axcX71+Nv4wj5uHnU9dsPgTH5yubSsO/uK\ni0mOtfDju/OYlxZx+OgTu+clMCUlAFB3uqLL57r27gFNI+6m5Uz/3X9jzh2L/3TJkN43fXXWQvSy\nwr9ObRJZwwSCPkIY5w6ob/JhDTWn7oyO6aB1z1FYf5z86n1kR2WyIG12n113oGHKaTbOp4oAkMIh\n1DMl6KKju71eHJOeAkBTRddrF7v2RGaP0fOvwJKRgX1WZGzc+wq6JctgIMpgZ1n2Ehr9Dv52+GVU\nTe1vkQSCIY8wzh3Q4Oz7mbOmabx6/G0kJFaM/QKyNHyHSZ+cgmw24ztVDIDrs92EXU6i5s7rdp/J\nOZFAMl8Xt1OF3W48hUcwZuegT4zEH1inTovIVbC32/IMBpblLGZc7BgO1h3hnaOXzqsvEAh6huH7\nrd9JGpx+bM17nPvKOB+pP0a5u5IZyVPJsnc+d/RQRJJljNk5BCsrCXs8NH70IUgS0Vdd3e0+M0am\nEUYCR9cqU7kK9kI4jH3GTJyeANv2lfPuIQdKRiaewiOEve1naxvMyJLMvRNXEGWw8+L+NyhynOpv\nkQSCIY0wzh1Q3+RvzQ7WV27tTWe2ArAkc1GfXG+g0+LadmzdjK+oCOvkKRi6ud4MYDEb8BhsGNwO\nNE3r9HktLu0/Fxv4zjOf8OTfdvPWtlMU27MgHMZz6GC3ZRoMRBnsfHninWhoPH/wH7iCF5byFAgE\nPYMwzh1Q7/RhbZ05975xrnBXcaT+GKOiR5AVNbxnzS20GOe6N18HIGbx5ecHD1qjsIY8NDR2LsBJ\n9XnxHDqIwxrPYafC+OxY7r5+PIkxJj7yRKK/XfuGtmsbIDd2FLdPvJFGv4P/2/cXdlfuxRlw9bdY\nAsGQQ+xz7oAGp59xanNAWFRUr1/vo+ZZ89VZC3v9WoOFlohtLRBAn5iEZeKky+5Tjo1DaiijrKiM\nuBm5HbZ37d+HFgpxwJ7OpBFxfP+OaSQm2lFDYf6x0UvQYse9fx9aOIyk0122fAOZL0y4jiOVReyv\nPUTx4RIkJLLsGWRGpeMP+XGHPHiDXmRJx8L0ucxInjqs4yYEgu4gjHMH1Dv9RKk+ZKsVWd+7CRhc\nATe7KveQYIpjSsKEXr3WYEKJi0dntxN2OolZfHWPZGkzJyVCEdSUlENnjHN+xKV91JbNXTPPejSu\nmJzKG1uLKDSlM7m+EO/JE1hyx162fAMZWZL5+uR7KHNVcLj+KIfrjnLScYoS55k2bTRN46SjmPeK\n32dZztXMSp6OTh7aDy4CQU8hjHM7hMIqTe4A1pAHJS6h16+3tWwHQTXEVZlXiJnGOUiShGXCJNwH\n9xO1oGc8CjGZaXh3gKu0vMO2mqriPnyYRr0NKTmVSSPjW48ZDToW56VzuC6dyRTi3rd3yBtniIxJ\nhj2NDHsa12YvxhvyUe9rwKyYsCgWjDoDdb56NpZ8xI6KfNYcWcf6Ux/yzamrSLb0faY9gWCwISxA\nOzQ6/ejUMIaQv9fXm4NqiC1ln2LSmZiXOrNXrzUYSb7vy4z4j6d6LBd2/JhmV3lVx8Y5UFaG5vVw\nxpTMkpmZyOcVy1iSl0G5LQUVCe+JEz0i32DDrJhIt6USZ4rFpBiRJIkEczx3jruVx+Y9whXpc6n1\n1vGnA2sIhAP9La5AMOARxrkd6p3nRmr37nrznqp9NAWczE+bJar/XARZb0Bn67ksaab0DDTA0lRD\nIBhut63r2FEAKmwpXDH5wkpY0TYjsyZnUGOIwVtSghZuv7/hRpwplpVjb2FR+nzK3ZWsPfp6l6Lk\nBYLhiDDO7VDv9GEL936ktqqpfHhmCxISV2Us6LXrCM4iG434bbEk+RsorWk/2rhi7wEAUqZNwmy8\n+ErQtbMyqTDFI4WCBMrLelzeocAtY24k257Jzsp8Pq3Y1d/iCAQDGmGc26FtApLeM84FNQcpc1Uw\nI3kq8ea4XruOoC1aUhpmNUBZ0aWNqaZphItP4NaZmH/l5Eu2S0+04YmPZB5znyzqcVmHAnpZ4SuT\nvoRFMbPu2JuccYqHGIHgUgjj3A5tE5D0TnawsBrmnaINyJLMDSOW9so1BBcnemQ2AKf3H79km/IT\npzH73Tji0klLaN+tHps7BoCqQ4U9J+QQI94cy70TVhBSQ/zpwBo8waGbVU0guByEcW6HvkjdubMy\nnypPDfNSZ5EkwR4MWQAAIABJREFUolj7lPjcUQB4Tp/G5Q1etM2hLfkAxE4c32F/o/PGEZR0+Jvz\ngAsuzqSE8SzLvppaXz2vn3i3v8URCAYkwji3Q4PTh11tNs4xPe/WDoaDvFv8PnpZ4XMjrunx/gXt\nY0yP7FeO99XzWeGFFaqCIRV3YSQYbPS86R32l5sdT40pDlNjDWpQRCS3xw0jlpJuS+XTil2caBQP\nMwLB+Qjj3A71TX5i8AOgi+r5mfOWsu00+h0syphPjLFva0ULiFSWMhhICjSy83DVBcf3HKsh2VVJ\nWDFgycnpuD9FJpiUjqypVB66tKtcADpZx8qxX0RC4sXCVwmqof4WSSAYUAjjfAlaEpDYVR+SwYBs\nNvdo/96Qjw0lmzDpTFybvbhH+xZ0DkmWMWVkkBB0cOJ0HfVNvjbHt+86TkLQgWHEyE6n5IwaMxqA\nMwWHe1zeocaI6CwWps+jylPN+yUf9bc4AsGAokPjrKoqP/3pT7njjju4++67KSkpaXN83bp13HLL\nLdx+++189FHkA9bY2MicOXO4++67ufvuu/nrX//aO9L3Io0uf2QfbNCDEh2NdF7iictl0+ktuIMe\nrsm6Epu+ZxJrCLqOMSMTWVOJCzSx68hZ13ZVvac1oUjMhI7Xm1vIyZsIgLtIRGx3hptHXUe0IYoN\npzZR5b5waUEgGK50aJw/+OADAoEAL7/8Mg899BBPPvlk67GamhrWrFnD2rVref7553n66acJBAIc\nPnyYG2+8kTVr1rBmzRruvffeXlWiN6hv8oOmYfC7e9ylXewo4YPTm7HrbSzOvKJH+xZ0DUPzunNy\nsJEdhytbX9+8r5xMX8RYmMd0nHu7haTR2QR0esy15R0mNxFEMovdnruckBbmpaOvieQkAkEzHRrn\n/Px8Fi6M5DOeNm0aBw+erVm7f/9+pk+fjsFgwG63k5WVRWFhIQcPHuTQoUN86Utf4sEHH6S6evA9\nETc4/VjCPiRN69FgsNPOUn6373lCWpiV427BpBh7rG9B1zFmZAIw3uzldJWLrfvLeeaV/fxrRwlj\nvGVIioJpxMhO9yfJMv6ENOICDo6eqOz4hEsQCIYJhtRunz+YmJo4ickJEzjeWMTmsk/7WxyBYEDQ\nYeELl8uF7Zy0iTqdjlAohKIouFwu7HZ76zGr1YrL5WLkyJFMmjSJ+fPn89Zbb7F69WqeeeaZdq8T\nG2tBUQZOxZqAWtWaHcyekkhior2DM85yqbZnHOX8ft/z+EJ+vj3nPhbmzO4RWQcKXXmPBgpB0zhK\ngRE6NwAvvBfZozwvxkfsSQfxi64gOePSRU8upnP8+LEEqkooP3iUqxeN67JMDU0+Hvm/7Tg9AfLG\nJjF3UiqzJ6ZgM/duVbSu0NNj/cC8u3h04xO8evxtRqdkMD318suC9gaD8R7vCYaj3v2tc4fG2Waz\n4Xa7W/+vqiqKolz0mNvtxm63M2XKFMzNAVRLly7t0DADNDR0ruh9X3GmwoG1eY9zQG+mpsbZqfMS\nE+0XbVvlqeE/9/wBZ8DNXeNuZZx1fKf7HAxcSu/BgBIbi1Zbybi8GKxmPctmZ2F7/xWaAOPMeZfU\n61I6x+SOovpjqD5QSHX14i7FK4TCKr9ZW0Bto5cYm4HtByrYfqCCWLuRx78yG4up/w1074y1nq9P\nupdn9j7Lb7f9ke/nPUCmPb2Hr3F5DOZ7/HIYjnr3lc7tPQB06NbOy8tjy5YtABQUFJCbe3b9bcqU\nKeTn5+P3+3E6nZw8eZLc3Fz+/d//nQ0bNgCwfft2Jk6ceLk69DkNTj+xwcjg6BO7nxwkpIbYVraT\n/9rzfzgDLm7LXc78tKE1Yx7sGNIzCTc28NDNuXzrC5MZGW/EuXsXSnw8lnGdDwZrwTo6kikszlHO\nyfKmLp376uaTHDvTyIyxifz2Wwv4j6/N4YopqTQ4/azfebrLsgwmRkZnc++ElQTDQf6w78/U+xr6\nWySBoN/o0DgvXboUg8HAihUreOKJJ/jRj37ECy+8wIcffkhiYiJ33303d955J/feey/f+973MBqN\nPPTQQ7z00kvcfffdrF27ln/7t3/rC116lKoGL4nhyBerIfnCSkQdEVRDbCndzmPbf8WLR1/FE/Jy\n65ibRWGLAYipeQ9z/fpItirnZ7vQ/H6iFyxEkru+21AfF4caHUeGt5qdhzq/7ry7sJoNu86QGm9h\n1efGI0kSqfFWvrQ0l1i7kfd3n6HB6e+yPIOJ6UmTuWX0DTgCTn6/788ivadg2NKhW1uWZX7xi1+0\neW3UqFGtf99+++3cfvvtbY5nZmayZs2aHhKx7wmFVSrq3FyjRVz2hpSUTp+raRr5Vft47cQ7NPod\n6GWFxZlXcE3WlSLRyAAldukynJ/tomHDegxpaTg+2QqSRNSC7kfSR40fh2vHp5wsOEr4mjHoOjDy\n9U0+/vzeEYwGHd/6wmTMRgXPkcOofj+2adNZfsUI/rK+kDc/KeK+67s+mx9MLM5cSK2vgc2l23hs\n+1MsypjHooz5RBmG37qnYPjSoXEejlTWewirGjF+B0psLLKpc/WVazx1PLflL+yrPIwiKyzJXMSS\nrCuJNoovlYGMzmol/f99l9P/8ThVf/sLhMNYJkxEH3/pQLCOsOaOxbXjU2Ibyig83cjEnParjb2x\ntRh/IMyXrx9HaryF+vXvUfvqOgDiblrO/BtvZsOu02zdX8G1s7JISxi6e+MlSeLWMTdh11v5qPQT\n1p/6kPdPb2ZOSh5TEiaSYI4n3hSLXtf/6+8CQW8hjPNFKK12oVeDmLxNGHImdNg+rIbZWPIx/yr5\nkJAaYnxcLrfnfp4kS/e/3AV9iyE5hbRvfpvS//wNAFFXLLys/szNsRmZ3ip2Hq5q1ziX1bjYdrCC\n9EQr8yckUf33v+HY/BFKbCySolD/9puEGhq4ddHn+J/XD/Pq5pP8vy9OuSz5BjqyJHP9iGtYkrWI\nHRWf8eHpLWwr38W28rN1oGOM0eREZTIjeRqT4sdjEMZaMIQQxvkilNa4zwaDdeDS1jSNl4+9wbby\nnUQZ7KyacTujTbk9nlFM0PtYxo0n9Stfx7VvL7bpMy6rL31yCjp7FFm+Gt4vrObua8eiVy7u2n51\ncxGaBl+8chS1L/0dx5aPMWZmkvbg95FkmbL/+S+aPtlCSijE6IwZ7D1eS0mlk+yUoe+RMegMLMqY\nzxXpczlUV0iZq4I6bz213nqqvbUU1BykoOYgRp2BKQmTWJQxl5HROf0ttkBw2QjjfBFKa1zEBxwA\nGFLaDwZ7v+RjtpXvJMOWxnem3092WtKw23YwlLDPnoN99pzL7keSJMy5uYTzP8PgbuRgUR3Tcy+M\n+j92ppGCE7XkZkQz3hqgZOtmDOkZZDzyY3TN2xEzH36UM796AueOT7np61fwn6UONu0p5cufG9pr\nz+ciSzKTEyYwOeGsJ0vTNMrdlXxWVUB+VQG7q/bwWdVerh9xDdfnLEGWROkAweBF3L0XobTGRZrU\nEgx2aeO8u3IvbxatJ9YYwwNTv4xF37PFMQSDG/OYsQBkeqvZeeTCqleapvHK5pMA3Lp4NA3vvQua\nRvzNn281zACyyUTcDTcCkFi4k4RoEzsPV+H2XbwG9XBBkiTSbaksH3U9P5/3Qx6c9nViTTG8V/w+\nvyt4HmfA1d8iCgTdRhjn8/D4gtQ3+UnTIh/sSxnn4w0n+fuRdZgVE9+cukpEYgsuoGXdOVerY8+x\nWgpL2u7b3bj7DCdKHUwfk0CW4qNp53YM6RnYpudd0Jdt+gz0iYk4P93GNeOjCYRUth3ofnrQoYYk\nSYyNG80PZ32HSfHjKGw4zhO7/kvUihYMWoRxPo/SmsiMOTbQhGQwoMTGXtCmylPDswf+hgZ8ffI9\npNk6v9VKMHwwZmQim82MDtWiaRr/9co+jjQb6Hc+PcXLm04QbTNwx5Ix1L/3Dqgq8TfefNG91ZIs\nE7N0GVooxKTaIyg6mY/2lolCEedh1Vu4f8p9LB91Pc6gi2f2PsdnVQX9LZZA0GWEcT6P0hoXaBpm\nZx2G5OQLvihVTeXvR9bhDXm5a9yt5MaO7idJBQMdSZYxjRqD3FDLt67NRlU1/vuf+/jj24d4bUsR\n8VFGfnhXHrFBF03bt2FITcM2Y+Yl+4tesBDZYsX7yWbmjImlqt7TauwFZ5ElmWuzF/PtqV9FL+v5\ny6GX+PjMtv4WSyDoEsI4n0dpjRt7yIMUCl7Upb2lbDtFjhLykqYwJ/XyInoFQx9Ls2t7ZKCab98y\nGVXT2H6oiqRYMz+8awbJsRbq3n0LVJW4S8yaW5CNRmKuWkzY5WQRZQB8tKesT/QYjIyNG813876B\nzWDln8ff5O2iDcLTIBg0CON8HqXVLhKCkbSd+vOMc72vgbdOrseimLktd3l/iCcYZFinTgOg8cMP\nmDwynu/eNpUrJqfyw7vyiI824S8vo2nbJxjS0rHP6jjneszV14BOhz7/E7KSrOw9XjvkU3peDpn2\nNB6e8S0SzPH869SHvFj4KoHw8A6kEwwOhHE+B03TKKt1kaOP5PM9d+asaRprj76OPxzgljE3iVSC\ngk5hTM/AOm06vpMn8B4tZEJOHKtuGE+MLVLHu/bVf4KmkfDF2zqVx1uJicE+YyaBinKWpYRQNY31\nO0t6W41BTYI5nodmfJNMWxqfVuziyd3/RZHjVH+LJRC0izDO51DX5MPrD5MutURqnw30+qyqgEN1\nhYyLHcPcFOHOFnSe+BtuAqDunbfavO45dhT3vgLMY3KxTpna6f6ir1wMQHbpARJjTHy0p4zqRlEg\noj2iDHa+P+ObLM68gmpPLU/n/4FXj79NIBzob9EEgosijPM5lFafjdSGSEpHAFfAzSvH30Iv61k5\n7haR/UvQJUwjRmKZOAlv4RG8x48DEU9M7SuR3NkJt97epXvKnDsWQ0oq7j2f8cWZyYRVjde3FHVJ\nJn8wzNb95Tz39iG27CvHFwh16fzBiEFn4NYxN/O9vAdItMSz6cxWfrHjN7xy/C0O1h7BFxLLA4KB\ng8gQdg6lNZEZs9lZhxIb11rw4pXjb+MKuvnC6BtIMMf3p4iCQUr8jTfjOXSQunfeJHbZ9bg+24Wv\n6CS2GTMxj+paxL8kSURftZiatS8yqvYo2SmJ7DxcxXWzszpM6dng9LN+RwnbDlbi9UcM8o5DVaz9\n8DhzJiRz0/wc4qI6V+hlsDIqJocfzfoe7xZvZHPpp3x05hM+OvMJOklHdlQGMcZobHorNr0Vu8FO\nmi2FDFsaIJayBH2HMM7nUFoTKXghOx0Yxk8E4FBdIbur9pBlz2BxRvdLCAqGN+YxuZjHjsNz6CCe\nQwcB0NmjSLjl1m71FzVvAbWv/pOmzR9z29cf4Tcv7+efH5/g4RXTL3nO0dMN/P6Ngzg9QaKtBpbM\nyGH6mAT2nahl6/4KNheUc6i4nh/elTfkDbRBp+cLo2/gxpHLKHac4kj9cQrrj1PsOI3GhRHdEhLp\nUSmkW9KYkTyNCXEif76gdxHG+RxKa9ykq2cLXvhCPl4qfA1ZkvnS+NvQybp+llAwmEm8bQU1L7+I\nMWcE1slTMI/JRdZ3r5KSzmrFPmsOTZ9+Qra3ikkj4jhYXM9nhdXMHJfUpq2maXyYX8rLm04AsGLJ\nGK7OS0dWQ6BqZM9K5aZ52by9vYS3tp3i1y/t5dG78lqD1oYyelkhN3Y0ubGjWT7qesJqGFfQHfkJ\nuGn0Oyh1lXPaWUqpq5zSpgp2VuaTYkliceYVzE6ZIaphCXoFYZybqXP4KK9183mqAbCMG8dbRf+i\nwd/IdTlLSLe1XwBDIOgIU04OmY/+uMf6i75qMU2ffkL9e+/wxS89wJGSyMz4qmlp3HrVaMxGHUdK\nGti4+wz7T9Zht+j55ucnMSpWR9Uf/gd3wd7WvnQxMSxd9TVCc7N5b0cJv1lbwCN3TifKYugxeQcD\nOllHtDGKaGNU62tziASAxidY2VNUyMel28iv2sdLR1/jraJ/cXXmIq7OvAKDbni9V4LeRffYY489\n1t9CAHg8/Rs1+XFBGYdPNXCDIx8l6Mfz+at5+cTbJFuS+PLEO9F1ssKN1Wrsd136g+God3/rrI+N\nw1dchOfwIZLGjiJvwWROljs4UFTP9kOVbNlXzsbdZ6hq8DImI5qH7phGfN0ZSp/+Df6SUxgzMzFl\n56BPSiZQVopz+zbGj4hDyxrJvpN1HClpYO6EZBRd23u/v/XuL2xWE/qwiWmJk5ifNhu9Ts/pplIO\n1h1hR8VuTDoT6bbUIVcNaziOd1/pbLVe2jsljDMRt9+aDUcxOOuZVf4Z5kmTWGM5ijvo4euT7yXB\nHNfpvobjjQzDU++BoLMpZwSNmz/CV3SSnBuWcWVeJjqdxMGiOjy+EHMmpHDv9WO5aX4Ovo/fp/LP\nf0QLBkm45TZSVn2NqHnziZo7D8uEiXgOHcRdsJcxiovQ2MnsL2rgTLWLWeOTkM9ZXx0IevcH5+pt\nUoyMjR3NFelzkZE41ljEvtqD7K0+gEUxk2xJHDJGejiOtzDO59Cfg3+m2sXbn57iOkMlCbUllORl\nsEup4MqM+SxMn9ulvobjjQzDU++BoLPOZkP1efEc2I+k12MbN46xWbEszstg2ews5k1MIdZmpO71\nV6l783WU2DjSv/swUbNntwlo0sfFETVvAf6SU3gOHmBivEx14kgOFNfT5A4wdVR8a/uBoHd/cDG9\n9bLC2LjRzE2diT8c4GjDCfbWHGBb+U58IR9JlkRMyuAOrhuO4y2M8zn05+Bv2HWGE2UObvQcQHI2\nsnZykDh7Il+ZdBeK3LVl+eF4I8Pw1Hug6GwaOYqmbVvxHDlM1Jy56CxWDHodBr0OTVWpWfsiDRv/\nhT4pmcxHfogxPf2i/cgGA7YZM3EfOojnwH5mTkjluBzP/pN1yLJEbmYMkiR1Su+KOjdHSho4UFTP\n7sJqTpQ6MBl0xNgMgzbKuT29TYqJyQkTmJU8HVmSOe0s40j9MT4u3caxhhOUuyvxBD3oZT0WxTyo\n3oOBcp/3JQPBOEvaAMkEX1Pj7JfrqqrGD/7wKbLHxVePraUiQeGd69P4wcxvk2xJ7HJ/iYn2ftOl\nPxmOeg8knR2fbKXqL88jm0zEXvc5Yq6+Bvf+Aurfe5dAeRmG9Awyvv8wSnRMh32FHI2c/uXjhOrq\nsN/5ZX5bqFDf5Gfm2ETuvX4cOZlxF9U7GFLJP1rNpr1lnCh1XLTvuCgjs8Ylcf3c7EEXbNaV8Q6E\nA3xWVcDWsh2ccZa12Z6lk3TY9BZsBhs2vZUoQxQJ5ljiTHEkmGNJsiQOqPrwA+k+7yv6SufExEvv\nnR/2xvnIqXp+vbaA5dFnGJ//EZ/k2Zm/4kHGxY3pVn/D8UaG4an3QNJZ0zQcH31I3VtvEnY5QZZB\nVUGWiZozj8Q7VqKz2Trdn7+8jDNP/geqz4ftnq/x11MGjpc6iI8y8r2VM4i36jEadKiaxolSBzsP\nV7G7sBqXN1JUYtKIOCaPjCcuykRclJH6Jh97jtWw70QdHn8Ii1Hh8wtHsDgvHV0ncooPBLo73r6Q\njzPOyHaskqYz1PkacAVcuIJufOGLZyVLMMeTGzOSMbGjyI0d1a/GeiDd532FMM7n0F+D/+d3j/DJ\noTPc5X2LzDMuah9cyfwpy7rd33C8kWF46j0QdQ57vTRs/BfOXTuxTJhA3LLr0Sd03QME4D15gtKn\nf40WCpHywLfZ5Izm7U9P0fKNYTYqKDoJpydikO0WPQsmpXLl9DSSYy0X7TMUVvlobxlvbC3G6w+R\nnmDl9qtHM2lE3IB39fbGeAfDQRyBJuq8DdT56qnzNVDqLOekoxhvyNfaLtOeztSESUxNnEiqNblP\n36uBeJ/3NsI4n0N/DL7LG+SR5z/AlvoZ9208STA2iqlPPnNZfQ7HGxmGp97DQWfP0ULK/vtpUFVS\n73+A8oRR5B+vpaLGRYPTj8cfYmJOHHMmJDMuOwadLKOFQviKiwlUVRCorCTscqKPT0CfnIwxIxND\nahpOb5DXtxSxpaAcDRifHctti0eRkxLVrjyNLj/HzjRyotTByXIHpTVuNE1DkiRkWSI7ycaEnDgm\n5MQxIs3eo7PyvhxvVVMpdZVzoqGIw/XHONpwAlVTI3KY4xkfN5ZxcaPJjR2FWTH3qizD4T4/H2Gc\nz6GvBz8QDPP4m2/TYNvJFzfXkl4TJGHlXcQtWXpZ/Q7HGxmGp97DRWf34UOUP/OfaKEQ1mnTGfuN\nr+JSrG3ahF0uPEeP4NqzB/f+AlTvpatkGdIziJq/gKi586jwK7zy8UkOFNUBkJ1sZ3xOLOOzY7GY\nFNzeIC5vkJJKF4dL6imrcbf2o5Ml0hOt6HUyqgaBUJjyGnfr6m6s3ciiqWksmppGrP3ys53153h7\ngl4O1RWyr+Ygh+uP4m+upiVLMln2DDJsqaRYk0mxJpFiSSLKYO+xjIbD5T4/F2Gcz6EvB98b9PH4\nB3/DYTzBos/cTD/mxjZjFqnf+OZlu4uG440Mw1Pv4aSz/8wZql/6O95jR5EUBWPOCJSoKGSzBf/p\nU/hLS2nxdytx8dimTcOYmYU+OQXFbidYW0ugqgrP0SO49++DcBh0OuwzZhKz+BpOKXG8s+M0x0sb\nCYUv/pWkV2RyM2OYkB3L6IxoclLs6JW2BsjlDXL0dAMHiurYdaQaXyCMLElMHR3PFZNTmTwq/oKk\nKp1loIx3WA1T3HSawvrjHG04zqmmM62z6hYkJCyKGZvB2lrEw6K3YNVbsCoW7EY7MYao1mxo7UWQ\nDxS9+5JBYZxVVeWxxx7j6NGjGAwGVq9eTXZ2duvxdevWsXbtWhRF4YEHHmDx4sXU19fz8MMP4/P5\nSEpK4oknnsBsbt/10ttvhKZplLrK2VmRzydn8glKXiaekLlmVyWGtDSyfvzT1ipUl8NwvJFheOo9\n3HTWNA3XZ7tpfOcNvOUVrcZYUhRMI0dhHjsO29TpGLOz233IDTudNO3eiWPzxwTKSgEwpKVhy5uB\nYfJ0zkjRFJ5pJBzWsJoVbGY9SbEWRqdHtTHGWjiM6vWiqRHDJEkSssWCpIu08QVC7Dxcxcd7yymp\nioyT3aJn9vhkxmfHkpsZg83c+bzYA3W8g+Eg1d5aKtxVVLqrqfJU4wy4cAbduAIu3EHPRYt5nItB\n1hNnim3+iSHWFEO0MZoYQxQjUlMJuWTMimnY1BcYFMZ548aNbNq0iSeffJKCggKeffZZ/vCHPwBQ\nU1PDqlWrePXVV/H7/dx55528+uqr/OpXv2LChAnccsstPPfccxgMBu677752hezpN8Ib8lLlqaHK\nXUOVp4YDtYcpd1cCoAX1WNwj+cbWfRAKkvVvP8OQktIj1x2oH+DeZjjqPRx1hoje1VUOwi4XqtuF\nkpCArO/6tihN0/AeO0rjpg9w7ytAC0VKWMpmM/rEJPRJyZEHZk0DVSXscRN2NhF2OiPXvpjrvNlA\nK/YolPh49PEJKPHxNClWDtSp7CrzUxfQ4Zf1IEmkJVhJiDYRYzMSYzNg0OuQJQmdrvnhouXbUYKY\naDMetx9FJ0f2kSuR30a9DqNBh1Evo+giPzo5cn5Y1VA1jVBIxR8MEwi2/A5HfodUwuFIG1XVkGUJ\nnRy5vlGvw2RQMBl0mI0KFqOC2aigV7o281c1FW/Ihzvoaf5x0xRw4fA34Qg00eh30OBrpN7XgCd0\n6eUIAJPOiFkxY1ZM6GU9ep0S+S3rUWQdiqygl5Xm33r0Lb91egyyHoPOgEHWo9cZMMgKep2+tZ1O\nUlBkHTpJh06WkSUdMhKyJEcevPow49pAMM4dZtjIz89n4cKFAEybNo2DBw+2Htu/fz/Tp0/HYDBg\nMBjIysqisLCQ/Px87r//fgAWLVrE008/3aFx7kn+e8+zHGs82eY1naRjWuIk8hKnU3vazrwr0pBy\npqGPi+8xwywQDBckWUaJioKo9gO42u1DkrCMHYdl7DhUnw/3oQO49u7Bf/o0gYpy/KdLLjxJp0Nn\ns6PExaOz2dBZrNDipg6rhN0uwi4nIYeDQGVFm1PHNf8AaJJMQDEQOCUTlHSotP3il9AiP5pGiw9A\nA0wRwQkh4ZdkNCRUSSYsyajIqJKEioQmyWiAJkV6ipwvtfYDEoftORyzZdNVlHMMt9GgQ6+TURQJ\nffNDgSzLyFLk/ZUkkCWJ2ROSmXVetbKL4Qv5qPc10uB34PA7aPQ78EteapoihtsT8uIJemnwOwiq\nQUJqqMvyXw7Suca6+e/zf3SSjE7Stfm/LOvQSTISMrJ09ryWfiKeHqn5HxiNegKBEDSPmUSkKMq1\n2Yv7rAhSh8bZ5XJhO2d/pE6nIxQKoSgKLpcLu/2s5bdarbhcrjavW61WnM6On0BiYy0oSs+4THIS\n0rGaTaTakkiLSibVnsyI2ExshuYglsktDa/qkeudT3tPQ0OZ4aj3cNQZekNvO2ReDdddDYCmqgTq\nG1CDgcgXpySjWK3orJZOx4WEvV78NTX4qmvw19QSqK0lUF9P0Okk6Ggi7PWiBoKEAwHUUBhN1Zrd\nvxJILT+6yG9avPhaxI2uqqCGImvnYRVJDSOdt+7bETnZ8Sy9eSqKTkKnixiNsKoRDquEwiq+QBiv\nP4THF8LjC+LxhXD7gnh9IbyBEF5/CKcnQDCkEgyphNVLO0HtNiOfWziqE1LZyaTzW+9UTSUUDhEI\nRwx1sOUnHCQYDhEIBwi0/g7gC0V++0MBAuFg8+tBAuEgYTVMSA0R0sKE1DCapqK2/jR7FzQVrfn3\nucfCWhhVjfw/pIWbHxzCqGqYsKZGftTwBWvzXSUvcyLTEnMvq4/O0qFxttlsuN1nIyRVVUVRlIse\nc7vd2O321tdNJhNut5uoTjxdNzR4uiP/RVmedeMFr3kdKl76xk0xXF2dw03v4agz9KXeBlDOcZd7\nVfC6utaFORayY1Gyc1GAi+++7hwd6a1pGmgaWjgcMd6aiqZGXmvdHK41PwBooLPbe3S/strsQg+r\nERe5pkVKG61vAAAOWklEQVQeNTQNrCal22PW+fGWAQN6DLSu5EtErMwAKk58roHXiLxnGpH3i+bH\ns/h4K7W1kXutZb1eJ8lY9JYevffbe8jt0Imfl5fHli1bACgoKCA39+xTw5QpU8jPz8fv9+N0Ojl5\n8iS5ubnk5eWxefNmALZs2cKMGTMuVweBQCAY0EiShCTLyHo9stGIbDKjs1jQWa0RF7zNhs5uj6yH\nR0X1eCIRWZZQdDJGffMatUmP1aTHZtYP+AQvfYksyehkXWQdXGfApBgxKyYsenNrRLvdaItEuhus\n2A027AYbFv3lPNp1nQ6fZ5YuXcq2bdtYsWIFmqbxy1/+khdeeIGsrCyWLFnC3XffzZ133ommaXzv\ne9/DaDTywAMP8Oijj7Ju3TpiY2P57W9/2xe6CAQCgUAwJBiW+5x7E+HqHD4MR51B6D3cGI56D4Ro\n7cGRcV4gEAgEgmGEMM4CgUAgEAwwhHEWCAQCgWCAIYyzQCAQCAQDDGGcBQKBQCAYYAjjLBAIBALB\nAEMYZ4FAIBAIBhjCOAsEAoFAMMAQxlkgEAgEggHGgMkQJhAIBAKBIIKYOQsEAoFAMMAQxlkgEAgE\nggGGMM4CgUAgEAwwhHEWCAQCgWCAIYyzQCAQCAQDDGGcBQKBQCAYYCj9LcBgRFVVHnvsMY4ePYrB\nYGD16tVkZ2e3Hl+3bh1r165FURQeeOABFi9e3I/S9hzBYJAf//jHlJWVEQgEeOCBB1iyZEnr8b/8\n5S/885//JC4uDoCf//znjBw5sr/E7VG+8IUvYLPZAMjIyOCJJ55oPTZUx/u1117j9ddfB8Dv93Pk\nyBG2bdtGVFQUAKtXr2bPnj1YrVYAfv/732O3X7p4/EBn3759/OY3v2HNmjWUlJTwwx/+EEmSGDNm\nDD/72c+Q5bNzGZ/Pxw9+8APq6uqwWq089dRTrff9YONcvY8cOcLjjz+OTqfDYDDw1FNPkZCQ0KZ9\ne5+FwcS5eh8+fJj777+fnJwcAFauXMnnPve51rb9Mt6aoMts2LBBe/TRRzVN07S9e/dq3/jGN1qP\nVVdXazfeeKPm9/u1pqam1r+HAq+88oq2evVqTdM0raGhQbvyyivbHH/ooYe0AwcO9INkvYvP59OW\nL19+0WNDebzP5bHHHtPWrl3b5rUVK1ZodXV1/SRRz/Lcc89pN954o3bbbbdpmqZp999/v7Zjxw5N\n0zTtJz/5ibZx48Y27f/85z9rzzzzjKZpmvbOO+9ojz/+eN8K3EOcr/ddd92lHT58WNM0TXvppZe0\nX/7yl23at/dZGEycr/e6deu0559//pLt+2O8hVu7G+Tn57Nw4UIApk2bxsGDB1uP7d+/n+nTp2Mw\nGLDb7WRlZVFYWNhfovYo1113Hd/5zncA0DQNnU7X5vihQ4d47rnnWLlyJc8++2x/iNgrFBYW4vV6\nWbVqFffccw8FBQWtx4byeLdw4MABTpw4wR133NH6mqqqlJSU8NOf/pQVK1bwyiuv9KOEl09WVhb/\n8z//0/r/Q4cOMXv2bAAWLVrEp59+2qb9ud8BixYtYvv27X0nbA9yvt5PP/0048ePByAcDmM0Gtu0\nb++zMJg4X++DBw/y8ccfc9ddd/HjH/8Yl8vVpn1/jLcwzt3A5XK1unUAdDodoVCo9di5rj2r1XrB\nQA9WrFYrNpsNl8vFgw8+yHe/+902x2+44QYee+wx/vrXv5Kfn89HH33UT5L2LCaTia985Ss8//zz\n/PznP+fhhx8eFuPdwrPPPsu3vvWtNq95PB6+9KUv8etf/5o//elPvPjii4P6oWTZsmUoytlVPk3T\nkCQJiIyp0+ls0/7ccb/Y8cHC+XonJSUBsGfPHv7+979z3333tWnf3mdhMHG+3lOmTOGRRx7hH//4\nB5mZmfzud79r074/xlsY525gs9lwu92t/1dVtXWgzz/mdrsH9Trc+VRUVHDPPfewfPlybrrpptbX\nNU3j3nvvJS4uDoPBwJVXXsnhw4f7UdKeY8SIEdx8881IksSIESOIiYmhpqYGGPrj3dTURHFxMXPn\nzm3zutls5p577sFsNmOz2Zg7d+6gNs7nc+76stvtbl1nb+Hccb/Y8cHMe++9x89+9jOee+65C9ZV\n2/ssDGaWLl3KpEmTWv8+/7urP8ZbGOdukJeXx5YtWwAoKCggNze39diUKVPIz8/H7/fjdDo5efJk\nm+ODmdraWlatWsUPfvADbr311jbHXC4XN954I263G03T2LlzZ+vNPth55ZVXePLJJwGoqqrC5XKR\nmJgIDO3xBti9ezfz5s274PVTp06xcuVKwuEwwWCQPXv2MHHixH6QsHeYMGECO3fuBGDLli3MnDmz\nzfG8vDw2b97cenzGjBl9LmNv8Oabb/L3v/+dNWvWkJmZecHx9j4Lg5mvfOUr7N+/H4Dt27dfcC/3\nx3iLwhfdoCVa+9ixY2iaxi9/+Uu2bNlCVlYWS5YsYd26dbz88stomsb999/PsmXL+lvkHmH16tWs\nX7++TQT2bbfdhtfr5Y477uCNN95gzZo1GAwG5s2bx4MPPtiP0vYcgUCAH/3oR5SXlyNJEg8//DD7\n9u0b8uMN8Kc//QlFUVrdmy+88EKr3n/6059Yv349er2e5cuXs3Llyv4V9jIpLS3l+9//PuvWraO4\nuJif/OQnBINBRo4cyerVq9HpdKxatYr/+7//IxwO8+ijj1JTU4Ner+e3v/3toDVSLXq/9NJLzJs3\nj9TU1NaZ4axZs3jwwQd55JFH+O53v0tCQsIFn4W8vLx+1qB7nDvehw4d4vHHH0ev15OQkMDjjz+O\nzWbr1/EWxlkgEAgEggGGcGsLBAKBQDDAEMZZIBAIBIIBhjDOAoFAIPj/7d1dSNNvH8fx95zLDoQQ\naoLGKnoYhERltkYLwxORKFtRkDSqAyHQHmiuBht5kJZumQ+FRRFBz5Fsmql5khE9kGZYLWpYamGQ\nRjqJxMzp/2A40tV9F7d/7xXfF+xg2/W7ftdvO/jy+45dHxFmpDgLIYQQYUaKsxBCCBFmpDgLMUE6\nOztJSEggPT19zOPSpUu/PZfL5cJqtQKQmZlJV1dXyBiTyRT8L+6/7dGjR5hMJgBsNhvPnz//6diy\nsjIeP348KesS4m8lqVRCTCC1Wk1VVdWEznnmzJkJne9/lZ+f/x/fb2pqQqfTTdJqhPg7SXEWYpJo\ntVq8Xi8QuDNubGykoKCABw8eUFBQwMjICHFxcRQVFY05LiUlhfPnz6NWq7HZbHg8HuLj4+nt7Q2O\nOX36NHV1dfj9fgwGAxaLBYVCQXFxMQ8fPqSvr4+YmBiOHz/OjBkzMBgMpKam0tzcjFKppKSkJGRH\nqHv37nHkyBGioqKYM2dO8HWTyUR2djazZs0iJyeH/v5+IiIisNvtdHR04PF4sNvtnDhxgr6+PoqL\nixkYGKCvrw+LxUJaWhpWq5Xo6GhevHhBV1cXWVlZbNy4EZ/Ph81mo62tjSlTpmC1WtHr9dy9e5ey\nsjKGhoaYOXMmhw4dIiYm5l/8toT4/5K2thATqLu7O6StPVqQf2RwcJCcnBwKCwuprq5Gq9UGM5TH\nu3DhAgB1dXXY7XbevXsHBLYT9Hg8VFRUUFlZSVdXFzdu3ODt27e0tbVx9epV6uvr0Wg0VFdXA/Dx\n40f0ej2VlZUkJSWFtN4HBwexWq2UlZXhcrmYOnVqyHoqKipYvXo1LpcLi8VCc3Mz69evJyEhgby8\nPLRaLRcvXiQvLw+3201+fj7l5eXB4z98+MDly5c5efIkDocDgNLSUjQaDXV1dTgcDkpKSujp6aGo\nqIizZ89SWVmJwWDg6NGjv/GtCPHnkTtnISbQ77a1vV4vsbGxwZi+ffv2AYE76/EaGxuDsY2zZ89m\nyZIlQGAv4GfPnrFhwwYgEAwfFxdHeno6Bw4c4Pr167S3t9PS0oJGownONxqBN3/+/JDfiL1eL2q1\nmrlz5wJgNBopLS0dM0av17Nr1y5evnxJcnIyW7duDVmz0+mkoaGBW7du8fTp0zEhIStXrkShULBg\nwQJ8Ph8QaImPFl6tVsu1a9doaGgIBq5AYPvcadOm/fcPV4g/mBRnISbRaBThaMyeSqUa8/7nz5/H\nFLDvKRQKhoeHg89Hk9D8fj/btm1jx44dQCBJSqlU4vF4MJvNbN++ndTUVCIiIvh+t97RrF6FQsH4\nXXzHn2t8djdAYmIiNTU13Llzh9raWtxuN+fOnRszJiMjA51Oh06nQ6/Xk5OT88Pzj7+mUW/evMHv\n97N06VJOnToFwNevX3/6GQnxt5C2thCTJCYmhtbWVkZGRrh9+zYQiODr6enh9evXQCBo4sqVKz88\nXq/Xc/PmTYaHh3n//j1PnjwBYMWKFVRVVfHlyxeGhobIysqivr6epqYmli9fzpYtW5g3bx7379/H\n7/f/0lq1Wi2fPn0KxkDW1NSEjHE4HFRVVWE0Gjl48GAwZk+pVOL3+/H5fHR0dLBnzx6Sk5N/6fzL\nli2jtrYWCBTmzMxMFi1aREtLC+3t7QCUl5cH2+BC/K3kzlmICTT6m/P3kpKSsNvtmM1mdu7cyfTp\n00lMTKS3t5eoqCicTif79+/n27dvaDQaHA4H9fX1IXNnZGTQ2tpKWloa8fHxwWjKlJQUXr16xebN\nm/H7/axatQqj0Uh3dzfZ2dmsXbsWlUqFVquls7Pzl65DpVJx7NgxLBYLkZGRLFy4MGSMyWTCbDbj\ndrtRKpXk5uYCgXZ5bm4uhYWFbNq0iTVr1hAdHc3ixYsZGBigv7//p+fdvXs3druddevWERkZicPh\nQK1Wc/jwYfbu3cvw8DCxsbE4nc5fug4h/lSSSiWEEEKEGWlrCyGEEGFGirMQQggRZqQ4CyGEEGFG\nirMQQggRZqQ4CyGEEGFGirMQQggRZqQ4CyGEEGFGirMQQggRZv4BP6vZguC+WcEAAAAASUVORK5C\nYII=\n", 284 | "text/plain": [ 285 | "" 286 | ] 287 | }, 288 | "metadata": {}, 289 | "output_type": "display_data" 290 | } 291 | ], 292 | "source": [ 293 | "plot_set1_intra = np.transpose(set1_intra,(1, 0, 2)).reshape(len(metrics_list), -1)\n", 294 | "plot_set2_intra = np.transpose(set2_intra,(1, 0, 2)).reshape(len(metrics_list), -1)\n", 295 | "plot_sets_inter = np.transpose(sets_inter,(1, 0, 2)).reshape(len(metrics_list), -1)\n", 296 | "for i in range(0,len(metrics_list)):\n", 297 | " sns.kdeplot(plot_set1_intra[i], label='intra_set1')\n", 298 | " sns.kdeplot(plot_sets_inter[i], label='inter')\n", 299 | " sns.kdeplot(plot_set2_intra[i], label='intra_set2')\n", 300 | "\n", 301 | " plt.title(metrics_list[i])\n", 302 | " plt.xlabel('Euclidean distance')\n", 303 | " plt.show()" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "metadata": { 309 | "deletable": true, 310 | "editable": true 311 | }, 312 | "source": [ 313 | "the difference of intra-set and inter-set distances." 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": null, 319 | "metadata": { 320 | "collapsed": false, 321 | "deletable": true, 322 | "editable": true 323 | }, 324 | "outputs": [ 325 | { 326 | "name": "stdout", 327 | "output_type": "stream", 328 | "text": [ 329 | "total_used_pitch:\n", 330 | "------------------------\n", 331 | " demo_set1\n", 332 | " Kullback–Leibler divergence: 0.254191068569358\n", 333 | " Overlap area: 0.556180263718\n", 334 | " demo_set2\n", 335 | " Kullback–Leibler divergence:" 336 | ] 337 | } 338 | ], 339 | "source": [ 340 | "for i in range(0, len(metrics_list)):\n", 341 | " print metrics_list[i] + ':'\n", 342 | " print '------------------------'\n", 343 | " print ' demo_set1'\n", 344 | " print ' Kullback–Leibler divergence:',utils.kl_dist(plot_set1_intra[i], plot_sets_inter[i])\n", 345 | " print ' Overlap area:', utils.overlap_area(plot_set1_intra[i], plot_sets_inter[i])\n", 346 | " \n", 347 | " print ' demo_set2'\n", 348 | " print ' Kullback–Leibler divergence:',utils.kl_dist(plot_set2_intra[i], plot_sets_inter[i])\n", 349 | " print ' Overlap area:', utils.overlap_area(plot_set2_intra[i], plot_sets_inter[i])\n", 350 | " " 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": null, 356 | "metadata": { 357 | "collapsed": true, 358 | "deletable": true, 359 | "editable": true 360 | }, 361 | "outputs": [], 362 | "source": [] 363 | } 364 | ], 365 | "metadata": { 366 | "kernelspec": { 367 | "display_name": "Python 2", 368 | "language": "python", 369 | "name": "python2" 370 | }, 371 | "language_info": { 372 | "codemirror_mode": { 373 | "name": "ipython", 374 | "version": 2 375 | }, 376 | "file_extension": ".py", 377 | "mimetype": "text/x-python", 378 | "name": "python", 379 | "nbconvert_exporter": "python", 380 | "pygments_lexer": "ipython2", 381 | "version": "2.7.13" 382 | } 383 | }, 384 | "nbformat": 4, 385 | "nbformat_minor": 2 386 | } 387 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 2.7.18 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mgeval 2 | 3 | An Objective evaluation toolbox for symbolic domain music generation. 4 | 5 | The work is published as [On the evaluation of generative models in music](https://link.springer.com/article/10.1007/s00521-018-3849-7?wt_mc=Internal.Event.1.SEM.ArticleAuthorOnlineFirst&utm_source=ArticleAuthorOnlineFirst&utm_medium=email&utm_content=AA_en_06082018&ArticleAuthorOnlineFirst_20181106) 6 | 7 | The article is provided as [journal online access](https://link.springer.com/epdf/10.1007/s00521-018-3849-7?author_access_token=Z7YxQv2K9z33nk1_XGlY9_e4RwlQNchNByi7wbcMAY5M_T6iwDlmVavmHfG20IIuk492IRWVj17BK1zhOxg5HA5fo8df4mI0b3U1YbTvprNarTF7BunHbKBquKplW2anwIy_TzUtUKq8g6tZzhCUzQ%3D%3D) and [downloadable preprint](http://www.musicinformatics.gatech.edu/wp-content_nondefault/uploads/2018/11/postprint.pdf) 8 | 9 | ## Introduction: 10 | 11 | ### Why? 12 | Machine learning and neural networks have demonsrate great potential in music generation. However, vary goals and definition of creativity makes evaluation toward generative music challenging. In recent research, subjective evaluations seem to the only viable way to do this. 13 | 14 | The goal of this toolbox is to provide an objective evaluation system to have a better reliability, validity, and replicability in the music generation. 15 | 16 | ### How? 17 | 18 | The toolbox propose a set of musically informed objective measures to obtain analyses that further driven series of evaluation strategy that involves: 19 | 20 | 1. Absolute metrics that can provide insights into properties of generated or collected set of data 21 | 22 | 2. Relative metrics in order to compare two sets of data, e.g., training and generated. 23 | 24 | ### Musically informed objective measures 25 | 26 | 1. Pitch count: The number of different pitches within a sample. The output is a scalar for each sample. 27 | 2. Pitch class histogram: The pitch class histogram is an octave-independent representation of the pitch content with a dimensionality of 12 for a chromatic scale. In our case, it represents to the octave-independent chromatic quantization of the frequency continuum. 28 | 3. Pitch class transition matrix: The transition of pitch classes contains useful information for tasks such as key detection, chord recognition, or genre pattern recognition. The two-dimensional pitch class transition matrix is a histogram-like representation computed by counting the pitch transitions for each (ordered) pair of notes. The resulting feature dimensionality is 12 × 12. 29 | 4. Pitch range: The pitch range is calculated by subtraction of the highest and lowest used pitch in semitones. The output is a scalar for each sample. 30 | 5. Average pitch interval: Average value of the interval between two consecutive pitches in semitones. The output is a scalar for each sample. 31 | 32 | 1. Note count: The number of used notes. As opposed to the pitch count, the note count does not contain pitch information but is a rhythm-related feature. The output is a scalar for each sample. 33 | 2. Average inter-onset-interval: To calculate the inter-onset-interval in the symbolic music domain, we find the time between two consecutive notes. The output is a scalar in seconds for each sample. 34 | 3. Note length histogram: To extract the note length histogram, we first define a set of allowable beat length classes [full, half, quarter, 8th, 16th, dot half, dot quarter, dot 8th, dot 16th, half note triplet, quarter note triplet, 8th note triplet]. The rest option, when activated, will double the vector size to represent the same lengths for rests. The classification of each event is performed by dividing the basic unit into the length of (barlength)/96, and each note length is quantized to the closest length category. The output vector has a length of either 12 or 24, respectively. 35 | 4. Note length transition matrix: Similar to the pitch class transition matrix, the note length tran- sition matrix provides useful information for rhythm description. The output feature dimension is 12 × 12 or 24 × 24, respectively. 36 | 37 | ### Dependencies 38 | --- 39 | * [`scipy`](http://www.scipy.org/) 40 | * [`numpy`](http://www.numpy.org) 41 | * [`pretty-midi`](https://github.com/craffel/pretty-midi) 42 | * [`python-midi`](https://github.com/vishnubob/python-midi) 43 | * [`sklearn`](https://scikit-learn.org/stable/) 44 | * [`pickle`](https://docs.python.org/3/library/pickle.html) (optional) 45 | 46 | ### To use 47 | --- 48 | 49 | #### Library Reference 50 | 51 | Detailed documentation included [here](https://github.com/RichardYang40148/mgeval/blob/master/mgeval/documentation.md). 52 | 53 | Demonstration of metrics included in [demo.ipynb](https://github.com/RichardYang40148/mgeval/commits?author=RichardYang40148) 54 | 55 | #### Standalone Module 56 | 57 | You can run mgeval as a standalone module with the following command on the root directory: 58 | 59 | ```shell 60 | python . 61 | ``` 62 | 63 | Provided both directories exist and contain valid MIDI files, this script calculates all available metrics for each set and save the result to `output_filename`, as a pickle. 64 | -------------------------------------------------------------------------------- /__main__.py: -------------------------------------------------------------------------------- 1 | 2 | import json 3 | from argparse import ArgumentParser 4 | import midi 5 | import glob 6 | import copy 7 | import os 8 | import numpy as np 9 | import pretty_midi 10 | from pprint import pprint 11 | import pickle 12 | from mgeval import core, utils 13 | from sklearn.model_selection import LeaveOneOut 14 | 15 | parser = ArgumentParser() 16 | parser.add_argument('--set1dir', required=True, type=str, 17 | help='Path (absolute) to the first dataset (folder)') 18 | parser.add_argument('--set2dir', required=True, type=str, 19 | help='Path (absolute) to the second dataset (folder)') 20 | parser.add_argument('--outfile', required=True, type=str, 21 | help='File (pickle) where the analysis will be stored') 22 | 23 | parser.add_argument('--num-bar', required=False, type=int, default=None, 24 | help='Number of bars to account for during processing') 25 | 26 | args = parser.parse_args() 27 | 28 | set1 = glob.glob(os.path.join(args.set1dir, '*')) 29 | set2 = glob.glob(os.path.join(args.set2dir, '*')) 30 | 31 | print('Evaluation sets (sample and baseline):') 32 | print(set1) 33 | print(set2) 34 | 35 | if not any(set1): 36 | print("Error: sample set it empty") 37 | exit() 38 | 39 | if not any(set2): 40 | print("Error: baseline set it empty") 41 | exit() 42 | 43 | # Initialize Evaluation Set 44 | num_samples = min(len(set2), len(set1)) 45 | 46 | print(num_samples) 47 | evalset = { 48 | 'total_used_pitch': np.zeros((num_samples, 1)) 49 | , 'pitch_range': np.zeros((num_samples, 1)) 50 | , 'avg_pitch_shift': np.zeros((num_samples, 1)) 51 | , 'avg_IOI': np.zeros((num_samples, 1)) 52 | , 'total_used_note': np.zeros((num_samples, 1)) 53 | , 'bar_used_pitch': np.zeros((num_samples, args.num_bar, 1)) 54 | , 'bar_used_note': np.zeros((num_samples, args.num_bar, 1)) 55 | , 'total_pitch_class_histogram': np.zeros((num_samples, 12)) 56 | , 'bar_pitch_class_histogram': np.zeros((num_samples, args.num_bar, 12)) 57 | , 'note_length_hist': np.zeros((num_samples, 12)) 58 | , 'pitch_class_transition_matrix': np.zeros((num_samples, 12, 12)) 59 | , 'note_length_transition_matrix': np.zeros((num_samples, 12, 12)) 60 | } 61 | 62 | bar_metrics = [ 'bar_used_pitch', 'bar_used_note', 'bar_pitch_class_histogram' ] 63 | 64 | for metric in bar_metrics: 65 | print(args.num_bar) 66 | if not args.num_bar: 67 | evalset.pop(metric) 68 | 69 | # print(evalset) 70 | 71 | metrics_list = evalset.keys() 72 | 73 | single_arg_metrics = ( 74 | [ 'total_used_pitch' 75 | , 'avg_IOI' 76 | , 'total_pitch_class_histogram' 77 | , 'pitch_range' 78 | ]) 79 | 80 | set1_eval = copy.deepcopy(evalset) 81 | set2_eval = copy.deepcopy(evalset) 82 | 83 | sets = [ (set1, set1_eval), (set2, set2_eval) ] 84 | 85 | 86 | # Extract Fetures 87 | for _set, _set_eval in sets: 88 | for i in range(0, num_samples): 89 | feature = core.extract_feature(_set[i]) 90 | for metric in metrics_list: 91 | evaluator = getattr(core.metrics(), metric) 92 | if metric in single_arg_metrics: 93 | tmp = evaluator(feature) 94 | elif metric in bar_metrics: 95 | # print(metric) 96 | tmp = evaluator(feature, 0, args.num_bar) 97 | # print(tmp.shape) 98 | else: 99 | tmp = evaluator(feature, 0) 100 | _set_eval[metric][i] = tmp 101 | 102 | loo = LeaveOneOut() 103 | loo.get_n_splits(np.arange(num_samples)) 104 | set1_intra = np.zeros((num_samples, len(metrics_list), num_samples - 1)) 105 | set2_intra = np.zeros((num_samples, len(metrics_list), num_samples - 1)) 106 | 107 | 108 | # Calculate Intra-set Metrics 109 | for i, metric in enumerate(metrics_list): 110 | for train_index, test_index in loo.split(np.arange(num_samples)): 111 | set1_intra[test_index[0]][i] = utils.c_dist( 112 | set1_eval[metrics_list[i]][test_index], set1_eval[metrics_list[i]][train_index]) 113 | set2_intra[test_index[0]][i] = utils.c_dist( 114 | set2_eval[metrics_list[i]][test_index], set2_eval[metrics_list[i]][train_index]) 115 | 116 | loo = LeaveOneOut() 117 | loo.get_n_splits(np.arange(num_samples)) 118 | sets_inter = np.zeros((num_samples, len(metrics_list), num_samples)) 119 | 120 | # Calculate Inter-set Metrics 121 | for i, metric in enumerate(metrics_list): 122 | for train_index, test_index in loo.split(np.arange(num_samples)): 123 | sets_inter[test_index[0]][i] = utils.c_dist(set1_eval[metric][test_index], set2_eval[metric]) 124 | 125 | 126 | plot_set1_intra = np.transpose( 127 | set1_intra, (1, 0, 2)).reshape(len(metrics_list), -1) 128 | plot_set2_intra = np.transpose( 129 | set2_intra, (1, 0, 2)).reshape(len(metrics_list), -1) 130 | plot_sets_inter = np.transpose( 131 | sets_inter, (1, 0, 2)).reshape(len(metrics_list), -1) 132 | 133 | 134 | output = {} 135 | for i, metric in enumerate(metrics_list): 136 | # print('calculating kl of: {}'.format(metric)) 137 | 138 | mean = np.mean(set1_eval[metric], axis=0).tolist() 139 | std = np.std(set1_eval[metric], axis=0).tolist() 140 | 141 | print(metric) 142 | pprint(plot_set1_intra[i]) 143 | pprint(plot_set2_intra[i]) 144 | pprint(plot_sets_inter[i]) 145 | 146 | kl1 = utils.kl_dist(plot_set1_intra[i], plot_sets_inter[i]) 147 | ol1 = utils.overlap_area(plot_set1_intra[i], plot_sets_inter[i]) 148 | kl2 = utils.kl_dist(plot_set2_intra[i], plot_sets_inter[i]) 149 | ol2 = utils.overlap_area(plot_set2_intra[i], plot_sets_inter[i]) 150 | 151 | print(kl1) 152 | print(kl2) 153 | output[metric] = [mean, std, kl1, ol1, kl2, ol2] 154 | 155 | 156 | # Save output 157 | if os.path.exists(args.outfile): 158 | os.remove(args.outfile) 159 | 160 | output_file = open(args.outfile, 'w') 161 | json.dump(output, output_file) 162 | output_file.close() 163 | 164 | print('Saved output to file: ' + args.outfile) 165 | -------------------------------------------------------------------------------- /demo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "source": [ 5 | "# Usage Demo : \n" 6 | ], 7 | "cell_type": "markdown", 8 | "metadata": { 9 | "deletable": true, 10 | "editable": true 11 | } 12 | }, 13 | { 14 | "source": [ 15 | "import midi\n", 16 | "import glob\n", 17 | "import numpy as np\n", 18 | "import pretty_midi\n", 19 | "import seaborn as sns\n", 20 | "import matplotlib.pyplot as plt\n", 21 | "from mgeval import core, utils\n", 22 | "from sklearn.model_selection import LeaveOneOut" 23 | ], 24 | "cell_type": "code", 25 | "metadata": { 26 | "collapsed": false, 27 | "deletable": true, 28 | "editable": true 29 | }, 30 | "execution_count": 1, 31 | "outputs": [] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": { 36 | "deletable": true, 37 | "editable": true 38 | }, 39 | "source": [ 40 | "## Absolute measurement: statistic analysis\n" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "deletable": true, 47 | "editable": true 48 | }, 49 | "source": [ 50 | "Assign dataset path" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 2, 56 | "metadata": { 57 | "collapsed": false, 58 | "deletable": true, 59 | "editable": true 60 | }, 61 | "outputs": [ 62 | { 63 | "output_type": "stream", 64 | "name": "stdout", 65 | "text": [ 66 | "['data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_12_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_08_R1_2013_wav--5.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_19_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_04_R2_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_11_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_01_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_06_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_02_7_10_13_Group_MID--AUDIO_12_R3_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_10_13_Group_MID--AUDIO_07_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_18_R2_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_15_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_18_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_03_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_10_13_Group_MID--AUDIO_07_R3_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_07_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_13_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_07_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_07_R2_2013_wav--2.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_19_R2_2013_wav--4.midi', 'data/output/ORIG-MIDI_03_7_6_13_Group__MID--AUDIO_10_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_12_R1_2013_wav--5.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_11_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_01_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_10_13_Group_MID--AUDIO_08_R3_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_10_13_Group_MID--AUDIO_12_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_10_13_Group_MID--AUDIO_17_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_15_R2_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_19_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_03_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_02_R2_2013_wav--5.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_12_R2_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_08_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_18_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_15_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_06_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_10_13_Group_MID--AUDIO_08_R3_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_18_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_03_R2_2013_wav--2.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_19_R2_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_07_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_14_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_16_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_10_13_Group_MID--AUDIO_12_R3_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_08_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_10_13_Group_MID--AUDIO_07_R3_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_13_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_11_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_18_R2_2013_wav--4.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_19_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_17_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_12_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_02_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_04_R1_2013_wav--3.midi', 'data/output/MIDI-UNPROCESSED_01-03_R1_2014_MID--AUDIO_01_R1_2014_wav--1.midi', 'data/output/ORIG-MIDI_03_7_10_13_Group_MID--AUDIO_17_R3_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_15_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_04_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_18_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_10_13_Group_MID--AUDIO_11_R3_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_02_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_6_13_Group__MID--AUDIO_09_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_03_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_03_7_6_13_Group__MID--AUDIO_09_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_06_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_03_7_10_13_Group_MID--AUDIO_18_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_01_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_15_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_02_R2_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_12_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_08_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_11_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_14_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_03_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_05_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_11_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_13_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_08_R2_2013_wav--2.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_17_R2_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_14_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_16_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_03_7_10_13_Group_MID--AUDIO_18_R3_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_12_R2_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_16_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_03_7_6_13_Group__MID--AUDIO_10_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_08_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_19_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_12_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_08_R2_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_07_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_03_7_10_13_Group_MID--AUDIO_17_R3_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_03_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_12_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_03_7_10_13_Group_MID--AUDIO_18_R3_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_17_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_04_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_6_13_Group__MID--AUDIO_10_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_03_7_6_13_Group__MID--AUDIO_10_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_14_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_05_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_6_13_Group__MID--AUDIO_09_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_13_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_11_R2_2013_wav--3.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_18_R1_2013_wav--5.midi', 'data/output/ORIG-MIDI_02_7_10_13_Group_MID--AUDIO_14_R3_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_10_13_Group_MID--AUDIO_08_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_10_13_Group_MID--AUDIO_15_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_04_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_02_R2_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_02_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_01_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_10_13_Group_MID--AUDIO_11_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_17_R1_2013_wav--4.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_15_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_04_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_7_13_Group__MID--AUDIO_14_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_08_R1_2013_wav--3.midi', 'data/output/ORIG-MIDI_01_7_8_13_Group__MID--AUDIO_02_R2_2013_wav--1.midi', 'data/output/ORIG-MIDI_03_7_6_13_Group__MID--AUDIO_09_R1_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_8_13_Group__MID--AUDIO_14_R2_2013_wav--4.midi', 'data/output/ORIG-MIDI_02_7_10_13_Group_MID--AUDIO_14_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_05_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_03_7_10_13_Group_MID--AUDIO_15_R3_2013_wav--2.midi', 'data/output/ORIG-MIDI_03_7_8_13_Group__MID--AUDIO_17_R2_2013_wav--2.midi', 'data/output/ORIG-MIDI_02_7_10_13_Group_MID--AUDIO_12_R3_2013_wav--4.midi', 'data/output/ORIG-MIDI_01_7_6_13_Group__MID--AUDIO_02_R1_2013_wav--5.midi', 'data/output/ORIG-MIDI_02_7_7_13_Group__MID--AUDIO_17_R1_2013_wav--2.midi', 'data/output/ORIG-MIDI_01_7_10_13_Group_MID--AUDIO_02_R3_2013_wav--1.midi', 'data/output/ORIG-MIDI_02_7_6_13_Group__MID--AUDIO_06_R1_2013_wav--1.midi']\n" 67 | ] 68 | } 69 | ], 70 | "source": [ 71 | "set1 = glob.glob('data/output/*')\n", 72 | "print(set1)\n" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": { 78 | "deletable": true, 79 | "editable": true 80 | }, 81 | "source": [ 82 | "construct empty dictionary to fill in measurement across samples" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 3, 88 | "metadata": { 89 | "collapsed": true, 90 | "deletable": true, 91 | "editable": true 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "#num_samples = 100\n", 96 | "num_samples = 20" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 4, 102 | "metadata": { 103 | "collapsed": false, 104 | "deletable": true, 105 | "editable": true 106 | }, 107 | "outputs": [], 108 | "source": [ 109 | "set1_eval = {'total_used_pitch':np.zeros((num_samples,1))}\n", 110 | "metrics_list = set1_eval.keys()\n", 111 | "for i in range(0, num_samples):\n", 112 | " feature = core.extract_feature(set1[i])\n", 113 | " set1_eval[metrics_list[0]][i] = getattr(core.metrics(), metrics_list[0])(feature)" 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "metadata": { 119 | "deletable": true, 120 | "editable": true 121 | }, 122 | "source": [ 123 | "repeat for second dataset" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 5, 129 | "metadata": { 130 | "collapsed": false, 131 | "deletable": true, 132 | "editable": true 133 | }, 134 | "outputs": [], 135 | "source": [ 136 | "# set2 = glob.glob('../data/set2/*.mid')\n", 137 | "set2 = glob.glob('data/baseline/*')\n", 138 | "set2_eval = {'total_used_pitch':np.zeros((num_samples,1))}\n", 139 | "for i in range(0, num_samples):\n", 140 | " feature = core.extract_feature(set2[i])\n", 141 | " set2_eval[metrics_list[0]][i] = getattr(core.metrics(), metrics_list[0])(feature)" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": { 147 | "deletable": true, 148 | "editable": true 149 | }, 150 | "source": [ 151 | "statistic analysis: absolute measurement" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 6, 157 | "metadata": { 158 | "collapsed": false, 159 | "deletable": true, 160 | "editable": true 161 | }, 162 | "outputs": [ 163 | { 164 | "output_type": "stream", 165 | "name": "stdout", 166 | "text": [ 167 | "total_used_pitch:\n------------------------\n demo_set\n mean: [62.35]\n std: [11.84176929]\n------------------------\n demo_set\n mean: [62.35]\n std: [11.84176929]\n" 168 | ] 169 | } 170 | ], 171 | "source": [ 172 | "for i in range(0, len(metrics_list)):\n", 173 | " print metrics_list[i] + ':'\n", 174 | " print '------------------------'\n", 175 | " print ' demo_set'\n", 176 | " print ' mean: ', np.mean(set1_eval[metrics_list[i]], axis=0)\n", 177 | " print ' std: ', np.std(set1_eval[metrics_list[i]], axis=0)\n", 178 | "\n", 179 | " print '------------------------'\n", 180 | " print ' demo_set'\n", 181 | " print ' mean: ', np.mean(set2_eval[metrics_list[i]], axis=0)\n", 182 | " print ' std: ', np.std(set2_eval[metrics_list[i]], axis=0)\n" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": { 188 | "deletable": true, 189 | "editable": true 190 | }, 191 | "source": [ 192 | "## Relative measurement: generalizes the result among features with various dimensions\n" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": { 198 | "deletable": true, 199 | "editable": true 200 | }, 201 | "source": [ 202 | "the features are sum- marized to \n", 203 | "- the intra-set distances\n", 204 | "- the difference of intra-set and inter-set distances." 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "metadata": { 210 | "deletable": true, 211 | "editable": true 212 | }, 213 | "source": [ 214 | "exhaustive cross-validation for intra-set distances measurement" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": 7, 220 | "metadata": { 221 | "collapsed": false, 222 | "deletable": true, 223 | "editable": true 224 | }, 225 | "outputs": [], 226 | "source": [ 227 | "loo = LeaveOneOut()\n", 228 | "loo.get_n_splits(np.arange(num_samples))\n", 229 | "set1_intra = np.zeros((num_samples, len(metrics_list), num_samples))\n", 230 | "set2_intra = np.zeros((num_samples, len(metrics_list), num_samples))\n", 231 | "for i in range(len(metrics_list)):\n", 232 | " for train_index, test_index in loo.split(np.arange(num_samples)):\n", 233 | " set1_intra[test_index[0]][i] = utils.c_dist(set1_eval[metrics_list[i]][test_index], set1_eval[metrics_list[i]][train_index])\n", 234 | " set2_intra[test_index[0]][i] = utils.c_dist(set2_eval[metrics_list[i]][test_index], set2_eval[metrics_list[i]][train_index])\n" 235 | ] 236 | }, 237 | { 238 | "cell_type": "markdown", 239 | "metadata": { 240 | "deletable": true, 241 | "editable": true 242 | }, 243 | "source": [ 244 | "exhaustive cross-validation for inter-set distances measurement" 245 | ] 246 | }, 247 | { 248 | "cell_type": "code", 249 | "execution_count": 8, 250 | "metadata": { 251 | "collapsed": false, 252 | "deletable": true, 253 | "editable": true 254 | }, 255 | "outputs": [], 256 | "source": [ 257 | "loo = LeaveOneOut()\n", 258 | "loo.get_n_splits(np.arange(num_samples))\n", 259 | "sets_inter = np.zeros((num_samples, len(metrics_list), num_samples))\n", 260 | "\n", 261 | "for i in range(len(metrics_list)):\n", 262 | " for train_index, test_index in loo.split(np.arange(num_samples)):\n", 263 | " sets_inter[test_index[0]][i] = utils.c_dist(set1_eval[metrics_list[i]][test_index], set2_eval[metrics_list[i]])" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": { 269 | "deletable": true, 270 | "editable": true 271 | }, 272 | "source": [ 273 | "visualization of intra-set and inter-set distances" 274 | ] 275 | }, 276 | { 277 | "cell_type": "code", 278 | "execution_count": 9, 279 | "metadata": { 280 | "collapsed": false, 281 | "deletable": true, 282 | "editable": true 283 | }, 284 | "outputs": [ 285 | { 286 | "output_type": "display_data", 287 | "data": { 288 | "image/png": "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\n", 289 | "text/plain": "
", 290 | "image/svg+xml": "\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n" 291 | }, 292 | "metadata": { 293 | "needs_background": "light" 294 | } 295 | } 296 | ], 297 | "source": [ 298 | "plot_set1_intra = np.transpose(set1_intra,(1, 0, 2)).reshape(len(metrics_list), -1)\n", 299 | "plot_set2_intra = np.transpose(set2_intra,(1, 0, 2)).reshape(len(metrics_list), -1)\n", 300 | "plot_sets_inter = np.transpose(sets_inter,(1, 0, 2)).reshape(len(metrics_list), -1)\n", 301 | "for i in range(0,len(metrics_list)):\n", 302 | " sns.kdeplot(plot_set1_intra[i], label='intra_set1')\n", 303 | " sns.kdeplot(plot_sets_inter[i], label='inter')\n", 304 | " sns.kdeplot(plot_set2_intra[i], label='intra_set2')\n", 305 | "\n", 306 | " plt.title(metrics_list[i])\n", 307 | " plt.xlabel('Euclidean distance')\n", 308 | " plt.show()" 309 | ] 310 | }, 311 | { 312 | "cell_type": "markdown", 313 | "metadata": { 314 | "deletable": true, 315 | "editable": true 316 | }, 317 | "source": [ 318 | "the difference of intra-set and inter-set distances." 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "execution_count": 10, 324 | "metadata": { 325 | "collapsed": false, 326 | "deletable": true, 327 | "editable": true 328 | }, 329 | "outputs": [ 330 | { 331 | "output_type": "stream", 332 | "name": "stdout", 333 | "text": [ 334 | "total_used_pitch:\n------------------------\n demo_set1\n Kullback–Leibler divergence: 0.0013766431838582623\n Overlap area: 0.893103183927\n demo_set2\n Kullback–Leibler divergence: 0.0013766431838582623\n Overlap area: 0.893103183927\n" 335 | ] 336 | } 337 | ], 338 | "source": [ 339 | "for i in range(0, len(metrics_list)):\n", 340 | " print metrics_list[i] + ':'\n", 341 | " print '------------------------'\n", 342 | " print ' demo_set1'\n", 343 | " print ' Kullback–Leibler divergence:',utils.kl_dist(plot_set1_intra[i], plot_sets_inter[i])\n", 344 | " print ' Overlap area:', utils.overlap_area(plot_set1_intra[i], plot_sets_inter[i])\n", 345 | " \n", 346 | " print ' demo_set2'\n", 347 | " print ' Kullback–Leibler divergence:',utils.kl_dist(plot_set2_intra[i], plot_sets_inter[i])\n", 348 | " print ' Overlap area:', utils.overlap_area(plot_set2_intra[i], plot_sets_inter[i])\n", 349 | " " 350 | ] 351 | }, 352 | { 353 | "cell_type": "code", 354 | "execution_count": null, 355 | "metadata": { 356 | "collapsed": true, 357 | "deletable": true, 358 | "editable": true 359 | }, 360 | "outputs": [], 361 | "source": [] 362 | } 363 | ], 364 | "metadata": { 365 | "kernelspec": { 366 | "display_name": "Python 2.7.18 64-bit ('2.7.18')", 367 | "language": "python", 368 | "name": "python271864bit271894de52302e004571a966b3cf0c9fedf6" 369 | }, 370 | "language_info": { 371 | "codemirror_mode": { 372 | "name": "ipython", 373 | "version": 2 374 | }, 375 | "file_extension": ".py", 376 | "mimetype": "text/x-python", 377 | "name": "python", 378 | "nbconvert_exporter": "python", 379 | "pygments_lexer": "ipython2", 380 | "version": "2.7.18-final" 381 | } 382 | }, 383 | "nbformat": 4, 384 | "nbformat_minor": 2 385 | } -------------------------------------------------------------------------------- /mgeval/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RichardYang40148/mgeval/1059c5a4c4128a15812376e2f62dce650e55cd96/mgeval/__init__.py -------------------------------------------------------------------------------- /mgeval/core.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | """core.py 3 | Include feature extractor and musically informed objective measures. 4 | """ 5 | import pretty_midi 6 | import numpy as np 7 | import sys 8 | import os 9 | import midi 10 | import glob 11 | import math 12 | 13 | 14 | # feature extractor 15 | def extract_feature(_file): 16 | """ 17 | This function extracts two midi feature: 18 | pretty_midi object: https://github.com/craffel/pretty-midi 19 | midi_pattern: https://github.com/vishnubob/python-midi 20 | 21 | Returns: 22 | dict(pretty_midi: pretty_midi object, 23 | midi_pattern: midi pattern contains a list of tracks) 24 | """ 25 | feature = {'pretty_midi': pretty_midi.PrettyMIDI(_file), 26 | 'midi_pattern': midi.read_midifile(_file)} 27 | return feature 28 | 29 | 30 | # musically informed objective measures. 31 | class metrics(object): 32 | def total_used_pitch(self, feature): 33 | """ 34 | total_used_pitch (Pitch count): The number of different pitches within a sample. 35 | 36 | Returns: 37 | 'used_pitch': pitch count, scalar for each sample. 38 | """ 39 | piano_roll = feature['pretty_midi'].instruments[0].get_piano_roll(fs=100) 40 | sum_notes = np.sum(piano_roll, axis=1) 41 | used_pitch = np.sum(sum_notes > 0) 42 | return used_pitch 43 | 44 | def bar_used_pitch(self, feature, track_num=1, num_bar=None): 45 | """ 46 | bar_used_pitch (Pitch count per bar) 47 | 48 | Args: 49 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 50 | 'num_bar': specify the number of bars in the midi pattern, if set as None, round to the number of complete bar. 51 | 52 | Returns: 53 | 'used_pitch': with shape of [num_bar,1] 54 | """ 55 | pattern = feature['midi_pattern'] 56 | pattern.make_ticks_abs() 57 | resolution = pattern.resolution 58 | for i in range(0, len(pattern[track_num])): 59 | if type(pattern[track_num][i]) == midi.events.TimeSignatureEvent: 60 | time_sig = pattern[track_num][i].data 61 | bar_length = time_sig[0] * resolution * 4 / 2**(time_sig[1]) 62 | if num_bar is None: 63 | num_bar = int(round(float(pattern[track_num][-1].tick) / bar_length)) 64 | used_notes = np.zeros((num_bar, 1)) 65 | else: 66 | used_notes = np.zeros((num_bar, 1)) 67 | 68 | 69 | 70 | elif type(pattern[track_num][i]) == midi.events.NoteOnEvent and pattern[track_num][i].data[1] != 0: 71 | if 'time_sig' not in locals(): # set default bar length as 4 beat 72 | bar_length = 4 * resolution 73 | time_sig = [4, 2, 24, 8] 74 | 75 | if num_bar is None: 76 | num_bar = int(round(float(pattern[track_num][-1].tick) / bar_length)) 77 | used_notes = np.zeros((num_bar, 1)) 78 | used_notes[pattern[track_num][i].tick / bar_length] += 1 79 | else: 80 | used_notes = np.zeros((num_bar, 1)) 81 | used_notes[pattern[track_num][i].tick / bar_length] += 1 82 | note_list = [] 83 | note_list.append(pattern[track_num][i].data[0]) 84 | 85 | else: 86 | for j in range(0, num_bar): 87 | if 'note_list'in locals(): 88 | pass 89 | else: 90 | note_list = [] 91 | note_list.append(pattern[track_num][i].data[0]) 92 | idx = pattern[track_num][i].tick / bar_length 93 | if idx >= num_bar: 94 | continue 95 | used_notes[idx] += 1 96 | # used_notes[pattern[track_num][i].tick / bar_length] += 1 97 | 98 | used_pitch = np.zeros((num_bar, 1)) 99 | current_note = 0 100 | for i in range(0, num_bar): 101 | used_pitch[i] = len(set(note_list[current_note:current_note + int(used_notes[i][0])])) 102 | current_note += int(used_notes[i][0]) 103 | 104 | return used_pitch 105 | 106 | def total_used_note(self, feature, track_num=1): 107 | """ 108 | total_used_note (Note count): The number of used notes. 109 | As opposed to the pitch count, the note count does not contain pitch information but is a rhythm-related feature. 110 | 111 | Args: 112 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 113 | 114 | Returns: 115 | 'used_notes': a scalar for each sample. 116 | """ 117 | pattern = feature['midi_pattern'] 118 | used_notes = 0 119 | for i in range(0, len(pattern[track_num])): 120 | if type(pattern[track_num][i]) == midi.events.NoteOnEvent and pattern[track_num][i].data[1] != 0: 121 | used_notes += 1 122 | return used_notes 123 | 124 | def bar_used_note(self, feature, track_num=1, num_bar=None): 125 | """ 126 | bar_used_note (Note count per bar). 127 | 128 | Args: 129 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 130 | 'num_bar': specify the number of bars in the midi pattern, if set as None, round to the number of complete bar. 131 | 132 | Returns: 133 | 'used_notes': with shape of [num_bar, 1] 134 | """ 135 | pattern = feature['midi_pattern'] 136 | pattern.make_ticks_abs() 137 | resolution = pattern.resolution 138 | for i in range(0, len(pattern[track_num])): 139 | if type(pattern[track_num][i]) == midi.events.TimeSignatureEvent: 140 | time_sig = pattern[track_num][i].data 141 | bar_length = time_sig[track_num] * resolution * 4 / 2**(time_sig[1]) 142 | if num_bar is None: 143 | num_bar = int(round(float(pattern[track_num][-1].tick) / bar_length)) 144 | used_notes = np.zeros((num_bar, 1)) 145 | else: 146 | used_notes = np.zeros((num_bar, 1)) 147 | 148 | elif type(pattern[track_num][i]) == midi.events.NoteOnEvent and pattern[track_num][i].data[1] != 0: 149 | if 'time_sig' not in locals(): # set default bar length as 4 beat 150 | bar_length = 4 * resolution 151 | time_sig = [4, 2, 24, 8] 152 | 153 | if num_bar is None: 154 | num_bar = int(round(float(pattern[track_num][-1].tick) / bar_length)) 155 | used_notes = np.zeros((num_bar, 1)) 156 | used_notes[pattern[track_num][i].tick / bar_length] += 1 157 | else: 158 | used_notes = np.zeros((num_bar, 1)) 159 | used_notes[pattern[track_num][i].tick / bar_length] += 1 160 | 161 | else: 162 | idx = pattern[track_num][i].tick / bar_length 163 | if idx >= num_bar: 164 | continue 165 | used_notes[idx] += 1 166 | return used_notes 167 | 168 | def total_pitch_class_histogram(self, feature): 169 | """ 170 | total_pitch_class_histogram (Pitch class histogram): 171 | The pitch class histogram is an octave-independent representation of the pitch content with a dimensionality of 12 for a chromatic scale. 172 | In our case, it represents to the octave-independent chromatic quantization of the frequency continuum. 173 | 174 | Returns: 175 | 'histogram': histrogram of 12 pitch, with weighted duration shape 12 176 | """ 177 | piano_roll = feature['pretty_midi'].instruments[0].get_piano_roll(fs=100) 178 | histogram = np.zeros(12) 179 | for i in range(0, 128): 180 | pitch_class = i % 12 181 | histogram[pitch_class] += np.sum(piano_roll, axis=1)[i] 182 | histogram = histogram / sum(histogram) 183 | return histogram 184 | 185 | def bar_pitch_class_histogram(self, feature, track_num=1, num_bar=None, bpm=120): 186 | """ 187 | bar_pitch_class_histogram (Pitch class histogram per bar): 188 | 189 | Args: 190 | 'bpm' : specify the assigned speed in bpm, default is 120 bpm. 191 | 'num_bar': specify the number of bars in the midi pattern, if set as None, round to the number of complete bar. 192 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 193 | 194 | Returns: 195 | 'histogram': with shape of [num_bar, 12] 196 | """ 197 | 198 | # todo: deal with more than one time signature cases 199 | pm_object = feature['pretty_midi'] 200 | if num_bar is None: 201 | numer = pm_object.time_signature_changes[-1].numerator 202 | deno = pm_object.time_signature_changes[-1].denominator 203 | bar_length = 60. / bpm * numer * 4 / deno * 100 204 | piano_roll = pm_object.instruments[track_num].get_piano_roll(fs=100) 205 | piano_roll = np.transpose(piano_roll, (1, 0)) 206 | actual_bar = len(piano_roll) / bar_length 207 | num_bar = int(round(actual_bar)) 208 | bar_length = int(round(bar_length)) 209 | else: 210 | numer = pm_object.time_signature_changes[-1].numerator 211 | deno = pm_object.time_signature_changes[-1].denominator 212 | bar_length = 60. / bpm * numer * 4 / deno * 100 213 | piano_roll = pm_object.instruments[track_num].get_piano_roll(fs=100) 214 | piano_roll = np.transpose(piano_roll, (1, 0)) 215 | actual_bar = len(piano_roll) / bar_length 216 | bar_length = int(math.ceil(bar_length)) 217 | 218 | if actual_bar > num_bar: 219 | mod = np.mod(len(piano_roll), bar_length*128) 220 | piano_roll = piano_roll[:-np.mod(len(piano_roll), bar_length)].reshape((num_bar, -1, 128)) # make exact bar 221 | elif actual_bar == num_bar: 222 | piano_roll = piano_roll.reshape((num_bar, -1, 128)) 223 | else: 224 | piano_roll = np.pad(piano_roll, ((0, int(num_bar * bar_length - len(piano_roll))), (0, 0)), mode='constant', constant_values=0) 225 | piano_roll = piano_roll.reshape((num_bar, -1, 128)) 226 | 227 | bar_histogram = np.zeros((num_bar, 12)) 228 | for i in range(0, num_bar): 229 | histogram = np.zeros(12) 230 | for j in range(0, 128): 231 | pitch_class = j % 12 232 | histogram[pitch_class] += np.sum(piano_roll[i], axis=0)[j] 233 | if sum(histogram) != 0: 234 | bar_histogram[i] = histogram / sum(histogram) 235 | else: 236 | bar_histogram[i] = np.zeros(12) 237 | return bar_histogram 238 | 239 | def pitch_class_transition_matrix(self, feature, normalize=0): 240 | """ 241 | pitch_class_transition_matrix (Pitch class transition matrix): 242 | The transition of pitch classes contains useful information for tasks such as key detection, chord recognition, or genre pattern recognition. 243 | The two-dimensional pitch class transition matrix is a histogram-like representation computed by counting the pitch transitions for each (ordered) pair of notes. 244 | 245 | Args: 246 | 'normalize' : If set to 0, return transition without normalization. 247 | If set to 1, normalizae by row. 248 | If set to 2, normalize by entire matrix sum. 249 | Returns: 250 | 'transition_matrix': shape of [12, 12], transition_matrix of 12 x 12. 251 | """ 252 | pm_object = feature['pretty_midi'] 253 | transition_matrix = pm_object.get_pitch_class_transition_matrix() 254 | 255 | if normalize == 0: 256 | return transition_matrix 257 | 258 | elif normalize == 1: 259 | sums = np.sum(transition_matrix, axis=1) 260 | sums[sums == 0] = 1 261 | return transition_matrix / sums.reshape(-1, 1) 262 | 263 | elif normalize == 2: 264 | return transition_matrix / sum(sum(transition_matrix)) 265 | 266 | else: 267 | print "invalid normalization mode, return unnormalized matrix" 268 | return transition_matrix 269 | 270 | def pitch_range(self, feature): 271 | """ 272 | pitch_range (Pitch range): 273 | The pitch range is calculated by subtraction of the highest and lowest used pitch in semitones. 274 | 275 | Returns: 276 | 'p_range': a scalar for each sample. 277 | """ 278 | piano_roll = feature['pretty_midi'].instruments[0].get_piano_roll(fs=100) 279 | pitch_index = np.where(np.sum(piano_roll, axis=1) > 0) 280 | p_range = np.max(pitch_index) - np.min(pitch_index) 281 | return p_range 282 | 283 | def avg_pitch_shift(self, feature, track_num=1): 284 | """ 285 | avg_pitch_shift (Average pitch interval): 286 | Average value of the interval between two consecutive pitches in semitones. 287 | 288 | Args: 289 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 290 | 291 | Returns: 292 | 'pitch_shift': a scalar for each sample. 293 | """ 294 | pattern = feature['midi_pattern'] 295 | pattern.make_ticks_abs() 296 | resolution = pattern.resolution 297 | total_used_note = self.total_used_note(feature, track_num=track_num) 298 | d_note = np.zeros((max(total_used_note - 1, 0))) 299 | # if total_used_note == 0: 300 | # return 0 301 | # d_note = np.zeros((total_used_note - 1)) 302 | current_note = 0 303 | counter = 0 304 | for i in range(0, len(pattern[track_num])): 305 | if type(pattern[track_num][i]) == midi.events.NoteOnEvent and pattern[track_num][i].data[1] != 0: 306 | if counter != 0: 307 | d_note[counter - 1] = current_note - pattern[track_num][i].data[0] 308 | current_note = pattern[track_num][i].data[0] 309 | counter += 1 310 | else: 311 | current_note = pattern[track_num][i].data[0] 312 | counter += 1 313 | pitch_shift = np.mean(abs(d_note)) 314 | return pitch_shift 315 | 316 | def avg_IOI(self, feature): 317 | """ 318 | avg_IOI (Average inter-onset-interval): 319 | To calculate the inter-onset-interval in the symbolic music domain, we find the time between two consecutive notes. 320 | 321 | Returns: 322 | 'avg_ioi': a scalar for each sample. 323 | """ 324 | 325 | pm_object = feature['pretty_midi'] 326 | onset = pm_object.get_onsets() 327 | ioi = np.diff(onset) 328 | avg_ioi = np.mean(ioi) 329 | return avg_ioi 330 | 331 | def note_length_hist(self, feature, track_num=1, normalize=True, pause_event=False): 332 | """ 333 | note_length_hist (Note length histogram): 334 | To extract the note length histogram, we first define a set of allowable beat length classes: 335 | [full, half, quarter, 8th, 16th, dot half, dot quarter, dot 8th, dot 16th, half note triplet, quarter note triplet, 8th note triplet]. 336 | The pause_event option, when activated, will double the vector size to represent the same lengths for rests. 337 | The classification of each event is performed by dividing the basic unit into the length of (barlength)/96, and each note length is quantized to the closest length category. 338 | 339 | Args: 340 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 341 | 'normalize' : If true, normalize by vector sum. 342 | 'pause_event' : when activated, will double the vector size to represent the same lengths for rests. 343 | 344 | Returns: 345 | 'note_length_hist': The output vector has a length of either 12 (or 24 when pause_event is True). 346 | """ 347 | 348 | pattern = feature['midi_pattern'] 349 | if pause_event is False: 350 | note_length_hist = np.zeros((12)) 351 | pattern.make_ticks_abs() 352 | resolution = pattern.resolution 353 | # basic unit: bar_length/96 354 | for i in range(0, len(pattern[track_num])): 355 | if type(pattern[track_num][i]) == midi.events.TimeSignatureEvent: 356 | time_sig = pattern[track_num][i].data 357 | bar_length = time_sig[track_num] * resolution * 4 / 2**(time_sig[1]) 358 | elif type(pattern[track_num][i]) == midi.events.NoteOnEvent and pattern[track_num][i].data[1] != 0: 359 | if 'time_sig' not in locals(): # set default bar length as 4 beat 360 | bar_length = 4 * resolution 361 | time_sig = [4, 2, 24, 8] 362 | unit = bar_length / 96. 363 | hist_list = [unit * 96, unit * 48, unit * 24, unit * 12, unit * 6, unit * 72, unit * 36, unit * 18, unit * 9, unit * 32, unit * 16, unit * 8] 364 | current_tick = pattern[track_num][i].tick 365 | current_note = pattern[track_num][i].data[0] 366 | # find next note off 367 | for j in range(i, len(pattern[track_num])): 368 | if type(pattern[track_num][j]) == midi.events.NoteOffEvent or (type(pattern[track_num][j]) == midi.events.NoteOnEvent and pattern[track_num][j].data[1] == 0): 369 | if pattern[track_num][j].data[0] == current_note: 370 | 371 | note_length = pattern[track_num][j].tick - current_tick 372 | distance = np.abs(np.array(hist_list) - note_length) 373 | idx = distance.argmin() 374 | note_length_hist[idx] += 1 375 | break 376 | else: 377 | note_length_hist = np.zeros((24)) 378 | pattern.make_ticks_abs() 379 | resolution = pattern.resolution 380 | # basic unit: bar_length/96 381 | for i in range(0, len(pattern[track_num])): 382 | if type(pattern[track_num][i]) == midi.events.TimeSignatureEvent: 383 | time_sig = pattern[track_num][i].data 384 | bar_length = time_sig[track_num] * resolution * 4 / 2**(time_sig[1]) 385 | elif type(pattern[track_num][i]) == midi.events.NoteOnEvent and pattern[track_num][i].data[1] != 0: 386 | check_previous_off = True 387 | if 'time_sig' not in locals(): # set default bar length as 4 beat 388 | bar_length = 4 * resolution 389 | time_sig = [4, 2, 24, 8] 390 | unit = bar_length / 96. 391 | tol = 3. * unit 392 | hist_list = [unit * 96, unit * 48, unit * 24, unit * 12, unit * 6, unit * 72, unit * 36, unit * 18, unit * 9, unit * 32, unit * 16, unit * 8] 393 | current_tick = pattern[track_num][i].tick 394 | current_note = pattern[track_num][i].data[0] 395 | # find next note off 396 | for j in range(i, len(pattern[track_num])): 397 | # find next note off 398 | if type(pattern[track_num][j]) == midi.events.NoteOffEvent or (type(pattern[track_num][j]) == midi.events.NoteOnEvent and pattern[track_num][j].data[1] == 0): 399 | if pattern[track_num][j].data[0] == current_note: 400 | 401 | note_length = pattern[track_num][j].tick - current_tick 402 | distance = np.abs(np.array(hist_list) - note_length) 403 | idx = distance.argmin() 404 | note_length_hist[idx] += 1 405 | break 406 | else: 407 | if pattern[track_num][j].tick == current_tick: 408 | check_previous_off = False 409 | 410 | # find previous note off/on 411 | if check_previous_off is True: 412 | for j in range(i - 1, 0, -1): 413 | if type(pattern[track_num][j]) == midi.events.NoteOnEvent and pattern[track_num][j].data[1] != 0: 414 | break 415 | 416 | elif type(pattern[track_num][j]) == midi.events.NoteOffEvent or (type(pattern[track_num][j]) == midi.events.NoteOnEvent and pattern[track_num][j].data[1] == 0): 417 | 418 | note_length = current_tick - pattern[track_num][j].tick 419 | distance = np.abs(np.array(hist_list) - note_length) 420 | idx = distance.argmin() 421 | if distance[idx] < tol: 422 | note_length_hist[idx + 12] += 1 423 | break 424 | 425 | if normalize is False: 426 | return note_length_hist 427 | 428 | elif normalize is True: 429 | 430 | return note_length_hist / np.sum(note_length_hist) 431 | 432 | def note_length_transition_matrix(self, feature, track_num=1, normalize=0, pause_event=False): 433 | """ 434 | note_length_transition_matrix (Note length transition matrix): 435 | Similar to the pitch class transition matrix, the note length tran- sition matrix provides useful information for rhythm description. 436 | 437 | Args: 438 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 439 | 'normalize' : If true, normalize by vector sum. 440 | 'pause_event' : when activated, will double the vector size to represent the same lengths for rests. 441 | 442 | 'normalize' : If set to 0, return transition without normalization. 443 | If set to 1, normalizae by row. 444 | If set to 2, normalize by entire matrix sum. 445 | 446 | Returns: 447 | 'transition_matrix': The output feature dimension is 12 × 12 (or 24 x 24 when pause_event is True). 448 | """ 449 | pattern = feature['midi_pattern'] 450 | if pause_event is False: 451 | transition_matrix = np.zeros((12, 12)) 452 | pattern.make_ticks_abs() 453 | resolution = pattern.resolution 454 | idx = None 455 | # basic unit: bar_length/96 456 | for i in range(0, len(pattern[track_num])): 457 | if type(pattern[track_num][i]) == midi.events.TimeSignatureEvent: 458 | time_sig = pattern[track_num][i].data 459 | bar_length = time_sig[track_num] * resolution * 4 / 2**(time_sig[1]) 460 | elif type(pattern[track_num][i]) == midi.events.NoteOnEvent and pattern[track_num][i].data[1] != 0: 461 | if 'time_sig' not in locals(): # set default bar length as 4 beat 462 | bar_length = 4 * resolution 463 | time_sig = [4, 2, 24, 8] 464 | unit = bar_length / 96. 465 | hist_list = [unit * 96, unit * 48, unit * 24, unit * 12, unit * 6, unit * 72, unit * 36, unit * 18, unit * 9, unit * 32, unit * 16, unit * 8] 466 | current_tick = pattern[track_num][i].tick 467 | current_note = pattern[track_num][i].data[0] 468 | # find note off 469 | for j in range(i, len(pattern[track_num])): 470 | if type(pattern[track_num][j]) == midi.events.NoteOffEvent or (type(pattern[track_num][j]) == midi.events.NoteOnEvent and pattern[track_num][j].data[1] == 0): 471 | if pattern[track_num][j].data[0] == current_note: 472 | note_length = pattern[track_num][j].tick - current_tick 473 | distance = np.abs(np.array(hist_list) - note_length) 474 | 475 | last_idx = idx 476 | idx = distance.argmin() 477 | if last_idx is not None: 478 | transition_matrix[last_idx][idx] += 1 479 | break 480 | else: 481 | transition_matrix = np.zeros((24, 24)) 482 | pattern.make_ticks_abs() 483 | resolution = pattern.resolution 484 | idx = None 485 | # basic unit: bar_length/96 486 | for i in range(0, len(pattern[track_num])): 487 | if type(pattern[track_num][i]) == midi.events.TimeSignatureEvent: 488 | time_sig = pattern[track_num][i].data 489 | bar_length = time_sig[track_num] * resolution * 4 / 2**(time_sig[1]) 490 | elif type(pattern[track_num][i]) == midi.events.NoteOnEvent and pattern[track_num][i].data[1] != 0: 491 | check_previous_off = True 492 | if 'time_sig' not in locals(): # set default bar length as 4 beat 493 | bar_length = 4 * resolution 494 | time_sig = [4, 2, 24, 8] 495 | unit = bar_length / 96. 496 | tol = 3. * unit 497 | hist_list = [unit * 96, unit * 48, unit * 24, unit * 12, unit * 6, unit * 72, unit * 36, unit * 18, unit * 9, unit * 32, unit * 16, unit * 8] 498 | current_tick = pattern[track_num][i].tick 499 | current_note = pattern[track_num][i].data[0] 500 | # find next note off 501 | for j in range(i, len(pattern[track_num])): 502 | # find next note off 503 | if type(pattern[track_num][j]) == midi.events.NoteOffEvent or (type(pattern[track_num][j]) == midi.events.NoteOnEvent and pattern[track_num][j].data[1] == 0): 504 | if pattern[track_num][j].data[0] == current_note: 505 | 506 | note_length = pattern[track_num][j].tick - current_tick 507 | distance = np.abs(np.array(hist_list) - note_length) 508 | last_idx = idx 509 | idx = distance.argmin() 510 | if last_idx is not None: 511 | transition_matrix[last_idx][idx] += 1 512 | break 513 | else: 514 | if pattern[track_num][j].tick == current_tick: 515 | check_previous_off = False 516 | 517 | # find previous note off/on 518 | if check_previous_off is True: 519 | for j in range(i - 1, 0, -1): 520 | if type(pattern[track_num][j]) == midi.events.NoteOnEvent and pattern[track_num][j].data[1] != 0: 521 | break 522 | 523 | elif type(pattern[track_num][j]) == midi.events.NoteOffEvent or (type(pattern[track_num][j]) == midi.events.NoteOnEvent and pattern[track_num][j].data[1] == 0): 524 | 525 | note_length = current_tick - pattern[track_num][j].tick 526 | distance = np.abs(np.array(hist_list) - note_length) 527 | 528 | last_idx = idx 529 | idx = distance.argmin() 530 | if last_idx is not None: 531 | if distance[idx] < tol: 532 | idx = last_idx 533 | transition_matrix[last_idx][idx + 12] += 1 534 | break 535 | 536 | if normalize == 0: 537 | return transition_matrix 538 | 539 | elif normalize == 1: 540 | 541 | sums = np.sum(transition_matrix, axis=1) 542 | sums[sums == 0] = 1 543 | return transition_matrix / sums.reshape(-1, 1) 544 | 545 | elif normalize == 2: 546 | 547 | return transition_matrix / sum(sum(transition_matrix)) 548 | 549 | else: 550 | print "invalid normalization mode, return unnormalized matrix" 551 | return transition_matrix 552 | 553 | # def chord_dependency(self, feature, bar_chord, bpm=120, num_bar=None, track_num=1): 554 | # pm_object = feature['pretty_midi'] 555 | # # compare bar chroma with chord chroma. calculate the ecludian 556 | # bar_pitch_class_histogram = self.bar_pitch_class_histogram(pm_object, bpm=bpm, num_bar=num_bar, track_num=track_num) 557 | # dist = np.zeros((len(bar_pitch_class_histogram))) 558 | # for i in range((len(bar_pitch_class_histogram))): 559 | # dist[i] = np.linalg.norm(bar_pitch_class_histogram[i] - bar_chord[i]) 560 | # average_dist = np.mean(dist) 561 | # return average_dist 562 | -------------------------------------------------------------------------------- /mgeval/documentation.md: -------------------------------------------------------------------------------- 1 | # core.py 2 | 3 | Include feature extractor and musically informed objective measures. 4 | 5 | ## extract_feature: 6 | This function extracts two midi feature: 7 | [pretty_midi object](https://github.com/craffel/pretty-midi) and 8 | [midi_pattern](https://github.com/vishnubob/python-midi) 9 | 10 | ``` 11 | Returns: 12 | dict(pretty_midi: pretty_midi object, 13 | midi_pattern: midi pattern contains a list of tracks) 14 | ``` 15 | 16 | ## metrics (Include feature extractor and musically informed objective measures) 17 | 18 | ### total_used_pitch (Pitch count): 19 | The number of different pitches within a sample. 20 | 21 | ``` 22 | Returns: 23 | 'used_pitch': pitch count, scalar for each sample. 24 | ``` 25 | 26 | ### bar_used_pitch (Pitch count per bar) 27 | 28 | ``` 29 | Args: 30 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 31 | 'num_bar': specify the number of bars in the midi pattern, if set as None, round to the number of complete bar. 32 | 33 | Returns: 34 | 'used_pitch': with shape of [num_bar,1] 35 | ``` 36 | 37 | ### total_used_note (Note count): 38 | 39 | The number of used notes. 40 | As opposed to the pitch count, the note count does not contain pitch information but is a rhythm-related feature. 41 | ``` 42 | Args: 43 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 44 | 45 | Returns: 46 | 'used_notes': a scalar for each sample. 47 | ``` 48 | 49 | 50 | ### bar_used_note (Note count per bar). 51 | 52 | ``` 53 | Args: 54 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 55 | 'num_bar': specify the number of bars in the midi pattern, if set as None, round to the number of complete bar. 56 | 57 | Returns: 58 | 'used_notes': with shape of [num_bar, 1] 59 | ``` 60 | 61 | ### total_pitch_class_histogram (Pitch class histogram): 62 | The pitch class histogram is an octave-independent representation of the pitch content with a dimensionality of 12 for a chromatic scale. 63 | In our case, it represents to the octave-independent chromatic quantization of the frequency continuum. 64 | ``` 65 | Returns: 66 | 'histogram': histrogram of 12 pitch, with weighted duration shape 12 67 | ``` 68 | 69 | ### bar_pitch_class_histogram (Pitch class histogram per bar): 70 | 71 | ``` 72 | Args: 73 | 'bpm' : specify the assigned speed in bpm, default is 120 bpm. 74 | 'num_bar': specify the number of bars in the midi pattern, if set as None, round to the number of complete bar. 75 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 76 | 77 | Returns: 78 | 'histogram': with shape of [num_bar, 12] 79 | ``` 80 | 81 | ### pitch_class_transition_matrix (Pitch class transition matrix): 82 | The transition of pitch classes contains useful information for tasks such as key detection, chord recognition, or genre pattern recognition. 83 | The two-dimensional pitch class transition matrix is a histogram-like representation computed by counting the pitch transitions for each (ordered) pair of notes. 84 | ``` 85 | Args: 86 | 'normalize' : If set to 0, return transition without normalization. 87 | If set to 1, normalizae by row. 88 | If set to 2, normalize by entire matrix sum. 89 | Returns: 90 | 'transition_matrix': shape of [12, 12], transition_matrix of 12 x 12. 91 | ``` 92 | 93 | ### pitch_range (Pitch range): 94 | 95 | The pitch range is calculated by subtraction of the highest and lowest used pitch in semitones. 96 | ``` 97 | Returns: 98 | 'p_range': a scalar for each sample. 99 | ``` 100 | 101 | ### avg_pitch_shift (Average pitch interval): 102 | 103 | Average value of the interval between two consecutive pitches in semitones. 104 | ``` 105 | Args: 106 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 107 | 108 | Returns: 109 | 'pitch_shift': a scalar for each sample. 110 | ``` 111 | 112 | ### avg_IOI (Average inter-onset-interval): 113 | To calculate the inter-onset-interval in the symbolic music domain, we find the time between two consecutive notes. 114 | ``` 115 | Returns: 116 | 'avg_ioi': a scalar for each sample. 117 | ``` 118 | 119 | ### note_length_hist (Note length histogram): 120 | 121 | To extract the note length histogram, we first define a set of allowable beat length classes: 122 | [full, half, quarter, 8th, 16th, dot half, dot quarter, dot 8th, dot 16th, half note triplet, quarter note triplet, 8th note triplet]. 123 | The pause_event option, when activated, will double the vector size to represent the same lengths for rests. 124 | The classification of each event is performed by dividing the basic unit into the length of (barlength)/96, and each note length is quantized to the closest length category. 125 | ``` 126 | Args: 127 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 128 | 'normalize' : If true, normalize by vector sum. 129 | 'pause_event' : when activated, will double the vector size to represent the same lengths for rests. 130 | 131 | Returns: 132 | 'note_length_hist': The output vector has a length of either 12 (or 24 when pause_event is True). 133 | ``` 134 | 135 | 136 | ### note_length_transition_matrix (Note length transition matrix): 137 | 138 | Similar to the pitch class transition matrix, the note length tran- sition matrix provides useful information for rhythm description. 139 | ``` 140 | Args: 141 | 'track_num' : specify the track number in the midi pattern, default is 1 (the second track). 142 | 'normalize' : If true, normalize by vector sum. 143 | 'pause_event' : when activated, will double the vector size to represent the same lengths for rests. 144 | 145 | 'normalize' : If set to 0, return transition without normalization. 146 | If set to 1, normalizae by row. 147 | If set to 2, normalize by entire matrix sum. 148 | 149 | Returns: 150 | 'transition_matrix': The output feature dimension is 12 × 12 (or 24 x 24 when pause_event is True). 151 | ``` 152 | -------------------------------------------------------------------------------- /mgeval/utils.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | """utils.py 3 | Include distance calculation for evaluation metrics 4 | """ 5 | import sys 6 | import os 7 | import glob 8 | import math 9 | import sklearn 10 | import numpy as np 11 | from scipy import stats, integrate 12 | 13 | 14 | # Calculate overlap between the two PDF 15 | def overlap_area(A, B): 16 | pdf_A = stats.gaussian_kde(A) 17 | pdf_B = stats.gaussian_kde(B) 18 | return integrate.quad(lambda x: min(pdf_A(x), pdf_B(x)), np.min((np.min(A), np.min(B))), np.max((np.max(A), np.max(B))))[0] 19 | 20 | 21 | # Calculate KL distance between the two PDF 22 | def kl_dist(A, B, num_sample=1000): 23 | pdf_A = stats.gaussian_kde(A) 24 | pdf_B = stats.gaussian_kde(B) 25 | sample_A = np.linspace(np.min(A), np.max(A), num_sample) 26 | sample_B = np.linspace(np.min(B), np.max(B), num_sample) 27 | return stats.entropy(pdf_A(sample_A), pdf_B(sample_B)) 28 | 29 | 30 | def c_dist(A, B, mode='None', normalize=0): 31 | c_dist = np.zeros(len(B)) 32 | for i in range(0, len(B)): 33 | if mode == 'None': 34 | c_dist[i] = np.linalg.norm(A - B[i]) 35 | elif mode == 'EMD': 36 | if normalize == 1: 37 | A_ = sklearn.preprocessing.normalize(A.reshape(1, -1), norm='l1')[0] 38 | B_ = sklearn.preprocessing.normalize(B[i].reshape(1, -1), norm='l1')[0] 39 | else: 40 | A_ = A.reshape(1, -1)[0] 41 | B_ = B[i].reshape(1, -1)[0] 42 | 43 | c_dist[i] = stats.wasserstein_distance(A_, B_) 44 | 45 | elif mode == 'KL': 46 | if normalize == 1: 47 | A_ = sklearn.preprocessing.normalize(A.reshape(1, -1), norm='l1')[0] 48 | B_ = sklearn.preprocessing.normalize(B[i].reshape(1, -1), norm='l1')[0] 49 | else: 50 | A_ = A.reshape(1, -1)[0] 51 | B_ = B[i].reshape(1, -1)[0] 52 | 53 | B_[B_ == 0] = 0.00000001 54 | c_dist[i] = stats.entropy(A_, B_) 55 | return c_dist 56 | --------------------------------------------------------------------------------