aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2019-10-22 13:32:43 +0200
committerMitja Felicijan <mitja.felicijan@gmail.com>2019-10-22 13:32:43 +0200
commitbe09bb704f8030a072114108fc094f07ee62efba (patch)
treeb05537d59b1f47398f38bacdbe138f1c83ac9399 /src
parent629d3907b89f795667ba5fe2f31b790bf56093cd (diff)
downloadmitjafelicijan.com-be09bb704f8030a072114108fc094f07ee62efba.tar.gz
Added 301 rules for old articles
Diffstat (limited to 'src')
-rw-r--r--src/experiments/encoding-binary-data-into-dna-sequence.md1
-rw-r--r--src/experiments/profiling-python-web-applications-with-visual-tools.md1
-rw-r--r--src/experiments/simple-iot-application.md1
-rw-r--r--src/experiments/using-digitalocean-spaces-object-storage-with-fuse.md1
-rw-r--r--src/experiments/using-sentiment-analysis-for-click-bait-detection-in-rss-feeds.md86
-rw-r--r--src/files/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb588
-rw-r--r--src/files/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb170
-rw-r--r--src/files/sentiment-analysis/guardian-sa-title-desc-relationship.pngbin0 -> 15404 bytes
-rw-r--r--src/files/sentiment-analysis/sentiment-analysis.ipynb170
-rw-r--r--src/notes/golang-profiling-simplified.md1
-rw-r--r--src/notes/simplifying-and-reducing-clutter.md1
-rw-r--r--src/notes/what-i-ve-learned-developing-ad-server.md1
-rw-r--r--src/static/style.css8
13 files changed, 1028 insertions, 1 deletions
diff --git a/src/experiments/encoding-binary-data-into-dna-sequence.md b/src/experiments/encoding-binary-data-into-dna-sequence.md
index cc42bd7..cdff15f 100644
--- a/src/experiments/encoding-binary-data-into-dna-sequence.md
+++ b/src/experiments/encoding-binary-data-into-dna-sequence.md
@@ -1,4 +1,5 @@
1title: Encoding binary data into DNA sequence 1title: Encoding binary data into DNA sequence
2description: Imagine a world where you could go outside and take a leaf from a tree and put it through your personal DNA sequencer and get data like music, videos or computer programs from it
2date: 2019-01-03 3date: 2019-01-03
3tags: experiment 4tags: experiment
4hide: false 5hide: false
diff --git a/src/experiments/profiling-python-web-applications-with-visual-tools.md b/src/experiments/profiling-python-web-applications-with-visual-tools.md
index 29e16d7..58d85bf 100644
--- a/src/experiments/profiling-python-web-applications-with-visual-tools.md
+++ b/src/experiments/profiling-python-web-applications-with-visual-tools.md
@@ -1,4 +1,5 @@
1title: Profiling Python web applications with visual tools 1title: Profiling Python web applications with visual tools
2description: Missing link when debugging and profiling python web application
2date: 2017-04-21 3date: 2017-04-21
3tags: experiment 4tags: experiment
4hide: false 5hide: false
diff --git a/src/experiments/simple-iot-application.md b/src/experiments/simple-iot-application.md
index b8744e6..1543e52 100644
--- a/src/experiments/simple-iot-application.md
+++ b/src/experiments/simple-iot-application.md
@@ -1,4 +1,5 @@
1title: Simple IOT application supported by real-time monitoring and data history 1title: Simple IOT application supported by real-time monitoring and data history
2description: Develop simple IOT application with Arduino MKR1000 and Python
2date: 2017-08-11 3date: 2017-08-11
3tags: experiment 4tags: experiment
4hide: false 5hide: false
diff --git a/src/experiments/using-digitalocean-spaces-object-storage-with-fuse.md b/src/experiments/using-digitalocean-spaces-object-storage-with-fuse.md
index bc00d1e..ab0079f 100644
--- a/src/experiments/using-digitalocean-spaces-object-storage-with-fuse.md
+++ b/src/experiments/using-digitalocean-spaces-object-storage-with-fuse.md
@@ -1,4 +1,5 @@
1title: Using DigitalOcean Spaces Object Storage with FUSE 1title: Using DigitalOcean Spaces Object Storage with FUSE
2description: Using DigitalOcean Spaces Object Storage with FUSE
2date: 2018-01-16 3date: 2018-01-16
3tags: experiment 4tags: experiment
4hide: false 5hide: false
diff --git a/src/experiments/using-sentiment-analysis-for-click-bait-detection-in-rss-feeds.md b/src/experiments/using-sentiment-analysis-for-click-bait-detection-in-rss-feeds.md
new file mode 100644
index 0000000..c27c6d0
--- /dev/null
+++ b/src/experiments/using-sentiment-analysis-for-click-bait-detection-in-rss-feeds.md
@@ -0,0 +1,86 @@
1title: Using sentiment analysis for click&#8209;bait detection in RSS feeds
2description: Using Python with sentiment analysis to detect if titles in RSS feeds are click-bait
3date: 2019-10-19
4tags: experiment
5hide: false
6----
7
8## Initial thoughts
9
10One of the things that interested me for a while now is if major well established news sites use click bait titles to drive additional traffic to their sites and generate additional impressions.
11
12Goal is to see how article titles and actual content of article differ from each other and see if titles are click-baited.
13
14## Preparing and cleaning data
15
16For this example I opted to just use RSS feed from a new website and decided to go with [The Guardian](https://www.theguardian.com) World news. While this gets us limited data (~40) articles and also description (actual content) is trimmed this really doesn't reflect the actual article contents.
17
18To get better content I could use web scraping and use RSS as link list and fetch contents directly from website, but for this simple example this will suffice.
19
20There are couple of requirements we need to install before we continue:
21
22- `pip3 install feedparser` (parses RSS feed from url)
23- `pip3 install vaderSentiment` (does sentiment polarity analysis)
24- `pip3 install matplotlib` (plots chart of results)
25
26So first we need to fetch RSS data and sanitize HTML content from description.
27
28```python
29import re
30import feedparser
31
32feed_url = "https://www.theguardian.com/world/rss"
33feed = feedparser.parse(feed_url)
34
35for item in feed.import re:
36 # sanitize html
37 item.description = re.sub('<[^<]+?>', '', item.description)
38```
39
40## Perform sentiment analysis
41
42Since we now have cleaned up data in our `feed.entries` object we can start with performing sentiment analysis.
43
44There are many sentiment analysis libraries available that range from rule-based sentiment analysis up to machine learning supported analysis. To keep things simple I decided to use rule-based analysis library [vaderSentiment](https://github.com/cjhutto/vaderSentiment) from [C.J. Hutto](https://github.com/cjhutto). Really nice library and quite easy to use.
45
46```python
47from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
48analyser = SentimentIntensityAnalyzer()
49
50sentiment_results = []
51for item in feed.entries:
52 sentiment_title = analyser.polarity_scores(item.title)
53 sentiment_description = analyser.polarity_scores(item.description)
54 sentiment_results.append([sentiment_title['compound'], sentiment_description['compound']])
55```
56
57Now that we have this data in a shape that is compatible with matplotlib we can plot results to see the difference between title and description sentiment of an article.
58
59```python
60import matplotlib.pyplot as plt
61
62plt.rcParams['figure.figsize'] = (15, 3)
63plt.plot(sentiment_results, drawstyle='steps')
64plt.title('Sentiment analysis relationship between title and description (Guardian World News)')
65plt.legend(['title', 'description'])
66plt.show()
67```
68
69## Results and assets
70
711. Because of the small sample size further conclusions are impossible to make.
722. Rule-based approach may not be the best way of doing this. By using deep learning we would be able to get better insights.
733. **Next step would be to** periodically fetch RSS items and store them over a longer period of time and then perform analysis again and use either machine learning or deep learning on top of it.
74
75![Relationship between title and description](/files/sentiment-analysis/guardian-sa-title-desc-relationship.png)
76
77Figure above displays difference between title and description sentiment for specific RSS feed item. 1 means positive and -1 means negative sentiment.
78
79[ยป Download Jupyter Notebook](/files/sentiment-analysis/sentiment-analysis.ipynb)
80
81## Going further
82
83- [Twitter Sentiment Analysis by Bryan Schwierzke](https://github.com/bswiss/news_mood)
84- [AFINN-based sentiment analysis for Node.js by Andrew Sliwinski](https://github.com/thisandagain/sentiment)
85- [Sentiment Analysis with LSTMs in Tensorflow by Adit Deshpande](https://github.com/adeshpande3/LSTM-Sentiment-Analysis)
86- [Sentiment analysis on tweets using Naive Bayes, SVM, CNN, LSTM, etc. by Abdul Fatir](https://github.com/abdulfatir/twitter-sentiment-analysis)
diff --git a/src/files/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb b/src/files/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb
new file mode 100644
index 0000000..e2a85c4
--- /dev/null
+++ b/src/files/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb
@@ -0,0 +1,588 @@
1{
2 "cells": [
3 {
4 "cell_type": "code",
5 "execution_count": 1,
6 "metadata": {},
7 "outputs": [
8 {
9 "name": "stderr",
10 "output_type": "stream",
11 "text": [
12 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:516: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
13 " _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
14 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:517: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
15 " _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
16 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:518: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
17 " _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
18 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:519: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
19 " _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
20 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:520: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
21 " _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
22 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
23 " np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
24 ]
25 },
26 {
27 "name": "stdout",
28 "output_type": "stream",
29 "text": [
30 "2.0.0-beta1\n"
31 ]
32 },
33 {
34 "name": "stderr",
35 "output_type": "stream",
36 "text": [
37 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:541: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
38 " _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
39 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:542: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
40 " _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
41 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:543: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
42 " _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
43 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:544: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
44 " _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
45 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:545: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
46 " _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
47 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:550: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
48 " np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
49 ]
50 }
51 ],
52 "source": [
53 "import tensorflow as tf\n",
54 "from tensorflow import keras\n",
55 "\n",
56 "# Helper libraries\n",
57 "import numpy as np\n",
58 "import matplotlib.pyplot as plt\n",
59 "\n",
60 "print(tf.__version__)"
61 ]
62 },
63 {
64 "cell_type": "code",
65 "execution_count": 2,
66 "metadata": {},
67 "outputs": [],
68 "source": [
69 "from numpy import genfromtxt\n",
70 "data = genfromtxt('data.csv', delimiter=',')"
71 ]
72 },
73 {
74 "cell_type": "code",
75 "execution_count": 3,
76 "metadata": {},
77 "outputs": [],
78 "source": [
79 "data_input = data[:,0:3]\n",
80 "data_labels = data[:,3]\n",
81 "\n",
82 "#data_input = np.transpose(data_input)\n",
83 "#data_labels = np.transpose(data_labels)"
84 ]
85 },
86 {
87 "cell_type": "code",
88 "execution_count": 4,
89 "metadata": {},
90 "outputs": [
91 {
92 "name": "stdout",
93 "output_type": "stream",
94 "text": [
95 "(600, 3)\n",
96 "[1.e-01 1.e+00 3.e+02]\n"
97 ]
98 }
99 ],
100 "source": [
101 "print(np.shape(data_input))\n",
102 "print(data_input[2])"
103 ]
104 },
105 {
106 "cell_type": "markdown",
107 "metadata": {},
108 "source": [
109 "print(len(data_input))\n",
110 "print(len(data_labels))"
111 ]
112 },
113 {
114 "cell_type": "code",
115 "execution_count": 5,
116 "metadata": {},
117 "outputs": [
118 {
119 "name": "stdout",
120 "output_type": "stream",
121 "text": [
122 "(500, 3)\n",
123 "(100, 3)\n",
124 "(500,)\n",
125 "(100,)\n"
126 ]
127 }
128 ],
129 "source": [
130 "data_input_train = data_input[0:500,:]\n",
131 "data_input_test = data_input[500:,:]\n",
132 "\n",
133 "data_labels_train = data_labels[0:500]\n",
134 "data_labels_test = data_labels[500:]\n",
135 "\n",
136 "print(np.shape(data_input_train))\n",
137 "print(np.shape(data_input_test))\n",
138 "\n",
139 "print(np.shape(data_labels_train))\n",
140 "print(np.shape(data_labels_test))"
141 ]
142 },
143 {
144 "cell_type": "code",
145 "execution_count": 6,
146 "metadata": {},
147 "outputs": [],
148 "source": [
149 "model = keras.Sequential([\n",
150 " keras.layers.Dense(128, activation='relu', input_shape=[3]),\n",
151 " keras.layers.Dense(512, activation='relu'),\n",
152 " keras.layers.Dense(512, activation='relu'),\n",
153 " keras.layers.Dense(512, activation='relu'),\n",
154 " keras.layers.Dense(128, activation='relu'),\n",
155 " keras.layers.Dense(1)\n",
156 "])"
157 ]
158 },
159 {
160 "cell_type": "code",
161 "execution_count": 7,
162 "metadata": {},
163 "outputs": [],
164 "source": [
165 "optimizer = tf.keras.optimizers.RMSprop(0.001)\n",
166 "model.compile(loss='mse',\n",
167 " optimizer=optimizer,\n",
168 " metrics=['accuracy'])"
169 ]
170 },
171 {
172 "cell_type": "code",
173 "execution_count": 8,
174 "metadata": {},
175 "outputs": [
176 {
177 "name": "stdout",
178 "output_type": "stream",
179 "text": [
180 "Train on 500 samples\n",
181 "Epoch 1/100\n",
182 "500/500 [==============================] - 0s 399us/sample - loss: 247.2794 - accuracy: 0.0040\n",
183 "Epoch 2/100\n",
184 "500/500 [==============================] - 0s 121us/sample - loss: 4.2495 - accuracy: 0.0060\n",
185 "Epoch 3/100\n",
186 "500/500 [==============================] - 0s 131us/sample - loss: 1.8787 - accuracy: 0.0040\n",
187 "Epoch 4/100\n",
188 "500/500 [==============================] - 0s 121us/sample - loss: 0.4284 - accuracy: 0.0060\n",
189 "Epoch 5/100\n",
190 "500/500 [==============================] - 0s 107us/sample - loss: 4.7904 - accuracy: 0.0080\n",
191 "Epoch 6/100\n",
192 "500/500 [==============================] - 0s 113us/sample - loss: 0.0819 - accuracy: 0.0040\n",
193 "Epoch 7/100\n",
194 "500/500 [==============================] - 0s 108us/sample - loss: 1.6904 - accuracy: 0.0040\n",
195 "Epoch 8/100\n",
196 "500/500 [==============================] - 0s 116us/sample - loss: 0.1761 - accuracy: 0.0040\n",
197 "Epoch 9/100\n",
198 "500/500 [==============================] - 0s 142us/sample - loss: 0.1135 - accuracy: 0.0040\n",
199 "Epoch 10/100\n",
200 "500/500 [==============================] - 0s 124us/sample - loss: 0.4387 - accuracy: 0.0040\n",
201 "Epoch 11/100\n",
202 "500/500 [==============================] - 0s 112us/sample - loss: 0.0815 - accuracy: 0.0040\n",
203 "Epoch 12/100\n",
204 "500/500 [==============================] - 0s 117us/sample - loss: 0.1725 - accuracy: 0.0040\n",
205 "Epoch 13/100\n",
206 "500/500 [==============================] - 0s 119us/sample - loss: 0.1487 - accuracy: 0.0040\n",
207 "Epoch 14/100\n",
208 "500/500 [==============================] - 0s 111us/sample - loss: 0.0720 - accuracy: 0.0040\n",
209 "Epoch 15/100\n",
210 "500/500 [==============================] - 0s 111us/sample - loss: 0.3110 - accuracy: 0.0040\n",
211 "Epoch 16/100\n",
212 "500/500 [==============================] - 0s 128us/sample - loss: 0.0947 - accuracy: 0.0040\n",
213 "Epoch 17/100\n",
214 "500/500 [==============================] - 0s 133us/sample - loss: 0.0739 - accuracy: 0.0040\n",
215 "Epoch 18/100\n",
216 "500/500 [==============================] - 0s 131us/sample - loss: 0.1353 - accuracy: 0.0060\n",
217 "Epoch 19/100\n",
218 "500/500 [==============================] - 0s 135us/sample - loss: 0.0837 - accuracy: 0.0040\n",
219 "Epoch 20/100\n",
220 "500/500 [==============================] - 0s 130us/sample - loss: 0.0754 - accuracy: 0.0040\n",
221 "Epoch 21/100\n",
222 "500/500 [==============================] - 0s 118us/sample - loss: 0.0840 - accuracy: 0.0040\n",
223 "Epoch 22/100\n",
224 "500/500 [==============================] - 0s 115us/sample - loss: 0.1105 - accuracy: 0.0040\n",
225 "Epoch 23/100\n",
226 "500/500 [==============================] - 0s 116us/sample - loss: 0.0651 - accuracy: 0.0040\n",
227 "Epoch 24/100\n",
228 "500/500 [==============================] - 0s 109us/sample - loss: 0.0615 - accuracy: 0.0040\n",
229 "Epoch 25/100\n",
230 "500/500 [==============================] - 0s 118us/sample - loss: 0.0656 - accuracy: 0.0040\n",
231 "Epoch 26/100\n",
232 "500/500 [==============================] - 0s 113us/sample - loss: 0.0695 - accuracy: 0.0040\n",
233 "Epoch 27/100\n",
234 "500/500 [==============================] - 0s 116us/sample - loss: 0.0585 - accuracy: 0.0040\n",
235 "Epoch 28/100\n",
236 "500/500 [==============================] - 0s 118us/sample - loss: 0.1300 - accuracy: 0.0040\n",
237 "Epoch 29/100\n",
238 "500/500 [==============================] - 0s 112us/sample - loss: 0.0567 - accuracy: 0.0040\n",
239 "Epoch 30/100\n",
240 "500/500 [==============================] - 0s 137us/sample - loss: 0.0647 - accuracy: 0.0040\n",
241 "Epoch 31/100\n",
242 "500/500 [==============================] - 0s 130us/sample - loss: 0.0559 - accuracy: 0.0040\n",
243 "Epoch 32/100\n",
244 "500/500 [==============================] - 0s 130us/sample - loss: 0.0576 - accuracy: 0.0040\n",
245 "Epoch 33/100\n",
246 "500/500 [==============================] - 0s 128us/sample - loss: 0.0578 - accuracy: 0.0040\n",
247 "Epoch 34/100\n",
248 "500/500 [==============================] - 0s 130us/sample - loss: 0.0512 - accuracy: 0.0040\n",
249 "Epoch 35/100\n",
250 "500/500 [==============================] - 0s 114us/sample - loss: 0.0601 - accuracy: 0.0040\n",
251 "Epoch 36/100\n",
252 "500/500 [==============================] - 0s 111us/sample - loss: 0.0531 - accuracy: 0.0040\n",
253 "Epoch 37/100\n",
254 "500/500 [==============================] - 0s 130us/sample - loss: 0.0532 - accuracy: 0.0040\n",
255 "Epoch 38/100\n",
256 "500/500 [==============================] - 0s 131us/sample - loss: 0.0480 - accuracy: 0.0040\n",
257 "Epoch 39/100\n",
258 "500/500 [==============================] - 0s 136us/sample - loss: 0.0503 - accuracy: 0.0040\n",
259 "Epoch 40/100\n",
260 "500/500 [==============================] - 0s 134us/sample - loss: 0.0468 - accuracy: 0.0040\n",
261 "Epoch 41/100\n",
262 "500/500 [==============================] - 0s 115us/sample - loss: 0.0509 - accuracy: 0.0040\n",
263 "Epoch 42/100\n",
264 "500/500 [==============================] - 0s 109us/sample - loss: 0.0453 - accuracy: 0.0040\n",
265 "Epoch 43/100\n",
266 "500/500 [==============================] - 0s 111us/sample - loss: 0.0484 - accuracy: 0.0040\n",
267 "Epoch 44/100\n",
268 "500/500 [==============================] - 0s 104us/sample - loss: 0.0458 - accuracy: 0.0040\n",
269 "Epoch 45/100\n",
270 "500/500 [==============================] - 0s 110us/sample - loss: 0.0481 - accuracy: 0.0040\n",
271 "Epoch 46/100\n",
272 "500/500 [==============================] - 0s 114us/sample - loss: 0.0468 - accuracy: 0.0060\n",
273 "Epoch 47/100\n",
274 "500/500 [==============================] - 0s 124us/sample - loss: 0.0473 - accuracy: 0.0060\n",
275 "Epoch 48/100\n",
276 "500/500 [==============================] - 0s 137us/sample - loss: 0.0455 - accuracy: 0.0040\n",
277 "Epoch 49/100\n",
278 "500/500 [==============================] - 0s 125us/sample - loss: 0.0431 - accuracy: 0.0060\n",
279 "Epoch 50/100\n",
280 "500/500 [==============================] - 0s 132us/sample - loss: 0.0432 - accuracy: 0.0060\n",
281 "Epoch 51/100\n",
282 "500/500 [==============================] - 0s 116us/sample - loss: 0.0484 - accuracy: 0.0060\n",
283 "Epoch 52/100\n",
284 "500/500 [==============================] - 0s 112us/sample - loss: 0.0482 - accuracy: 0.0040\n",
285 "Epoch 53/100\n",
286 "500/500 [==============================] - 0s 117us/sample - loss: 0.0444 - accuracy: 0.0060\n",
287 "Epoch 54/100\n",
288 "500/500 [==============================] - 0s 109us/sample - loss: 0.0469 - accuracy: 0.0060\n",
289 "Epoch 55/100\n",
290 "500/500 [==============================] - 0s 106us/sample - loss: 0.0427 - accuracy: 0.0040\n",
291 "Epoch 56/100\n",
292 "500/500 [==============================] - 0s 110us/sample - loss: 0.0433 - accuracy: 0.0040\n",
293 "Epoch 57/100\n",
294 "500/500 [==============================] - 0s 102us/sample - loss: 0.0437 - accuracy: 0.0060\n",
295 "Epoch 58/100\n",
296 "500/500 [==============================] - 0s 117us/sample - loss: 0.0425 - accuracy: 0.0040\n",
297 "Epoch 59/100\n",
298 "500/500 [==============================] - 0s 105us/sample - loss: 0.0418 - accuracy: 0.0040\n",
299 "Epoch 60/100\n",
300 "500/500 [==============================] - 0s 109us/sample - loss: 0.0397 - accuracy: 0.0040\n",
301 "Epoch 61/100\n",
302 "500/500 [==============================] - 0s 119us/sample - loss: 0.0507 - accuracy: 0.0040\n",
303 "Epoch 62/100\n",
304 "500/500 [==============================] - 0s 112us/sample - loss: 0.0402 - accuracy: 0.0060\n",
305 "Epoch 63/100\n",
306 "500/500 [==============================] - 0s 133us/sample - loss: 0.0397 - accuracy: 0.0040\n",
307 "Epoch 64/100\n",
308 "500/500 [==============================] - 0s 132us/sample - loss: 0.0427 - accuracy: 0.0060\n",
309 "Epoch 65/100\n",
310 "500/500 [==============================] - 0s 138us/sample - loss: 0.0398 - accuracy: 0.0040\n",
311 "Epoch 66/100\n",
312 "500/500 [==============================] - 0s 145us/sample - loss: 0.0375 - accuracy: 0.0060\n",
313 "Epoch 67/100\n",
314 "500/500 [==============================] - 0s 138us/sample - loss: 0.0402 - accuracy: 0.0060\n",
315 "Epoch 68/100\n",
316 "500/500 [==============================] - 0s 132us/sample - loss: 0.0388 - accuracy: 0.0080\n",
317 "Epoch 69/100\n",
318 "500/500 [==============================] - 0s 115us/sample - loss: 0.0375 - accuracy: 0.0080\n",
319 "Epoch 70/100\n",
320 "500/500 [==============================] - 0s 113us/sample - loss: 0.0384 - accuracy: 0.0040\n",
321 "Epoch 71/100\n",
322 "500/500 [==============================] - 0s 109us/sample - loss: 0.0360 - accuracy: 0.0080\n",
323 "Epoch 72/100\n",
324 "500/500 [==============================] - 0s 111us/sample - loss: 0.0350 - accuracy: 0.0080\n",
325 "Epoch 73/100\n",
326 "500/500 [==============================] - 0s 118us/sample - loss: 0.0370 - accuracy: 0.0060\n",
327 "Epoch 74/100\n",
328 "500/500 [==============================] - 0s 95us/sample - loss: 0.0354 - accuracy: 0.0080\n",
329 "Epoch 75/100\n",
330 "500/500 [==============================] - 0s 102us/sample - loss: 0.0376 - accuracy: 0.0060\n",
331 "Epoch 76/100\n",
332 "500/500 [==============================] - 0s 106us/sample - loss: 0.0371 - accuracy: 0.0080\n",
333 "Epoch 77/100\n",
334 "500/500 [==============================] - 0s 100us/sample - loss: 0.0369 - accuracy: 0.0060\n",
335 "Epoch 78/100\n"
336 ]
337 },
338 {
339 "name": "stdout",
340 "output_type": "stream",
341 "text": [
342 "500/500 [==============================] - 0s 98us/sample - loss: 0.0315 - accuracy: 0.0060\n",
343 "Epoch 79/100\n",
344 "500/500 [==============================] - 0s 97us/sample - loss: 0.0355 - accuracy: 0.0060\n",
345 "Epoch 80/100\n",
346 "500/500 [==============================] - 0s 100us/sample - loss: 0.0278 - accuracy: 0.0080\n",
347 "Epoch 81/100\n",
348 "500/500 [==============================] - 0s 99us/sample - loss: 0.0320 - accuracy: 0.0080\n",
349 "Epoch 82/100\n",
350 "500/500 [==============================] - 0s 99us/sample - loss: 0.0321 - accuracy: 0.0080\n",
351 "Epoch 83/100\n",
352 "500/500 [==============================] - 0s 94us/sample - loss: 0.0332 - accuracy: 0.0060\n",
353 "Epoch 84/100\n",
354 "500/500 [==============================] - 0s 106us/sample - loss: 0.0317 - accuracy: 0.0060\n",
355 "Epoch 85/100\n",
356 "500/500 [==============================] - 0s 103us/sample - loss: 0.0293 - accuracy: 0.0080\n",
357 "Epoch 86/100\n",
358 "500/500 [==============================] - 0s 107us/sample - loss: 0.0304 - accuracy: 0.0060\n",
359 "Epoch 87/100\n",
360 "500/500 [==============================] - 0s 101us/sample - loss: 0.0327 - accuracy: 0.0040\n",
361 "Epoch 88/100\n",
362 "500/500 [==============================] - 0s 100us/sample - loss: 0.0290 - accuracy: 0.0080\n",
363 "Epoch 89/100\n",
364 "500/500 [==============================] - 0s 123us/sample - loss: 0.0293 - accuracy: 0.0060\n",
365 "Epoch 90/100\n",
366 "500/500 [==============================] - 0s 104us/sample - loss: 0.0246 - accuracy: 0.0060\n",
367 "Epoch 91/100\n",
368 "500/500 [==============================] - 0s 124us/sample - loss: 0.0303 - accuracy: 0.0060\n",
369 "Epoch 92/100\n",
370 "500/500 [==============================] - 0s 129us/sample - loss: 0.0376 - accuracy: 0.0080\n",
371 "Epoch 93/100\n",
372 "500/500 [==============================] - 0s 122us/sample - loss: 0.0264 - accuracy: 0.0080\n",
373 "Epoch 94/100\n",
374 "500/500 [==============================] - 0s 102us/sample - loss: 0.0265 - accuracy: 0.0080\n",
375 "Epoch 95/100\n",
376 "500/500 [==============================] - 0s 108us/sample - loss: 0.0291 - accuracy: 0.0080\n",
377 "Epoch 96/100\n",
378 "500/500 [==============================] - 0s 101us/sample - loss: 0.0314 - accuracy: 0.0080\n",
379 "Epoch 97/100\n",
380 "500/500 [==============================] - 0s 95us/sample - loss: 0.0257 - accuracy: 0.0060\n",
381 "Epoch 98/100\n",
382 "500/500 [==============================] - 0s 100us/sample - loss: 0.0248 - accuracy: 0.0080\n",
383 "Epoch 99/100\n",
384 "500/500 [==============================] - 0s 94us/sample - loss: 0.0250 - accuracy: 0.0040\n",
385 "Epoch 100/100\n",
386 "500/500 [==============================] - 0s 106us/sample - loss: 0.0312 - accuracy: 0.0060\n"
387 ]
388 },
389 {
390 "data": {
391 "text/plain": [
392 "<tensorflow.python.keras.callbacks.History at 0x7f55a3853f60>"
393 ]
394 },
395 "execution_count": 8,
396 "metadata": {},
397 "output_type": "execute_result"
398 }
399 ],
400 "source": [
401 "#model.fit(data_input_train, data_labels_train, validation_data=(data_input_test, data_labels_test), epochs=100)\n",
402 "model.fit(data_input_train, data_labels_train, epochs=100)"
403 ]
404 },
405 {
406 "cell_type": "code",
407 "execution_count": 9,
408 "metadata": {},
409 "outputs": [
410 {
411 "name": "stdout",
412 "output_type": "stream",
413 "text": [
414 "100/100 - 0s - loss: 0.0470 - accuracy: 0.0100\n",
415 "\n",
416 "Test accuracy: 0.01\n"
417 ]
418 }
419 ],
420 "source": [
421 "test_loss, test_acc = model.evaluate(data_input_test, data_labels_test, verbose=2)\n",
422 "\n",
423 "print('\\nTest accuracy:', test_acc)"
424 ]
425 },
426 {
427 "cell_type": "code",
428 "execution_count": 10,
429 "metadata": {},
430 "outputs": [
431 {
432 "name": "stdout",
433 "output_type": "stream",
434 "text": [
435 "[[0.3141548]]\n"
436 ]
437 }
438 ],
439 "source": [
440 "input = np.array([0.46,2,136])\n",
441 "input.shape = (1,3)\n",
442 "\n",
443 "prediction = model.predict(input)\n",
444 "print(prediction)"
445 ]
446 },
447 {
448 "cell_type": "code",
449 "execution_count": 11,
450 "metadata": {},
451 "outputs": [],
452 "source": [
453 "predictions = model.predict(data_input_test)"
454 ]
455 },
456 {
457 "cell_type": "code",
458 "execution_count": 12,
459 "metadata": {},
460 "outputs": [],
461 "source": [
462 "%matplotlib qt \n",
463 "plt.plot(predictions)\n",
464 "plt.plot(data_labels_test, 'r')\n",
465 "plt.show()"
466 ]
467 },
468 {
469 "cell_type": "code",
470 "execution_count": 204,
471 "metadata": {},
472 "outputs": [],
473 "source": [
474 "%matplotlib qt\n",
475 "a = data_labels_test - predictions\n",
476 "plt.plot(a[0])\n",
477 "plt.show()"
478 ]
479 },
480 {
481 "cell_type": "code",
482 "execution_count": 207,
483 "metadata": {},
484 "outputs": [],
485 "source": [
486 "%matplotlib qt\n",
487 "a = data_labels_test - predictions\n",
488 "plt.plot(predictions)\n",
489 "plt.plot(data_labels_test, 'r')\n",
490 "plt.plot(a[0], 'g')\n",
491 "plt.show()"
492 ]
493 },
494 {
495 "cell_type": "code",
496 "execution_count": 180,
497 "metadata": {},
498 "outputs": [
499 {
500 "data": {
501 "text/plain": [
502 "-0.08489150602276586"
503 ]
504 },
505 "execution_count": 180,
506 "metadata": {},
507 "output_type": "execute_result"
508 }
509 ],
510 "source": [
511 "np.average(a[0])"
512 ]
513 },
514 {
515 "cell_type": "code",
516 "execution_count": 182,
517 "metadata": {},
518 "outputs": [
519 {
520 "name": "stdout",
521 "output_type": "stream",
522 "text": [
523 "Model: \"sequential_13\"\n",
524 "_________________________________________________________________\n",
525 "Layer (type) Output Shape Param # \n",
526 "=================================================================\n",
527 "dense_38 (Dense) (None, 128) 512 \n",
528 "_________________________________________________________________\n",
529 "dense_39 (Dense) (None, 512) 66048 \n",
530 "_________________________________________________________________\n",
531 "dense_40 (Dense) (None, 512) 262656 \n",
532 "_________________________________________________________________\n",
533 "dense_41 (Dense) (None, 512) 262656 \n",
534 "_________________________________________________________________\n",
535 "dense_42 (Dense) (None, 128) 65664 \n",
536 "_________________________________________________________________\n",
537 "dense_43 (Dense) (None, 1) 129 \n",
538 "=================================================================\n",
539 "Total params: 657,665\n",
540 "Trainable params: 657,665\n",
541 "Non-trainable params: 0\n",
542 "_________________________________________________________________\n"
543 ]
544 }
545 ],
546 "source": [
547 "model.summary()"
548 ]
549 },
550 {
551 "cell_type": "code",
552 "execution_count": 183,
553 "metadata": {},
554 "outputs": [],
555 "source": [
556 "model.save('my_model.h5')"
557 ]
558 },
559 {
560 "cell_type": "code",
561 "execution_count": null,
562 "metadata": {},
563 "outputs": [],
564 "source": []
565 }
566 ],
567 "metadata": {
568 "kernelspec": {
569 "display_name": "Python 3",
570 "language": "python",
571 "name": "python3"
572 },
573 "language_info": {
574 "codemirror_mode": {
575 "name": "ipython",
576 "version": 3
577 },
578 "file_extension": ".py",
579 "mimetype": "text/x-python",
580 "name": "python",
581 "nbconvert_exporter": "python",
582 "pygments_lexer": "ipython3",
583 "version": "3.7.3"
584 }
585 },
586 "nbformat": 4,
587 "nbformat_minor": 2
588}
diff --git a/src/files/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb b/src/files/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb
new file mode 100644
index 0000000..2c0934c
--- /dev/null
+++ b/src/files/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb
@@ -0,0 +1,170 @@
1{
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "# Sentiment analysis of Guardian World News articles"
8 ]
9 },
10 {
11 "cell_type": "markdown",
12 "metadata": {},
13 "source": [
14 "## Get articles from a website"
15 ]
16 },
17 {
18 "cell_type": "markdown",
19 "metadata": {},
20 "source": [
21 "### Install rss parser dependency"
22 ]
23 },
24 {
25 "cell_type": "code",
26 "execution_count": null,
27 "metadata": {},
28 "outputs": [],
29 "source": [
30 "!pip3 install feedparser"
31 ]
32 },
33 {
34 "cell_type": "markdown",
35 "metadata": {},
36 "source": [
37 "### Parsing RSS feed for world news"
38 ]
39 },
40 {
41 "cell_type": "code",
42 "execution_count": null,
43 "metadata": {},
44 "outputs": [],
45 "source": [
46 "import feedparser\n",
47 "feed_url = \"https://www.theguardian.com/world/rss\"\n",
48 "feed = feedparser.parse(feed_url)"
49 ]
50 },
51 {
52 "cell_type": "code",
53 "execution_count": null,
54 "metadata": {},
55 "outputs": [],
56 "source": [
57 "import re\n",
58 "for item in feed.entries:\n",
59 " # sanitize html\n",
60 " item.description = re.sub('<[^<]+?>', '', item.description)"
61 ]
62 },
63 {
64 "cell_type": "markdown",
65 "metadata": {},
66 "source": [
67 "### Install Vader Sentiment library and perform sentiment analysis"
68 ]
69 },
70 {
71 "cell_type": "code",
72 "execution_count": null,
73 "metadata": {},
74 "outputs": [],
75 "source": [
76 "!pip3 install vaderSentiment"
77 ]
78 },
79 {
80 "cell_type": "code",
81 "execution_count": null,
82 "metadata": {},
83 "outputs": [],
84 "source": [
85 "from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer\n",
86 "analyser = SentimentIntensityAnalyzer()"
87 ]
88 },
89 {
90 "cell_type": "code",
91 "execution_count": null,
92 "metadata": {},
93 "outputs": [],
94 "source": [
95 "sentiment_results = []\n",
96 "for item in feed.entries:\n",
97 " sentiment_title = analyser.polarity_scores(item.title)\n",
98 " sentiment_description = analyser.polarity_scores(item.description)\n",
99 " sentiment_results.append([sentiment_title['compound'], sentiment_description['compound']])"
100 ]
101 },
102 {
103 "cell_type": "markdown",
104 "metadata": {},
105 "source": [
106 "### Install Matplotlib and visualize compound score"
107 ]
108 },
109 {
110 "cell_type": "code",
111 "execution_count": null,
112 "metadata": {},
113 "outputs": [],
114 "source": [
115 "!pip3 install matplotlib"
116 ]
117 },
118 {
119 "cell_type": "code",
120 "execution_count": null,
121 "metadata": {},
122 "outputs": [],
123 "source": [
124 "import matplotlib.pyplot as plt"
125 ]
126 },
127 {
128 "cell_type": "code",
129 "execution_count": null,
130 "metadata": {},
131 "outputs": [],
132 "source": [
133 "%matplotlib inline\n",
134 "plt.rcParams['figure.figsize'] = (15, 3)\n",
135 "plt.plot(sentiment_results, drawstyle='steps')\n",
136 "plt.title('Sentiment analysis relationship between title and description (Guardian World News)')\n",
137 "plt.legend(['title', 'description'])\n",
138 "plt.show()"
139 ]
140 },
141 {
142 "cell_type": "code",
143 "execution_count": null,
144 "metadata": {},
145 "outputs": [],
146 "source": []
147 }
148 ],
149 "metadata": {
150 "kernelspec": {
151 "display_name": "Python 3",
152 "language": "python",
153 "name": "python3"
154 },
155 "language_info": {
156 "codemirror_mode": {
157 "name": "ipython",
158 "version": 3
159 },
160 "file_extension": ".py",
161 "mimetype": "text/x-python",
162 "name": "python",
163 "nbconvert_exporter": "python",
164 "pygments_lexer": "ipython3",
165 "version": "3.7.3"
166 }
167 },
168 "nbformat": 4,
169 "nbformat_minor": 4
170}
diff --git a/src/files/sentiment-analysis/guardian-sa-title-desc-relationship.png b/src/files/sentiment-analysis/guardian-sa-title-desc-relationship.png
new file mode 100644
index 0000000..7195bbf
--- /dev/null
+++ b/src/files/sentiment-analysis/guardian-sa-title-desc-relationship.png
Binary files differ
diff --git a/src/files/sentiment-analysis/sentiment-analysis.ipynb b/src/files/sentiment-analysis/sentiment-analysis.ipynb
new file mode 100644
index 0000000..2c0934c
--- /dev/null
+++ b/src/files/sentiment-analysis/sentiment-analysis.ipynb
@@ -0,0 +1,170 @@
1{
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "# Sentiment analysis of Guardian World News articles"
8 ]
9 },
10 {
11 "cell_type": "markdown",
12 "metadata": {},
13 "source": [
14 "## Get articles from a website"
15 ]
16 },
17 {
18 "cell_type": "markdown",
19 "metadata": {},
20 "source": [
21 "### Install rss parser dependency"
22 ]
23 },
24 {
25 "cell_type": "code",
26 "execution_count": null,
27 "metadata": {},
28 "outputs": [],
29 "source": [
30 "!pip3 install feedparser"
31 ]
32 },
33 {
34 "cell_type": "markdown",
35 "metadata": {},
36 "source": [
37 "### Parsing RSS feed for world news"
38 ]
39 },
40 {
41 "cell_type": "code",
42 "execution_count": null,
43 "metadata": {},
44 "outputs": [],
45 "source": [
46 "import feedparser\n",
47 "feed_url = \"https://www.theguardian.com/world/rss\"\n",
48 "feed = feedparser.parse(feed_url)"
49 ]
50 },
51 {
52 "cell_type": "code",
53 "execution_count": null,
54 "metadata": {},
55 "outputs": [],
56 "source": [
57 "import re\n",
58 "for item in feed.entries:\n",
59 " # sanitize html\n",
60 " item.description = re.sub('<[^<]+?>', '', item.description)"
61 ]
62 },
63 {
64 "cell_type": "markdown",
65 "metadata": {},
66 "source": [
67 "### Install Vader Sentiment library and perform sentiment analysis"
68 ]
69 },
70 {
71 "cell_type": "code",
72 "execution_count": null,
73 "metadata": {},
74 "outputs": [],
75 "source": [
76 "!pip3 install vaderSentiment"
77 ]
78 },
79 {
80 "cell_type": "code",
81 "execution_count": null,
82 "metadata": {},
83 "outputs": [],
84 "source": [
85 "from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer\n",
86 "analyser = SentimentIntensityAnalyzer()"
87 ]
88 },
89 {
90 "cell_type": "code",
91 "execution_count": null,
92 "metadata": {},
93 "outputs": [],
94 "source": [
95 "sentiment_results = []\n",
96 "for item in feed.entries:\n",
97 " sentiment_title = analyser.polarity_scores(item.title)\n",
98 " sentiment_description = analyser.polarity_scores(item.description)\n",
99 " sentiment_results.append([sentiment_title['compound'], sentiment_description['compound']])"
100 ]
101 },
102 {
103 "cell_type": "markdown",
104 "metadata": {},
105 "source": [
106 "### Install Matplotlib and visualize compound score"
107 ]
108 },
109 {
110 "cell_type": "code",
111 "execution_count": null,
112 "metadata": {},
113 "outputs": [],
114 "source": [
115 "!pip3 install matplotlib"
116 ]
117 },
118 {
119 "cell_type": "code",
120 "execution_count": null,
121 "metadata": {},
122 "outputs": [],
123 "source": [
124 "import matplotlib.pyplot as plt"
125 ]
126 },
127 {
128 "cell_type": "code",
129 "execution_count": null,
130 "metadata": {},
131 "outputs": [],
132 "source": [
133 "%matplotlib inline\n",
134 "plt.rcParams['figure.figsize'] = (15, 3)\n",
135 "plt.plot(sentiment_results, drawstyle='steps')\n",
136 "plt.title('Sentiment analysis relationship between title and description (Guardian World News)')\n",
137 "plt.legend(['title', 'description'])\n",
138 "plt.show()"
139 ]
140 },
141 {
142 "cell_type": "code",
143 "execution_count": null,
144 "metadata": {},
145 "outputs": [],
146 "source": []
147 }
148 ],
149 "metadata": {
150 "kernelspec": {
151 "display_name": "Python 3",
152 "language": "python",
153 "name": "python3"
154 },
155 "language_info": {
156 "codemirror_mode": {
157 "name": "ipython",
158 "version": 3
159 },
160 "file_extension": ".py",
161 "mimetype": "text/x-python",
162 "name": "python",
163 "nbconvert_exporter": "python",
164 "pygments_lexer": "ipython3",
165 "version": "3.7.3"
166 }
167 },
168 "nbformat": 4,
169 "nbformat_minor": 4
170}
diff --git a/src/notes/golang-profiling-simplified.md b/src/notes/golang-profiling-simplified.md
index a49de67..c8c6f16 100644
--- a/src/notes/golang-profiling-simplified.md
+++ b/src/notes/golang-profiling-simplified.md
@@ -1,4 +1,5 @@
1title: Golang profiling simplified 1title: Golang profiling simplified
2description: Golang profiling demystified
2date: 2017-03-07 3date: 2017-03-07
3tags: blog 4tags: blog
4hide: false 5hide: false
diff --git a/src/notes/simplifying-and-reducing-clutter.md b/src/notes/simplifying-and-reducing-clutter.md
index b435834..064f08b 100644
--- a/src/notes/simplifying-and-reducing-clutter.md
+++ b/src/notes/simplifying-and-reducing-clutter.md
@@ -1,4 +1,5 @@
1title: Simplifying and reducing clutter in my life and work 1title: Simplifying and reducing clutter in my life and work
2description: Simplifying and reducing clutter in my life and work
2date: 2019-10-14 3date: 2019-10-14
3tags: blog 4tags: blog
4hide: false 5hide: false
diff --git a/src/notes/what-i-ve-learned-developing-ad-server.md b/src/notes/what-i-ve-learned-developing-ad-server.md
index 527f9d0..d1cc791 100644
--- a/src/notes/what-i-ve-learned-developing-ad-server.md
+++ b/src/notes/what-i-ve-learned-developing-ad-server.md
@@ -1,4 +1,5 @@
1title: What I've learned developing ad server 1title: What I've learned developing ad server
2description: Lessons I learned developing contextual ad server
2date: 2017-04-17 3date: 2017-04-17
3tags: blog 4tags: blog
4hide: false 5hide: false
diff --git a/src/static/style.css b/src/static/style.css
index 4654ae7..3cb585a 100644
--- a/src/static/style.css
+++ b/src/static/style.css
@@ -4,7 +4,7 @@ body {
4} 4}
5 5
6main { 6main {
7 max-width: 680px; 7 max-width: 660px;
8 padding: 20px 30px; 8 padding: 20px 30px;
9} 9}
10 10
@@ -68,6 +68,12 @@ th, td {
68 padding: 5px 10px; 68 padding: 5px 10px;
69} 69}
70 70
71p.modified {
72 font-style: oblique;
73 font-size: 90%;
74 margin-top: 50px;
75}
76
71::selection { 77::selection {
72 background: #ff0; 78 background: #ff0;
73 color: #000; 79 color: #000;