Dec 4, 2018

Using git (VS 2017 edition) with VSCode

Make sure the folder contains git.exe is in PATH in Windows.

For Visual Studio Community Edition git.exe is in:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Git\cmd

Add project to local git

cd "folder path to your repo"
git init
git add . # add everything
git commit -m "initial commit" 

Use source control tab in VS Code

If you don't see GIT in source control tab you can update your git.exe location.

  1. Go to settings in VSCode and search for "git path".
  2. Click "Edit in settings.json"
  3. Add path to user settings

"git.path": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\Common7\\IDE\\CommonExtensions\\Microsoft\\TeamFoundation\\Team Explorer\\Git\\cmd\\git.exe"

Add to remote repository

C:\repo>git config credential.helper store

C:\repo>git push https://gitlab.com/username/repo.git --all
git: 'remote-https' is not a git command. See 'git --help'.
git-remote-https command is not reachable
C:\repo>git-remote-https
'git-remote-https' is not recognized as an internal or external command,
operable program or batch file.
Add git-remote-https.exe folder path to PATH.
C:\repo>SET PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Git\mingw32\bin
Now it is reachable.
C:\repo> git-remote-https                                                                                                      
error: remote-curl: usage: git remote-curl  []
C:\repo>git push https://gitlab.com/username/repo.git
git: 'credential-cache' is not a git command. See 'git --help'.
Username for 'https://gitlab.com': username
Password for 'https://username@gitlab.com':
git: 'credential-cache' is not a git command. See 'git --help'.
Counting objects: 2653, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2324/2324), done.
Writing objects: 100% (2653/2653), 23.62 MiB | 170.00 KiB/s, done.
Total 2653 (delta 670), reused 0 (delta 0)
remote: Resolving deltas: 100% (670/670), done.
To https://gitlab.com/username/repo.git
 * [new branch]      master -> master
Error: 'credential-cache' is not a git command

For msysgit versions 1.8.1 and above
git config --global credential.helper wincred
Versions older than 1.8.1
git config --global credential.helper winstore
Git config file:
[credential]
 helper = winstore
Related errors:
Git http-push is not a git-command
Adding "..\mingw32\bin" folder also solves it.

VSCode commit

Now you should be able to commit and push to remote repository in VSCode. After any change go to source control tab and press "Stage Changes" button. Fill the message and press Commit (check icon) button.

Nov 26, 2018

Cordova build errors and fixes

Creating a new cordova project

This is where we start to create a new project.
cordova create hello com.example.hello HelloWorld
Adding Android platform.
C:\hello>cordova platform add android
Using cordova-fetch for cordova-android@~7.1.1
Adding android project...
Creating Cordova project for the Android platform:
        Path: platforms\android
        Package: com.example.hello
        Name: hello
        Activity: MainActivity
        Android target: android-27
Android project created with cordova-android@7.1.2
Android Studio project detected
Android Studio project detected
Discovered plugin "cordova-plugin-whitelist" in config.xml. Adding it to the project
Installing "cordova-plugin-whitelist" for android

Adding cordova-plugin-whitelist to package.json
Saved plugin info for "cordova-plugin-whitelist" to config.xml
--save flag or autosave detected
Saving android@~7.1.2 into config.xml file ...

Run the following command to build the project for all platforms

cordova build

Build Errors

ERROR1:
Error occurred during initialization of VM
Could not reserve enough space for 2097152KB object heap
Fix
Go to Start->Control Panel->System->Advanced(tab)->Environment Variables->System
Variables->New:
Variable name: _JAVA_OPTIONS   
Variable value: -Xmx512M

Variable name: Path  
Variable value: ;C:\Program Files\Java\jre6\bin;F:\JDK\bin;  
Change this to your appropriate path.
Restart computer!
ERROR2:
File C:\Users\oktay\.android\repositories.cfg could not be loaded.
Checking the license for package Android SDK Build-Tools 26.0.2 in C:\Program Files (x86)\Android\android-sdk\licenses

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':CordovaLib'.
> You have not accepted the license agreements of the following SDK components:
  [Android SDK Build-Tools 26.0.2].
  Before building your project, you need to accept the license agreements and complete the installation of the missing components using the Android Studio SDK Manager.
  Alternatively, to learn how to transfer the license agreements from one workstation to another, go to http://d.android.com/r/studio-ui/export-licenses.html
Fix
Create license file in %ANDROID_HOME%
mkdir "%ANDROID_HOME%\licenses"
echo |set /p="8933bad161af4178b1185d1a37fbf41ea5269c55" > "%ANDROID_HOME%\licenses\android-sdk-license"
ERROR3:
Warning: License for package Android SDK Build-Tools 26.0.2 not accepted.
Fix
Manually accept the license.
C:\Program Files (x86)\Android\android-sdk\tools\bin>sdkmanager --update && yes | sdkmanager --licenses
ERROR4:
Checking the license for package Android SDK Build-Tools 26.0.2 in C:\Program Files (x86)\Android\android-sdk\licenses
License for package Android SDK Build-Tools 26.0.2 accepted.
Preparing "Install Android SDK Build-Tools 26.0.2 (revision: 26.0.2)".
Warning: Failed to read or create install properties file.

The SDK directory (C:\Program Files (x86)\Android\android-sdk) is not writeable,
  please update the directory permissions.
Fix
Give Full permission to Everyone for sdk folder ( C:\Program Files (x86)\Android\android-sdk)

Giving full permission to "ALL APPLICATION PACKAGES" and "TrustedInstaller" didn't solve my problem.
Checking the license for package Android SDK Build-Tools 26.0.2 in C:\Program Files (x86)\Android\android-sdk\licenses
License for package Android SDK Build-Tools 26.0.2 accepted.
Preparing "Install Android SDK Build-Tools 26.0.2 (revision: 26.0.2)".
...
BUILD SUCCESSFUL in 2m 55s
46 actionable tasks: 46 executed
Built the following apk(s):
        C:\hello\platforms\android\app\build\outputs\apk\debug\app-debug.apk

Build project and Emulate in Andorid

cordova build
cordova emulate android
APPENDIX: A WARNING
C:\Program Files (x86)\Android\android-sdk\tools\bin>sdkmanager
Picked up _JAVA_OPTIONS: -Xmx512M
Warning: cvc-pattern-valid: Value '' is not facet-valid with respect to pattern '[a-zA-Z0-9_-]+' for type 'idType'.
Warning: cvc-type.3.1.3: The value '' of element 'id' is not valid.
Warning: cvc-pattern-valid: Value '' is not facet-valid with respect to pattern '[a-zA-Z0-9_-]+' for type 'idType'.
Warning: cvc-type.3.1.3: The value '' of element 'id' is not valid.
Warning: File C:\Users\oktay\.android\repositories.cfg could not be loaded.
[=======================================] 100% Computing updates...
Error resolved by creating an empty repositories.cfg file.

Cordova installation info is here

Nov 14, 2018

Web Api Post Types (C#)

You can find some implementations of Web Api Post types here.
Model

public class Model
{
 public string Name { get; set; }
 public string Id { get; set; }

 public string Save()
 {
  return "Saved";
 }
}

1. Post Raw

Web Api

[HttpPost]
public async Task PostRaw()
{
 string json = await Request.Content.ReadAsStringAsync();

 Model model = Newtonsoft.Json.JsonConvert.DeserializeObject(json);

 return model.Save();
}
Request
POST http://localhost:63693/api/test/PostRaw HTTP/1.1
Content-Type: application/json

{"Id":"1","Name":"Model1"}

2. FromBody

Web Api

[HttpPost]
public string PostFromBody([FromBody]string body)
{
 Model model = Newtonsoft.Json.JsonConvert.DeserializeObject(body);

 return model.Save();
}
Request
Escape json: "{\"Id\":\"1\",\"Name\":\"Model1\"}"
POST http://localhost:63693/api/test/PostModel HTTP/1.1
Content-Type: application/json

"{\"Id\":\"1\",\"Name\":\"Model1\"}"
or
POST http://localhost:63693/api/test/PostFromBody HTTP/1.1
Content-Type: application/x-www-form-urlencoded

%7B%22body%22=%7B%22Id%22%3A%221%22%2C%22Name%22%3A%22Model1%22%7D%7D

3. Class parameter

Web Api

[HttpPost]
public string PostModel(Model model)
{
 return model.Save();
}
Request
POST http://localhost:63693/api/test/PostModel HTTP/1.1
Content-Type: application/json

{"Id":"1","Name":"Model1"}

4. String parameter + Request.Content

Web Api

[HttpPost]
public string PostModelJson(string key)
{
 //You may check key here...

 var contentType = Request.Content.Headers.ContentType.MediaType;
 var body = Request.Content.ReadAsStringAsync().Result;

 Model model = null;

 if (contentType == "application/json")
 {
  model = Newtonsoft.Json.JsonConvert.DeserializeObject(body);

  return model.Save();
 }
 else
  throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
Request
POST http://localhost:63693/api/test/PostModelJson?key=1 HTTP/1.1
Content-Type: application/json

{"Id":"1","Name":"Model1"}

5. Post uri parameter

Web Api

[HttpPost]
public string PostModelFromUri([FromUri]Model model)
{
 return model.Save();
}
Request
POST http://localhost:63693/api/test/PostModelFromUri?id=1&name=Model1 HTTP/1.1

6. Multipart Form Data

Web Api

[HttpPost]
public string PostMultipart()
{
 var contentType = Request.Content.Headers.ContentType.MediaType;

 if (contentType == "multipart/form-data")
 {
  var parts = Request.Content.ReadAsMultipartAsync().Result;

  var contents = parts.Contents;
  Model model = new Model();

  foreach (StreamContent item in contents)
  {
   if (item.Headers.ContentDisposition.Name.Trim('"') == "Id")
    model.Id = item.ReadAsStringAsync().Result;
   else if (item.Headers.ContentDisposition.Name.Trim('"') == "Name")
    model.Name = item.ReadAsStringAsync().Result;
  }

  return model.Save();
 }
 else
  throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);            
}
Request
POST http://localhost:63693/api/test/PostMultipart HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrKvJKnAHtuVvEERM

------WebKitFormBoundaryrKvJKnAHtuVvEERM
Content-Disposition: form-data; name="Id"

1
------WebKitFormBoundaryrKvJKnAHtuVvEERM
Content-Disposition: form-data; name="Name"

Model1
------WebKitFormBoundaryrKvJKnAHtuVvEERM--

Nov 12, 2018

Install MySQL Docker (Windows)

I assume Docker already installed and running.

Pull mysql container

You can specify version (5.7). If version is not given it will download latest version.
C:\>docker pull mysql/mysql-server:5.7
5.7: Pulling from mysql/mysql-server
e64f6e679e1a: Already exists
478c78606b7e: Pull complete
81ab104e859d: Pull complete
d3565df0a804: Pull complete
Digest: sha256:79d65bf4360056b0709b4a1c4996f7ef8265ae6ca67462a8570ac1fa0855758b
Status: Downloaded newer image for mysql/mysql-server:5.7
Check docker image
C:\>docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
mysql/mysql-server         5.7                 76ac6291d3cf        2 weeks ago         234MB
Run mysql instance
docker run --name mysql1 -e MYSQL_USER=root -e MYSQL_PASSWORD=root -e MYSQL_DATABASE=homedb -p 3306:3306 -d mysql/mysql-server:5.7 
Check docker processes
C:\>docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS                             PORTS                 NAMES
44f6c176bb23        mysql/mysql-server:5.7   "/entrypoint.sh mysq…"   14 seconds ago      Up 13 seconds (health: starting)   3306/tcp, 33060/tcp   mysql1

Connect MySQL on docker

docker exec -it mysql1 mysql -uroot -p
If you did not provide a password in docker run command then system will generate a password. To change password and give some permissions:
C:\>docker logs mysql1 2>&1 | FindStr GENERATED
[Entrypoint] GENERATED ROOT PASSWORD: yBiG5ynmyvVurAw93HDok3buGhi

docker exec -it mysql1 mysql -uroot -p

ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';

CREATE USER 'root'@'%' IDENTIFIED BY 'root';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;

SHOW GRANTS FOR 'root'@'%';

Connect MySQL on client

C:\Program Files\MySQL\MySQL Workbench 8.0 CE>mysql -h localhost -P 3306 -u root -p
mysql> select @@hostname;
+--------------+
| @@hostname   |
+--------------+
| 44f6c176bb23 |
+--------------+
1 row in set (0.00 sec)

Oct 15, 2018

Encryption function (dotnet & nodejs)

Following functions give same result on dotnet and nodejs platforms.
Nodejs uses "crypto-js" package.
Dotnet uses "System.Security.Cryptography" namespace.

Dotnet


void Main()  
 {  
     string clearText = "oktay";  
     Console.WriteLine("clearText: " + clearText);  
     string encrypted = Crypto.EncryptToBase64(clearText);  
     Console.WriteLine("encrypted: " + encrypted);  
 }  
 public static class Crypto  
 {  
   public static string EncryptToBase64(string decryptedText)  
   {  
     byte[] rawSecretKey = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };  
     string PassPhrase = "passPhrase";  
     MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();  
     byte[] data = Encoding.UTF8.GetBytes(PassPhrase);  
         byte[] passwordKey = x.ComputeHash(data);  
         Console.WriteLine("key: " + BitConverter.ToString(passwordKey).Replace("-", ""));  
         Console.WriteLine("iv : " + BitConverter.ToString(rawSecretKey).Replace("-", ""));  
         RijndaelManaged rijndael = new RijndaelManaged();  
     ICryptoTransform rijndaelEncryptor = rijndael.CreateEncryptor(passwordKey, rawSecretKey);  
     try  
     {  
       byte[] decryptedData = Encoding.UTF8.GetBytes(decryptedText);  
       byte[] newClearData = rijndaelEncryptor.TransformFinalBlock(decryptedData, 0, decryptedData.Length);  
       return Convert.ToBase64String(newClearData, 0, newClearData.Length);  
     }  
     catch (Exception ex)  
     {  
       throw ex;  
     }  
   }  
 }  

Node.js

 
 var CryptoJS = require("crypto-js");  
 function byteArrayToHexString(byteArray) {  
  return Array.prototype.map  
   .call(byteArray, function(byte) {  
    return ("0" + (byte & 0xff).toString(16)).slice(-2);  
   })  
   .join("");  
 }  

 function EncryptToBase64(password) {
  console.log("clearText: " + password); 
  var PassPhrase = "passPhrase";  
  var rawSecretKey = [ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 ];
  
  var myRijndaelKeyBytes = CryptoJS.enc.Utf8.parse(PassPhrase);  
  var myRijndaelKey = CryptoJS.MD5(CryptoJS.enc.Utf8.parse(PassPhrase));  
  console.log("key: " + myRijndaelKey);  
  var myRijndaelIV = byteArrayToHexString(rawSecretKey);  
  var ivCodeWords = CryptoJS.enc.Hex.parse(myRijndaelIV);  
  console.log("iv: " + ivCodeWords);  
  var encrypted = CryptoJS.AES.encrypt(  
   CryptoJS.enc.Utf8.parse(password),  
   myRijndaelKey,  
   {  
    iv: ivCodeWords,  
    mode: CryptoJS.mode.CBC,  
    padding: CryptoJS.pad.Pkcs7  
   }  
  );  
  var base64 = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);  
  console.log("encrypted: " + base64);  
 }  
 EncryptToBase64("oktay");  
 return;  

Result

clearText: oktay
key: C6CEC8C6CAA9A579644664F0575DB2F5
iv : 01010101010101010101010101010101
encrypted: S+6CSoMM6no9atihmfyayQ==

Sep 13, 2018

iPhone X 2018 Models - Differences

Table below shows differences of 2018 iPhone models - iPhone XS, iPhone XS Max, iPhone XR.
For full list visit this Apple link.
iPhone XS iPhone XS Max iPhone XR
Colors Silver, Space Gray, Gold Silver, Space Gray, Gold Blue, White, Black, Yellow, Coral, Red
Display 5.8”
Super Retina HD display
OLED Multi‑Touch display
HDR display
3D Touch
6.5”
Super Retina HD display
OLED Multi‑Touch display
HDR display
3D Touch
6.1”
Liquid Retina HD display
LCD Multi‑Touch display with IPS technology
NO HDR display
NO 3D Touch
Camera - Rear Dual
12MP
wide-angle and
telephoto cameras
Dual
12MP
wide-angle and
telephoto cameras
12MP
Water resistant 2m
Water resistant to a depth of 2 meters for up to 30 minutes
Rated IP68
2m
Water resistant to a depth of 2 meters for up to 30 minutes
Rated IP68
1m
Water resistant to a depth of 1 meter for up to 30 minutes
Rated IP67
Capacity 64GB
256GB
512GB
64GB
256GB
512GB
64GB
128GB
256GB
Resolution 2436-by-1125-pixel resolution at 458 ppi 2688-by-1242-pixel resolution at 458 ppi 1792-by-828-pixel resolution at 326 ppi
Size and Weight Height
5.65 inches (143.6 mm)
Width
2.79 inches (70.9 mm)
Weight
6.24 ounces (177 grams)
Height
6.20 inches (157.5 mm)
Width
3.05 inches (77.4 mm)
Weight
7.34 ounces (208 grams)
Height
5.94 inches (150.9 mm)
Width
2.98 inches (75.7 mm)
Weight
6.84 ounces (194 grams)
Battery Lasts up to 30 minutes longer than iPhone X Lasts up to 1.5 hours longer than iPhone X Lasts up to 1.5 hours longer than iPhone 8 Plus

Sep 10, 2018

PWA to App Shortcut in Chrome

If you are interested to open a web application like a desktop application in Chrome follow this.

Prerequisites
  • A web application
  • Web server
  • HTTPS support
  • Service Worker on web app
  • Google Chrome (My version: Version 69.0.3497.81)

Web App

If you don't have a web app you can download a sample html application here

Web Server

You can use IIS, Apache or any kind of webserver.
Or just for local testing use python package SimpleHTTPServer.
python -m SimpleHTTPServer 5000

HTTPS

For IIS it is easy to add https in Bindings link. You will need an SSL certificate. Creating a local certificate not included in here.
SSL development certificate is available for local webserver via IIS Express.

Service Worker

To complete our aim we need to add service worker to your web app.

If you downloaded my sample you can look at following files.
  • manifest.json: Contains definition for our web application.
  • sw.js: Contains service worker functions
  • default.html: Contains user interface elements, interactive functions and service worker register functions.
Or you can follow sample in Google Developer blog to add service workers to your web app.

Google Chrome

You will need to enable PWA.

Go to chrome://flags/ url in Chrome.
Enable Desktop PWAs
Experimental windowing and install banner treatment for Progressive Web Apps on desktop platforms. Implies #enable-experimental-app-banners. – Mac, Windows, Linux, Chrome OS #enable-desktop-pwas

Check service workers

You will need Chrome developer tools.

In the sample application log lines added to show status in console.



Go to Application tab > Manifest to check manifest settings.



Go to Application tab > Service Workers to check service worker.



If you followed our sample app press "Add to Home" button to see a prompt.


After that you will see a new window appears with our web application.


Shortcut appears in Chrome Apps.


Now your application looks like desktop app with it is own window. It is useful for kiosk-like apps.

Appendix: Errors

If you see an error check your manifest and worker functions.

Some error samples:
default.html:39 Uncaught TypeError: Cannot read property 'prompt' of undefined at HTMLButtonElement.btnAdd.addEventListener 

Site cannot be installed: no matching service worker detected. You may need to reload the page, or check that the service worker for the current page also controls the start URL from the manifest
Check start_url in manifest.
If start url starts with "/" it may help to remove "/".
Change 
"start_url": "/default.html?source=pwa" 
to 
""start_url": "default.html?source=pwa","

If you want to try with other browsers remember that:
beforeinstallprompt Is Not a Web Standard

Aug 10, 2018

Apt-get install error

You may get following error when you use apt-get install command.
E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)
E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?
Run ps command to see which processes are using apt.
# ps aux | grep apt
root       3701  0.0  0.0   4628   772 ?        Ss   01:17   0:00 /bin/sh /usr/lib/apt/apt.systemd.daily install
root       3705  0.0  0.0   4628  1680 ?        S    01:17   0:00 /bin/sh /usr/lib/apt/apt.systemd.daily lock_is_held install
_apt       3744  0.5  0.4  88960  8560 ?        S    01:18   0:00 /usr/lib/apt/methods/http
root       3755  0.0  0.0  21536  1000 pts/0    S+   01:18   0:00 grep --color=auto apt
Kill processes
# kill -9 3701
# kill -9 3705
# kill -9 3744
Check ps
# ps aux | grep apt
root       3757  0.0  0.0  21536  1028 pts/0    S+   01:18   0:00 grep --color=auto apt
After killing processes and restart apt-get install command I could install packages.

If you have interrupted apt-get session when you install a package you may see an error.
E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.
In this case to continue setup run:
sudo dpkg --configure -a

Aug 4, 2018

Serve transmission torrent client on Nginx

Transmission web runs on localhost.
http://127.0.0.1:9091/transmission/web/
To make web interface reachable from WAN you can use nginx.

Edit nginx default settings file

/etc/nginx/sites-available$ sudo nano default

server {
       listen 9092;
       listen [::]:9092;

       server_name _;

 add_header Strict-Transport-Security max-age=31536000;

       location / {
         proxy_read_timeout 300;
         proxy_pass_header  X-Transmission-Session-Id;
         proxy_set_header   X-Forwarded-Host   $host;
         proxy_set_header   X-Forwarded-Server $host;
         proxy_set_header   X-Forwarded-For    $proxy_add_x_forwarded_for;       
         proxy_pass         http://127.0.0.1:9091/transmission/web/;
     }
       
     location /rpc {
         proxy_pass         http://127.0.0.1:9091/transmission/rpc;
     }
       
     location /upload {
         proxy_pass         http://127.0.0.1:9091/transmission/upload;
     }
}
We opened port 9092 to internet. Don't forget give permission on firewall for that port.
http://your_website:9092/

Aug 2, 2018

Linux torrent client - transmission-remote

This article shows installing, configure transmission remote package. Some configurations passed to see errors and how to fix them. If you already installed transmission-cli package you can use remote package:
$ sudo transmission-remote --download-dir "/home/ubuntu/Downloads" -a magnet:?xt=urn:btih:2c83f573753d9e987a5bf0fcf8979c4aa137e869&dn=Linux All-In-One For Dummies, 6th Edition&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://tracker.coppersurfer.tk:6969&tr=udp://tracker.opentrackr.org:1337&tr=udp://tracker.pirateparty.gr:6969&tr=udp://eddie4.nl:6969 
Unlike cli package, remote package works on background. It does not refresh status on terminal. Use following parameter to see status of download.
$ transmission-remote -l

Error#1: (http://localhost:9091/transmission/rpc/) Couldn't connect to server

If you see following error then you may not installed daemon or not started it.
[2018-07-29 12:53:33.664] transmission-remote:  (http://localhost:9091/transmission/rpc/) Couldn't connect to server
[2]+  Exit 127                dn=Linux All-In-One For Dummies, 6th Edition
You can install all services from beginning.
$ sudo apt-get update
$ sudo apt-get install transmission-cli transmission-common transmission-daemon
After installation, stop daemon and check settings.
$ sudo service transmission-daemon stop

$ cat /var/lib/transmission-daemon/info/settings.json
Settings not included in this article.
I only changed following parameter to give full access to files/folders created by transmission.
"umask": 2,
Start and check service.
$ sudo service transmission-daemon start

$ ps aux | grep transmission
debian-+ 12324  0.0  0.7 282064  7664 ?        Ssl  13:06   0:00 /usr/bin/transmission-daemon -f --log-error
root     12371  0.0  0.1  14856  1100 pts/0    S+   13:08   0:00 grep --color=auto transmission

$ netstat -tapen | grep transmission
tcp        0      0 0.0.0.0:9091            0.0.0.0:*               LISTEN      113        137537     12324transmission- 
tcp        0      0 0.0.0.0:51413           0.0.0.0:*               LISTEN      113        137538     12324transmission- 
tcp6       0      0 :::51413                :::*                    LISTEN      113        137540     12324transmission-  
Now service is working.

Error#2: Unauthorized User


Start torrent again.
$ sudo transmission-remote --download-dir "/home/ubuntu/Downloads" -a magnet:?xt=urn:btih:2c83f573753d9e987a5bf0fcf8979c4aa137e869&dn=Linux All-In-One For Dummies, 6th Edition&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://tracker.coppersurfer.tk:6969&tr=udp://tracker.opentrackr.org:1337&tr=udp://tracker.pirateparty.gr:6969&tr=udp://eddie4.nl:6969 
[1] 12380
[2] 12381
[3] 12382
[4] 12383
[5] 12384
[6] 12385
$ Unexpected response: <h1> 401: Unauthorized</h1> Unauthorized User
Unexpected response: <h1> 401: Unauthorized</h1>Unauthorized User
All-In-One: command not found
^C
[1]   Exit 1                  sudo transmission-remote --download-dir "/home/ubuntu/Downloads" -a magnet:?xt=urn:btih:2c83f573753d9e987a5bf0fcf8979c4aa137e869
[2]   Exit 127                dn=Linux All-In-One For Dummies, 6th Edition
[3]   Done                    tr=udp://tracker.leechers-paradise.org:6969
[4]   Done                    tr=udp://tracker.coppersurfer.tk:6969
[5]-  Done                    tr=udp://tracker.opentrackr.org:1337
[6]+  Done                    tr=udp://tracker.pirateparty.gr:6969
Service has username and password defined in settings file.
"rpc-password": "{95a4599e6748c68a07fbdfb7a49e37cb27d1c9b8NjXpGV6G",
"rpc-username": "transmission",
Default username and password: transmission
To use remote commands we need to add auth parameter.
Start torrent again.
$ transmission-remote --auth transmission:transmission --download-dir "/home/ubuntu/Downloads" -a magnet:?xt=urn:btih:2c83f573753d9e987a5bf0fcf8979c4aa137e869&dn=Linux All-In-One For Dummies, 6th Edition&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://tracker.coppersurfer.tk:6969&tr=udp://tracker.opentrackr.org:1337&tr=udp://tracker.pirateparty.gr:6969&tr=udp://eddie4.nl:6969 
[1] 12422
[2] 12423
[3] 12424
[4] 12425
[5] 12426
[6] 12427
$ localhost:9091/transmission/rpc/ responded: "success"
localhost:9091/transmission/rpc/ responded: "success"
All-In-One: command not found

[1]   Done                    transmission-remote --auth transmission:transmission --download-dir "/home/ubuntu/Downloads" -a magnet:?xt=urn:btih:2c83f573753d9e987a5bf0fcf8979c4aa137e869
[2]   Exit 127                dn=Linux All-In-One For Dummies, 6th Edition
[3]   Done                    tr=udp://tracker.leechers-paradise.org:6969
[4]   Done                    tr=udp://tracker.coppersurfer.tk:6969
[5]-  Done                    tr=udp://tracker.opentrackr.org:1337
[6]+  Done                    tr=udp://tracker.pirateparty.gr:6969
$ transmission-remote -l
Unexpected response: <h1> 401: Unauthorized</h1>Unauthorized User
Check torrent status.
$ transmission-remote --auth transmission:transmission -l
ID     Done       Have  ETA           Up    Down  Ratio  Status       Name
   1    n/a       None  Unknown      0.0     0.0   None  Idle         2c83f573753d9e987a5bf0fcf8979c4aa137e869
Sum:              None               0.0     0.0

Error#3: Couldn't create folder


Check service status.
$ sudo service transmission-daemon status
● transmission-daemon.service - Transmission BitTorrent Daemon
   Loaded: loaded (/lib/systemd/system/transmission-daemon.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2018-07-29 13:06:31 UTC; 20min ago
  Process: 12279 ExecStop=/bin/kill -s STOP $MAINPID (code=exited, status=0/SUCCESS)
 Main PID: 12324 (transmission-da)
   Status: "Idle."
    Tasks: 3 (limit: 1152)
   CGroup: /system.slice/transmission-daemon.service
           └─12324 /usr/bin/transmission-daemon -f --log-error

Jul 29 13:17:12 ip-172 transmission-daemon[12324]: [2018-07-29 13:17:12.138] Couldn't create "/home/ubuntu/Downloads/Linux All-In-One For
...
We need to give some permissions
$ sudo usermod -a -G debian-transmission ubuntu

$ sudo chgrp -R debian-transmission /home/ubuntu/Downloads/

$ sudo chmod -R 775 /home/ubuntu/Downloads/
Before starting torrent again, check torrent.
$ transmission-remote --auth transmission:transmission -l
ID     Done       Have  ETA           Up    Down  Ratio  Status       Name
   1*    0%   49.15 kB  Unknown      0.0     0.0    0.0  Stopped      Linux All-In-One For Dummies, 6th Edition
Sum:          49.15 kB               0.0     0.0
We can remove a torrent from the list.
$ sudo transmission-remote --auth transmission:transmission -t 1 -r
localhost:9091/transmission/rpc/ responded: "success"
$ transmission-remote --auth transmission:transmission -l
ID     Done       Have  ETA           Up    Down  Ratio  Status       Name
Sum:              None               0.0     0.0
Start torrent again and watch for status.
$ transmission-remote --auth transmission:transmission --download-dir "/home/ubuntu/Downloads" -a magnet:?xt=urn:btih:2c83f573753d9e987a5bf0fcf8979c4aa137e869&dn=Linux All-In-One For Dummies, 6th Edition&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://tracker.coppersurfer.tk:6969&tr=udp://tracker.opentrackr.org:1337&tr=udp://tracker.pirateparty.gr:6969&tr=udp://eddie4.nl:6969 
[1] 12563
[2] 12564
[3] 12565
[4] 12566
[5] 12567
[6] 12568
$ localhost:9091/transmission/rpc/ responded: "success"
localhost:9091/transmission/rpc/ responded: "success"
All-In-One: command not found

[1]   Done                    transmission-remote --auth transmission:transmission --download-dir "/home/ubuntu/Downloads" -a magnet:?xt=urn:btih:2c83f573753d9e987a5bf0fcf8979c4aa137e869
[2]   Exit 127                dn=Linux All-In-One For Dummies, 6th Edition
[3]   Done                    tr=udp://tracker.leechers-paradise.org:6969
[4]   Done                    tr=udp://tracker.coppersurfer.tk:6969
[5]-  Done                    tr=udp://tracker.opentrackr.org:1337
[6]+  Done                    tr=udp://tracker.pirateparty.gr:6969
$ transmission-remote --auth transmission:transmission -l
ID     Done       Have  ETA           Up    Down  Ratio  Status       Name
   2     0%       None  Unknown      0.0     0.0   None  Idle         Linux All-In-One For Dummies, 6th Edition
Sum:              None               0.0     0.0
$ transmission-remote --auth transmission:transmission -l
ID     Done       Have  ETA           Up    Down  Ratio  Status       Name
   2     3%   507.9 kB  4 min        0.0   258.0    0.0  Downloading  Linux All-In-One For Dummies, 6th Edition
Sum:          507.9 kB               0.0   258.0
$ transmission-remote --auth transmission:transmission -l
ID     Done       Have  ETA           Up    Down  Ratio  Status       Name
   2   100%   13.37 MB  Done         0.0     0.0    0.0  Idle         Linux All-In-One For Dummies, 6th Edition
Sum:          13.37 MB               0.0     0.0

Jul 31, 2018

Ubuntu torrent client - Transmission-cli

If you need a torrent client on Ubuntu server you can use transmission package. This tutorial explains only command line interface.

Install
sudo apt-get install transmission-cli
Cli package has no setting file! You have to give settings with parameters.

Get help
$ transmission-cli --help
transmission-cli 2.92 (14714)
A fast and easy BitTorrent client

Usage: transmission-cli [options] <file|url|magnet>

Options:
 -h  --help                          Display this help page and exit
 -b  --blocklist                     Enable peer blocklists
 -B  --no-blocklist                  Disable peer blocklists
 -d  --downlimit            <speed>  Set max download speed in kB/s
 -D  --no-downlimit                  Don't limit the download speed
 -er --encryption-required           Encrypt all peer connections
 -ep --encryption-preferred          Prefer encrypted peer connections
 -et --encryption-tolerated          Prefer unencrypted peer connections
 -f  --finish               <script> Run a script when the torrent finishes
 -g  --config-dir           <path>   Where to find configuration files
 -m  --portmap                       Enable portmapping via NAT-PMP or UPnP
 -M  --no-portmap                    Disable portmapping
 -p  --port                 <port>   Port for incoming peers (Default: 51413)
 -t  --tos                  <tos>    Peer socket TOS (0 to 255,
                                     default=default)
 -u  --uplimit              <speed>  Set max upload speed in kB/s
 -U  --no-uplimit                    Don't limit the upload speed
 -v  --verify                        Verify the specified torrent
 -V  --version                       Show version number and exit
 -w  --download-dir         <path>   Where to save downloaded data
Usage: transmission-cli [options]
Download a torrent with download directory parameter.
sudo transmission-cli  http://torrent.ubuntu.com:6969/file?info_hash=D%C0%809M3%5B%03%0B%13%FA%F1%3F%A8%84%CD%22%15%028 --download-dir "/home/ubuntu/Downloads"
You can use magnet link instead of torrent file url.
If you are using AWS or any firewall, don't forget to give permission for "Port for incoming peers (Default: 51413)"
After download finishes you will see transmission will continue to run for seeding. It may be annoying if you are working on terminal because it interrupts terminal window (even you press to Ctrl-C to quit).
To kill the process type ps to see process id.
  PID TTY          TIME CMD
11659 pts/0    00:00:00 sudo
11668 pts/0    00:00:00 transmission-cl
Then kill process.
$ kill 11668

Jul 29, 2018

Linux commands - Process

List running processes
$ ps -A
  PID TTY          TIME CMD
    1 ?        00:00:03 systemd
    2 ?        00:00:00 kthreadd
    4 ?        00:00:00 kworker/0:0H
    6 ?        00:00:00 mm_percpu_wq
    7 ?        00:00:00 ksoftirqd/0
    8 ?        00:00:00 rcu_sched
    9 ?        00:00:00 rcu_bh
   10 ?        00:00:00 migration/0
   11 ?        00:00:00 watchdog/0
   12 ?        00:00:00 cpuhp/0
 4712 ?        00:00:00 nginx
Kill a process
$ kill [signal] PID(s)

$ kill -9 3139

Signal Name  Signal Value  Behaviour
SIGHUP   1   Hangup
SIGKILL   9   Kill Signal
SIGTERM   15   Terminate
Filter process by name
$ ps aux | grep nginx

root      4712  0.0  0.1 140644  1452 ?        Ss   Jul27   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data  4714  0.0  0.4 143260  4212 ?        S    Jul27   0:00 nginx: worker process
ubuntu   11494  0.0  0.1  14856  1056 pts/0    S+   10:50   0:00 grep --color=auto nginx

$ pgrep nginx

4712
4714
Kill process by name
$ pkill nginx

$ killall nginx

Jul 6, 2018

Anonymous level security token - Windows Server

During a software installation if setup fails and shows similar logs like below then it is related with Windows Component system.

MSI (c) (48:B0) SOFTWARE RESTRICTION POLICY: Verifying package --> '...\NC.x64.msi' against software restriction policy 
MSI (c) (48:B0)  Note: 1: 2262 2: DigitalSignature 3: -2147287038  
MSI (c) (48:B0)  SOFTWARE RESTRICTION POLICY: ...\NC.x64.msi is not digitally signed 
MSI (c) (48:B0) SOFTWARE RESTRICTION POLICY: ...\NC.x64.msi is permitted to run at the 'unrestricted' authorization level.
The software which I tried to install had prerequisites (Dotnet Framework 3.5 etc).
After error, I tried to install Dotnet 3.5 manually from "Server Manager" by clicking "Add roles and features" link. But it failed and showed error below:

Anonymous level security token
To solve I followed these steps:

  1. Click Start > Run, type dcomcnfg.exe
  2. Click OK if you see the UAC warning
  3. Go to Component Services> Computers in the tree
  4. Right click My Computer > select Properties.
  5. Click Default Properties tab
  6. Select Connect in the Default Authentication Level list 
  7. Select Identify in the Default Impersonation Level list
  8. Click OK, and confirm the selection
  9. Close Component Services console




Feb 5, 2018

Python code to exe (Windows)

PyInstaller helps you convert your python code to executable software package.

Our test environment: Windows 7, Python 3.6

Create your python code file (hello.py)
print("Hello World!")
Download PyInstaller via pip
pip install pyinstaller
Run PyInstaller with python code file parameter on console
"C:\Program Files\Python36\Scripts\pyinstaller.exe" hello.py
You will see some commands on the screen. A few seconds later it will finish building. Build time is dependent your code (referenced packages).

Check dist folder for distribution copy of your application (hello.exe)

Size of the folder for hello.py is around 11mb.

I tried also py file with reference of cv2 library. Build time is around 30seconds and folder size becomes 157mb.