事情是這樣的,evernote免費版只能在2個裝置內使用。
第三個裝置總是使用網頁版的來存取也不方便,想想還是專業版訂閱下去使用。
但是一定下去之後卻發現evernote的應用程式安裝時發生錯誤:
學無止盡
2019年10月29日 星期二
2019年8月15日 星期四
特定網站自動開啟Fiddler
繼上一篇。我們成功的使用一個暫時的解決方法來避免網站瀏覽時出現跑版/功能不正常。
不過這個方法有很大的侷限:必須在瀏覽網頁時同時開啟fiddler。
這意味著我們必須將fiddler與瀏覽器綑綁再一起:只要瀏覽器打開,fiddler也需要一起開啟。
不過fiddler只是為了某個特定的網站才需要,而且這個網站也不是每次開啟瀏覽器都會去逛。因此,能不能做到只有在瀏覽特定網站的時候,自動開啟fiddler呢?
這就是本文的重點。
要達成這個目標,我們需要做到以下幾點:
不過這個方法有很大的侷限:必須在瀏覽網頁時同時開啟fiddler。
這意味著我們必須將fiddler與瀏覽器綑綁再一起:只要瀏覽器打開,fiddler也需要一起開啟。
不過fiddler只是為了某個特定的網站才需要,而且這個網站也不是每次開啟瀏覽器都會去逛。因此,能不能做到只有在瀏覽特定網站的時候,自動開啟fiddler呢?
這就是本文的重點。
要達成這個目標,我們需要做到以下幾點:
- 設定Fiddler,使其能轉換https到http
- 讓瀏覽器能開啟Fiddler
- 讓特定的網站才開啟Fiddler
2019年7月12日 星期五
使用Fiddler將https導成http
緣由:
筆者有個常逛的網站依然使用http,不過該網站的超連結偶爾會將網址導去https下。
如果該網站使用https瀏覽的時候,有一些資源(例如css或是java script)依舊是使用http的方式從外部讀取,這導致觸發了Firefox的混合內容(mixed content)的安全性警示。
在預設的情況下Firefox會將較不安全的http連結封鎖,於是該網站的版面就跑掉了(因為css被擋住無法載入)。
目的:
當超連結導去的網址是https的時候,將其改回http,確保在瀏覽網頁的期間所有的連結都會是http。
方法:
使用Fiddler的AutoResponder的功能來將https轉成http。
※Fiddler是一個web debugging tool。他能記錄瀏覽網頁時的各種資料,也能用客製化的內容來取代網站的回應。
筆者有個常逛的網站依然使用http,不過該網站的超連結偶爾會將網址導去https下。
如果該網站使用https瀏覽的時候,有一些資源(例如css或是java script)依舊是使用http的方式從外部讀取,這導致觸發了Firefox的混合內容(mixed content)的安全性警示。
在預設的情況下Firefox會將較不安全的http連結封鎖,於是該網站的版面就跑掉了(因為css被擋住無法載入)。
目的:
當超連結導去的網址是https的時候,將其改回http,確保在瀏覽網頁的期間所有的連結都會是http。
方法:
使用Fiddler的AutoResponder的功能來將https轉成http。
※Fiddler是一個web debugging tool。他能記錄瀏覽網頁時的各種資料,也能用客製化的內容來取代網站的回應。
2018年5月30日 星期三
函式傳遞的進化論 (4) - lambda expression
前面講到了delegate(委派)的語法,不過使用上還是有些繁瑣。
除了要宣告委派類別外,同樣必須要先宣告與定義符合委派類別的方法才可以使用。
如你所見,有時候我們只是需要很簡單的方法(僅僅1-2行)或是該方法僅僅只使用個1-2次,但是卻需要額外宣告方法以及包覆的類別(如Operator類別)。
那麼有沒有更簡便的寫法呢?
有,C#有提供匿名方法(Anonymous Method)的方式讓我們可以省下方法的宣告:
在第4行時就是使用匿名方法的方式,直接定義出一個方法以及其主體(return a + b)。
如此在使用委派時就可以隨時定義出想使用的方法。
不過...這樣就結束了嗎? 還沒呢!! C#還提供更懶人的方式:Lambda Expression
左邊的 (int a, int b) 表示方法的輸入參數,
中間的 => 即是lamdba expression的關鍵語法。
右方的 { return a+b; } 則是方法的主體。
整體來說這跟匿名方法有些相似,同樣都沒有方法名稱、輸入與輸出都一模一樣,唯一的差別就是少了關鍵字delegate以及多了 => 符號。
Lambda expression可不只這樣。
首先我們可以知道此Lambda expression會指派給Calculator委派,該委派的方法簽章是輸入兩個int並且回傳一個int。
因此藉由型別推斷,編譯器可以知道Lambda expression的輸入與輸出的型別。
所以左方的(int a, int b)可以省略型別宣告:
其次,因為方法主體只有一行而已,而且也只有單一動作,所以程式碼區塊的大括號{}以及return關鍵字也可以省略,編譯器會知道a+b就是回傳值。
唯一的缺點就是跟以往的語法相比相差比較大,初次接觸lambda expression的人會需要一段時間熟悉。
另外,如果方法的傳入參數只有一個的話,連左邊的小括號也可以省略。例如Linq的Where方法:
除了要宣告委派類別外,同樣必須要先宣告與定義符合委派類別的方法才可以使用。
- public delegate int Calculator(int a, int b);
- public class Operator
- {
- public static int Plus(int a, int b)
- {
- return a + b;
- }
- public static int Sub(int a, int b)
- {
- return a - b;
- }
- public static int Mul(int a, int b)
- {
- return a * b;
- }
- public static int Div(int a, int b)
- {
- return a / b;
- }
- }
- public static void Main()
- {
- var calc = new Calculator(Operator.Plus);
- Console.WriteLine(calc(3,5));
- calc = new Calculator(Operator.Sub);
- Console.WriteLine(calc(3,5));
- }
如你所見,有時候我們只是需要很簡單的方法(僅僅1-2行)或是該方法僅僅只使用個1-2次,但是卻需要額外宣告方法以及包覆的類別(如Operator類別)。
那麼有沒有更簡便的寫法呢?
有,C#有提供匿名方法(Anonymous Method)的方式讓我們可以省下方法的宣告:
- public delegate int Calculator(int a, int b);
- public static void Main()
- {
- Calculator calc = delegate(int a, int b)
- {
- return a+b;
- };
- Console.WriteLine(calc(3,5));
- }
在第4行時就是使用匿名方法的方式,直接定義出一個方法以及其主體(return a + b)。
如此在使用委派時就可以隨時定義出想使用的方法。
不過...這樣就結束了嗎? 還沒呢!! C#還提供更懶人的方式:Lambda Expression
第4行的(int a, int b) => { return a+b; }; 即是lamdba expression。
- public delegate int Calculator(int a, int b);
- public static void Main()
- {
- Calculator calc = (int a, int b) => { return a+b; };
- Console.WriteLine(calc(3,5));
- }
左邊的 (int a, int b) 表示方法的輸入參數,
中間的 => 即是lamdba expression的關鍵語法。
右方的 { return a+b; } 則是方法的主體。
整體來說這跟匿名方法有些相似,同樣都沒有方法名稱、輸入與輸出都一模一樣,唯一的差別就是少了關鍵字delegate以及多了 => 符號。
Lambda expression可不只這樣。
首先我們可以知道此Lambda expression會指派給Calculator委派,該委派的方法簽章是輸入兩個int並且回傳一個int。
因此藉由型別推斷,編譯器可以知道Lambda expression的輸入與輸出的型別。
所以左方的(int a, int b)可以省略型別宣告:
- Calculator calc = (a, b) => { return a+b; };
其次,因為方法主體只有一行而已,而且也只有單一動作,所以程式碼區塊的大括號{}以及return關鍵字也可以省略,編譯器會知道a+b就是回傳值。
如此,是不是比匿名方法簡潔許多呢?
- Calculator calc = (a, b) => a+b;
唯一的缺點就是跟以往的語法相比相差比較大,初次接觸lambda expression的人會需要一段時間熟悉。
另外,如果方法的傳入參數只有一個的話,連左邊的小括號也可以省略。例如Linq的Where方法:
- var list = new List
{1,2,3,4,5}; var list2 = list.Where(x => x > 3);
2018年5月28日 星期一
函式傳遞的進化論 (3) - delegate
C#也是物件導向程式語言家族中的一員,因此同樣無法直接將方法傳遞給另一個方法。
C#同樣可以使用interface的技巧來包覆方法,不過這邊將介紹C#本身提供的方式:delegate(委派)
Delegate有一點像C的function pointer,其作用就是可以接收與傳遞方法。
首先使用關鍵字delegate來宣告一個delegate的類別
接著宣告一個方法可以接收Comparator類別,此方法會調用指派給委派物件的方法(有點繞口,讓我們看接下來的程式碼)
接下來我們要宣告符合Comparator的方法:
然後在呼叫bubbleSort時將此方法傳遞給Comparator物件
整體完整的程式如下:
我們重新再看一次此程式。
首先先宣告一個委派類別Comparator(line 4),接著宣告符合此委派類別的方法SortByAsc(line 37)。
在第12行時將SortByAsc方法傳遞給BubbleSort的第二個引數Comparator c,
而BubbleSort會在第27行時呼叫c所接收到的方法,即sorter.SortByAsc方法
C#同樣可以使用interface的技巧來包覆方法,不過這邊將介紹C#本身提供的方式:delegate(委派)
Delegate有一點像C的function pointer,其作用就是可以接收與傳遞方法。
首先使用關鍵字delegate來宣告一個delegate的類別
這邊宣告名為Comparator的delegate類別,Comparator將會接受一種"參數是2個int並回傳1個int"的這種方法。
- public delegate int Comparator(int first, int second);
接著宣告一個方法可以接收Comparator類別,此方法會調用指派給委派物件的方法(有點繞口,讓我們看接下來的程式碼)
在第7行時呼叫此Comparator所接收到的方法。
- public void BubbleSort(int[] array, Comparator c)
- {
- for(var round=0; round < array.Length; round++)
- {
- for(var i=0; i<array.Length-1; i++)
- {
- if(c(array[i], array[i+1]) > 0)
- {
- var temp = array[i];
- array[i] = array[i+1];
- array[i+1] = temp;
- }
- }
- }
- }
接下來我們要宣告符合Comparator的方法:
- public int SortByAsc(int first, int second)
- {
- if(first < second)
- {
- return -1;
- }
- else if(first > second)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
然後在呼叫bubbleSort時將此方法傳遞給Comparator物件
- public static void Main()
- {
- var array = new [] {4,7,1,6,9};
- var sorter = new Sorter();
- sorter.BubbleSort(array, sorter.SortByAsc);
- foreach(var elem in array)
- {
- Console.WriteLine(elem);
- }
- }
整體完整的程式如下:
- using System.IO;
- using System;
- public delegate int Comparator(int first, int second);
- public class Sorter
- {
- public static void Main()
- {
- var array = new int[] {4,7,1,6,9};
- var sorter = new Sorter();
- sorter.BubbleSort(array, sorter.SortByAsc);
- foreach(var elem in array)
- {
- Console.WriteLine(elem);
- }
- }
- public void BubbleSort(int[] array, Comparator c)
- {
- for(var round=0; round < array.Length; round++)
- {
- for(var i=0; i<array.Length-1; i++)
- {
- if(c(array[i], array[i+1]) > 0)
- {
- var temp = array[i];
- array[i] = array[i+1];
- array[i+1] = temp;
- }
- }
- }
- }
- public int SortByAsc(int first, int second)
- {
- if(first < second)
- {
- return -1;
- }
- else if(first > second)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- }
我們重新再看一次此程式。
首先先宣告一個委派類別Comparator(line 4),接著宣告符合此委派類別的方法SortByAsc(line 37)。
在第12行時將SortByAsc方法傳遞給BubbleSort的第二個引數Comparator c,
而BubbleSort會在第27行時呼叫c所接收到的方法,即sorter.SortByAsc方法
2018年4月2日 星期一
函式傳遞的進化論 (2) - function object
在上一篇中講到利用函式指標與callback函式可以讓我們的程式更有彈性。
不過在一些物件導向的程式語言(例如Java)中,我們沒辦法直接把函式傳遞給另一個函式
註:在物件導向的程式語言中,函式(function)被稱做方法(method),之後我會使用方法一詞
在Java中萬物都是物件(唔,其實還有primitive type這東西的存在,不過我們先忽略它),方法沒有辦法單獨宣告與使用,它必須依附在某個類別下。
所以一個通用的解法是用一個interface將方法包起來
此時我們的bubbleSort可以將Comparator物件傳遞進來,並且在需要時呼叫Comparator的compare方法(第10行)
同樣當我們需要不同排序邏輯時,只需要實做Comparator介面就好
使用時只要new一個有實做Comparator介面的物件即可。
這裡的SortByAsc就是所謂的function object,它僅僅是方法(函式)的物件而已。
不過在一些物件導向的程式語言(例如Java)中,我們沒辦法直接把函式傳遞給另一個函式
註:在物件導向的程式語言中,函式(function)被稱做方法(method),之後我會使用方法一詞
在Java中萬物都是物件(唔,其實還有primitive type這東西的存在,不過我們先忽略它),方法沒有辦法單獨宣告與使用,它必須依附在某個類別下。
所以一個通用的解法是用一個interface將方法包起來
- //Comparator.java
- public interface Comparator{
- int compare(int first, int second);
- }
此時我們的bubbleSort可以將Comparator物件傳遞進來,並且在需要時呼叫Comparator的compare方法(第10行)
- //Sorter.java
- public class Sorter{
- public static void main(String []args){
- ...
- }
- public void bubbleSort(int[] array, Comparator c){
- for(int round=0; round<array.length; round++){
- for(int i=0; i<array.length-1; i++){
- if( c.compare(array[i],array[i+1]) > 0){
- int temp = array[i];
- array[i] = array[i+1];
- array[i+1] = temp;
- }
- }
- }
- }
- }
同樣當我們需要不同排序邏輯時,只需要實做Comparator介面就好
- //SortByAsc.java
- public class SortByAsc implements Comparator{
- public int compare(int first, int second){
- if(first < second){
- return -1;
- }
- else if(first > second){
- return 1;
- }
- else{
- return 0;
- }
- }
- }
使用時只要new一個有實做Comparator介面的物件即可。
- //Sorter.java
- public class Sorter{
- public static void main(String []args){
- int[] array = {5,2,8,1};
- Sorter obj = new Sorter();
- obj.bubbleSort(array, new SortByAsc());
- for(int elem : array){
- System.out.println(elem);
- }
- }
- public void bubbleSort(int[] array, Comparator c){
- ...
- }
- }
這裡的SortByAsc就是所謂的function object,它僅僅是方法(函式)的物件而已。
2018年4月1日 星期日
函式傳遞的進化論 (1) - function pointer
在C語言中,可以使用function pointer (函式指標, 一個特殊的指標用來指向函式) 將一個函式當作參數傳給另一個函式。
程式碼如上。宣告2個函式add & subtract以及1個函式calculator。
其中calculator的參數允許傳入一個函式來讓calculator呼叫該函式。
在第10行時同樣宣告一個函式指標fp,並且指向add函式。
第11行時則將函式指標fp作為引數傳遞給calculator函式。因為此時fp指向add函式,因此claculator函式會呼叫add函式。
在13行時則將函式指標fp改成指向subtract函式,因此在14行的calculator會呼叫subtract函式。
以上是教科書講到函式指標時經常舉的例子。
我還在念書時對這段程式常有疑惑:
- #include <stdio.h>
- int add (int firstNumber, int secondNumber);
- int subtract (int firstNumber, int secondNumber);
- int calculator (int firstNumber, int secondNumber, int (*fp) (int, int));
- int main ()
- {
- int firstNumber = 1;
- int secondNumber = 2;
- int (*fp) (int, int) = add;
- printf ("%d\n", calculator (firstNumber, secondNumber, fp));
- fp = subtract;
- printf ("%d\n", calculator (firstNumber, secondNumber, fp));
- return 0;
- }
- int add (int firstNumber, int secondNumber)
- {
- return firstNumber + secondNumber;
- }
- int subtract (int firstNumber, int secondNumber)
- {
- return firstNumber - secondNumber;
- }
- int calculator (int firstNumber, int secondNumber, int (*fp) (int, int))
- {
- return (*fp) (firstNumber, secondNumber);
- }
程式碼如上。宣告2個函式add & subtract以及1個函式calculator。
其中calculator的參數允許傳入一個函式來讓calculator呼叫該函式。
在第10行時同樣宣告一個函式指標fp,並且指向add函式。
第11行時則將函式指標fp作為引數傳遞給calculator函式。因為此時fp指向add函式,因此claculator函式會呼叫add函式。
在13行時則將函式指標fp改成指向subtract函式,因此在14行的calculator會呼叫subtract函式。
以上是教科書講到函式指標時經常舉的例子。
我還在念書時對這段程式常有疑惑:
像這樣直接呼叫add & subtract函式不就好了,為什麼還要多宣告一個函式指標來指向函式?讓函式指標呼叫該函式,這不是多此一舉嗎?
- printf ("%d\n", add(firstNumber, secondNumber));
- printf ("%d\n", subtract(firstNumber, secondNumber));
訂閱:
文章 (Atom)