问:
Transfer files directly from FTP to Azure File Storage without keeping them locally in memory or disk
I have to transfer files from FTP to an Azure File Storage. My code works fine, but I'm transferring those files in memory which is not a best practice. So first I read the stream to an Byte array in memory. Then I upload the output to an Azure file storage.

Now I know it's better to do this asynchronicaly. But I don't know if this is possible and how to do it.

My code:

```<code>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using System.Configuration;
using Microsoft.WindowsAzure.Storage.File;
using System.IO;
using Microsoft.Azure;
using System.Net;

namespace TransferFtpToAzure
{
    class Program
    {
        public static void Main(string[] args)
        {
            List<FileName> sourceFileList = new List<FileName>();
            List<FileName> targetFileList = new List<FileName>();

            string targetShareReference = ConfigurationManager.AppSettings["AzureShare"];
            string targetDirectoryReference = ConfigurationManager.AppSettings["Environment"] + "/" + Enums.AzureFolders.Mos + "/" + Enums.AzureFolders.In;
            string sourceURI = (ConfigurationManager.AppSettings["FtpConnectionString"] + ConfigurationManager.AppSettings["Environment"].ToUpper() +"/"+ Enums.FtpFolders.Mos + "/").Replace("\\","/");
            string sourceUser = ConfigurationManager.AppSettings["FtpServerUserName"];
            string sourcePass = ConfigurationManager.AppSettings["FtpServerPassword"];

            getFileLists(sourceURI, sourceUser, sourcePass, sourceFileList, targetShareReference, targetDirectoryReference, targetFileList);

            Console.WriteLine(sourceFileList.Count + " files found!");

            CheckLists(sourceFileList, targetFileList);
            targetFileList.Sort();

            Console.WriteLine(sourceFileList.Count + " unique files on sourceURI" + Environment.NewLine + "Attempting to move them.");

            foreach (var file in sourceFileList)
            {
                try
                {
                    CopyFile(file.fName, sourceURI, sourceUser, sourcePass, targetShareReference, targetDirectoryReference);
                }
                catch
                {
                    Console.WriteLine("There was move error with : " + file.fName);
                }
            }
        }

        public class FileName : IComparable<FileName>
        {
            public string fName { get; set; }
            public int CompareTo(FileName other)
            {
                return fName.CompareTo(other.fName);
            }
        }

        public static void CheckLists(List<FileName> sourceFileList, List<FileName> targetFileList)
        {
            for (int i = 0; i < sourceFileList.Count; i++)
            {
                if (targetFileList.BinarySearch(sourceFileList[i]) > 0)
                {
                    sourceFileList.RemoveAt(i);
                    i--;
                }
            }
        }

        public static void getFileLists(string sourceURI, string sourceUser, string sourcePass, List<FileName> sourceFileList, string targetShareReference, string targetDirectoryReference, List<FileName> targetFileList)
        {
            string line = "";
            /////////Source FileList
            FtpWebRequest sourceRequest;
            sourceRequest = (FtpWebRequest)WebRequest.Create(sourceURI);
            sourceRequest.Credentials = new NetworkCredential(sourceUser, sourcePass);
            sourceRequest.Method = WebRequestMethods.Ftp.ListDirectory;
            sourceRequest.UseBinary = true;
            sourceRequest.KeepAlive = false;
            sourceRequest.Timeout = -1;
            sourceRequest.UsePassive = true;
            FtpWebResponse sourceRespone = (FtpWebResponse)sourceRequest.GetResponse();
            //Creates a list(fileList) of the file names
            using (Stream responseStream = sourceRespone.GetResponseStream())
            {
                using (StreamReader reader = new StreamReader(responseStream))
                {
                    line = reader.ReadLine();
                    while (line != null)
                    {
                        var fileName = new FileName
                        {
                            fName = line
                        };
                        sourceFileList.Add(fileName);
                        line = reader.ReadLine();
                    }
                }
            }
            /////////////Target FileList
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
            CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
            //var test = fileClient.ListShares();
            CloudFileShare fileShare = fileClient.GetShareReference(targetShareReference);
            if (fileShare.Exists())
            {
                CloudFileDirectory rootDirectory = fileShare.GetRootDirectoryReference();
                if (rootDirectory.Exists())
                {
                    CloudFileDirectory customDirectory = rootDirectory.GetDirectoryReference(targetDirectoryReference);
                    if (customDirectory.Exists())
                    {
                        var fileCollection = customDirectory.ListFilesAndDirectories().OfType<CloudFile>();
                        foreach (var item in fileCollection)
                        {
                            var fileName = new FileName
                            {
                                fName = item.Name
                            };
                            targetFileList.Add(fileName);
                        }
                    }
                }
            }
        }

        public static void CopyFile(string fileName, string sourceURI, string sourceUser, string sourcePass, string targetShareReference, string targetDirectoryReference)
        {
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(sourceURI + fileName);
                request.Method = WebRequestMethods.Ftp.DownloadFile;
                request.Credentials = new NetworkCredential(sourceUser, sourcePass);
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                Upload(fileName, ToByteArray(responseStream), targetShareReference, targetDirectoryReference);
                responseStream.Close();
            }
            catch
            {
                Console.WriteLine("There was an error with :" + fileName);
            }
        }

        public static Byte[] ToByteArray(Stream stream)
        {
            MemoryStream ms = new MemoryStream();
            byte[] chunk = new byte[4096];
            int bytesRead;
            while ((bytesRead = stream.Read(chunk, 0, chunk.Length)) > 0)
            {
                ms.Write(chunk, 0, bytesRead);
            }

            return ms.ToArray();
        }

        public static bool Upload(string FileName, byte[] Image, string targetShareReference, string targetDirectoryReference)
        {
            try
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
                CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
                //var test = fileClient.ListShares();
                CloudFileShare fileShare = fileClient.GetShareReference(targetShareReference);
                if (fileShare.Exists())
                {
                    CloudFileDirectory rootDirectory = fileShare.GetRootDirectoryReference();
                    if (rootDirectory.Exists())
                    {
                        CloudFileDirectory customDirectory = rootDirectory.GetDirectoryReference(targetDirectoryReference);
                        if (customDirectory.Exists())
                        {
                            var cloudFile = customDirectory.GetFileReference(FileName);
                            using (var stream = new MemoryStream(Image, writable: false))
                            {
                                cloudFile.UploadFromStream(stream);
                            }
                        }
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}
</code>```

答:
Using Azure Storage File Share this is the only way it worked for me without loading the entire ZIP into Memory. I tested with a 3GB ZIP File (with thousands of files or with a big file inside) and Memory/CPU was low and stable. I hope it helps!</p>

```<code>var zipFiles = _directory.ListFilesAndDirectories()
    .OfType<CloudFile>()
    .Where(x => x.Name.ToLower().Contains(".zip"))
    .ToList();

foreach (var zipFile in zipFiles)
{
    using (var zipArchive = new ZipArchive(zipFile.OpenRead()))
    {
        foreach (var entry in zipArchive.Entries)
        {
            if (entry.Length > 0)
            {
                CloudFile extractedFile = _directory.GetFileReference(entry.Name);

                using (var entryStream = entry.Open())
                {
                    byte[] buffer = new byte[16 * 1024];
                    using (var ms = extractedFile.OpenWrite(entry.Length))
                    {
                        int read;
                        while ((read = entryStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            ms.Write(buffer, 0, read);
                        }
                    }
                }
            }
        }
    }
}
</code>```

Body:
I have to transfer files from FTP to an Azure File Storage. My code works fine, but I'm transferring those files in memory which is not a best practice. So first I read the stream to an Byte array in memory. Then I upload the output to an Azure file storage.

Now I know it's better to do this asynchronicaly. But I don't know if this is possible and how to do it.

My code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;
using System.Configuration;
using Microsoft.WindowsAzure.Storage.File;
using System.IO;
using Microsoft.Azure;
using System.Net;

namespace TransferFtpToAzure
{
    class Program
    {
        public static void Main(string[] args)
        {
            List<FileName> sourceFileList = new List<FileName>();
            List<FileName> targetFileList = new List<FileName>();

            string targetShareReference = ConfigurationManager.AppSettings["AzureShare"];
            string targetDirectoryReference = ConfigurationManager.AppSettings["Environment"] + "/" + Enums.AzureFolders.Mos + "/" + Enums.AzureFolders.In;
            string sourceURI = (ConfigurationManager.AppSettings["FtpConnectionString"] + ConfigurationManager.AppSettings["Environment"].ToUpper() +"/"+ Enums.FtpFolders.Mos + "/").Replace("\\","/");
            string sourceUser = ConfigurationManager.AppSettings["FtpServerUserName"];
            string sourcePass = ConfigurationManager.AppSettings["FtpServerPassword"];

            getFileLists(sourceURI, sourceUser, sourcePass, sourceFileList, targetShareReference, targetDirectoryReference, targetFileList);

            Console.WriteLine(sourceFileList.Count + " files found!");

            CheckLists(sourceFileList, targetFileList);
            targetFileList.Sort();

            Console.WriteLine(sourceFileList.Count + " unique files on sourceURI" + Environment.NewLine + "Attempting to move them.");

            foreach (var file in sourceFileList)
            {
                try
                {
                    CopyFile(file.fName, sourceURI, sourceUser, sourcePass, targetShareReference, targetDirectoryReference);
                }
                catch
                {
                    Console.WriteLine("There was move error with : " + file.fName);
                }
            }
        }

        public class FileName : IComparable<FileName>
        {
            public string fName { get; set; }
            public int CompareTo(FileName other)
            {
                return fName.CompareTo(other.fName);
            }
        }

        public static void CheckLists(List<FileName> sourceFileList, List<FileName> targetFileList)
        {
            for (int i = 0; i < sourceFileList.Count; i++)
            {
                if (targetFileList.BinarySearch(sourceFileList[i]) > 0)
                {
                    sourceFileList.RemoveAt(i);
                    i--;
                }
            }
        }

        public static void getFileLists(string sourceURI, string sourceUser, string sourcePass, List<FileName> sourceFileList, string targetShareReference, string targetDirectoryReference, List<FileName> targetFileList)
        {
            string line = "";
            /////////Source FileList
            FtpWebRequest sourceRequest;
            sourceRequest = (FtpWebRequest)WebRequest.Create(sourceURI);
            sourceRequest.Credentials = new NetworkCredential(sourceUser, sourcePass);
            sourceRequest.Method = WebRequestMethods.Ftp.ListDirectory;
            sourceRequest.UseBinary = true;
            sourceRequest.KeepAlive = false;
            sourceRequest.Timeout = -1;
            sourceRequest.UsePassive = true;
            FtpWebResponse sourceRespone = (FtpWebResponse)sourceRequest.GetResponse();
            //Creates a list(fileList) of the file names
            using (Stream responseStream = sourceRespone.GetResponseStream())
            {
                using (StreamReader reader = new StreamReader(responseStream))
                {
                    line = reader.ReadLine();
                    while (line != null)
                    {
                        var fileName = new FileName
                        {
                            fName = line
                        };
                        sourceFileList.Add(fileName);
                        line = reader.ReadLine();
                    }
                }
            }
            /////////////Target FileList
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
            CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
            //var test = fileClient.ListShares();
            CloudFileShare fileShare = fileClient.GetShareReference(targetShareReference);
            if (fileShare.Exists())
            {
                CloudFileDirectory rootDirectory = fileShare.GetRootDirectoryReference();
                if (rootDirectory.Exists())
                {
                    CloudFileDirectory customDirectory = rootDirectory.GetDirectoryReference(targetDirectoryReference);
                    if (customDirectory.Exists())
                    {
                        var fileCollection = customDirectory.ListFilesAndDirectories().OfType<CloudFile>();
                        foreach (var item in fileCollection)
                        {
                            var fileName = new FileName
                            {
                                fName = item.Name
                            };
                            targetFileList.Add(fileName);
                        }
                    }
                }
            }
        }

        public static void CopyFile(string fileName, string sourceURI, string sourceUser, string sourcePass, string targetShareReference, string targetDirectoryReference)
        {
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(sourceURI + fileName);
                request.Method = WebRequestMethods.Ftp.DownloadFile;
                request.Credentials = new NetworkCredential(sourceUser, sourcePass);
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                Upload(fileName, ToByteArray(responseStream), targetShareReference, targetDirectoryReference);
                responseStream.Close();
            }
            catch
            {
                Console.WriteLine("There was an error with :" + fileName);
            }
        }

        public static Byte[] ToByteArray(Stream stream)
        {
            MemoryStream ms = new MemoryStream();
            byte[] chunk = new byte[4096];
            int bytesRead;
            while ((bytesRead = stream.Read(chunk, 0, chunk.Length)) > 0)
            {
                ms.Write(chunk, 0, bytesRead);
            }

            return ms.ToArray();
        }

        public static bool Upload(string FileName, byte[] Image, string targetShareReference, string targetDirectoryReference)
        {
            try
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
                CloudFileClient fileClient = storageAccount.CreateCloudFileClient();
                //var test = fileClient.ListShares();
                CloudFileShare fileShare = fileClient.GetShareReference(targetShareReference);
                if (fileShare.Exists())
                {
                    CloudFileDirectory rootDirectory = fileShare.GetRootDirectoryReference();
                    if (rootDirectory.Exists())
                    {
                        CloudFileDirectory customDirectory = rootDirectory.GetDirectoryReference(targetDirectoryReference);
                        if (customDirectory.Exists())
                        {
                            var cloudFile = customDirectory.GetFileReference(FileName);
                            using (var stream = new MemoryStream(Image, writable: false))
                            {
                                cloudFile.UploadFromStream(stream);
                            }
                        }
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

Body:
Using Azure Storage File Share this is the only way it worked for me without loading the entire ZIP into Memory. I tested with a 3GB ZIP File (with thousands of files or with a big file inside) and Memory/CPU was low and stable. I hope it helps!

var zipFiles = _directory.ListFilesAndDirectories()
    .OfType<CloudFile>()
    .Where(x => x.Name.ToLower().Contains(".zip"))
    .ToList();

foreach (var zipFile in zipFiles)
{
    using (var zipArchive = new ZipArchive(zipFile.OpenRead()))
    {
        foreach (var entry in zipArchive.Entries)
        {
            if (entry.Length > 0)
            {
                CloudFile extractedFile = _directory.GetFileReference(entry.Name);

                using (var entryStream = entry.Open())
                {
                    byte[] buffer = new byte[16 * 1024];
                    using (var ms = extractedFile.OpenWrite(entry.Length))
                    {
                        int read;
                        while ((read = entryStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            ms.Write(buffer, 0, read);
                        }
                    }
                }
            }
        }
    }
}


来源: stackexchange

问:
Confused about Rewards in David Silver Lecture 2
While watching the Reinforcement Learning course by David Silver on youtube (and the slide: Lecture 2 MDP), I found the "Reward" and "Value Function" really confusing.

I tried to understand the "given rewards" marked on the slide (P11), but I cannot figure out why it is the case. Like, the "Class 1: R = -2" but "Pub: R = +1"

why the negative reward for Class and the positive reward for Pub? why the different value?

How to calculate the reward with the Discount Factor? (P17 and P18)

I think the lack of intuition for Reinforcement Learning is the main reason why I have encountered this kind of problem...

So, I'd really appreciate it if someone can give me a little hint.

答:
You usually set the reward and the discount such that using RL you will drive the agent to solve a task.
In the student example the goal is to pass the exam. The student can spend his time attending a class, sleeping, on Facebook or at the pub. Attending a class is something "boring", so the student doesn't see the immediate benefits of doing it. Hence the negative reward. On the contrary, going to the pub is fun and gives a positive reward. However, only by attending all 3 classes the student can pass the exam and get the big final reward.
Now the question is: how much does the student value immediate vs future rewards? The discount factor tells you that: a small discount gives more importance to immediate rewards, because future rewards just "fade" in the long run. If we use a small discount, the student may prefer to always go to the pub or to sleep. With a discount close to 0, already after one step all rewards get close to 0 as well, so at each state the student will try to maximize the immediate reward, because after that "nothing else matter".

On the contrary, high discounts (max 1) value long-term rewards more: in this case the optimal student will attend all classes and pass the exam.

Choosing the discount can be tricky, especially if there is no terminal state (in this case "sleep" is terminal), because with a discount of 1 the agent may ignore the number of steps used to reach the highest reward. For instance, if classes would give a reward of -1 instead of -2, for the agent would be the same to spend time alternating between "class" and "pub" forever and at some point to pass the exam, because with discount 1 the rewards never fade, so even after 10 years the students will still get +10 for passing the exam.

Think also of a virtual agent having to reach a goal position. With discount 1, the agent would not learn to reach it in the least amount of steps: as long as it reaches it, it's the same for him.

Beside that, there is also a numerical problem with discount 1. Since the goal is to maximize the cumulative sum of the discounted reward, if rewards are not discounted (and the horizon is infinite) the sum will not converge.

ContentLicense: CC BY-SA 4.0


问:
Docker nginx 502 bad gateway for GET/Post requests but not websocket
There have been various similar cases here on stackoverflow but they're pretty much all refer to incorrect ports or using localhost as the IP instead of the docker-machine ip.

The vue.js app connects perfectly fine to the websocket and works. However, the GET requests to 192.168.99.100:8080/meows and other endpoints all hit the nginx 502 bad gateway. Manually accessing the endpoints (instead of vue.js) also hit 502 bad gateway.

The ip's are properly set. Ports are the same everywhere :8080. endpoints have the correct http verband all have an nginx upstream pointing at the server location /..{}. Yet no problems connecting to the network, all data passing through no problem.

EDIT: Im running windows 7 with the docker-toolbox because my windows version doesnt have the whole virtualization thing. No further configuration after installation has been done.

The architecture is the following:

docker-compose

```<code>version: "3.6"

services:
  meow:
    build: "."
    command: "meow-service"
    depends_on:
      - "postgres"
      - "nats"
    environment:
      POSTGRES_DB: "meower"
      POSTGRES_USER: "meower"
      POSTGRES_PASSWORD: "123456"
      NATS_ADDRESS: "nats:4222"
  query:
    build: "."
    command: "query-service"
    depends_on:
      - "postgres"
      - "nats"
    environment:
      POSTGRES_DB: "meower"
      POSTGRES_USER: "meower"
      POSTGRES_PASSWORD: "123456"
      NATS_ADDRESS: "nats:4222"
      ELASTICSEARCH_ADDRESS: "elasticsearch:9200"
  pusher:
    build: "."
    command: "pusher-service"
    depends_on:
      - "nats"
    environment:
      NATS_ADDRESS: "nats:4222"
  postgres:
    build: "./postgres"
    restart: "always"
    environment:
      POSTGRES_DB: "meower"
      POSTGRES_USER: "meower"
      POSTGRES_PASSWORD: "123456"
  nats:
    image: "nats-streaming:0.9.2"
    restart: "always"
  elasticsearch:
    image: 'docker.elastic.co/elasticsearch/elasticsearch:6.2.3'
  nginx:
    build: "./nginx"
    ports:
      - "8080:80"
    depends_on:
      - "meow"
      - "query"
      - "pusher"
</code>```

nginx.conf:

```<code>user nginx;
worker_processes 1;

events {
  worker_connections 1024;
}

http {
  upstream meows_POST {
    server meow:8080;
  }

  upstream meows_GET {
    server query:8080;
  }

  upstream search_GET {
    server query:8080;
  }

  upstream pusher {
    server pusher:8080;
  }

  server {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    add_header Access-Control-Allow-Origin *;

    location /meows {
      limit_except GET POST OPTIONS {
        deny all;
      }
      proxy_pass http://meows_$request_method;
    }

    location /search {
      limit_except GET OPTIONS {
        deny all;
      }
      proxy_pass http://search_GET;
    }

    location /pusher {
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_pass http://pusher;
    }
  }
}
</code>```

And to show that the go application also uses the correct ports, the following is the port listening for

```<code>func newRouter() (router *mux.Router) {
    router = mux.NewRouter()
    router.HandleFunc("/meows", listMeowsHandler).
        Methods("GET")
    router.HandleFunc("/search", searchMeowsHandler).
        Methods("GET")
    return
}

router := newRouter()
if err := http.ListenAndServe(":8080", router); err != nil {
    log.Fatal(err)
}
</code>```

答:
Removed all

```<code>  ports:
  - "8080"
</code>```

properties from all services in the ngix.conf as was proposed.

The underlying problem however was the elasticsearch docker image. Using docker ps -a i could see that after a minute it would exit 78. Using docker-compose logs elasticsearch the error was max virtual memory areas vm.max_map_count px[ is too low, increase to at least [x]. Using belows command the host machine allocated more memory for the containers and everything was solved.

```<code>docker-machine ssh
sudo sysctl -w vm.max_map_count=262144
</code>```

Body:
There have been various similar cases here on stackoverflow but they're pretty much all refer to incorrect ports or using localhost as the IP instead of the docker-machine ip.

The vue.js app connects perfectly fine to the websocket and works. However, the GET requests to 192.168.99.100:8080/meows and other endpoints all hit the nginx 502 bad gateway. Manually accessing the endpoints (instead of vue.js) also hit 502 bad gateway.

The ip's are properly set. Ports are the same everywhere :8080. endpoints have the correct http verband all have an nginx upstream pointing at the server location /..{}. Yet no problems connecting to the network, all data passing through no problem.

EDIT: Im running windows 7 with the docker-toolbox because my windows version doesnt have the whole virtualization thing. No further configuration after installation has been done.

The architecture is the following:

docker-compose

version: "3.6"

services:
  meow:
    build: "."
    command: "meow-service"
    depends_on:
      - "postgres"
      - "nats"
    environment:
      POSTGRES_DB: "meower"
      POSTGRES_USER: "meower"
      POSTGRES_PASSWORD: "123456"
      NATS_ADDRESS: "nats:4222"
  query:
    build: "."
    command: "query-service"
    depends_on:
      - "postgres"
      - "nats"
    environment:
      POSTGRES_DB: "meower"
      POSTGRES_USER: "meower"
      POSTGRES_PASSWORD: "123456"
      NATS_ADDRESS: "nats:4222"
      ELASTICSEARCH_ADDRESS: "elasticsearch:9200"
  pusher:
    build: "."
    command: "pusher-service"
    depends_on:
      - "nats"
    environment:
      NATS_ADDRESS: "nats:4222"
  postgres:
    build: "./postgres"
    restart: "always"
    environment:
      POSTGRES_DB: "meower"
      POSTGRES_USER: "meower"
      POSTGRES_PASSWORD: "123456"
  nats:
    image: "nats-streaming:0.9.2"
    restart: "always"
  elasticsearch:
    image: 'docker.elastic.co/elasticsearch/elasticsearch:6.2.3'
  nginx:
    build: "./nginx"
    ports:
      - "8080:80"
    depends_on:
      - "meow"
      - "query"
      - "pusher"

nginx.conf:

user nginx;
worker_processes 1;

events {
  worker_connections 1024;
}

http {
  upstream meows_POST {
    server meow:8080;
  }

  upstream meows_GET {
    server query:8080;
  }

  upstream search_GET {
    server query:8080;
  }

  upstream pusher {
    server pusher:8080;
  }

  server {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    add_header Access-Control-Allow-Origin *;

    location /meows {
      limit_except GET POST OPTIONS {
        deny all;
      }
      proxy_pass http://meows_$request_method;
    }

    location /search {
      limit_except GET OPTIONS {
        deny all;
      }
      proxy_pass http://search_GET;
    }

    location /pusher {
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_pass http://pusher;
    }
  }
}

And to show that the go application also uses the correct ports, the following is the port listening for

func newRouter() (router *mux.Router) {
    router = mux.NewRouter()
    router.HandleFunc("/meows", listMeowsHandler).
        Methods("GET")
    router.HandleFunc("/search", searchMeowsHandler).
        Methods("GET")
    return
}

router := newRouter()
if err := http.ListenAndServe(":8080", router); err != nil {
    log.Fatal(err)
}

Body:
Removed all

  ports:
  - "8080"

properties from all services in the ngix.conf as was proposed.

The underlying problem however was the elasticsearch docker image. Using docker ps -a i could see that after a minute it would exit 78. Using docker-compose logs elasticsearch the error was max virtual memory areas vm.max_map_count px[ is too low, increase to at least [x]. Using belows command the host machine allocated more memory for the containers and everything was solved.

docker-machine ssh
sudo sysctl -w vm.max_map_count=262144


问:
How to integrate sonarqube in android studio?
How we can integrate sonarqube in android studio? I have come across static code analysis using sonarqube. Explain how we can achieve that. There are many link available to integrate sonar-runner and sonarqube but either outdated or not sufficient to get the job done.</p>

答:
Integrating Sonarqube can be a bit hard, I wrote a Gradle plugin for Android to make it easier.

Here is an article about it: https://proandroiddev.com/android-analyzer-df0e4d80dc74

Here is the plugin: https://github.com/pinchbv/android-analyzer

ContentLicense: CC BY-SA 3.0


问:
Is /dev/random considered truly random?
For instance, could it be used to generate a one-time pad key?

Also, what are its sources and how could it be used to generate a random number between x and y?

答:
Strictly speaking, /dev/random is not really completely random. /dev/random feeds on hardware sources which are assumed to be unpredictible in some way; then it mixes such data using functions (hash functions, mostly) which are also assumed to be one-way. So the "true randomness" of /dev/random is thus relative to the inherent security of the mixing functions, security which is no more guaranteed than that of any other cryptographic primitive, in particular the PRNG hidden in /dev/urandom.

The difference between /dev/random and /dev/urandom is that the former will try to maintain an estimate (which means "a wild guess") of how much entropy it has gathered, and will refuse to output more bits than that. On the other hand, /dev/urandom will happily produce megabytes of data from the entropy it has.

The security difference between the two approaches is meaningless unless you assume that "classical" cryptographic algorithms can be broken, and you use one of the very few information-theoretic algorithms (e.g. OTP or Shamir's secret sharing); and, even then, /dev/random may be considered as more secure than /dev/urandom only if the mixing functions are still considered to be one-way, which is not compatible with the idea that a classical cryptographic algorithm can be broken. So, in practice and even in theory, no difference whatsoever. You can use the output of /dev/urandom for an OTP and it will not be broken because of any structure internal to /dev/urandom -- actual management of the obtained stream will be the weak point (especially long-time storage). On the other hand, /dev/random has very real practical issues, namely that it can block at untimely instants. It is really irksome when an automated OS install blocks (for hours !) because SSH server key generation insists on using /dev/random and needlessly stalls for entropy.

There are many applications which read /dev/random as a kind of ritual, as if it was "better" than /dev/urandom, probably on a karmic level. This is plain wrong, especially when the alea is to be used with classical cryptographic algorithms (e.g. to generate a SSH server public key). Do not do that. Instead, use /dev/urandom and you will live longer and happier. Even for one-time pad.

(Just for completeness, there is a quirk with /dev/urandom as implemented on Linux: it will never block, even if it has not gathered any entropy at all since previous boot. Distributions avoid this problem by creating a "random seed" at installation time, with /dev/random, and using that seed at each boot to initialize the PRNG used by /dev/urandom; a new random seed is regenerated immediately, for next boot. This ensures that /dev/urandom always works over a sufficiently big internal seed. The FreeBSD implementation of /dev/urandom will block until a given entropy threshold is reached, which is safer.)

Title: Is /dev/random considered truly random?


问:
Use generated string in another field
I have several fields on a web page. The first two fields require a unique string to be entered every time the test suite is run. I have code that generates a random string in the first 'Name' field. I want to copy whatever string is generated into the second 'Label' field, so they both match.

I have tried using a copy function, but this doesn't seem to work correctly in Cypress. I also tried logging the value created in the generation function, then using that logged value in the next test. But that didn't work either. I'm not sure if there is a way around this?

Code to generate the random string in the first field:

```<code>cy.get('#Name')
        .should('exist')

        .type(Name_Alpha_Numeric())
            // Enter random string
            function Name_Alpha_Numeric() {
                var text = "";
                var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

                for (var i = 0; i < 10; i++)
                text += possible.charAt(Math.floor(Math.random() * possible.length));

                return text;
            }
</code>```

Hoping there is a very straightforward solution to this.

答:
This should work:

// 0. write the function
function Name_Alpha_Numeric() {
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i = 0; i < 10; i++)
    text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
}

// 1. generate the string and store it in a variable
const randomName = Name_Alpha_Numeric()

// 2. type it in
cy.get('#Name').type(randomName)

// 3. verify that #Label also has this text
cy.get('#Label').should('have.text', randomName)
```

Title: Use generated string in another field

Body:
I have several fields on a web page. The first two fields require a unique string to be entered every time the test suite is run. I have code that generates a random string in the first 'Name' field. I want to copy whatever string is generated into the second 'Label' field, so they both match.

I have tried using a copy function, but this doesn't seem to work correctly in Cypress. I also tried logging the value created in the generation function, then using that logged value in the next test. But that didn't work either. I'm not sure if there is a way around this?

Code to generate the random string in the first field:

cy.get('#Name')
        .should('exist')

        .type(Name_Alpha_Numeric())
            // Enter random string
            function Name_Alpha_Numeric() {
                var text = "";
                var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

                for (var i = 0; i < 10; i++)
                text += possible.charAt(Math.floor(Math.random() * possible.length));

                return text;
            }

Hoping there is a very straightforward solution to this.


问:
Rails cron with whenever, setting the environment
This question will probably only make sense if you know about the whenever gem for creating cron jobs. I have a task in my schedule.rb like

```<code>every 1.day, :at => '4am' do
  command "cd #{RAILS_ROOT} && rake thinking_sphinx:stop RAILS_ENV=#{RAILS_ENV}"
  command "cd #{RAILS_ROOT} && rake thinking_sphinx:index RAILS_ENV=#{RAILS_ENV}"
  command "cd #{RAILS_ROOT} && rake thinking_sphinx:start RAILS_ENV=#{RAILS_ENV}"
end
</code>```

However when I update my crontab using

```<code>whenever --update-crontab appname --set environment=production
</code>```

the cron jobs still have RAILS_ENV=development.  My tasks on production and development are the same right now, I just need to change the environment variable because thinking_sphinx needs to know the current environment.  Any ideas on how to do this?

Thanks!

答:
I was having an issue where environment wasn't being set up for whenever cron jobs - /usr/bin/bundle was being picked up instead of /usr/local/bin/bundle.

The solution was to add following to top of schedule.rb

```<code>env 'PATH', ENV['PATH']
</code>```

ContentLicense: CC BY-SA 2.5

Body:
This question will probably only make sense if you know about the whenever gem for creating cron jobs. I have a task in my schedule.rb like

every 1.day, :at => '4am' do
  command "cd #{RAILS_ROOT} && rake thinking_sphinx:stop RAILS_ENV=#{RAILS_ENV}"
  command "cd #{RAILS_ROOT} && rake thinking_sphinx:index RAILS_ENV=#{RAILS_ENV}"
  command "cd #{RAILS_ROOT} && rake thinking_sphinx:start RAILS_ENV=#{RAILS_ENV}"
end

However when I update my crontab using

whenever --update-crontab appname --set environment=production

the cron jobs still have RAILS_ENV=development.  My tasks on production and development are the same right now, I just need to change the environment variable because thinking_sphinx needs to know the current environment.  Any ideas on how to do this?

Thanks!

Body:
I was having an issue where environment wasn't being set up for whenever cron jobs - /usr/bin/bundle was being picked up instead of /usr/local/bin/bundle.

The solution was to add following to top of schedule.rb

env 'PATH', ENV['PATH']


问:
How to re-add a deleted VSTO Add-In
I've got a strange issue with a Word VSTO add-in on one machine where running the visual studio project opens word but does not attempt to start the add in as far as I can tell.

I got to this point because I accidentally clicked Remove for the Add-in on the Manage COM Add-ins  page, instead of re-enabling it after a failure.

I want to know how to re-enable a deleted add-in - I'm thinking that perhaps there is a registry key somewhere I need to get rid of.

When I run the project from Visual Studio it does not attempt to
start up at all, Word starts instantly with no "something-is-failing"
type pause.

No breakpoints in ThisAddIn_Startup are hit.

In Word : File/Options/Add-ins - the add-in does not appear under Inactive or Disabled Addins

Word : Manage COM Add-ins Go... it does not appear.

Word : Manage Disabled Items Go... is empty.

I've tried installing and uninstalling the published version, to see if that wakes anything up, and I've tried changing the path of the VS project, just in case that makes a difference (and various restarts, cleans, rebuilds, locally deleting and re-cloning from git etc) but I can't find a way to get this to work again. On a different machine, cloning the add-in from Git and opening it in Visual Studio and its all fine.

I've tried re-adding via the select DLL (or select .) dialog on the COM Add-ins but nothing I select appears to be a valid add-in.

Any help to figure out how to get back to a working development environment would be appreciated.

EDIT
There's a lot going on below - so I thought I'd clarify that the successful solution was the online-repair of Office

答:
The most extreme steps I've had to take when things aren't working as expected are to clear out the VSTA cache, either in the registry or the filesystem. Note that I work with template-based customizations that are attached to documents, not add-ins that are always present, so this may not apply to you. Or maybe it does, I don't know.

Registry

Look for an entry for your add-in under HKCU:\Software\Microsoft\VSTA\Solutions. I use PowerShell for this, and an example command chain would be something like this:

```<code>gci "HKCU:\Software\Microsoft\VSTA\Solutions"

    Hive: HKEY_CURRENT_USER\Software\Microsoft\VSTA\Solutions

Name                           Property
----                           --------
1234abcd-1234-abcd-1234-abcd12 Url                 : file:///Z:/path/to/your/addin.vsto
34abcd                         SubscriptionID      : addin.vsto, Culture=neutral, PublicKeyToken=<removed>, processorArchitecture=msil
                               ApplicationID       : file:///Z:/path/to/your/addin.vsto#addin.vsto, Version=<removed>, Culture=neutral,
                                                     PublicKeyToken=<removed>, processorArchitecture=msil/addin.dll, Version=<removed>, Culture=neutral, PublicKeyToken=<removed>,
                               processorArchitecture=msil, type=win32
                               ProductName         : addin
                               LastCheckedTime     : {4, 201, 185, 1...}
                               UpdateEnabled       : 1
                               UpdateInterval      : 1
                               UpdateIntervalUnits : days

remove-item "HKCU:\Software\Microsoft\VSTA\Solutions\1234abcd-1234-abcd-1234-abcd1234abcd"
</code>```

Filesystem

My customizations (see note at the start) are installed at %localappdata%\Apps\2.0 and on rare occasions I need to delete them manually. Clearing this one out is less straightforward, but usually there's a single anonymized folder like ABCDEFG0.QWE. I just delete that, and along with the other half of this, I've never run into a problem I couldn't solve. FYI if you have multiple deployments this might uninstall all of them. I don't do it very often so I'm not 100% familiar with how this area works, but I've never made anything worse by doing this.

I don't know how this differs, if at all, for application-level add-ins, that can be installed to Program Files.

Edit: adding some relevant links.

How do I completely uninstall a ClickOnce application from my computer?

Clear the .NET-downloaded application cache without Mage?

Title: How to re-add a deleted VSTO Add-In

Body:
The most extreme steps I've had to take when things aren't working as expected are to clear out the VSTA cache, either in the registry or the filesystem. Note that I work with template-based customizations that are attached to documents, not add-ins that are always present, so this may not apply to you. Or maybe it does, I don't know.

Registry

Look for an entry for your add-in under HKCU:\Software\Microsoft\VSTA\Solutions. I use PowerShell for this, and an example command chain would be something like this:

gci "HKCU:\Software\Microsoft\VSTA\Solutions"

    Hive: HKEY_CURRENT_USER\Software\Microsoft\VSTA\Solutions

Name                           Property
----                           --------
1234abcd-1234-abcd-1234-abcd12 Url                 : file:///Z:/path/to/your/addin.vsto
34abcd                         SubscriptionID      : addin.vsto, Culture=neutral, PublicKeyToken=<removed>, processorArchitecture=msil
                               ApplicationID       : file:///Z:/path/to/your/addin.vsto#addin.vsto, Version=<removed>, Culture=neutral,
                                                     PublicKeyToken=<removed>, processorArchitecture=msil/addin.dll, Version=<removed>, Culture=neutral, PublicKeyToken=<removed>,
                               processorArchitecture=msil, type=win32
                               ProductName         : addin
                               LastCheckedTime     : {4, 201, 185, 1...}
                               UpdateEnabled       : 1
                               UpdateInterval      : 1
                               UpdateIntervalUnits : days

remove-item "HKCU:\Software\Microsoft\VSTA\Solutions\1234abcd-1234-abcd-1234-abcd1234abcd"

Filesystem

My customizations (see note at the start) are installed at %localappdata%\Apps\2.0 and on rare occasions I need to delete them manually. Clearing this one out is less straightforward, but usually there's a single anonymized folder like ABCDEFG0.QWE. I just delete that, and along with the other half of this, I've never run into a problem I couldn't solve. FYI if you have multiple deployments this might uninstall all of them. I don't do it very often so I'm not 100% familiar with how this area works, but I've never made anything worse by doing this.

I don't know how this differs, if at all, for application-level add-ins, that can be installed to Program Files.

Edit: adding some relevant links.

How do I completely uninstall a ClickOnce application from my computer?

Clear the .NET-downloaded application cache without Mage?


问:
How do I check "no exception occurred" in my MSTest unit test?
I'm writing a unit test for this one method which returns "void".  I would like to have one case that the test passes when there is no exception thrown.  How do I write that in C#?

```<code>Assert.IsTrue(????)
</code>```

(My guess is this is how I should check, but what goes into "???")

I hope my question is clear enough.

答:
My friend Tim told me about ExpectedException.  I really like this b/c it is more succinct, less code, and very explicit that you are testing for an exception.

```<code>[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
    int numerator = 4;
    int denominator = 0;
    int actual = numerator / denominator;
}
</code>```

You can read way more about it here: ExpectedException Attribute Usage.

Body:
I'm writing a unit test for this one method which returns "void".  I would like to have one case that the test passes when there is no exception thrown.  How do I write that in C#?

Assert.IsTrue(????)

(My guess is this is how I should check, but what goes into "???")

I hope my question is clear enough.

Body:
My friend Tim told me about ExpectedException.  I really like this b/c it is more succinct, less code, and very explicit that you are testing for an exception.

[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
    int numerator = 4;
    int denominator = 0;
    int actual = numerator / denominator;
}

You can read way more about it here: ExpectedException Attribute Usage.


问:
$(window).scrollTop() Counter
I have two functions. The first checks whether an element is within view as the page is scrolled. The second one is meant to calculate the scroll top and if the first function is true, that is when the element is in view, it sets the scrollTop of that element to 0.

My solution to get this done was to start a separate counter that is only activated when the element is in view, but I am having trouble making a working counter. As it is now, the value of i is stuck at 1. Below is my code, any input is appreciated.

var img = $('.banner_img_desktop').find('img');

function isScrolledIntoView(elem) {
  var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();
  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();
  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

$(window).scroll(function() {
  var scrollTop = $(window).scrollTop();
  var i = 0; // <-- my counter
  if (isScrolledIntoView(img)) {
    i = i + 1;
    var elemScroll = i;
    var imgPos = (elemScroll / 8) + 'px';
    img.css('transform', 'translateY(' + imgPos + ')');
  }
});
```

答: As per @GrafiCode Studios's advice! The scope of the variable i was local to the scroll function and I wanted to use it as global! The solution was to  declare it outside the scroll function!

Title: $(window).scrollTop() Counter


问:
Adding extra constness causes compiler error
This compiles fine on GCC 8.2:

```<code>class M
{
public:
    const Pointer* getPointer() const {return _ptr;}
private:
    Pointer* _ptr{nullptr};
};
</code>```

but when I add another const to the function:

```<code>class M
{
public:
    const Pointer* const getPointer() const {return _ptr;}
private:
    Pointer* _ptr{nullptr};
};
</code>```

I get the compiler error:

```<code>error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]
</code>```

Why would it not let me add additional const-ness? Since when was extra const bad?

答:
Because returning a const something by value like here makes no difference with or without.

For example:

```<code>const int GetMyInt()
{
  int k = 42;
  return k;
}

//later..
int ret = GetMyInt();
// modify ret.
</code>```

Because the returned value from GetMyInt will be copied into ret anyway (not taking (N)RVO into account), having GetMyInt return const makes no difference.

Normally this is a warning because it's superfluous code but -Werror turns every warning into an error so there's that.

Body:
This compiles fine on GCC 8.2:

class M
{
public:
    const Pointer* getPointer() const {return _ptr;}
private:
    Pointer* _ptr{nullptr};
};

but when I add another const to the function:

class M
{
public:
    const Pointer* const getPointer() const {return _ptr;}
private:
    Pointer* _ptr{nullptr};
};

I get the compiler error:

error: type qualifiers ignored on function return type [-Werror=ignored-qualifiers]

Why would it not let me add additional const-ness? Since when was extra const bad?

Body:
Because returning a const something by value like here makes no difference with or without.

For example:

const int GetMyInt()
{
  int k = 42;
  return k;
}

//later..
int ret = GetMyInt();
// modify ret.

Because the returned value from GetMyInt will be copied into ret anyway (not taking (N)RVO into account), having GetMyInt return const makes no difference.

Normally this is a warning because it's superfluous code but -Werror turns every warning into an error so there's that.


问:
How to authenticate deployed Google App Script?
I'm building Google App Script product, when I deployed GAS project, I only want people in my organization can access to the app. It's ok with the browser when user already login with my organization email. But how I can access deployed URL by Postman or Terminal, Do I need access token or anything else?
Any advice is welcome!

Any advice is welcome!

答: I would like to suggest to use the OAuth PlayGround using the Google Apps Script deployed projects. You can also check this similar SO post for more solutions regarding your issue.</p>


问:
Serial communication printing issue
I am working on serial communication between two MCU's particularly teensy(similar to Arduino) for generating fake GPS data. I have been able to write GPS data and read from the other MCU fine but if u look closely, the data that is printed has some ambiguity. The last values are changed somehow and I don't understand why is this because of sprintf command or conversion of float to string or what?

Some help will be appreciated.

Below are the working code and snippet of the serial terminal.

Thank you

```<code>float lat = 37.4980608;
char str1[21];

void setup()
{
  Serial3.begin(115200);
  Serial.begin(115200); // Config serial port (USB)

  while(!Serial);
  while(!Serial3);

  Serial.println("Sending gps data");
}

void loop()
{
  sprintf(str1, "%.7f%.7f", lon, lat);
  Serial.println(str1);
  Serial3.write(str1);
  Serial3.flush();
  delay(500);
}
</code>```

答:
What you are seeing is the compiler's approximation of your floats because their values are exceeding the precision possible with a float (4-bytes).  Using a double won't help unless your MCU supports 8-byte doubles; I've not used a teensy but I highly doubt it supports 8-byte doubles.

This is not a clever solution but it should get you pointed in the right direction.

Define a struct that can represent large real number values

```<code>typedef struct {
    int whole;
    unsigned long fraction;
} BigNumber;
</code>```

The you may declare/initialize latitude and longitude l

```<code>BigNumber latitude { 126, 9653503 };
BigNumber longitude { 37, 4980608 };
</code>```

Then printing is easy:

```<code>sprintf(strbuf, "%i.%lu %i.%lu",
    latitude.whole, latitude.fraction,
    longitude.whole, longitude.fraction
  );
</code>```

However if mathematical operations are necessary - add, subtract, etc. -  this won't cut it; find an arbitrary big number library like Nick Gammon's

Lastly, have a care: in your code str1 is too small - there is no accounting for the null terminator appended by sprintf, so you're getting plain lucky your program is not crashing.

Title: Serial communication printing issue

Body:
I am working on serial communication between two MCU's particularly teensy(similar to Arduino) for generating fake GPS data. I have been able to write GPS data and read from the other MCU fine but if u look closely, the data that is printed has some ambiguity. The last values are changed somehow and I don't understand why is this because of sprintf command or conversion of float to string or what?

Some help will be appreciated.

Below are the working code and snippet of the serial terminal.

Thank you

float lat = 37.4980608;
char str1[21];

void setup()
{
  Serial3.begin(115200);
  Serial.begin(115200); // Config serial port (USB)

  while(!Serial);
  while(!Serial3);

  Serial.println("Sending gps data");
}

void loop()
{
  sprintf(str1, "%.7f%.7f", lon, lat);
  Serial.println(str1);
  Serial3.write(str1);
  Serial3.flush();
  delay(500);
}

Body:
What you are seeing is the compiler's approximation of your floats because their values are exceeding the precision possible with a float (4-bytes).  Using a double won't help unless your MCU supports 8-byte doubles; I've not used a teensy but I highly doubt it supports 8-byte doubles.

This is not a clever solution but it should get you pointed in the right direction.

Define a struct that can represent large real number values

typedef struct {
    int whole;
    unsigned long fraction;
} BigNumber;

The you may declare/initialize latitude and longitude l

BigNumber latitude { 126, 9653503 };
BigNumber longitude { 37, 4980608 };

Then printing is easy:

sprintf(strbuf, "%i.%lu %i.%lu",
    latitude.whole, latitude.fraction,
    longitude.whole, longitude.fraction
  );

However if mathematical operations are necessary - add, subtract, etc. -  this won't cut it; find an arbitrary big number library like Nick Gammon's

Lastly, have a care: in your code str1 is too small - there is no accounting for the null terminator appended by sprintf, so you're getting plain lucky your program is not crashing.


问:
Using single ngOnDestroy in parent component
In our application we have some components that inherit from a BaseComponent.

The base component implements OnDestroy interface and emits with a Subject to notify the children to unsubscribe from eventual open streams.

Is this an acceptable approach or rather every single component should have its own ngOnDestroy implementation? From this article I read that Lifecycle hooks are not inherited.

BaseComponent

```<code>export abstract class ComponentBase implements OnDestroy {
  protected destroy$ = new Subject<boolean>();

  ngOnDestroy() {
    this.destroy$.next(true);
  }
}
</code>```

ChildComponent

```<code>export class ChildComponent extends ComponentBase implements OnInit {

 ngOnInit() {
    this.service
      .getById(userId)
      .pipe(takeUntil(this.destroy$)) // this is emitted by the parent
      .subscribe(user => { ...}
 }
}
</code>```

答:
Is this an acceptable approach or rather every single component should have its own ngOnDestroy implementation?

Acceptable is just a matter of opinion, but I would strongly discourage this approach for the following reason.

```<code>@Component({...})
export class MyComponent extends BaseComponent implements OnDestroy {
      public ngOnDestroy() {
         // do work
      }
}

export class BaseComponent implements OnDestroy {
      public ngOnDestroy() {
         // never executed
      }
}
</code>```

There is no TypeScript warning issued for the above example that the super method is never executed, and so I would be tempted to call this an anti-pattern.

Furthermore, in the future you will be tempted to add additional lifecycle hooks like OnInit to the base class. To which, you'll have to search all of the descendants to ensure they call super.ngOnInit().

While it might seem like more work but it is safer to use encapsulation.

```<code>export class BaseComponent implements OnDestroy {
     public ngOnDestroy() {
        // do work
     }
}

@Component({...})
export class MyComponent implements OnDestroy {
  private readonly _base: BaseComponent = new BaseComponent();
  public ngOnDestroy() {
     this._base.ngOnDestroy();
  }
}
</code>```

There are a lot of articles on the net about the pros/cons between encapsulation vs. inheritance. It's actually a lengthy discussion in computer science, and some programming languages don't support inheritance specifically because of the problems. I guess I'm trying to say that this is a broad topic and a matter of personal choice for you, but it's partly why you asked the question.

https://www.developer.com/design/article.php/3525076/Encapsulation-vs-Inheritance.htm

Body:
In our application we have some components that inherit from a BaseComponent.

The base component implements OnDestroy interface and emits with a Subject to notify the children to unsubscribe from eventual open streams.

Is this an acceptable approach or rather every single component should have its own ngOnDestroy implementation? From this article I read that Lifecycle hooks are not inherited.

BaseComponent

export abstract class ComponentBase implements OnDestroy {
  protected destroy$ = new Subject<boolean>();

  ngOnDestroy() {
    this.destroy$.next(true);
  }
}

ChildComponent

export class ChildComponent extends ComponentBase implements OnInit {

 ngOnInit() {
    this.service
      .getById(userId)
      .pipe(takeUntil(this.destroy$)) // this is emitted by the parent
      .subscribe(user => { ...}
 }
}

Body:
Is this an acceptable approach or rather every single component should have its own ngOnDestroy implementation?

Acceptable is just a matter of opinion, but I would strongly discourage this approach for the following reason.

@Component({...})
export class MyComponent extends BaseComponent implements OnDestroy {
      public ngOnDestroy() {
         // do work
      }
}

export class BaseComponent implements OnDestroy {
      public ngOnDestroy() {
         // never executed
      }
}

There is no TypeScript warning issued for the above example that the super method is never executed, and so I would be tempted to call this an anti-pattern.

Furthermore, in the future you will be tempted to add additional lifecycle hooks like OnInit to the base class. To which, you'll have to search all of the descendants to ensure they call super.ngOnInit().

While it might seem like more work but it is safer to use encapsulation.

export class BaseComponent implements OnDestroy {
     public ngOnDestroy() {
        // do work
     }
}

@Component({...})
export class MyComponent implements OnDestroy {
  private readonly _base: BaseComponent = new BaseComponent();
  public ngOnDestroy() {
     this._base.ngOnDestroy();
  }
}

There are a lot of articles on the net about the pros/cons between encapsulation vs. inheritance. It's actually a lengthy discussion in computer science, and some programming languages don't support inheritance specifically because of the problems. I guess I'm trying to say that this is a broad topic and a matter of personal choice for you, but it's partly why you asked the question.

https://www.developer.com/design/article.php/3525076/Encapsulation-vs-Inheritance.htm


问:
Azure - trigger notification from service bus queue
I am trying to create the following process:

An IoT device sends a message to the IoT Hub which in turn, if the message contains some value, triggers a notification to all of the registered android devices through the Notification Hub.

At first, I do not care what is the content of the message itself, and I just want to trigger a notification on every incoming message.

I have managed to set up the IoT device and connect it to the IoT hub.
I have also managed to set up the Notification Hub, and connect it with the android app, in a way that when I use the "test send" in the Notification Hub, a notification is received on the android device.

In order to connect both ends (IoT Hub and Notification Hub), I tried to follow the following tutorial: https://www.developer.com/ws/android/sending-notifications-to-mobile-apps-from-azure-function-apps.html

In addition, I have added routing from the IoT Hub to the appropriate queue in the service bus.

Now, whenever the IoT device sends a message to the hub, I can see that the queue receives a message. However, I can't seem to use the queue to trigger the notification.

The ServiceHubQueueTrigger function I have added has the following error in the portal:

```<code>Error:

Function (ServiceBusQueueTrigger1) Error: The binding type(s) 'notificationHub' are not registered. Please ensure the type is correct and the binding extension is installed.
</code>```

Its function.json looks like this:

```<code>{
  "bindings": [
    {
      "name": "myQueueItem",
      "type": "serviceBusTrigger",
      "direction": "in",
      "queueName": "notificationqueue",
      "connection": "ServiceBusConnection",
      "accessRights": "manage"
    },
    {
      "name": "notification",
      "type": "notificationHub",
      "hubName": "<hub-name>",
      "connection": "NotificationConnString",
      "platform": "gcm",
      "tagExpression": "",
      "direction": "out"
    }
  ]
}
</code>```

where hub-name is the name of the Notification Hub.

How can I trigger the notifications to the android devices through the queue?
Is there a way to trigger them directly from an IoT Hub Event Trigger function?

Thanks!

答:
It seems like a simple 1.x vs 2.x Functions version problem indeed.

To solve it, if you are using the Azure portal:

Create a new Function App.

In the Function App Settings, set the version to ~1:

Note that for a new Function App, the option to set the version won't be grayed out and you could set it to ~1.

Then, follow the guide at the link in the quetion.

If you are using Visual Studio, simply choose v1 when creating the function.

As written in Microsoft's documentation, Notification binding do not support Functions 2.x, unfortunately.

Body:
I am trying to create the following process:

An IoT device sends a message to the IoT Hub which in turn, if the message contains some value, triggers a notification to all of the registered android devices through the Notification Hub.

At first, I do not care what is the content of the message itself, and I just want to trigger a notification on every incoming message.

I have managed to set up the IoT device and connect it to the IoT hub.
I have also managed to set up the Notification Hub, and connect it with the android app, in a way that when I use the "test send" in the Notification Hub, a notification is received on the android device.

In order to connect both ends (IoT Hub and Notification Hub), I tried to follow the following tutorial: https://www.developer.com/ws/android/sending-notifications-to-mobile-apps-from-azure-function-apps.html

In addition, I have added routing from the IoT Hub to the appropriate queue in the service bus.

Now, whenever the IoT device sends a message to the hub, I can see that the queue receives a message. However, I can't seem to use the queue to trigger the notification.

The ServiceHubQueueTrigger function I have added has the following error in the portal:

Error:

Function (ServiceBusQueueTrigger1) Error: The binding type(s) 'notificationHub' are not registered. Please ensure the type is correct and the binding extension is installed.

Its function.json looks like this:

{
  "bindings": [
    {
      "name": "myQueueItem",
      "type": "serviceBusTrigger",
      "direction": "in",
      "queueName": "notificationqueue",
      "connection": "ServiceBusConnection",
      "accessRights": "manage"
    },
    {
      "name": "notification",
      "type": "notificationHub",
      "hubName": "<hub-name>",
      "connection": "NotificationConnString",
      "platform": "gcm",
      "tagExpression": "",
      "direction": "out"
    }
  ]
}

where hub-name is the name of the Notification Hub.

How can I trigger the notifications to the android devices through the queue?
Is there a way to trigger them directly from an IoT Hub Event Trigger function?

Thanks!


问:
How to use year function inside the Countif in excel formula?
I'm having an trouble making an excel formula at the moment which would first search for the value by getting the year from the dates and then search another value from the sheet. Finally return the count.

Please, let me know how can I do this. I've been stuck at this a long time.

Right now i'm using this formula.

```<code>=COUNTIFS('Inc'!$F$2:$F$984,"YEAR('Incg'!$F$2:$F$984)=2017",'Incident Log'!$J$2:$J$984,$F9)`
</code>```

答:
You can't use YEAR() as an argument to COUNTIFS in this case, because its output is the numerical value 2017 whereas the value you want to use for your comparison is 42736, the internal representation of this year. A possible workaround is:

```<code>=COUNTIFS('Incident Log'!$F$2:$F$984,">="&DATE(2017,1,1),'Incident Log'!$F$2:$F$984,"<"&DATE(2018,1,1), ...)
</code>```

This extracts the numerical date values of January 1 2017 and 2018, and checks whether each value lies between those dates.

If you do want to use YEAR() then you can use it with SUMPRODUCT, which was the usual way of solving problems like this before COUNTIFS became available.

```<code>=SUMPRODUCT(--(YEAR('Incident Log'!$F$2:$F$984)=2017),--('Incident Log'!$J$2:$J$984=$F9))
</code>```

Body:
I'm having an trouble making an excel formula at the moment which would first search for the value by getting the year from the dates and then search another value from the sheet. Finally return the count.

Please, let me know how can I do this. I've been stuck at this a long time.

Right now i'm using this formula.

=COUNTIFS('Inc'!$F$2:$F$984,"YEAR('Incg'!$F$2:$F$984)=2017",'Incident Log'!$J$2:$J$984,$F9)`

Body:
You can't use YEAR() as an argument to COUNTIFS in this case, because its output is the numerical value 2017 whereas the value you want to use for your comparison is 42736, the internal representation of this year. A possible workaround is:

=COUNTIFS('Incident Log'!$F$2:$F$984,">="&DATE(2017,1,1),'Incident Log'!$F$2:$F$984,"<"&DATE(2018,1,1), ...)

This extracts the numerical date values of January 1 2017 and 2018, and checks whether each value lies between those dates.

If you do want to use YEAR() then you can use it with SUMPRODUCT, which was the usual way of solving problems like this before COUNTIFS became available.

=SUMPRODUCT(--(YEAR('Incident Log'!$F$2:$F$984)=2017),--('Incident Log'!$J$2:$J$984=$F9))


答:
The const qualifier has no effect in this position, since the returned value is a prvalue of non-class type and therefore cannot be modified anyway.

Notice that the compiler message says -Werror=, meaning that it's normally a warning (so the code is not wrong, but warning-worthy). It has been turned into an error by your compilation settings.

Title: Adding extra constness causes compiler error


问:
Copying from Dropbox to UNIX machine using rsync or similar?
Is there any way I can copy data directly from the Dropbox servers to a UNIX server, without being root or having Dropbox software installed there?

Something like:

```<code>rsync -aP myusername@dropbox.com:somepath/ .
</code>```

(The reason for wanting to do this is that the transfer speed between the UNIX server and the Dropbox server would be much faster since they are both on the backbone, than between my local machine and the UNIX server, which have a home broadband connection).

答:
Try rclone https://github.com/dropbox/dbxcli/issues/60#issuecomment-497713363

install

```<code>$ curl -OJN https://downloads.rclone.org/rclone-current-linux-amd64.zip
$ unzip rclone-current-linux-amd64.zip
$ cp rclone-v1.47.0-linux-amd64/rclone ~/bin/
</code>```

config https://rclone.org/dropbox/

```<code>$ rclone config
2019/05/31 15:00:07 NOTICE: Config file "/home/roman/.config/rclone/rclone.conf" not found - using defaults
No remotes found - make a new one
n) New remote
s) Set configuration password
q) Quit config
n/s/q> n
name> dropbox
Type of storage to configure.
Enter a string value. Press Enter for the default ("").
Choose a number from below, or type in your own value
 1 / A stackable unification remote, which can appear to merge the contents of several remotes
   \ "union"
 2 / Alias for a existing remote
   \ "alias"
 3 / Amazon Drive
   \ "amazon cloud drive"
 4 / Amazon S3 Compliant Storage Provider (AWS, Alibaba, Ceph, Digital Ocean, Dreamhost, IBM COS, Minio, etc)
   \ "s3"
 5 / Backblaze B2
   \ "b2"
 6 / Box
   \ "box"
 7 / Cache a remote
   \ "cache"
 8 / Dropbox
   \ "dropbox"
 9 / Encrypt/Decrypt a remote
   \ "crypt"
10 / FTP Connection
   \ "ftp"
11 / Google Cloud Storage (this is not Google Drive)
   \ "google cloud storage"
12 / Google Drive
   \ "drive"
13 / Hubic
   \ "hubic"
14 / JottaCloud
   \ "jottacloud"
15 / Koofr
   \ "koofr"
16 / Local Disk
   \ "local"
17 / Mega
   \ "mega"
18 / Microsoft Azure Blob Storage
   \ "azureblob"
19 / Microsoft OneDrive
   \ "onedrive"
20 / OpenDrive
   \ "opendrive"
21 / Openstack Swift (Rackspace Cloud Files, Memset Memstore, OVH)
   \ "swift"
22 / Pcloud
   \ "pcloud"
23 / QingCloud Object Storage
   \ "qingstor"
24 / SSH/SFTP Connection
   \ "sftp"
25 / Webdav
   \ "webdav"
26 / Yandex Disk
   \ "yandex"
27 / http Connection
   \ "http"
Storage> 8
** See help for dropbox backend at: https://rclone.org/dropbox/ **

Dropbox App Client Id
Leave blank normally.
Enter a string value. Press Enter for the default ("").
client_id>
Dropbox App Client Secret
Leave blank normally.
Enter a string value. Press Enter for the default ("").
client_secret>
Edit advanced config? (y/n)
y) Yes
n) No
y/n> n
Remote config
Use auto config?
 * Say Y if not sure
 * Say N if you are working on a remote or headless machine
y) Yes
n) No
y/n>
y/n> y
If your browser doesn't open automatically go to the following link: http://127.0.0.1:53682/auth
Log in and authorize rclone for access
Waiting for code...
Got code
--------------------
[dropbox]
type = dropbox
token = {"access_token":"<token>","token_type":"bearer","expiry":"0001-01-01T00:00:00Z"}
--------------------
y) Yes this is OK
e) Edit this remote
d) Delete this remote
y/e/d> y
Current remotes:

Name                 Type
====                 ====
dropbox              dropbox

e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> q
</code>```

copy all files from dropbox https://rclone.org/docs/

```<code>$ rclone copy --dry-run dropbox:/ .
$ rclone copy dropbox:/ .
</code>```

Body:
Is there any way I can copy data directly from the Dropbox servers to a UNIX server, without being root or having Dropbox software installed there?

Something like:

rsync -aP myusername@dropbox.com:somepath/ .

(The reason for wanting to do this is that the transfer speed between the UNIX server and the Dropbox server would be much faster since they are both on the backbone, than between my local machine and the UNIX server, which have a home broadband connection).

Body:
Try rclone https://github.com/dropbox/dbxcli/issues/60#issuecomment-497713363

install

$ curl -OJN https://downloads.rclone.org/rclone-current-linux-amd64.zip
$ unzip rclone-current-linux-amd64.zip
$ cp rclone-v1.47.0-linux-amd64/rclone ~/bin/

config https://rclone.org/dropbox/

$ rclone config
2019/05/31 15:00:07 NOTICE: Config file "/home/roman/.config/rclone/rclone.conf" not found - using defaults
No remotes found - make a new one
n) New remote
s) Set configuration password
q) Quit config
n/s/q> n
name> dropbox
Type of storage to configure.
Enter a string value. Press Enter for the default ("").
Choose a number from below, or type in your own value
 1 / A stackable unification remote, which can appear to merge the contents of several remotes
   \ "union"
 2 / Alias for a existing remote
   \ "alias"
 3 / Amazon Drive
   \ "amazon cloud drive"
 4 / Amazon S3 Compliant Storage Provider (AWS, Alibaba, Ceph, Digital Ocean, Dreamhost, IBM COS, Minio, etc)
   \ "s3"
 5 / Backblaze B2
   \ "b2"
 6 / Box
   \ "box"
 7 / Cache a remote
   \ "cache"
 8 / Dropbox
   \ "dropbox"
 9 / Encrypt/Decrypt a remote
   \ "crypt"
10 / FTP Connection
   \ "ftp"
11 / Google Cloud Storage (this is not Google Drive)
   \ "google cloud storage"
12 / Google Drive
   \ "drive"
13 / Hubic
   \ "hubic"
14 / JottaCloud
   \ "jottacloud"
15 / Koofr
   \ "koofr"
16 / Local Disk
   \ "local"
17 / Mega
   \ "mega"
18 / Microsoft Azure Blob Storage
   \ "azureblob"
19 / Microsoft OneDrive
   \ "onedrive"
20 / OpenDrive
   \ "opendrive"
21 / Openstack Swift (Rackspace Cloud Files, Memset Memstore, OVH)
   \ "swift"
22 / Pcloud
   \ "pcloud"
23 / QingCloud Object Storage
   \ "qingstor"
24 / SSH/SFTP Connection
   \ "sftp"
25 / Webdav
   \ "webdav"
26 / Yandex Disk
   \ "yandex"
27 / http Connection
   \ "http"
Storage> 8
** See help for dropbox backend at: https://rclone.org/dropbox/ **

Dropbox App Client Id
Leave blank normally.
Enter a string value. Press Enter for the default ("").
client_id>
Dropbox App Client Secret
Leave blank normally.
Enter a string value. Press Enter for the default ("").
client_secret>
Edit advanced config? (y/n)
y) Yes
n) No
y/n> n
Remote config
Use auto config?
 * Say Y if not sure
 * Say N if you are working on a remote or headless machine
y) Yes
n) No
y/n>
y/n> y
If your browser doesn't open automatically go to the following link: http://127.0.0.1:53682/auth
Log in and authorize rclone for access
Waiting for code...
Got code
--------------------
[dropbox]
type = dropbox
token = {"access_token":"<token>","token_type":"bearer","expiry":"0001-01-01T00:00:00Z"}
--------------------
y) Yes this is OK
e) Edit this remote
d) Delete this remote
y/e/d> y
Current remotes:

Name                 Type
====                 ====
dropbox              dropbox

e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> q

copy all files from dropbox https://rclone.org/docs/

$ rclone copy --dry-run dropbox:/ .
$ rclone copy dropbox:/ .


问:
Change O365 script to change job title with user prompts for input?
I have made a script to change an office 365 user's job title.However I want it so there are two user prompt boxes asking for the email address entry and then new job title entry, rather than me changing the users email and title every time.</p>

```<code>$user = Read-Host -Prompt 'Input the users email address'
$job = Read-Host -Prompt 'Enter the new Job Title'
Set-MsolUser -UserPrincipalName $user  -Title $job
</code>```

答:
This is not too difficult!

Here's a small helper function you can use to make the worlds most basic text input GUI in PowerShell, with params to customize the title and the message shown to the user.

```<code>Function Get-TextInput {
Param($Description='Please enter the information in the space below:',$Title="Data Entry Form")
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing

    $form = New-Object System.Windows.Forms.Form
    $form.Text = $Title
    $form.Size = New-Object System.Drawing.Size(300,200)
    $form.StartPosition = 'CenterScreen'

    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Point(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = 'OK'
    $OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $form.AcceptButton = $OKButton
    $form.Controls.Add($OKButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Point(150,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = 'Cancel'
    $CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
    $form.CancelButton = $CancelButton
    $form.Controls.Add($CancelButton)

    $label = New-Object System.Windows.Forms.Label
    $label.Location = New-Object System.Drawing.Point(10,20)
    $label.Size = New-Object System.Drawing.Size(280,20)
    $label.Text = $Description
    $form.Controls.Add($label)

    $textBox = New-Object System.Windows.Forms.TextBox
    $textBox.Location = New-Object System.Drawing.Point(10,40)
    $textBox.Size = New-Object System.Drawing.Size(260,20)
    $form.Controls.Add($textBox)

    $form.Topmost = $true

    $form.Add_Shown({$textBox.Select()})
    $result = $form.ShowDialog()

    if ($result -eq [System.Windows.Forms.DialogResult]::OK)
    {
        $x = $textBox.Text
        $x
    }
}
</code>```

Gives you a UI like this:

Here's how you'd use it:

```<code>#Include the whole function in the body of the script here
$UserPrincipleName = Get-TextInput -Description "Enter User Name" -Title "MSOL Script"
$UserTitle = Get-TextInput -Description "Enter Title For this position" -Title "MSOL Script"
Set-MsolUser -UserPrincipalName $UserPrincipleName -Title $UserTitle
</code>```

If you want to know how this is made, check out one of these two sources:

Microsoft Source for the adapted code sample above

My own blog series covering how to make UIs and show them in PowerShell

Body:
I have made a script to change an office 365 user's job title.However I want it so there are two user prompt boxes asking for the email address entry and then new job title entry, rather than me changing the users email and title every time.

$user = Read-Host -Prompt 'Input the users email address'
$job = Read-Host -Prompt 'Enter the new Job Title'
Set-MsolUser -UserPrincipalName $user  -Title $job

Body:
This is not too difficult!

Here's a small helper function you can use to make the worlds most basic text input GUI in PowerShell, with params to customize the title and the message shown to the user.

Function Get-TextInput {
Param($Description='Please enter the information in the space below:',$Title="Data Entry Form")
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing

    $form = New-Object System.Windows.Forms.Form
    $form.Text = $Title
    $form.Size = New-Object System.Drawing.Size(300,200)
    $form.StartPosition = 'CenterScreen'

    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Point(75,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = 'OK'
    $OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $form.AcceptButton = $OKButton
    $form.Controls.Add($OKButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Point(150,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = 'Cancel'
    $CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
    $form.CancelButton = $CancelButton
    $form.Controls.Add($CancelButton)

    $label = New-Object System.Windows.Forms.Label
    $label.Location = New-Object System.Drawing.Point(10,20)
    $label.Size = New-Object System.Drawing.Size(280,20)
    $label.Text = $Description
    $form.Controls.Add($label)

    $textBox = New-Object System.Windows.Forms.TextBox
    $textBox.Location = New-Object System.Drawing.Point(10,40)
    $textBox.Size = New-Object System.Drawing.Size(260,20)
    $form.Controls.Add($textBox)

    $form.Topmost = $true

    $form.Add_Shown({$textBox.Select()})
    $result = $form.ShowDialog()

    if ($result -eq [System.Windows.Forms.DialogResult]::OK)
    {
        $x = $textBox.Text
        $x
    }
}

Gives you a UI like this:

Here's how you'd use it:

#Include the whole function in the body of the script here
$UserPrincipleName = Get-TextInput -Description "Enter User Name" -Title "MSOL Script"
$UserTitle = Get-TextInput -Description "Enter Title For this position" -Title "MSOL Script"
Set-MsolUser -UserPrincipalName $UserPrincipleName -Title $UserTitle

If you want to know how this is made, check out one of these two sources:

Microsoft Source for the adapted code sample above

My own blog series covering how to make UIs and show them in PowerShell


问:
Phantom
 within carousel
Having more trouble with this infographic. There seems to be a phantom
 appearing at the end of the carousel. Does anyone know how this has appeared?

http://weaver-wp.weavertest.com/radiation-infographic/

Cheers,
Dave

答:
@Dalogi: Still can't find the issue, so this will have to be the band-aid for now --

```<code>$('#radiation-infographic').tinycarousel({
    pager: true,
    interval: false,
    callback: function(element, index) {
        // hide 'next' button when on last slide; unhide when not
        index == 30 ? $('a.next').hide() : $('a.next').show();

        console.log(element, index);
    }
});
</code>```

I'll update my answer if I have a break-through with a better solution.

Title: Phantom <li> within carousel

Body:
@Dalogi: Still can't find the issue, so this will have to be the band-aid for now --

$('#radiation-infographic').tinycarousel({
    pager: true,
    interval: false,
    callback: function(element, index) {
        // hide 'next' button when on last slide; unhide when not
        index == 30 ? $('a.next').hide() : $('a.next').show();

        console.log(element, index);
    }
});

I'll update my answer if I have a break-through with a better solution.