Skip to content

Instantly share code, notes, and snippets.

@oxinabox
Last active October 12, 2015 08:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oxinabox/4f51dba39154fbb2edbd to your computer and use it in GitHub Desktop.
Save oxinabox/4f51dba39154fbb2edbd to your computer and use it in GitHub Desktop.
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
" likely near /home/wheel/oxinabox/.julia/v0.5/RDatasets/src/dataset.jl:1\n",
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
" likely near /home/wheel/oxinabox/.julia/v0.5/RDatasets/src/dataset.jl:1\n",
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
" likely near /home/wheel/oxinabox/.julia/v0.5/RDatasets/src/datasets.jl:1\n"
]
}
],
"source": [
"using Optim\n",
"using RDatasets"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"unpack (generic function with 1 method)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"export pack,pack!, unpack, unpack!\n",
"\n",
"function pack{T}(sources::AbstractArray{T}...)\n",
" total_length = sum(map(length,sources))\n",
" package = Vector{T}(total_length)\n",
" pack!(Vector{T}(total_length), sources...)\n",
"end\n",
"\n",
"function pack!{T}(output::Vector{T}, sources::AbstractArray{T}...)\n",
" ii = 1\n",
" for s in sources\n",
" output[ii:ii+length(s)-1]=vec(s)\n",
" ii+=length(s)\n",
" end\n",
" output\n",
"end\n",
"\n",
"function unpack!{T}(package::Vector{T}, dests::AbstractArray{T}...)\n",
" ii = 1\n",
" for s in dests\n",
" s[:]= package[ii:ii+length(s)-1]\n",
" ii+=length(s)\n",
" end\n",
" dests\n",
"end\n",
"\n",
"function unpack{T}(package::Vector{T}, sizes::Union{Int,Tuple{Vararg{Int}}}...)\n",
" ds = [Array{T}(sz) for sz in sizes]\n",
" unpack!(package, ds...)\n",
"end\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"data": {
"text/html": [
"<table class=\"data-frame\"><tr><th></th><th>Country</th><th>SR</th><th>Pop15</th><th>Pop75</th><th>DPI</th><th>DDPI</th></tr><tr><th>1</th><td>Australia</td><td>11.43</td><td>29.35</td><td>2.87</td><td>2329.68</td><td>2.87</td></tr><tr><th>2</th><td>Austria</td><td>12.07</td><td>23.32</td><td>4.41</td><td>1507.99</td><td>3.93</td></tr><tr><th>3</th><td>Belgium</td><td>13.17</td><td>23.8</td><td>4.43</td><td>2108.47</td><td>3.82</td></tr><tr><th>4</th><td>Bolivia</td><td>5.75</td><td>41.89</td><td>1.67</td><td>189.13</td><td>0.22</td></tr><tr><th>5</th><td>Brazil</td><td>12.88</td><td>42.19</td><td>0.83</td><td>728.47</td><td>4.56</td></tr><tr><th>6</th><td>Canada</td><td>8.79</td><td>31.72</td><td>2.85</td><td>2982.88</td><td>2.43</td></tr><tr><th>7</th><td>Chile</td><td>0.6</td><td>39.74</td><td>1.34</td><td>662.86</td><td>2.67</td></tr><tr><th>8</th><td>China</td><td>11.9</td><td>44.75</td><td>0.67</td><td>289.52</td><td>6.51</td></tr><tr><th>9</th><td>Colombia</td><td>4.98</td><td>46.64</td><td>1.06</td><td>276.65</td><td>3.08</td></tr><tr><th>10</th><td>Costa Rica</td><td>10.78</td><td>47.64</td><td>1.14</td><td>471.24</td><td>2.8</td></tr><tr><th>11</th><td>Denmark</td><td>16.85</td><td>24.42</td><td>3.93</td><td>2496.53</td><td>3.99</td></tr><tr><th>12</th><td>Ecuador</td><td>3.59</td><td>46.31</td><td>1.19</td><td>287.77</td><td>2.19</td></tr><tr><th>13</th><td>Finland</td><td>11.24</td><td>27.84</td><td>2.37</td><td>1681.25</td><td>4.32</td></tr><tr><th>14</th><td>France</td><td>12.64</td><td>25.06</td><td>4.7</td><td>2213.82</td><td>4.52</td></tr><tr><th>15</th><td>Germany</td><td>12.55</td><td>23.31</td><td>3.35</td><td>2457.12</td><td>3.44</td></tr><tr><th>16</th><td>Greece</td><td>10.67</td><td>25.62</td><td>3.1</td><td>870.85</td><td>6.28</td></tr><tr><th>17</th><td>Guatamala</td><td>3.01</td><td>46.05</td><td>0.87</td><td>289.71</td><td>1.48</td></tr><tr><th>18</th><td>Honduras</td><td>7.7</td><td>47.32</td><td>0.58</td><td>232.44</td><td>3.19</td></tr><tr><th>19</th><td>Iceland</td><td>1.27</td><td>34.03</td><td>3.08</td><td>1900.1</td><td>1.12</td></tr><tr><th>20</th><td>India</td><td>9.0</td><td>41.31</td><td>0.96</td><td>88.94</td><td>1.54</td></tr><tr><th>21</th><td>Ireland</td><td>11.34</td><td>31.16</td><td>4.19</td><td>1139.95</td><td>2.99</td></tr><tr><th>22</th><td>Italy</td><td>14.28</td><td>24.52</td><td>3.48</td><td>1390.0</td><td>3.54</td></tr><tr><th>23</th><td>Japan</td><td>21.1</td><td>27.01</td><td>1.91</td><td>1257.28</td><td>8.21</td></tr><tr><th>24</th><td>Korea</td><td>3.98</td><td>41.74</td><td>0.91</td><td>207.68</td><td>5.81</td></tr><tr><th>25</th><td>Luxembourg</td><td>10.35</td><td>21.8</td><td>3.73</td><td>2449.39</td><td>1.57</td></tr><tr><th>26</th><td>Malta</td><td>15.48</td><td>32.54</td><td>2.47</td><td>601.05</td><td>8.12</td></tr><tr><th>27</th><td>Norway</td><td>10.25</td><td>25.95</td><td>3.67</td><td>2231.03</td><td>3.62</td></tr><tr><th>28</th><td>Netherlands</td><td>14.65</td><td>24.71</td><td>3.25</td><td>1740.7</td><td>7.66</td></tr><tr><th>29</th><td>New Zealand</td><td>10.67</td><td>32.61</td><td>3.17</td><td>1487.52</td><td>1.76</td></tr><tr><th>30</th><td>Nicaragua</td><td>7.3</td><td>45.04</td><td>1.21</td><td>325.54</td><td>2.48</td></tr><tr><th>&vellip;</th><td>&vellip;</td><td>&vellip;</td><td>&vellip;</td><td>&vellip;</td><td>&vellip;</td><td>&vellip;</td></tr></table>"
],
"text/plain": [
"50x6 DataFrames.DataFrame\n",
"| Row | Country | SR | Pop15 | Pop75 | DPI | DDPI |\n",
"|-----|------------------|-------|-------|-------|---------|-------|\n",
"| 1 | \"Australia\" | 11.43 | 29.35 | 2.87 | 2329.68 | 2.87 |\n",
"| 2 | \"Austria\" | 12.07 | 23.32 | 4.41 | 1507.99 | 3.93 |\n",
"| 3 | \"Belgium\" | 13.17 | 23.8 | 4.43 | 2108.47 | 3.82 |\n",
"| 4 | \"Bolivia\" | 5.75 | 41.89 | 1.67 | 189.13 | 0.22 |\n",
"| 5 | \"Brazil\" | 12.88 | 42.19 | 0.83 | 728.47 | 4.56 |\n",
"| 6 | \"Canada\" | 8.79 | 31.72 | 2.85 | 2982.88 | 2.43 |\n",
"| 7 | \"Chile\" | 0.6 | 39.74 | 1.34 | 662.86 | 2.67 |\n",
"| 8 | \"China\" | 11.9 | 44.75 | 0.67 | 289.52 | 6.51 |\n",
"| 9 | \"Colombia\" | 4.98 | 46.64 | 1.06 | 276.65 | 3.08 |\n",
"| 10 | \"Costa Rica\" | 10.78 | 47.64 | 1.14 | 471.24 | 2.8 |\n",
"| 11 | \"Denmark\" | 16.85 | 24.42 | 3.93 | 2496.53 | 3.99 |\n",
"⋮\n",
"| 39 | \"Sweden\" | 6.86 | 21.44 | 4.54 | 3299.49 | 3.01 |\n",
"| 40 | \"Switzerland\" | 14.13 | 23.49 | 3.73 | 2630.96 | 2.7 |\n",
"| 41 | \"Turkey\" | 5.13 | 43.42 | 1.08 | 389.66 | 2.96 |\n",
"| 42 | \"Tunisia\" | 2.81 | 46.12 | 1.21 | 249.87 | 1.13 |\n",
"| 43 | \"United Kingdom\" | 7.81 | 23.27 | 4.46 | 1813.93 | 2.01 |\n",
"| 44 | \"United States\" | 7.56 | 29.81 | 3.43 | 4001.89 | 2.45 |\n",
"| 45 | \"Venezuela\" | 9.22 | 46.4 | 0.9 | 813.39 | 0.53 |\n",
"| 46 | \"Zambia\" | 18.56 | 45.25 | 0.56 | 138.33 | 5.14 |\n",
"| 47 | \"Jamaica\" | 7.72 | 41.12 | 1.73 | 380.47 | 10.23 |\n",
"| 48 | \"Uruguay\" | 9.24 | 28.13 | 2.72 | 766.54 | 1.88 |\n",
"| 49 | \"Libya\" | 8.89 | 43.69 | 2.07 | 123.58 | 16.71 |\n",
"| 50 | \"Malaysia\" | 4.71 | 47.2 | 0.66 | 242.69 | 5.08 |"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"const lcs_data = dataset(\"datasets\",\"LifeCycleSavings\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"50x5 Array{Float64,2}:\n",
" 29.35 2.87 2329.68 2.87 1.0\n",
" 23.32 4.41 1507.99 3.93 1.0\n",
" 23.8 4.43 2108.47 3.82 1.0\n",
" 41.89 1.67 189.13 0.22 1.0\n",
" 42.19 0.83 728.47 4.56 1.0\n",
" 31.72 2.85 2982.88 2.43 1.0\n",
" 39.74 1.34 662.86 2.67 1.0\n",
" 44.75 0.67 289.52 6.51 1.0\n",
" 46.64 1.06 276.65 3.08 1.0\n",
" 47.64 1.14 471.24 2.8 1.0\n",
" 24.42 3.93 2496.53 3.99 1.0\n",
" 46.31 1.19 287.77 2.19 1.0\n",
" 27.84 2.37 1681.25 4.32 1.0\n",
" ⋮ \n",
" 21.44 4.54 3299.49 3.01 1.0\n",
" 23.49 3.73 2630.96 2.7 1.0\n",
" 43.42 1.08 389.66 2.96 1.0\n",
" 46.12 1.21 249.87 1.13 1.0\n",
" 23.27 4.46 1813.93 2.01 1.0\n",
" 29.81 3.43 4001.89 2.45 1.0\n",
" 46.4 0.9 813.39 0.53 1.0\n",
" 45.25 0.56 138.33 5.14 1.0\n",
" 41.12 1.73 380.47 10.23 1.0\n",
" 28.13 2.72 766.54 1.88 1.0\n",
" 43.69 2.07 123.58 16.71 1.0\n",
" 47.2 0.66 242.69 5.08 1.0"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"const Y_train = convert(Vector{Float64},lcs_data[:,2])\n",
"const bias_size = (size(lcs_data,1),1)\n",
"const X_train = [convert(Matrix{Float64}, lcs_data[:,3:end]) ones(bias_size)]\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"f (generic function with 1 method)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function feedforward(x, W₁, W₂)\n",
" h = tanh(x*W₁)\n",
" ŷ = h*W₂\n",
"end\n",
"\n",
"function loss(Ŷ,Y)\n",
" mean(abs(Ŷ - Y))\n",
"end\n",
"\n",
"function f(θ)\n",
" w1, w2 = unpack(θ, w1_size, w2_size)\n",
" Ŷ_train = feedforward(X_train, w1, w2)\n",
" loss(Ŷ_train, Y_train)\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(10,1)"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"const hidden_layer_size=10\n",
"const w1_size = (5,hidden_layer_size)\n",
"const w2_size = (hidden_layer_size,1)\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Iter Function value Gradient norm \n",
" 0 7.705977e+00 1.621270e+02\n",
" "
]
},
{
"ename": "LoadError",
"evalue": "LoadError: Search direction is not a direction of descent; this error may indicate that user-provided derivatives are inaccurate. (dphia = 0.050360; dphib = 0.378584)\nwhile loading In[7], in expression starting on line 5",
"output_type": "error",
"traceback": [
"LoadError: Search direction is not a direction of descent; this error may indicate that user-provided derivatives are inaccurate. (dphia = 0.050360; dphib = 0.378584)\nwhile loading In[7], in expression starting on line 5",
"",
" in error at ./error.jl:21",
" [inlined code] from printf.jl:145",
" in secant2! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:402",
" in hz_linesearch! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:321",
" in hz_linesearch! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:176 (repeats 10 times)",
" in __l_bfgs#9__ at /home/wheel/oxinabox/.julia/v0.5/Optim/src/l_bfgs.jl:169",
" in optimize at /home/wheel/oxinabox/.julia/v0.5/Optim/src/optimize.jl:508"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" 1 3.691467e+00 2.800000e-01\n",
" 2 3.581033e+00 8.042983e-02\n",
" 3 3.526629e+00 1.564189e+01\n"
]
}
],
"source": [
"srand(5000) #Same random numbers everytime this is run\n",
"w1_init = 0.01*rand(w1_size)\n",
"w2_init = 0.5*rand(w2_size)\n",
"θ_init = pack(w1_init, w2_init)\n",
"res = optimize(f, θ_init,\n",
" method=:l_bfgs,\n",
" show_trace=true,\n",
" iterations = 3000);\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Julia Version 0.5.0-dev+672\n",
"Commit d3af973 (2015-10-08 06:15 UTC)\n",
"Platform Info:\n",
" System: Linux (x86_64-linux-gnu)\n",
" CPU: Intel(R) Xeon(R) CPU E5520 @ 2.27GHz\n",
" WORD_SIZE: 64\n",
" BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Nehalem)\n",
" LAPACK: libopenblas64_\n",
" LIBM: libopenlibm\n",
" LLVM: libLLVM-3.3\n"
]
}
],
"source": [
"versioninfo()"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5 required packages:\n",
" - Gadfly 0.3.17\n",
" - IJulia 1.1.7\n",
" - Optim 0.4.3\n",
" - PyCall 1.1.2\n",
" - RDatasets 0.1.2\n",
"39 additional packages:\n",
" - ArrayViews 0.6.4\n",
" - BinDeps 0.3.18\n",
" - Calculus 0.1.13\n",
" - Codecs 0.1.5\n",
" - ColorTypes 0.1.7\n",
" - Colors 0.5.4\n",
" - Compat 0.7.5\n",
" - Compose 0.3.17\n",
" - Conda 0.1.7\n",
" - Contour 0.0.8\n",
" - DataArrays 0.2.19\n",
" - DataFrames 0.6.10\n",
" - DataStructures 0.3.13\n",
" - Dates 0.4.4\n",
" - Distances 0.2.1\n",
" - Distributions 0.8.7\n",
" - Docile 0.5.19\n",
" - DualNumbers 0.1.5\n",
" - FixedPointNumbers 0.0.12\n",
" - GZip 0.2.18\n",
" - Grid 0.4.0\n",
" - Hexagons 0.0.4\n",
" - ImmutableArrays 0.0.10\n",
" - Iterators 0.1.9\n",
" - JSON 0.5.0\n",
" - KernelDensity 0.1.1\n",
" - Loess 0.0.4\n",
" - NaNMath 0.1.1\n",
" - Nettle 0.2.0\n",
" - PDMats 0.3.6\n",
" - Reexport 0.0.3\n",
" - SHA 0.1.2\n",
" - Showoff 0.0.6\n",
" - SortingAlgorithms 0.0.6\n",
" - StatsBase 0.7.3\n",
" - StatsFuns 0.1.4\n",
" - URIParser 0.1.1\n",
" - WoodburyMatrices 0.1.2\n",
" - ZMQ 0.3.0\n"
]
}
],
"source": [
"Pkg.status()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"rosenbrock_gradient! (generic function with 1 method)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function rosenbrock(x::Vector)\n",
" return (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2\n",
"end\n",
"\n",
"function rosenbrock_gradient!(x::Vector, storage::Vector)\n",
" storage[1] = -2.0 * (1.0 - x[1]) - 400.0 * (x[2] - x[1]^2) * x[1]\n",
" storage[2] = 200.0 * (x[2] - x[1]^2)\n",
"end\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"rosenbrock_gradient! (generic function with 1 method)"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fr = rosenbrock\n",
"gr! = rosenbrock_gradient!\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2-element Array{Float64,1}:\n",
" 0.0464979\n",
" 0.610378 "
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"t=[0.046497946064945506,0.6103779534361964]"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "LoadError",
"evalue": "LoadError: Search direction is not a direction of descent; this error may indicate that user-provided derivatives are inaccurate. (dphia = 0.000014; dphib = 0.000015)\nwhile loading In[13], in expression starting on line 1",
"output_type": "error",
"traceback": [
"LoadError: Search direction is not a direction of descent; this error may indicate that user-provided derivatives are inaccurate. (dphia = 0.000014; dphib = 0.000015)\nwhile loading In[13], in expression starting on line 1",
"",
" in error at ./error.jl:21",
" [inlined code] from printf.jl:145",
" in secant2! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:402",
" in hz_linesearch! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:321",
" in hz_linesearch! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:176 (repeats 10 times)",
" in __l_bfgs#9__ at /home/wheel/oxinabox/.julia/v0.5/Optim/src/l_bfgs.jl:169",
" in optimize at /home/wheel/oxinabox/.julia/v0.5/Optim/src/optimize.jl:508"
]
}
],
"source": [
"optimize(fr, t, method = :l_bfgs)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "LoadError",
"evalue": "LoadError: Search direction is not a direction of descent; this error may indicate that user-provided derivatives are inaccurate. (dphia = 0.000014; dphib = 0.000015)\nwhile loading In[14], in expression starting on line 1",
"output_type": "error",
"traceback": [
"LoadError: Search direction is not a direction of descent; this error may indicate that user-provided derivatives are inaccurate. (dphia = 0.000014; dphib = 0.000015)\nwhile loading In[14], in expression starting on line 1",
"",
" in error at ./error.jl:21",
" [inlined code] from printf.jl:145",
" in secant2! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:402",
" in hz_linesearch! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:321",
" in hz_linesearch! at /home/wheel/oxinabox/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:176 (repeats 10 times)",
" in __l_bfgs#9__ at /home/wheel/oxinabox/.julia/v0.5/Optim/src/l_bfgs.jl:169",
" in optimize at /home/wheel/oxinabox/.julia/v0.5/Optim/src/optimize.jl:396"
]
}
],
"source": [
"optimize(fr, gr!, t, method = :l_bfgs)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 0.5.0-dev",
"language": "julia",
"name": "julia-0.5"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "0.5.0"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment