diff --git a/sotorrent/README.md b/sotorrent/README.md index 2824898..d8a48d9 100644 --- a/sotorrent/README.md +++ b/sotorrent/README.md @@ -1,4 +1,412 @@ -## Importing the SOTorrent dataset +# About The SO and SOTorrent + +Stack Overflow (SO) is the most popular question-and-answer (Q&A) website for software developers, providing a large amount of copyable code snippets. SOTorrent, an open dataset based on the official SO data dump. SOTorrent provides access to the version history of SO content at the level of whole posts and individual text and code blocks. +[Reference](https://arxiv.org/pdf/1809.02814.pdf) + +## Related Papers + +1. [SOTorrent: Studying the Origin, Evolution, and Usage of Stack Overflow Code Snippets](https://arxiv.org/abs/1809.02814) +2. [SOTorrent: Reconstructing and Analyzing the Evolution of Stack Overflow Posts](https://arxiv.org/abs/1803.07311) + +## Dataset + +The Stack Overflow data has been extracted from the official [Stack Exchange data dump](https://archive.org/details/stackexchange) released 2021-09-07. + +The GitHub references have been retrieved from the [Google BigQuery GitHub data set](https://cloud.google.com/bigquery/public-data/github) on 2021-01-04 (last updated 2020-12-31 according to table info). + + +## Stack Exchange Vs. Stack Overflow + +Stack Exchange is a network of sites, of which Stack Overflow is one. [This website](https://stackexchange.com/sites) indicates the coverage of the Stack Exchange website. In addition, Stack Overflow is a question and answer site for professional and enthusiast programmers. It's built and run by you as part of the Stack Exchange network of Q&A sites. +[Reference](https://meta.stackexchange.com/questions/79593/what-is-the-difference-between-stack-overflow-and-stack-exchange) + + +## Offline Working - For OSX and Linux OSs + +### 1. Import the Stack Exchange data dump to PC + +As I mentioned before, on the [Stack Exchange data dump](https://archive.org/details/stackexchange) page we can find all data dumps that Stack Exchange covers inside itself. However, we currently need just datasets related to the Stack Overflow website. + + 0. Change the current directory to the working directory. + ```console + aminghadesi@MOOSELab$ cd + aminghadesi@MOOSELab$ wget https://github.com/ghadesi/db-scripts/archive/refs/heads/master.zip + aminghadesi@MOOSELab$ unzip master.zip + aminghadesi@MOOSELab$ mkdir sotorrent && cd ./sotorrent + ``` + 1. Run the [`1_download_so-dump.sh`](so-dump/1_download_so-dump.sh) script. This script download files related to Stack Overflow. + ```console + aminghadesi@MOOSELab$ chmod +x ../db-scripts-master/sotorrent/so-dump/1_download_so-dump.sh + aminghadesi@MOOSELab$ sh ../db-scripts-master/sotorrent/so-dump/1_download_so-dump.sh + ``` +If you are using SSH, it's better to run the task at background. + ```console + aminghadesi@MOOSELab$ nohup sh ../db-scripts-master/sotorrent/so-dump/1_download_so-dump.sh & +``` +By the bellow command we can check the status of download. + ```console + aminghadesi@MOOSELab$ watch tail -2 nohup.out +``` + 2. Run the [`2_process_7z_files.sh`](so-dump/2_process_7z_files.sh) script. This script unzips all CSV and XML files. + ```console + aminghadesi@MOOSELab$ source ../db-scripts-master/sotorrent/so-dump/2_process_7z_files.sh + ``` + +### 2. Install MySQL +In this step, we have to create a SQL database for inserting dataset into our local database. + +> Set password for `root` and `sotorrent` MySQL users + +* For OSX 11.5.2: + - [This doc](https://flaviocopes.com/mysql-how-to-install/) helps us to create and start this service on our OSX. +* For Ubuntu Distribution 20.04: + - [This doc](https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-18-04) aids to establish and prepare MySQL service on Ubuntu OS. + +### 3. Prepare and Load SOTorrent Dataset + +Edit the SQL script [`load_sotorrent.sh`](load_sotorrent.sh) to change: +- The passwords for the `root` and `sotorrent` MySQL users +- The path where the MySQL dump files are located. + +For loading the SOTorrent dataset to created database, we should run [`load_sotorrent.sh`](load_sotorrent.sh) script. +```console + aminghadesi@MOOSELab$ source load_sotorrent.sh +``` + + +## Database schema of SOTorrent +Then below photo indicates the tables and their relations from the offical SO dump that are marked gray. + +![DB_scheme](database-model/sotorrent_2018-12-09_model.png) + +## Phase 0: Create Tags based on Stackoverflow (SO) + +### We defined the major ML frameworks based on the Python language, including: + +- TensorFlow: (https://www.tensorflow.org/) TensorFlow was developed at Google Brain and an open-source project. TF can: Perform regression, classification, neural networks, etc., and run on both CPUs and GPUs. + +- PyTorch: (https://pytorch.org/) PyTorch was developed by FAIR, Facebook AI Research. It is the leading competitor to TensorFlow. In addition, it provides almost the same TensorFlow services. + +- Sikit-learn: (https://scikit-learn.org/stable/#) Scikit-learn provides a range of supervised and unsupervised learning algorithms via a consistent interface in Python. + +- Keras: (https://keras.io/) Keras is a neural network library and a deep learning API written in Python, running on top of the machine learning platform TensorFlow. It was developed with a focus on enabling fast experimentation. + +- NLTK: (https://www.nltk.org/) The Natural Language Toolkit, more commonly NLTK, is a suite of libraries and programs for symbolic and statistical natural language processing for English written in the Python programming language. + +- Huggingface: (https://huggingface.co/) Hugging Face is an open-source provider of natural language processing (NLP) technologies. + +- Spark ML: (https://spark.apache.org/docs/1.2.2/ml-guide.html) aims to provide a uniform set of high-level APIs that help users create and tune practical machine learning pipelines. + +- Torch: (http://torch.ch/) We ignore this framework due to the Lua programming language. + +### Find ML tags on the section of Stackoverflow (https://stackoverflow.com/tags): + +This [website](https://data.stackexchange.com/stackoverflow/queries) aids us in extracting tags from SO DB; also, we can use pattern matching for our queries. The LIKE keyword searches specific patterns based on the regular expression to contain the pattern. Besides that, this [link](https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms187489(v=sql.105)?redirectedfrom=MSDN) helps us to work with LIKE statement properly. In the end, we can find many quarry examples on this [page](https://data.stackexchange.com/stackoverflow/queries). + +[Example](https://data.stackexchange.com/stackoverflow/query/1468684/identify-the-tensorflow-tags): +``` sql +-- Identify the Tensorflow tags related to ML +Select +CASE + WHEN TagName LIKE '%tensorflow%' THEN 'tensorflow' + WHEN TagName LIKE '%pytorch%' THEN 'pytorch' + WHEN TagName LIKE '%scikit-learn%' THEN 'scikit-learn' + WHEN TagName LIKE '%keras%' THEN 'keras' + WHEN TagName LIKE '%nltk%' THEN 'nltk' + WHEN TagName LIKE '%huggingface%' THEN 'huggingface' + WHEN TagName LIKE '%spark-ml%' THEN 'spark-ml' +END As Framework, TagName, [Count] +From Tags +Where (TagName LIKE '%tensorflow%' OR + TagName LIKE '%pytorch%' OR + TagName LIKE '%scikit-learn%' OR + TagName LIKE '%keras%' OR + TagName LIKE '%nltk%' OR + TagName LIKE '%huggingface%' OR + TagName LIKE '%spark-ml%') AND + [Count] > 0 -- We can ignore small tags numbers +ORDER BY [Count] DESC +``` + +The result is [here](TF_ML_Tags.csv). + +## Phase 1: Exteract Q/A posts on Stackoverflow (SO) Based on the favorit tags from SOTorrent +### Informattion about SOTorrent DB: +1. The `sotorrent-org.2020_12_31.Posts` table: For each question post we select these informaion. +- question_id +- title +- body +- creation date +- view count +- answer count +- comment count +- score of question +- with accepted answer or not +- time to get accepted answer +- time to get first answer + +2. The `PostType` table: + + | Id | Type | + |----|----------| + | 1 | Question | + | 2 | Answer | + +### Prepare the BigQuary environment for our project: +We did this part of the project by the BigQuary service. We added the SOTorrent DB from this [website](https://empirical-software.engineering/sotorrent/). We have to make sure that we signed in to the Gmail account, and by clicking on the left blue button, Online Access (BigQuary), we redirected to the Google Cloud Platform service. Then, we can see two projects in the "Explorer" section, including `sotorrent` and `bigquary-public-data`. The "+ COMPOSE NEW QUARY" button on the top right of the window aids us in implementing our SQL queries inside this environment. I have to mention that clicking on the `sotorrent` project indicates entire tables. If we want to see the schema and data on tables, we can see all of them just by double-clicking on a table. + +At the first time, we usually receive the below error: + +> Access Denied: Project sotorrent-org: User does not have bigquery.jobs.create permission in project sotorrent-org. + +First of all, we should create a project by clicking on "Select a project", close to the Google Cloud Platform name on the top left, and then click on the "NEW PROJECT" button. We have to choose a name for our new project at the next step; we set "Project 37413" and also accepted `bamboo-creek-327421` name for Project ID. In the end, we have to select this project in the "Select a project" section. + +### Upload the CSV of the favorite tags to : + +In the next step, we have to insert our favorite tags, the Phase 0 result, into this environment. We can press three points on the right of the `bamboo-creek-327421` and click on the "Create dataset" option after that. We defined the `Tags` name for our Dataset ID and pressed the "CREATE DATASET" button. Then, we have to open the Tags dataset and choose the "+ CREATE TABLE" button and configure the below setups: + +![Setup_photo](tableSettings.png) + +### Find Q/A based on the ML framework tags on Stackoverflow: + +By the below command, we can reach our goal on this step: + +```sql +SELECT posts.Id, posts.PostTypeId, + posts.AcceptedAnswerId, + posts.CreationDate, + posts.ViewCount, + posts.AnswerCount, + posts.CommentCount, + posts.Score, + posts.Title, + posts.Body, + posts.Tags +FROM `sotorrent-org.2020_12_31.Posts` As posts +LEFT JOIN `smooth-zenith-326513.Tags.DesireTags` As tags On TRUE +WHERE posts.PostTypeId=2 OR (posts.PostTypeId=1 AND posts.Tags like '%' || tags.TagName || '%') +``` +Unfortunately, because of the numbers of answer rows, 30,680,111, and limitations on BigQuery: + +```sql +SELECT COUNT(Id) +FROM `sotorrent-org.2020_12_31.Posts` AS posts +WHERE posts.PostTypeId=2 +``` + +We cannot aggregate top conditions with together, So we decided to separate the conditions: + +#### Query 1 (Questions) +```sql +SELECT posts.Id, posts.PostTypeId, + posts.AcceptedAnswerId, + posts.CreationDate, + posts.ViewCount, + posts.AnswerCount, + posts.CommentCount, + posts.Score, + posts.Title, + posts.Body, + posts.Tags +FROM `sotorrent-org.2020_12_31.Posts` As posts +LEFT JOIN `smooth-zenith-326513.Tags.DesireTags` As tags On TRUE +WHERE posts.PostTypeId=1 AND posts.Tags like '%' || tags.TagName || '%' +``` +#### Query 2 (Answers) +```sql +SELECT posts.Id, posts.PostTypeId, + posts.AcceptedAnswerId, + posts.CreationDate, + posts.ViewCount, + posts.AnswerCount, + posts.CommentCount, + posts.ParentId, + posts.Score, + posts.Title, + posts.Body, + posts.Tags +FROM `sotorrent-org.2020_12_31.Posts` As posts +WHERE posts.PostTypeId=2 +``` +#### Query 3: Find the median of numberical values +```sql +SELECT + PERCENTILE_CONT(posts.ViewCount, 0.5) OVER () AS View_median, + PERCENTILE_CONT(posts.AnswerCount, 0.5) OVER () AS Ans_count_median, + PERCENTILE_CONT(posts.CommentCount, 0.5) OVER () AS Com_count_median, + PERCENTILE_CONT(posts.Score, 0.5) OVER () AS Score_median +FROM + `sotorrent-org.2020_12_31.Posts` As posts +LIMIT + 1 + ``` + + +We change the query configuration to the below parameters: + +![query_photo](quarySettings.png) + +### Phase 1 results: + +Email Test: yutyuy6urt@gmail.com + +#### Result of Query 1 + +|Job Parameter|Description| +| ------------- |-------------| +|Job ID|`bamboo-creek-327421:US.bquxjob_20dcde75_17c2e80008b`| +|User|`amin[dot]ghadesi[at]gmail[dot]com`| +|Location|`United States (US)`| +|Creation time|`Sep 28, 2021, 6:21:53 PM`| +|Start time|`Sep 28, 2021, 6:21:53 PM`| +|End time|`Sep 28, 2021, 6:22:14 PM`| +|Duration|**20.9 sec**| +|Bytes processed|**56.49 GB**| +|Bytes billed|**56.49 GB**| +|Job priority|`INTERACTIVE`| +|Destination table|`bamboo-creek-327421:Tags.results-tag-1`| +|Use legacy SQL|`false`| +|Write preference|`Overwrite table`| +|Slot time consumed|`27 min 43.396 sec`| +|Bytes shuffled|`723.07 MB`| +|Bytes spilled to disk|`0 B`| +|Size|**359.3 MB**| +|Number of rows|**163,194**| + +#### Update Query: Find updated posts +```sql +SELECT p.Id, p.PostTypeId, + p.AcceptedAnswerId, + p.CreationDate, + p.ViewCount, + p.AnswerCount, + p.CommentCount, + p.Score, + p.Title, + p.Body, + p.Tags +FROM Posts as p +inner join posts q + on q.id = coalesce(p.parentid, p.id) -- only questions have tags +WHERE p.CreationDate > '2020-12-31' AND -- After this time + p.PostTypeId=1 AND -- Just questions + (p.Tags LIKE '%tensorflow%' OR + p.Tags LIKE '%pytorch%' OR + p.Tags LIKE '%scikit-learn%' OR + p.Tags LIKE '%keras%' OR + p.Tags LIKE '%nltk%' OR + p.Tags LIKE '%huggingface%' OR + p.Tags LIKE '%spark-ml%') +``` + +#### Update Query: Find updated answers +```sql +with cte1 as ( +SELECT + p.Id, + p.PostTypeId, + p.AcceptedAnswerId, + p.CreationDate, + p.ViewCount, + p.AnswerCount, + p.CommentCount, + p.Score, + p.Title, + p.Body, + p.Tags, + p.parentid + +FROM Posts as p +inner join posts q + on q.id = coalesce(p.parentid, p.id) -- only questions have tags + +WHERE p.CreationDate > '2020-12-31' AND -- After this time + p.PostTypeId=1 AND -- Just answers + (p.Tags LIKE '%tensorflow%' OR + p.Tags LIKE '%pytorch%' OR + p.Tags LIKE '%scikit-learn%' OR + p.Tags LIKE '%keras%' OR + p.Tags LIKE '%nltk%' OR + p.Tags LIKE '%huggingface%' OR + p.Tags LIKE '%spark-ml%') +) +select + r.Id, + --r.AcceptedAnswerId, + --r.PostTypeId, + r.parentid, + --cte1.Id, + --cte1.PostTypeId, + cte1.AcceptedAnswerId, + cte1.CreationDate, + cte1.ViewCount, + cte1.AnswerCount, + cte1.CommentCount, + cte1.Score, + cte1.Title, + cte1.Body, + cte1.Tags, + cte1.parentid + +from posts r +inner join cte1 + on cte1.id = r.parentid +where + r.PostTypeId=2 +``` + +#### Update Query: Find the accepted answer metadata for each library + +```sql +with cte1 as ( +SELECT + p.Id, + p.PostTypeId, + p.AcceptedAnswerId, + p.CreationDate, + p.ViewCount, + p.AnswerCount, + p.CommentCount, + p.Score, + p.Title, + p.Body, + p.Tags, + p.parentid + +FROM Posts as p +inner join posts q + on q.id = coalesce(p.parentid, p.id) -- only questions have tags + +WHERE + p.PostTypeId=1 AND -- Just answers + p.AcceptedAnswerId IS NOT NULL AND -- Has acc answer + p.Tags LIKE '%tensorflow%' + --(p.Tags LIKE '%tensorflow%' OR + -- p.Tags LIKE '%pytorch%' OR + -- p.Tags LIKE '%scikit-learn%' OR + -- p.Tags LIKE '%keras%' OR + -- p.Tags LIKE '%nltk%' OR + -- p.Tags LIKE '%huggingface%' OR + -- p.Tags LIKE '%spark-ml%') +) +select + r.Id, + r.parentid, + r.PostTypeId, + r.parentid, + r.CreationDate, + r.Score, + r.Body, + r.LastActivityDate + +from posts r +inner join cte1 + on cte1.id = r.parentid +where + r.PostTypeId=2 +``` + +---- 1. Unzip all CSV and XML files. @@ -18,11 +426,8 @@ 4. Run the `load_sotorrent.sh` script. -## Data +---- -The Stack Overflow data has been extracted from the official [Stack Exchange data dump](https://archive.org/details/stackexchange) released 2020-12-08. - -The GitHub references have been retrieved from the [Google BigQuery GitHub data set](https://cloud.google.com/bigquery/public-data/github) on 2021-01-04 (last updated 2020-12-31 according to table info). ## MySQL Troubleshooting diff --git a/sotorrent/TF_ML_Tags.csv b/sotorrent/TF_ML_Tags.csv new file mode 100644 index 0000000..718435b --- /dev/null +++ b/sotorrent/TF_ML_Tags.csv @@ -0,0 +1,64 @@ +Framework,TagName,Count +"tensorflow","tensorflow","71931" +"keras","keras","36808" +"scikit-learn","scikit-learn","24215" +"pytorch","pytorch","13942" +"nltk","nltk","6649" +"tensorflow","tensorflow2.0","4780" +"spark-ml","apache-spark-mllib","2197" +"tensorflow","tensorflow-lite","1738" +"tensorflow","tensorflow-datasets","1703" +"keras","tf.keras","1621" +"keras","keras-layer","1444" +"tensorflow","tensorflow.js","1313" +"tensorflow","tensorflow-serving","1204" +"huggingface","huggingface-transformers","1091" +"spark-ml","apache-spark-ml","888" +"tensorflow","tensorflow-estimator","670" +"tensorflow","tensorflow-gpu","429" +"tensorflow","tensorflow-probability","284" +"tensorflow","tensorflow-hub","270" +"keras","keras-2","268" +"tensorflow","tensorflow2.x","254" +"tensorflow","tensorflow-federated","241" +"huggingface","huggingface-tokenizers","173" +"pytorch","pytorch-lightning","159" +"tensorflow","tensorflowjs-converter","124" +"pytorch","pytorch-dataloader","113" +"keras","keras-tuner","100" +"tensorflow","tensorflow-slim","87" +"tensorflow","tensorflow-model-garden","79" +"tensorflow","tensorflow1.15","71" +"tensorflow","tensorflow-transform","70" +"keras","keras-rl","68" +"keras","auto-keras","62" +"tensorflow","tensorflow-xla","61" +"tensorflow","tensorflow2","56" +"pytorch","spacy-pytorch-transformers","41" +"nltk","nltk-trainer","41" +"nltk","nltk-book","40" +"tensorflow","tensorflow-agents","37" +"tensorflow","tensorflow-data-validation","36" +"huggingface","huggingface-datasets","28" +"tensorflow","tensorflow-model-analysis","26" +"tensorflow","tensorflow-gradient","23" +"tensorflow","distributed-tensorflow","22" +"tensorflow","tensorflow-ssd","22" +"tensorflow","tensorflowsharp","21" +"tensorflow","tensorflowjs","19" +"pytorch","gpytorch","18" +"tensorflow","tensorflow-android","16" +"tensorflow","swift-for-tensorflow","15" +"tensorflow","tensorflow-quantum","15" +"tensorflow","tensorflow-c++","14" +"scikit-learn","scikit-learn-pipeline","12" +"tensorflow","tensorflow-layers","12" +"keras","keras-vggface","10" +"keras","keras-metrics","10" +"pytorch","pytorch-ignite","9" +"tensorflow","intel-tensorflow","6" +"pytorch","pytorch3d","5" +"pytorch","intel-pytorch","3" +"keras","keras-lambda","3" +"tensorflow","tensorflow1.12","1" +"tensorflow","tensorflow-addons","1" \ No newline at end of file diff --git a/sotorrent/load_sotorrent.sh b/sotorrent/load_sotorrent.sh index b03b799..4479e71 100644 --- a/sotorrent/load_sotorrent.sh +++ b/sotorrent/load_sotorrent.sh @@ -1,8 +1,14 @@ #!/bin/sh set -Eeuo pipefail -root_password="_AqUjvtv68E\$N!r]" # update this according to your local configuration -sotorrent_password="4ar7JKS2mfgGHiDA" # update this according to your local configuration +# Update this part according to your local configuration +root_password="_AqUjvtv68E\$N!r]" +sotorrent_password="4ar7JKS2mfgGHiDA" + +# Absolute path to SQL dump files (consider MySQL's secure-file-priv option) +data_path="/tmp" # For ~~> Linux and OSX +# data_path="E:/Temp" # Cygwin ~~> For Windows OS + log_file="sotorrent.log" sotorrent_db="sotorrent20_12" db_init=false @@ -10,10 +16,6 @@ load_so=false load_gh=false load_sotorrent=false -# absolute path to SQL dump files (consider MySQL's secure-file-priv option) -data_path="E:/Temp" # Cygwin -#data_path="/tmp" # Linux - sql_import_prefix="SET autocommit=0; SET unique_checks=0; SET foreign_key_checks=0;" sql_import_suffix="SET unique_checks=1; SET foreign_key_checks=1; COMMIT; SET autocommit=1;"; diff --git a/sotorrent/quarySettings.png b/sotorrent/quarySettings.png new file mode 100644 index 0000000..3e2e0bc Binary files /dev/null and b/sotorrent/quarySettings.png differ diff --git a/sotorrent/so-dump/1_download_so-dump.sh b/sotorrent/so-dump/1_download_so-dump.sh index 3f5c866..90f1b8c 100755 --- a/sotorrent/so-dump/1_download_so-dump.sh +++ b/sotorrent/so-dump/1_download_so-dump.sh @@ -1,11 +1,34 @@ -#!/bin/bash -set -Eeuo pipefail +# The env command wrapping +#!/usr/bin/env bash +DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd) +#set -Eeuo pipefail -wget https://archive.org/download/stackexchange/stackoverflow.com-Badges.7z -wget https://archive.org/download/stackexchange/stackoverflow.com-Comments.7z -wget https://archive.org/download/stackexchange/stackoverflow.com-PostHistory.7z -wget https://archive.org/download/stackexchange/stackoverflow.com-PostLinks.7z -wget https://archive.org/download/stackexchange/stackoverflow.com-Posts.7z -wget https://archive.org/download/stackexchange/stackoverflow.com-Tags.7z -wget https://archive.org/download/stackexchange/stackoverflow.com-Users.7z -wget https://archive.org/download/stackexchange/stackoverflow.com-Votes.7z +# POSIX sh and especially bash have a number of settings that can help write safe shell scripts. +# NAME +# set - allows us to change the values of shell option +# COMMAND-LINE OPTIONS +# -E +# Allow error traps on function calls, subshell environment, and command substitutions. +# -e +# If a command fails, this switch will make the whole script exit. +# -u +# Treat unset variables as an error, and immediately exit. +# -o option-name +# pipefail +# If set, the return value of a pipeline is the value of the last (rightmost) command to +# exit with a non-zero status, or zero if all commands in the pipeline exit successfully. +# This option is disabled by default. +# +# Reference: +# https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html +# https://transang.me/best-practice-to-make-a-shell-script/ +# https://sipb.mit.edu/doc/safe-shell/ + +wget -c https://archive.org/download/stackexchange/stackoverflow.com-Badges.7z +wget -c https://archive.org/download/stackexchange/stackoverflow.com-Comments.7z +wget -c https://archive.org/download/stackexchange/stackoverflow.com-PostHistory.7z +wget -c https://archive.org/download/stackexchange/stackoverflow.com-PostLinks.7z +wget -c https://archive.org/download/stackexchange/stackoverflow.com-Posts.7z +wget -c https://archive.org/download/stackexchange/stackoverflow.com-Tags.7z +wget -c https://archive.org/download/stackexchange/stackoverflow.com-Users.7z +wget -c https://archive.org/download/stackexchange/stackoverflow.com-Votes.7z diff --git a/sotorrent/tableSettings.png b/sotorrent/tableSettings.png new file mode 100644 index 0000000..26ef517 Binary files /dev/null and b/sotorrent/tableSettings.png differ