2017/11/21

mac - 關閉 chrome 的兩指滑動換頁功能

markdown 在 mac 上的 chrome 有一個功能是使用兩指向右滑動可以回到上一頁,可是幹,我只是想看左邊的東西欸,所以我找到怎麼把這個功能關閉的方法。 在 bash 下輸入以下指令: ``` defaults write com.google.Chrome AppleEnableMouseSwipeNavigateWithScrolls -bool false defaults write com.google.Chrome AppleEnableSwipeNavigateWithScrolls -bool false ``` 然後重開 chrome

2017/11/8

rails - encode & decode

markdown HTML encode ``` require 'cgi' CGI.escapeHTML('<') # "&lt;" ``` HTML decode ``` require 'cgi' CGI.unescapeHTML('&lt;') # "<" ```

mac - 移除所有 ANSI escape code

markdown 當你用 rspec 跑測試並且生成結果檔案時,檔案的內容可能會包含 [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) 所表示的顏色。 舉例來說,如果你用以下程式跑測試: ``` rspec --format documentation --out result.txt ``` 你可以使用 cat 去讀他 ``` cat result.txt ``` 結果看起來像這樣:
但是打開 result.txt 時,你會看到這樣的東西: ``` ... Finished in 1.76 seconds (files took 6.55 seconds to load) [32m1 example, 0 failures [0m Randomized with seed 1 ``` [32m [0m 代表的就是顏色,這被稱為 [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors)。 但是我希望讓他消失,在請教大大之後得到一個不錯的解法,有人用 node.js 做了一個簡單的指令[strip-ansi](https://github.com/chalk/strip-ansi-cli)。 安裝方法(如果你有node.js) ``` # 這裡是 bash npm install --global strip-ansi-cli ``` 使用方法 ``` # 基本用法 strip-ansi 字串 # 透過 | cat 輸入檔案路徑 | strip-ansi > 輸出檔案路徑 ```

2017/11/6

Ruby - warning: toplevel constant B referenced by A::B

markdown ##問題 warning: toplevel constant B referenced by A::B ##成因 當 A 是一個 class 且 A::B 還沒有被定義時,ruby 找不到 A::B 時,若 B 有定義,就先使用 B, 而不是拋出 Module#const_missing。 ``` class A end A::String #warning: toplevel constant String referenced by A::String ``` 但 rails 的 autoload 是透過修改 Module#const_missing 而完成的。也就是說,rails 還來不及 autoload 就已經被 toplevel constant 攔截了。 ##解法一 在使用到 A::B 的檔案前面都加 require_dependency 'a/b' ##解法二 在使用到 B 的檔案後面加 require_dependency 'a/b' 確保 rails 不可能會有知道 B 的存在但不知道 A::B 的存在的可能發生。 參考文件 [http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html](http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html) [https://stackoverflow.com/questions/18515100/warning-toplevel-constant-referenced](https://stackoverflow.com/questions/18515100/warning-toplevel-constant-referenced)

2017/10/30

Python - numpy 的使用方法

markdown [NumPy Reference](https://docs.scipy.org/doc/numpy-1.13.0/reference/index.html) 數列生成 ``` >>> np.zeros(5) #array([ 0., 0., 0., 0., 0.]) >>> np.ones(5) #array([ 1., 1., 1., 1., 1.]) >>> np.arange(5) #array([0, 1, 2, 3, 4]) ``` [更多的數列生成](https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.array-creation.html) 數列變形 ``` >>> np.arange(12) #array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) >>> np.arange(12).reshape(2,6) #array([[ 0, 1, 2, 3, 4, 5], # [ 6, 7, 8, 9, 10, 11]]) >>> np.arange(12).reshape(3,4) #array([[ 0, 1, 2, 3], # [ 4, 5, 6, 7], # [ 8, 9, 10, 11]]) >>> np.arange(12).reshape(4,3) #array([[ 0, 1, 2], # [ 3, 4, 5], # [ 6, 7, 8], # [ 9, 10, 11]]) >>> np.arange(12).reshape(6,2) #array([[ 0, 1], # [ 2, 3], # [ 4, 5], # [ 6, 7], # [ 8, 9], # [10, 11]]) >>> np.arange(12).reshape(12,1).flatten() #array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) ``` 查看數列形狀 ``` >>> np.arange(12).reshape(1,2,3,2) #array([[[[ 0, 1], # [ 2, 3], # [ 4, 5]], # # [[ 6, 7], # [ 8, 9], # [10, 11]]]]) >>> np.arange(12).reshape(1,2,3,2).shape #(1, 2, 3, 2) ``` [更多的數列操作](https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.array-manipulation.html)

2017/10/26

Rails - Apartment 的使用方法

markdown #簡介 Apartment : [https://github.com/influitive/apartment](https://github.com/influitive/apartment) 這個套件的功能是讓你在 rails 可以透過切換 db schema,來存取不同的資料。 在 postgresql 中,預設的 schema 名稱為 public ,而所有的 table 都在 schema 'public' 下。 你可以簡單地把 schema 看成 namespace,在 apartment 中,這被稱為是 tenant。 #安裝步驟 請參考 : [https://github.com/influitive/apartment](https://github.com/influitive/apartment) #使用方法 ## 在 rails c 環境下 新增 tenant ``` Apartment::Tenant.create('abc') ``` 這個指令會在 schema 'abc' 下複製 public 上的所有表格。所以 tenant 就是具有相同表格的 schema。 在以下的示範,看到 abc 的地方,代表的是要填入你的 schema name。 顯示目前所在的 tenant ``` Apartment::Tenant.current # "public" ``` 切換 tenant ``` Apartment::Tenant.switch!('abc') Apartment::Tenant.current # "abc" Apartment::Tenant.switch!('public') Apartment::Tenant.current # "public" Apartment::Tenant.switch('abc') do Apartment::Tenant.current # "abc" end Apartment::Tenant.current # "public" ``` 有暫時切換跟永久切換兩種 ## 在 rails db 環境下 列出所有 schema ``` \dn # List of schemas # Name | Owner #--------+---------- # public | postgres # abc | etrex # (2 rows) ``` 顯示目前所在的 schema ``` SHOW search_path; # search_path #----------------- # "$user", public # (1 row) ``` 切換 schema ``` SET search_path TO abc; # SET SET search_path TO 'abc'; # SET ``` 字串要不要加引號都可以,當 search_path 的值不在 schema 的列表上時不會跳 error,可以想像成連接到一個空的 schema,而這樣並不代表新增了一個 schema。 在 select 的當下使用 schema ``` SELECT * FROM schema_name.table_name; ``` ## 關於 excluded_models 在 apartment 提供的功能中有一個功能,這個功能是可以設定在切換 schema 的時候,讓某些表格不要被切換,也就是做成全域的表格。 舉例來說,假設我有兩個 table,是使用以下 code 所生成。 ``` # 這裡是 bash rails g model a rails g model b a:references rails db:migrate ``` 然後我將 B 做成全域的表格 ``` # 這裡是 /config/initializers/apartment.rb 約 18 行的位置 config.excluded_models = %w{ B } ``` 然後建立一個 tenant 'abc' 並且切換過去,在這個環境下做測試 ``` # 這裡是 rails c 環境下 Apartment::Tenant.create('abc') Apartment::Tenant.switch!('abc') ``` 對 A 做一些事情 ``` A.count # (3.8ms) SELECT COUNT(*) FROM "as" # => 0 ``` 對 B 也做一些事情 ``` B.count # (0.5ms) SELECT COUNT(*) FROM "public"."bs" # => 0 ``` 在這裡可以看到,當你對 B 進行操作時,其實是會強制加上 "public" 的,也就是說,對於 B ,不管在哪一個 tenant 下,都只會去存取 schema 'public' 下的表格,所以其他的 schema 的表格 bs 應該會都是空的。 嘗試在 tenant 'abc' 下新增資料 ``` a = A.create() # (0.2ms) BEGIN # SQL (0.4ms) INSERT INTO "as" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2017-10-25 17:16:22.084365"], ["updated_at", "2017-10-25 17:16:22.084365"]] b = B.create(a:a) # (0.2ms) BEGIN # SQL (1.5ms) INSERT INTO "public"."bs" ("a_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["a_id", 3], ["created_at", "2017-10-25 17:16:24.957753"], ["updated_at", "2017-10-25 17:16:24.957753"]] # (0.2ms) ROLLBACK #ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR: insert or update on table "bs" violates foreign #key constraint "fk_rails_ddf8c0c4b5" #DETAIL: Key (a_id)=(3) is not present in table "as". #: INSERT INTO "public"."bs" ("a_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" # from (irb):31 ``` 這時候出大問題了,因為 A 建立在 abc 下,但是 B 建立在 public 下。而 public.bs 有一個外來鍵限制是 a_id 必須要在 public.as 中有出現。 使用 [pgAdmin](https://www.pgadmin.org/) 連進去看,對 db_name/Schemas/public/Tables/bs/Constraints/fk_rails_ddf8c04b5 按右鍵選 CREATE Script: 。
會看到生成的 script 內容為: ``` -- Constraint: fk_rails_ddf8c0c4b5 -- ALTER TABLE public.bs DROP CONSTRAINT fk_rails_ddf8c0c4b5; ALTER TABLE public.bs ADD CONSTRAINT fk_rails_ddf8c0c4b5 FOREIGN KEY (a_id) REFERENCES public."as" (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION; ``` 在這裡明確地指出跟 public.bs 有關係的表格是 public.as ,而不是其他 schema 下的 as,但是 Apartment 不處理,所以會出問題。

2017/10/19

Network debug 方法

markdown ## linux 環境下 查詢所有 process ``` ps ``` 輸出 ``` PID TTY TIME CMD 21968 ttys000 0:00.16 -bash ``` 查詢 port 3000 被誰占用 ``` lsof -i :3000 ``` 輸出 ``` COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ruby 20308 etrex 25u IPv4 0xd000000000000 0t0 TCP *:hbci (LISTEN) ``` 刪除某個 process ``` kill 20308 ``` ## 參考文件 kill process:[https://blog.gtwang.org/linux/linux-kill-killall-xkill/](https://blog.gtwang.org/linux/linux-kill-killall-xkill/)

Ruby - RSpec 的使用方法

markdown ## RSpec 簡介 RSpec 在執行的時候不保證執行順序,每個測試產生的資料不會自動被清除。 新增測試的generator語法: ``` rails generate rspec:model user ``` 這樣寫會建立一個檔案在 spec/models/user_spec.rb 執行測試的指令是在 rails 專案目錄下輸入以下指令: ``` # 這裡是 bash # 執行所有測試 rspec # 執行某個資料夾下的所有測試 rspec ./spec/models # 執行某個檔案裡的所有測試 rspec ./spec/models/user_spec.rb # 執行某個檔案裡的某個測試 rspec ./spec/models/user_spec.rb:8 ``` 簡單的範例 ``` require 'rails_helper' RSpec.describe "規格說明" do describe "處於某個狀態下" do # 設定狀態變數 let(:a) { 1 } it "should be 1" do puts "should be 1" expect(a).to eq(1) end end end ``` let 在每次測試裡,第一次存取變數時就會執行對應的程式 ``` require 'rails_helper' RSpec.describe "規格說明" do describe "處於某個狀態下" do let(:a) { puts "let a"; 1 } it "1" do puts "1" puts "a=#{a}" end it "2" do puts "2" puts "a=#{a}" puts "a=#{a}" puts "a=#{a}" end end end ``` 輸出 ``` 1 let a a=1 .2 let a a=1 a=1 a=1 . ``` before 和 after 會在所有測試的執行前後做事 ``` RSpec.describe "規格說明" do describe "處於某個狀態下" do before { puts "before" } after { puts "after" } it "1" do puts "1" end it "2" do puts "2" end end end ``` 執行結果 ``` before 1 after .before 2 after . ``` 因為測試對資料庫的操作會互相影響,如果想要確保每個測試都是在資料庫乾淨的狀態下,可以使用 [database_cleaner](https://github.com/DatabaseCleaner/database_cleaner)。 ``` require 'database_cleaner' ... RSpec.configure do |config| ... config.before(:suite) do DatabaseCleaner.strategy = :transaction DatabaseCleaner.clean_with(:truncation) end config.around(:each) do |example| DatabaseCleaner.cleaning do example.run end end ... end ``` 其中的 before、around 可以參考官網說明文件:[https://relishapp.com/rspec/rspec-core/v/2-13/docs/hooks/before-and-after-hooks#before/after-blocks-defined-in-config-are-run-in-order](https://relishapp.com/rspec/rspec-core/v/2-13/docs/hooks/before-and-after-hooks#before/after-blocks-defined-in-config-are-run-in-order) 如果想要控制 rspec 執行每一個 test 的順序,可以這樣寫: ``` # 這裡是 bash rspec --order defined rspec --seed 1 ``` 詳細的介紹可以參考 [https://relishapp.com/rspec/rspec-core/docs/command-line/order](https://relishapp.com/rspec/rspec-core/docs/command-line/order) 如果想要把結果輸出到檔案,可以這樣寫: ``` # 這裡是 bash rspec --out result.txt rspec --format documentation --out result.txt ``` 上面兩行會使檔案內容不同,詳細的介紹可以參考 [https://relishapp.com/rspec/rspec-core/v/2-4/docs/command-line/format-option](https://relishapp.com/rspec/rspec-core/v/2-4/docs/command-line/format-option)

Ruby - debug 方法

markdown ## 查詢繼承關係 ``` File.ancestors # [File, IO, File::Constants, Enumerable, Object, Kernel, BasicObject] ``` ## 從物件找方法 ``` # 查 File 的類別方法 File.methods # 查 File 的實體方法 File.instance_methods # 查 File 的實體方法 File.new('/').methods # 取得繼承樹上所有的方法 File.methods(true) # 只取得屬於 File 的方法 File.methods(false) ``` ## 從方法找定義 ``` File.method(:read) # #Method: File(IO).read IO.method(:read) # #Method: IO.read IO.method(:read).source_location # nil ``` 因為 IO.read 的定義是寫在 c 語言,所以就不顯示了。 ## 參考文件 為什麼File.method(:read)是nil:[https://ja.stackoverflow.com/questions/5755/ruby-file-read-%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AE%E8%AA%AC%E6%98%8E%E3%82%92api%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%81%A7%E8%AA%BF%E3%81%B9%E3%81%9F%E3%81%84](https://ja.stackoverflow.com/questions/5755/ruby-file-read-%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AE%E8%AA%AC%E6%98%8E%E3%82%92api%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%81%A7%E8%AA%BF%E3%81%B9%E3%81%9F%E3%81%84)

Python - 電腦字體數字辨識

markdown 續前篇:[Python - draw text on image and image to numpy array](http://etrex.blogspot.tw/2017/10/python-draw-text-on-image-and-image-to.html) ## 目標 嘗試建立一個簡單的類神經網路,只針對電腦字體數字 0~9 共 10 張圖片作訓練,訓練資料就是測試資料,在 40 次左右的訓練後正確度可達到 100%。 ## 本文包含 * keras 的使用 * keras Model 輸出成圖片 ## 程式碼 ``` import numpy as np from PIL import Image from PIL import ImageFont from PIL import ImageDraw image_size = (8,13) font_size = 10 x_train = np.array([]) y_train = np.array([]) for i in range(10): # 空白圖片生成 image = Image.new('L', image_size, 0) # 取得繪圖器 draw = ImageDraw.Draw(image) # 字型設定 # font = ImageFont.truetype("C:/Windows/Fonts/cour.ttf", font_size) font = ImageFont.truetype("C:/Windows/Fonts/msjh.ttc", font_size) # 關閉反鋸齒 draw.fontmode = '1' # 測量文字尺寸 text_size = draw.textsize(str(i),font) # print('text_size:', text_size) # 文字置中 text_position = ((image_size[0]-text_size[0])//2,(image_size[1]-text_size[1])//2) # print('text_position:', text_position) # 畫上文字 draw.text(text_position, str(i), 255, font) # 存檔 image.save(str(i)+'.bmp') # 轉成 numpy array na = np.array(image.getdata()).reshape(image.size[1], image.size[0]) # 加入訓練資料 x_train = np.append(x_train,na) y_train = np.append(y_train,i) import keras from keras.models import Sequential from keras.layers import Dense from keras.optimizers import RMSprop # 每次更新時所採用的資料筆數 batch_size = 1 # 總共有幾種數字 num_classes = 10 # 要更新幾次 epochs = 100 # 把資料轉成 model 需要的格式 x_train = x_train.reshape(10, 104) x_train = x_train.astype('float32') x_train /= 255 print(x_train.shape[0], 'train samples') y_train = keras.utils.to_categorical(y_train, num_classes) # 建立 model model = Sequential() # 一層 + softmax model.add(Dense(num_classes, input_shape=(104,), activation='softmax')) # ?? model.summary() # 選擇 loss function 和 optimizer model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) # 開始訓練 history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_train, y_train)) # 計算分數 score = model.evaluate(x_train, y_train, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1]) # 儲存 model 至圖片 from keras.utils import plot_model plot_model(model, to_file='model.png') ``` ## 輸出 ``` Using TensorFlow backend. 10 train samples _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_1 (Dense) (None, 10) 1050 ================================================================= Total params: 1,050 Trainable params: 1,050 Non-trainable params: 0 _________________________________________________________________ Train on 10 samples, validate on 10 samples Epoch 1/100 10/10 [==============================] - ETA: 0s - loss: 2.5473 - acc: 0.0000e+00 - val_loss: 2.4555 - val_acc: 0.1000 Epoch 2/100 10/10 [==============================] - ETA: 0s - loss: 2.4563 - acc: 0.1000 - val_loss: 2.3924 - val_acc: 0.1000 Epoch 3/100 10/10 [==============================] - ETA: 0s - loss: 2.3926 - acc: 0.1000 - val_loss: 2.3334 - val_acc: 0.2000 Epoch 4/100 10/10 [==============================] - ETA: 0s - loss: 2.3336 - acc: 0.2000 - val_loss: 2.2760 - val_acc: 0.2000 Epoch 5/100 10/10 [==============================] - ETA: 0s - loss: 2.2766 - acc: 0.2000 - val_loss: 2.2196 - val_acc: 0.2000 Epoch 6/100 10/10 [==============================] - ETA: 0s - loss: 2.2203 - acc: 0.2000 - val_loss: 2.1636 - val_acc: 0.4000 Epoch 7/100 10/10 [==============================] - ETA: 0s - loss: 2.1640 - acc: 0.4000 - val_loss: 2.1090 - val_acc: 0.5000 Epoch 8/100 10/10 [==============================] - ETA: 0s - loss: 2.1096 - acc: 0.4000 - val_loss: 2.0545 - val_acc: 0.5000 Epoch 9/100 10/10 [==============================] - ETA: 0s - loss: 2.0556 - acc: 0.5000 - val_loss: 2.0013 - val_acc: 0.5000 Epoch 10/100 10/10 [==============================] - ETA: 0s - loss: 2.0023 - acc: 0.5000 - val_loss: 1.9484 - val_acc: 0.5000 Epoch 11/100 10/10 [==============================] - ETA: 0s - loss: 1.9493 - acc: 0.5000 - val_loss: 1.8971 - val_acc: 0.5000 Epoch 12/100 10/10 [==============================] - ETA: 0s - loss: 1.8985 - acc: 0.5000 - val_loss: 1.8453 - val_acc: 0.5000 Epoch 13/100 10/10 [==============================] - ETA: 0s - loss: 1.8464 - acc: 0.5000 - val_loss: 1.7949 - val_acc: 0.5000 Epoch 14/100 10/10 [==============================] - ETA: 0s - loss: 1.7962 - acc: 0.5000 - val_loss: 1.7448 - val_acc: 0.5000 Epoch 15/100 10/10 [==============================] - ETA: 0s - loss: 1.7464 - acc: 0.5000 - val_loss: 1.6958 - val_acc: 0.5000 Epoch 16/100 10/10 [==============================] - ETA: 0s - loss: 1.6971 - acc: 0.5000 - val_loss: 1.6471 - val_acc: 0.5000 Epoch 17/100 10/10 [==============================] - ETA: 0s - loss: 1.6486 - acc: 0.5000 - val_loss: 1.5994 - val_acc: 0.5000 Epoch 18/100 10/10 [==============================] - ETA: 0s - loss: 1.6007 - acc: 0.5000 - val_loss: 1.5520 - val_acc: 0.7000 Epoch 19/100 10/10 [==============================] - ETA: 0s - loss: 1.5538 - acc: 0.7000 - val_loss: 1.5064 - val_acc: 0.7000 Epoch 20/100 10/10 [==============================] - ETA: 0s - loss: 1.5078 - acc: 0.7000 - val_loss: 1.4612 - val_acc: 0.7000 Epoch 21/100 10/10 [==============================] - ETA: 0s - loss: 1.4629 - acc: 0.7000 - val_loss: 1.4168 - val_acc: 0.7000 Epoch 22/100 10/10 [==============================] - ETA: 0s - loss: 1.4190 - acc: 0.7000 - val_loss: 1.3736 - val_acc: 0.7000 Epoch 23/100 10/10 [==============================] - ETA: 0s - loss: 1.3758 - acc: 0.7000 - val_loss: 1.3311 - val_acc: 0.8000 Epoch 24/100 10/10 [==============================] - ETA: 0s - loss: 1.3331 - acc: 0.8000 - val_loss: 1.2891 - val_acc: 0.8000 Epoch 25/100 10/10 [==============================] - ETA: 0s - loss: 1.2913 - acc: 0.8000 - val_loss: 1.2488 - val_acc: 0.9000 Epoch 26/100 10/10 [==============================] - ETA: 0s - loss: 1.2513 - acc: 0.9000 - val_loss: 1.2091 - val_acc: 0.9000 Epoch 27/100 10/10 [==============================] - ETA: 0s - loss: 1.2114 - acc: 0.9000 - val_loss: 1.1701 - val_acc: 0.9000 Epoch 28/100 10/10 [==============================] - ETA: 0s - loss: 1.1721 - acc: 0.9000 - val_loss: 1.1324 - val_acc: 0.9000 Epoch 29/100 10/10 [==============================] - ETA: 0s - loss: 1.1349 - acc: 0.9000 - val_loss: 1.0957 - val_acc: 0.9000 Epoch 30/100 10/10 [==============================] - ETA: 0s - loss: 1.0984 - acc: 0.9000 - val_loss: 1.0596 - val_acc: 0.9000 Epoch 31/100 10/10 [==============================] - ETA: 0s - loss: 1.0620 - acc: 0.9000 - val_loss: 1.0243 - val_acc: 0.9000 Epoch 32/100 10/10 [==============================] - ETA: 0s - loss: 1.0269 - acc: 0.9000 - val_loss: 0.9905 - val_acc: 1.0000 Epoch 33/100 10/10 [==============================] - ETA: 0s - loss: 0.9932 - acc: 1.0000 - val_loss: 0.9571 - val_acc: 1.0000 Epoch 34/100 10/10 [==============================] - ETA: 0s - loss: 0.9597 - acc: 1.0000 - val_loss: 0.9247 - val_acc: 1.0000 Epoch 35/100 10/10 [==============================] - ETA: 0s - loss: 0.9276 - acc: 1.0000 - val_loss: 0.8934 - val_acc: 1.0000 Epoch 36/100 10/10 [==============================] - ETA: 0s - loss: 0.8962 - acc: 1.0000 - val_loss: 0.8629 - val_acc: 1.0000 Epoch 37/100 10/10 [==============================] - ETA: 0s - loss: 0.8655 - acc: 1.0000 - val_loss: 0.8330 - val_acc: 1.0000 Epoch 38/100 10/10 [==============================] - ETA: 0s - loss: 0.8359 - acc: 1.0000 - val_loss: 0.8047 - val_acc: 1.0000 Epoch 39/100 10/10 [==============================] - ETA: 0s - loss: 0.8077 - acc: 1.0000 - val_loss: 0.7766 - val_acc: 1.0000 Epoch 40/100 10/10 [==============================] - ETA: 0s - loss: 0.7797 - acc: 1.0000 - val_loss: 0.7501 - val_acc: 1.0000 Epoch 41/100 10/10 [==============================] - ETA: 0s - loss: 0.7529 - acc: 1.0000 - val_loss: 0.7239 - val_acc: 1.0000 Epoch 42/100 10/10 [==============================] - ETA: 0s - loss: 0.7270 - acc: 1.0000 - val_loss: 0.6988 - val_acc: 1.0000 Epoch 43/100 10/10 [==============================] - ETA: 0s - loss: 0.7018 - acc: 1.0000 - val_loss: 0.6744 - val_acc: 1.0000 Epoch 44/100 10/10 [==============================] - ETA: 0s - loss: 0.6773 - acc: 1.0000 - val_loss: 0.6511 - val_acc: 1.0000 Epoch 45/100 10/10 [==============================] - ETA: 0s - loss: 0.6542 - acc: 1.0000 - val_loss: 0.6283 - val_acc: 1.0000 Epoch 46/100 10/10 [==============================] - ETA: 0s - loss: 0.6312 - acc: 1.0000 - val_loss: 0.6065 - val_acc: 1.0000 Epoch 47/100 10/10 [==============================] - ETA: 0s - loss: 0.6097 - acc: 1.0000 - val_loss: 0.5852 - val_acc: 1.0000 Epoch 48/100 10/10 [==============================] - ETA: 0s - loss: 0.5882 - acc: 1.0000 - val_loss: 0.5647 - val_acc: 1.0000 Epoch 49/100 10/10 [==============================] - ETA: 0s - loss: 0.5677 - acc: 1.0000 - val_loss: 0.5451 - val_acc: 1.0000 Epoch 50/100 10/10 [==============================] - ETA: 0s - loss: 0.5482 - acc: 1.0000 - val_loss: 0.5261 - val_acc: 1.0000 Epoch 51/100 10/10 [==============================] - ETA: 0s - loss: 0.5291 - acc: 1.0000 - val_loss: 0.5078 - val_acc: 1.0000 Epoch 52/100 10/10 [==============================] - ETA: 0s - loss: 0.5108 - acc: 1.0000 - val_loss: 0.4900 - val_acc: 1.0000 Epoch 53/100 10/10 [==============================] - ETA: 0s - loss: 0.4928 - acc: 1.0000 - val_loss: 0.4729 - val_acc: 1.0000 Epoch 54/100 10/10 [==============================] - ETA: 0s - loss: 0.4759 - acc: 1.0000 - val_loss: 0.4567 - val_acc: 1.0000 Epoch 55/100 10/10 [==============================] - ETA: 0s - loss: 0.4596 - acc: 1.0000 - val_loss: 0.4409 - val_acc: 1.0000 Epoch 56/100 10/10 [==============================] - ETA: 0s - loss: 0.4440 - acc: 1.0000 - val_loss: 0.4258 - val_acc: 1.0000 Epoch 57/100 10/10 [==============================] - ETA: 0s - loss: 0.4286 - acc: 1.0000 - val_loss: 0.4113 - val_acc: 1.0000 Epoch 58/100 10/10 [==============================] - ETA: 0s - loss: 0.4143 - acc: 1.0000 - val_loss: 0.3971 - val_acc: 1.0000 Epoch 59/100 10/10 [==============================] - ETA: 0s - loss: 0.4001 - acc: 1.0000 - val_loss: 0.3835 - val_acc: 1.0000 Epoch 60/100 10/10 [==============================] - ETA: 0s - loss: 0.3864 - acc: 1.0000 - val_loss: 0.3706 - val_acc: 1.0000 Epoch 61/100 10/10 [==============================] - ETA: 0s - loss: 0.3735 - acc: 1.0000 - val_loss: 0.3580 - val_acc: 1.0000 Epoch 62/100 10/10 [==============================] - ETA: 0s - loss: 0.3611 - acc: 1.0000 - val_loss: 0.3459 - val_acc: 1.0000 Epoch 63/100 10/10 [==============================] - ETA: 0s - loss: 0.3487 - acc: 1.0000 - val_loss: 0.3343 - val_acc: 1.0000 Epoch 64/100 10/10 [==============================] - ETA: 0s - loss: 0.3370 - acc: 1.0000 - val_loss: 0.3232 - val_acc: 1.0000 Epoch 65/100 10/10 [==============================] - ETA: 0s - loss: 0.3261 - acc: 1.0000 - val_loss: 0.3125 - val_acc: 1.0000 Epoch 66/100 10/10 [==============================] - ETA: 0s - loss: 0.3152 - acc: 1.0000 - val_loss: 0.3023 - val_acc: 1.0000 Epoch 67/100 10/10 [==============================] - ETA: 0s - loss: 0.3049 - acc: 1.0000 - val_loss: 0.2925 - val_acc: 1.0000 Epoch 68/100 10/10 [==============================] - ETA: 0s - loss: 0.2953 - acc: 1.0000 - val_loss: 0.2828 - val_acc: 1.0000 Epoch 69/100 10/10 [==============================] - ETA: 0s - loss: 0.2854 - acc: 1.0000 - val_loss: 0.2736 - val_acc: 1.0000 Epoch 70/100 10/10 [==============================] - ETA: 0s - loss: 0.2762 - acc: 1.0000 - val_loss: 0.2648 - val_acc: 1.0000 Epoch 71/100 10/10 [==============================] - ETA: 0s - loss: 0.2675 - acc: 1.0000 - val_loss: 0.2563 - val_acc: 1.0000 Epoch 72/100 10/10 [==============================] - ETA: 0s - loss: 0.2588 - acc: 1.0000 - val_loss: 0.2481 - val_acc: 1.0000 Epoch 73/100 10/10 [==============================] - ETA: 0s - loss: 0.2506 - acc: 1.0000 - val_loss: 0.2403 - val_acc: 1.0000 Epoch 74/100 10/10 [==============================] - ETA: 0s - loss: 0.2429 - acc: 1.0000 - val_loss: 0.2327 - val_acc: 1.0000 Epoch 75/100 10/10 [==============================] - ETA: 0s - loss: 0.2351 - acc: 1.0000 - val_loss: 0.2254 - val_acc: 1.0000 Epoch 76/100 10/10 [==============================] - ETA: 0s - loss: 0.2279 - acc: 1.0000 - val_loss: 0.2184 - val_acc: 1.0000 Epoch 77/100 10/10 [==============================] - ETA: 0s - loss: 0.2209 - acc: 1.0000 - val_loss: 0.2117 - val_acc: 1.0000 Epoch 78/100 10/10 [==============================] - ETA: 0s - loss: 0.2140 - acc: 1.0000 - val_loss: 0.2053 - val_acc: 1.0000 Epoch 79/100 10/10 [==============================] - ETA: 0s - loss: 0.2078 - acc: 1.0000 - val_loss: 0.1989 - val_acc: 1.0000 Epoch 80/100 10/10 [==============================] - ETA: 0s - loss: 0.2011 - acc: 1.0000 - val_loss: 0.1929 - val_acc: 1.0000 Epoch 81/100 10/10 [==============================] - ETA: 0s - loss: 0.1954 - acc: 1.0000 - val_loss: 0.1872 - val_acc: 1.0000 Epoch 82/100 10/10 [==============================] - ETA: 0s - loss: 0.1894 - acc: 1.0000 - val_loss: 0.1817 - val_acc: 1.0000 Epoch 83/100 10/10 [==============================] - ETA: 0s - loss: 0.1841 - acc: 1.0000 - val_loss: 0.1763 - val_acc: 1.0000 Epoch 84/100 10/10 [==============================] - ETA: 0s - loss: 0.1784 - acc: 1.0000 - val_loss: 0.1711 - val_acc: 1.0000 Epoch 85/100 10/10 [==============================] - ETA: 0s - loss: 0.1732 - acc: 1.0000 - val_loss: 0.1662 - val_acc: 1.0000 Epoch 86/100 10/10 [==============================] - ETA: 0s - loss: 0.1684 - acc: 1.0000 - val_loss: 0.1614 - val_acc: 1.0000 Epoch 87/100 10/10 [==============================] - ETA: 0s - loss: 0.1636 - acc: 1.0000 - val_loss: 0.1568 - val_acc: 1.0000 Epoch 88/100 10/10 [==============================] - ETA: 0s - loss: 0.1590 - acc: 1.0000 - val_loss: 0.1523 - val_acc: 1.0000 Epoch 89/100 10/10 [==============================] - ETA: 0s - loss: 0.1542 - acc: 1.0000 - val_loss: 0.1480 - val_acc: 1.0000 Epoch 90/100 10/10 [==============================] - ETA: 0s - loss: 0.1501 - acc: 1.0000 - val_loss: 0.1438 - val_acc: 1.0000 Epoch 91/100 10/10 [==============================] - ETA: 0s - loss: 0.1457 - acc: 1.0000 - val_loss: 0.1399 - val_acc: 1.0000 Epoch 92/100 10/10 [==============================] - ETA: 0s - loss: 0.1418 - acc: 1.0000 - val_loss: 0.1360 - val_acc: 1.0000 Epoch 93/100 10/10 [==============================] - ETA: 0s - loss: 0.1379 - acc: 1.0000 - val_loss: 0.1323 - val_acc: 1.0000 Epoch 94/100 10/10 [==============================] - ETA: 0s - loss: 0.1343 - acc: 1.0000 - val_loss: 0.1287 - val_acc: 1.0000 Epoch 95/100 10/10 [==============================] - ETA: 0s - loss: 0.1306 - acc: 1.0000 - val_loss: 0.1252 - val_acc: 1.0000 Epoch 96/100 10/10 [==============================] - ETA: 0s - loss: 0.1271 - acc: 1.0000 - val_loss: 0.1218 - val_acc: 1.0000 Epoch 97/100 10/10 [==============================] - ETA: 0s - loss: 0.1237 - acc: 1.0000 - val_loss: 0.1185 - val_acc: 1.0000 Epoch 98/100 10/10 [==============================] - ETA: 0s - loss: 0.1204 - acc: 1.0000 - val_loss: 0.1154 - val_acc: 1.0000 Epoch 99/100 10/10 [==============================] - ETA: 0s - loss: 0.1172 - acc: 1.0000 - val_loss: 0.1124 - val_acc: 1.0000 Epoch 100/100 10/10 [==============================] - ETA: 0s - loss: 0.1141 - acc: 1.0000 - val_loss: 0.1095 - val_acc: 1.0000 Test loss: 0.109465420246 Test accuracy: 1.0 ``` ## 輸出的圖片 plot_model 的執行,需要安裝 pydot 和 graphviz ``` pip3 install pydot ``` ## plot_model 的環境安裝 在 windows 上,graphviz 必須手動安裝,安裝檔可以到他們官網下載。 [http://www.graphviz.org/Download_windows.php](http://www.graphviz.org/Download_windows.php) 安裝好之後必須在環境變數 path 加上 C:\Program Files (x86)\Graphviz2.30\bin 才能使用。 cmd 下輸入指令: ``` dot -version ``` 若顯示以下訊息,表示正確安裝。 ``` dot - graphviz version 2.30.1 (20130214.1330) libdir = "C:\Program Files (x86)\Graphviz2.30\bin" Activated plugin library: gvplugin_pango.dll Using textlayout: textlayout:cairo Activated plugin library: gvplugin_dot_layout.dll Using layout: dot:dot_layout Activated plugin library: gvplugin_core.dll Using render: dot:core Using device: dot:dot:core The plugin configuration file: C:\Program Files (x86)\Graphviz2.30\bin\config6 was successfully loaded. render : cairo dot fig gd gdiplus map pic pov ps svg tk vml vrml xdot layout : circo dot fdp neato nop nop1 nop2 osage patchwork sfdp twopi textlayout : textlayout device : bmp canon cmap cmapx cmapx_np dot emf emfplus eps fig gd gd2 gif gv imap imap_np ismap jpe jpeg jpg metafile pdf p ic plain plain-ext png pov ps ps2 svg svgz tif tiff tk vml vmlz vrml wbmp xdot loadimage : (lib) bmp eps gd gd2 gif jpe jpeg jpg png ps svg ``` ## 參考文件 plot_model 在 windows 上的環境建立:[https://zhuanlan.zhihu.com/p/28158957](https://zhuanlan.zhihu.com/p/28158957) graphviz 的使用:[https://www.openfoundry.org/tw/foss-programs/8820-graphviz-](https://www.openfoundry.org/tw/foss-programs/8820-graphviz-)

2017/10/17

Python - draw text on image and image to numpy array

markdown ## 目標 嘗試生成以微軟正黑體寫成的數字0~9並轉換成 numpy array ##本文包含 * 生成圖片和保存圖片 * 在圖片上寫出指定字型和大小的字 * 設定反鋸齒模式 * 圖片轉成 numpy array ## 程式碼 ``` import numpy from PIL import Image from PIL import ImageFont from PIL import ImageDraw image_size = (8,13) font_size = 10 for i in range(10): # 空白圖片生成 image = Image.new('L', image_size, 0) # 取得繪圖器 draw = ImageDraw.Draw(image) # 微軟正黑體 font = ImageFont.truetype("C:/Windows/Fonts/msjh.ttc", font_size) # 關閉反鋸齒 draw.fontmode = '1' # 測量文字尺寸 text_size = draw.textsize(str(i),font) # print('text_size:', text_size) # 文字置中 text_position = ((image_size[0]-text_size[0])//2,(image_size[1]-text_size[1])//2) # print('text_position:', text_position) # 畫上文字 draw.text(text_position, str(i), 255, font) # 存檔 image.save(str(i)+'.bmp') # 轉成 numpy array na = numpy.array(image.getdata()).reshape(image.size[1], image.size[0]) # 印出 print(na) ``` ## 輸出 ``` Using TensorFlow backend. [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 255 255 255 255 0 0] [ 0 0 255 0 0 255 255 0] [ 0 255 0 0 0 0 255 0] [ 0 255 0 0 0 0 255 0] [ 0 255 0 0 0 0 255 0] [ 0 255 0 0 0 0 255 0] [ 0 255 255 0 0 255 0 0] [ 0 0 255 255 255 255 0 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 255 255 0 0 0] [ 0 0 255 255 255 0 0 0] [ 0 0 0 0 255 0 0 0] [ 0 0 0 0 255 0 0 0] [ 0 0 0 0 255 0 0 0] [ 0 0 0 0 255 0 0 0] [ 0 0 0 0 255 0 0 0] [ 0 0 255 255 255 255 255 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 255 255 255 0 0] [ 0 0 255 0 0 0 255 0] [ 0 0 0 0 0 0 255 0] [ 0 0 0 0 0 0 255 0] [ 0 0 0 0 0 255 0 0] [ 0 0 0 0 255 0 0 0] [ 0 0 0 255 0 0 0 0] [ 0 0 255 255 255 255 255 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 255 255 0 0 0] [ 0 0 255 0 0 255 0 0] [ 0 0 0 0 0 255 0 0] [ 0 0 0 255 255 0 0 0] [ 0 0 0 0 0 255 0 0] [ 0 0 0 0 0 255 0 0] [ 0 0 255 0 0 255 0 0] [ 0 0 255 255 255 0 0 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 255 255 0 0] [ 0 0 0 0 255 255 0 0] [ 0 0 0 255 0 255 0 0] [ 0 0 255 0 0 255 0 0] [ 0 255 0 0 0 255 0 0] [ 0 255 255 255 255 255 255 0] [ 0 0 0 0 0 255 0 0] [ 0 0 0 0 0 255 0 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 255 255 255 255 0 0] [ 0 0 255 0 0 0 0 0] [ 0 0 255 0 0 0 0 0] [ 0 0 255 255 255 0 0 0] [ 0 0 0 0 0 255 0 0] [ 0 0 0 0 0 255 0 0] [ 0 0 255 0 0 255 0 0] [ 0 0 255 255 255 0 0 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 255 255 255 0] [ 0 0 0 255 0 0 0 0] [ 0 0 255 0 0 0 0 0] [ 0 0 255 0 255 255 0 0] [ 0 0 255 255 0 0 255 0] [ 0 0 255 0 0 0 255 0] [ 0 0 255 0 0 0 255 0] [ 0 0 0 255 255 255 0 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 255 255 255 255 255 255 0] [ 0 0 0 0 0 255 0 0] [ 0 0 0 0 0 255 0 0] [ 0 0 0 0 255 0 0 0] [ 0 0 0 0 255 0 0 0] [ 0 0 0 255 0 0 0 0] [ 0 0 0 255 0 0 0 0] [ 0 0 255 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 255 255 0 0 0] [ 0 0 255 0 0 255 0 0] [ 0 0 255 0 0 255 0 0] [ 0 0 0 255 255 0 0 0] [ 0 0 0 255 0 255 0 0] [ 0 0 255 0 0 0 255 0] [ 0 0 255 0 0 0 255 0] [ 0 0 0 255 255 255 0 0] [ 0 0 0 0 0 0 0 0]] [[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 255 255 255 0 0] [ 0 0 255 0 0 0 255 0] [ 0 0 255 0 0 0 255 0] [ 0 0 255 0 0 0 255 0] [ 0 0 0 255 255 255 255 0] [ 0 0 0 0 0 0 255 0] [ 0 0 0 0 0 255 0 0] [ 0 0 255 255 255 0 0 0] [ 0 0 0 0 0 0 0 0]] ``` ## 參考文件 PIL影像相關:[http://pillow.readthedocs.io/en/stable/reference/index.html](http://pillow.readthedocs.io/en/stable/reference/index.html)

2017/10/13

Python - 印出 mnist 的手寫圖形

markdown ## 安裝 keras 請參考 [https://etrex.blogspot.tw/2017/10/windows-10-keras.html](https://etrex.blogspot.tw/2017/10/windows-10-keras.html) ## 安裝 PIL 在 cmd 輸入以下指令: ``` pip3 install Image ``` 若想查看已安裝了哪些套件,可在 cmd 輸入以下指令: ``` pip3 list ``` ## 印出 MNIST 的手寫數字圖形 [MNIST](http://yann.lecun.com/exdb/mnist/) 是一個知名的手寫數字資料集,被當作機器學習界的 hello world 來使用。 ``` import keras from keras.datasets import mnist from PIL import Image (x_train, y_train), (x_test, y_test) = mnist.load_data() Image.fromarray(x_train[0,]).show() ``` x_train 是一個大小為 60000,28,28 的三維陣列,代表 60000 張 28x28 的灰階圖檔。 可輸入以下指令查看: ``` x_train.shape # (60000,28,28) ``` x_train[0,] 是一個大小為 28,28 的二維陣列,代表第一張圖片。 Image.fromarray(x_train[0,]).show() 把代表第一張圖片的二維陣列轉為圖片並顯示。

Python - debug 方法

印出變數值 ``` a = 1 print(a) # 1 ``` 印出變數型態 ``` a = 1 print(type(a)) # ``` 印出變數成員 ``` a = 1 print(dir(a)) # ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes'] ``` 印出模組成員 ``` import json dir(json) # ['JSONDecodeError', 'JSONDecoder', 'JSONEncoder', '__all__', '__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', '_default_decoder', '_default_encoder', 'decoder', 'dump', 'dumps', 'encoder', 'load', 'loads', 'scanner'] ``` 呼叫成員 ``` a = -1 print(a.__abs__) # print(a.__abs__()) # -1 ``` 印出json ``` import json print(json.dumps([1, 2, 3])) # '[1, 2, 3]' ```

JS - 重複組合

給兩個序列 a 跟 b ,在不改變 a 和 b 序列順序的情況下,列出所有 a 跟 b 混合後的結果 使用[重複組合](https://zh.wikipedia.org/wiki/%E7%B5%84%E5%90%88#.E9.87.8D.E8.A4.87.E7.B5.84.E5.90.88.E7.90.86.E8.AB.96.E8.88.87.E5.85.AC.E5.BC.8F)的概念,兩個序列混合後的結果等同於其中一個序列的 index 的組合 舉例來說序列 a 為 `--`,序列 b 為 `**`,其所有混和結果為: ``` --** -*-* *--* -**- *-*- **-- ``` 共六種,而我們可以把 a 序列所在的 index 寫出: ``` 1,2 1,3 2,3 1,4 2,4 3,4 ``` 而這是 C4取2 的所有組合結果。 假設已知 b 序列長度為 6,我們可以使用迴圈生成組合。 ``` var set = { "a":['b','b','b','b'], "b":['3','4','5','6','7','8'] } var n = set['a'].length + set['b'].length; var c = []; for(var i1 = 0 ; i1 < n ; i1 ++) for(var i2 = i1+1 ; i2 < n ; i2 ++) for(var i3 = i2+1 ; i3 < n ; i3 ++) for(var i4 = i3+1 ; i4 < n ; i4 ++) for(var i5 = i4+1 ; i5 < n ; i5 ++) for(var i6 = i5+1 ; i6 < n ; i6 ++){ var ab = []; for(var i = 0 ; i < n ; i ++) ab.push('a'); ab[i1] = 'b'; ab[i2] = 'b'; ab[i3] = 'b'; ab[i4] = 'b'; ab[i5] = 'b'; ab[i6] = 'b'; var c0 = []; var index = {"a":0,"b":0}; for(var i = 0 ; i < n ; i ++){ c0.push(set[ab[i]][index[ab[i]]]); index[ab[i]] = index[ab[i]] + 1; } c.push(c0); console.log(c0); } ```

2017/10/11

在 Windows 10 上安裝 Keras 的流程

markdown Keras 是一個在 Python 上的深度學習工具,用這個工具可以快速打造出複雜的類神經網路結構 他需要用到 TensorFlow,所以在安裝 Keras 之前要先安裝 TensorFlow 在安裝 TensorFlow 之前要先安裝 Python 2.7 或 3.5。 ##先裝 Python 我個人是安裝 Python 3.5,安裝流程請參考 [https://pygame.hackersir.org/Lessons/01/Python_install.html](https://pygame.hackersir.org/Lessons/01/Python_install.html), 正確安裝後,在 cmd 下輸入指令: ``` python -V ``` 若顯示 Python 3.5.2 表示正確安裝。 ##接著裝 TensorFlow 以下介紹cpu版本的安裝,若需要gpu版本的安裝流程請參考[https://rreadmorebooks.blogspot.tw/2017/04/win10cudacudnn.html](https://rreadmorebooks.blogspot.tw/2017/04/win10cudacudnn.html) 在 cmd 下輸入指令: ``` pip3 install --upgrade tensorflow ``` 裝好後,接著輸入 python 進入互動模式: ``` python ``` 再輸入以下的 python 程式碼(可直接複製貼上四行) ``` import tensorflow as tf hello = tf.constant('Hello, TensorFlow!') sess = tf.Session() print(sess.run(hello)) ``` 若顯示 b'Hello, TensorFlow!' 表示正確安裝,此時可輸入 exit() 離開 python 互動模式。 ##SciPy 在裝 Keras 之前,可能需要手動裝 SciPy,因為 SciPy 的自動安裝流程在 Windows 上似乎不完整。 先開啟[http://www.lfd.uci.edu/~gohlke/pythonlibs/#scipy](http://www.lfd.uci.edu/~gohlke/pythonlibs/#scipy), 然後點選 scipy‑1.0.0rc1‑cp35‑cp35m‑win_amd64.whl 下載檔案。 下載好了之後,在 cmd 切換目錄至下載目錄,然後輸入指令: ``` pip3 install scipy‑1.0.0rc1‑cp35‑cp35m‑win_amd64.whl ``` ##最後裝 Keras 直接在 cmd 輸入指令: ``` pip3 install keras ``` 裝好後,接著輸入 python 進入互動模式: ``` python ``` 再輸入以下的 python 程式碼 ``` import keras ``` 若顯示 Using TensorFlow backend. 表示正確安裝,此時可輸入 exit() 離開 python 互動模式。 ##參考連結: 安裝 Python [https://pygame.hackersir.org/Lessons/01/Python_install.html](https://pygame.hackersir.org/Lessons/01/Python_install.html) 安裝 TensorFlow [https://www.tensorflow.org/install/install_windows](https://www.tensorflow.org/install/install_windows) 安裝 SciPy [http://codewenda.com/windows%E4%B8%8A%E4%BD%BF%E7%94%A8pip%E5%AE%89%E8%A3%85scipy%E9%94%99%E8%AF%AF%EF%BC%9Arunning-setup-py-bdist_wheel-for-scipy-error/](http://codewenda.com/windows%E4%B8%8A%E4%BD%BF%E7%94%A8pip%E5%AE%89%E8%A3%85scipy%E9%94%99%E8%AF%AF%EF%BC%9Arunning-setup-py-bdist_wheel-for-scipy-error/) 安裝 Keras [https://keras-cn.readthedocs.io/en/latest/#_2](https://keras-cn.readthedocs.io/en/latest/#_2)

安裝 nokogiri 失敗時的解決方法

(參考此篇文章)[https://github.com/sparklemotion/nokogiri/issues/1483] 在 bash 輸入 xcode-select --install 可解決問題。 在我的 macbook 上的錯誤訊息如下: ``` Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/etrex/.rvm/gems/ruby-2.4.1@-global/gems/nokogiri-1.8.0/ext/nokogiri /Users/etrex/.rvm/rubies/ruby-2.4.1/bin/ruby -r ./siteconf20171011-80748-pgpdll.rb extconf.rb checking if the C compiler accepts ... yes checking if the C compiler accepts -Wno-error=unused-command-line-argument-hard-error-in-future... no Building nokogiri using packaged libraries. Using mini_portile version 2.2.0 checking for iconv.h... yes checking for gzdopen() in -lz... yes checking for iconv using --with-opt-* flags... yes ************************************************************************ IMPORTANT NOTICE: Building Nokogiri with a packaged version of libxml2-2.9.4 with the following patches applied: - 0001-Fix-comparison-with-root-node-in-xmlXPathCmpNodes.patch - 0002-Fix-XPointer-paths-beginning-with-range-to.patch - 0003-Disallow-namespace-nodes-in-XPointer-ranges.patch Team Nokogiri will keep on doing their best to provide security updates in a timely manner, but if this is a concern for you and want to use the system library instead; abort this installation process and reinstall nokogiri as follows: gem install nokogiri -- --use-system-libraries [--with-xml2-config=/path/to/xml2-config] [--with-xslt-config=/path/to/xslt-config] If you are using Bundler, tell it to use the option: bundle config build.nokogiri --use-system-libraries bundle install Note, however, that nokogiri is not fully compatible with arbitrary versions of libxml2 provided by OS/package vendors. ************************************************************************ Extracting libxml2-2.9.4.tar.gz into tmp/x86_64-apple-darwin15.4.0/ports/libxml2/2.9.4... OK Running git apply with /Users/etrex/.rvm/gems/ruby-2.4.1@-global/gems/nokogiri-1.8.0/patches/libxml2/0001-Fix-comparison-with-root-node-in-xmlXPathCmpNodes.patch... OK Running git apply with /Users/etrex/.rvm/gems/ruby-2.4.1@-global/gems/nokogiri-1.8.0/patches/libxml2/0002-Fix-XPointer-paths-beginning-with-range-to.patch... OK Running git apply with /Users/etrex/.rvm/gems/ruby-2.4.1@-global/gems/nokogiri-1.8.0/patches/libxml2/0003-Disallow-namespace-nodes-in-XPointer-ranges.patch... OK Running 'configure' for libxml2 2.9.4... OK Running 'compile' for libxml2 2.9.4... ERROR, review '/Users/etrex/.rvm/gems/ruby-2.4.1@-global/gems/nokogiri-1.8.0/ext/nokogiri/tmp/x86_64-apple-darwin15.4.0/ports/libxml2/2.9.4/compile.log' to see what happened. Last lines are: ======================================================================== unsigned short* in = (unsigned short*) inb; ^~~~~~~~~~~~~~~~~~~~~ encoding.c:815:27: warning: cast from 'unsigned char *' to 'unsigned short *' increases required alignment from 1 to 2 [-Wcast-align] unsigned short* out = (unsigned short*) outb; ^~~~~~~~~~~~~~~~~~~~~~ 4 warnings generated. CC error.lo CC parserInternals.lo CC parser.lo CC tree.lo CC hash.lo CC list.lo CC xmlIO.lo xmlIO.c:1450:52: error: use of undeclared identifier 'LZMA_OK' ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1; ^ 1 error generated. make[2]: *** [xmlIO.lo] Error 1 make[1]: *** [all-recursive] Error 1 make: *** [all] Error 2 ======================================================================== *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. ```

2017/9/21

[早午餐] 再一塊吧ing 蘆洲

markdown ## [早午餐] 再一塊吧ing 蘆洲 ## 食物 * 份量:很充足 * 味道:花生醬漢堡一開始吃覺得不錯,但吃到最後有點膩。凱薩沙拉的蘿美很脆,沙拉很棒。 * 價格:125~250 * 送餐時間:送餐方式是一道一道做好就上。飲料秒上,幾分鐘後上沙拉,在你沙拉還沒吃完前漢堡就好了。 ## 舒適度 * 座位間距:還算寬敞 * 乾淨程度:優 * 廁所:還行 * Wi-Fi:together/together ## 裝潢風格 * 配色:白、黑、綠、木紋 * 元素:大理石磁磚地板、木紋桌椅、綠色植物、黑白木色裝飾小物 ## 資訊 * 營業時間:9:00-18:00 * 地址:247新北市蘆洲區長安街108巷12號 * 電話:02 2848 8272

2017/9/19

[早午餐] 早茶餐管 蘆洲

[早午餐] 早茶餐管 蘆洲

裝潢:工業風、空間乾淨舒適、座位間距適當、冷氣有點涼

味道:主餐跟套餐配的薯條都很棒

份量:一般、飲料量偏少

價格區間:90~190

地址:247新北市蘆洲區集賢路222-4號

電話:02 8286 8003





2017/9/18

[早午餐] 豐滿總匯三明治 蘆洲店

[早午餐] 豐滿總匯三明治 蘆洲店

裝潢:空間乾淨舒適、座位間距很大、還有小孩的遊樂區

味道:比麥當勞好吃

份量:偏多

價格區間:150~200

地址:247新北市蘆洲區長樂路53號

電話:02 8286 3871

2017/9/14

rails debug 技巧

markdown 在 controller 裡的 action 可以取得 request 物件 ``` class TestController < ApplicationController def index p request.class render plain: "ok" end end ``` 會發現 request 物件是 [ActionDispatch::Request](http://api.rubyonrails.org/classes/ActionDispatch/Request.html) 類別 request.headers 是 [ActionDispatch::Http::Headers](http://api.rubyonrails.org/classes/ActionDispatch/Http/Headers.html) 類別 我們可以用 each 去印出 headers 的所有內容: ``` request.headers.each{|header| p header } ``` 仔細觀察會發現 header 是一個長度為2的陣列, header[0] 代表 key,header[1] 則代表 value。 ``` def index headers = request.headers.to_a.keep_if { |header| header[0].index('HTTP') == 0 }.map{ |header| "#{header}" } render plain: headers.join("\n") end ``` 可以透過 keep_if 保留想要關注的資訊

2017/9/13

mac 環境變數的設定

markdown mac 環境變數的設定 讀取:在 bash 輸入 ``` echo $PATH ``` 寫入:在 bash 輸入 ``` export PATH=完整的PATH值要寫在這裡 ``` 增加一段路徑:在 bash 輸入 ``` export PATH=$PATH:新的路徑要寫在這裡 ``` 或者 ``` export PATH=新的路徑要寫在這裡:$PATH ``` 可以注意到 $PATH 的路徑是以 : 號作為分隔符號,所以上面是把舊的$PATH值加上分隔符號:,再加上新的路徑,再存回$PATH。 另外,可以將環境變數值修改的程式寫在 ~/.bash_profile,這個檔案會在每次開啟 bash 時執行,這樣可以確保不影響其他使用者。 ~/.bash_profile 檔修改後,如果不想重開 bash,也可以在 bash 輸入 ``` source ~/.bash_profile ``` 這樣就會執行 ~/.bash_profile 檔了 PATH 功能是當你在 bash 輸入一個指令時,可以讓系統知道該去哪些目錄找到這個指令的執行檔,他會按照PATH的順序一個個目錄去找。所以當新的路徑寫在原有的路徑前面時,代表你希望系統先去新的路徑找找看。

在 ruby 可執行 js 的爬蟲

markdown [watir](https://github.com/watir/watir) 是一個自動測試工具,我打算拿來做爬蟲,因為我的爬蟲需要執行頁面 js 獲得動態 dom 結果,而 watir 剛好可以做到這件事情。 watir 需要搭配瀏覽器使用,我先試著使用 phantomjs 這個瀏覽器。 phantomjs 是一款無頭瀏覽器 [Headless_browser](https://en.wikipedia.org/wiki/Headless_browser), 因為他不需要真正顯示畫面,所以他的效能比較好。 [怎麼在 heroku 上跑 watir (phantomjs)](https://github.com/edelpero/watir-examples/blob/master/watir_on_heroku.md) 但是因為 chrome 也做了無頭版的瀏覽器,所以 phantomjs 的作者後來就不更新了。 [Getting Started with Headless Chrome](https://developers.google.com/web/updates/2017/04/headless-chrome) [Headless Capybara Feature Specs with Chrome](https://robots.thoughtbot.com/headless-feature-specs-with-chrome) [資料來源1](https://ruby-china.org/topics/31784)

Heroku

markdown Heroku Dyno 可以提供虛擬的執行環境 他的運作流程大概是: 當有新的 code push 上去時觸發 1 建立一個 linux 的空環境 2 根據 buildpack 的資訊安裝系統環境 3 在 /app 下放入 push 上去的 code 4 根據 /app/gemfile 安裝對應的套件 5 根據 procfile 的資訊 啟動網站 你可以使用以下指令去觀察環境 ``` heroku run bash ```

2017/9/12

ruby 反射筆記

markdown 查看相關 module ``` Array.included_modules ``` 查看相關 method ``` Enumerable.instance_methods ``` 查看 class 繼承樹 ``` a.class a.class.superclass a.class.superclass.superclass ```

2017/9/1

line bot 的新功能範例code

Line 於今天發表了 Messaging API 的新功能:[[Messaging API] New template message features released](https://developers.line.me/news?ny=2017&nm=09) 其中包含了一個新的 template:image_carousel,以及一個新的 postback:datetimepicker image_carousel 可以讓你一次傳最多五張圖以橫向捲動方式瀏覽 datetimepicker 可以在按下按鈕時彈出日期時間選擇器 iOS line 7.9 版本以上才能使用 datetimepicker android line 7.12 版本以上才能使用 datetimepicker 結合這兩個新功能的範例 message json 如下: ``` { "type": "template", "altText": "this is a image carousel template", "template": { "type": "image_carousel", "columns": [ { "imageUrl": "https://www.petfinder.com/wp-content/uploads/2012/11/91615172-find-a-lump-on-cats-skin-632x475.jpg", "action": { "type": "datetimepicker", "label": "選日期", "data": "q1", "mode": "date" } }, { "imageUrl": "https://www.cats.org.uk/uploads/images/featurebox_sidebar_kids/grief-and-loss.jpg", "action": { "type": "datetimepicker", "label": "選時間", "data": "q2", "mode": "time" } }, { "imageUrl": "https://static.pexels.com/photos/126407/pexels-photo-126407.jpeg", "action": { "type": "datetimepicker", "label": "選日期時間", "data": "q3", "mode": "datetime" } } ] } } ``` 他的點擊範圍是整張圖 點第一張圖: 點第二張圖: 點第三張圖: datetime picker 的三種傳回結果:

2017/8/28

rails 直接執行 SQL 且避免 sql injection

markdown 以下是一個 sql update 的範例程式: ``` old_value = ActiveRecord::Base.sanitize(old_value) new_value = ActiveRecord::Base.sanitize(new_value) updated_at = ActiveRecord::Base.sanitize(Time.current) results = ActiveRecord::Base.connection.execute( "update table set field=#{new_value}, updated_at=#{updated_at} where field=#{old_value}" ) ```

2017/8/22

sql 的 where in 查詢效能問題

markdown 問題:當我想要where in 一個很大的陣列,或者子查詢,該怎麼寫呢? 在[Performance issue in update query](https://stackoverflow.com/questions/24647503/performance-issue-in-update-query)提到: 各種方法,從慢到快: * 打N次query,用 where = 每次只查一個值 * 打1次query,用 where in 或是 where exists * 使用 join values * (當資料量足夠大時) 建立一個暫時表並且加上索引,然後使用join 在[SQL: When it comes to NOT IN and NOT EQUAL TO, which is more efficient and why?](https://stackoverflow.com/questions/17037508/sql-when-it-comes-to-not-in-and-not-equal-to-which-is-more-efficient-and-why/17038097#17038097)提到, 各種 query 從慢到快: * where field = v1 and field = v2 and ... and field = vn * where field in (v1,v2...vn) * 使用 CTE 做 values join 或 values subquery 都比前面快100倍以上 * 暫存表 join 跟 暫存表 subquery 跟 CTE values join 差不多快 (也許是資料量大小的問題) CTE:Common Table Expression 是一種臨時定義一個 table 的語法,只能在下一個 select 使用,文章中有提到: ``` WITH excluded(item) AS ( VALUES('item1'), ('item2'), ('item3'), ('item4'),('item5') ) SELECT * FROM thetable t WHERE NOT EXISTS(SELECT 1 FROM excluded e WHERE t.item = e.item); ``` 其中的 WITH AS 就是建立 CTE 的語法 在[Optimizing a Postgres query with a large IN](https://dba.stackexchange.com/questions/91247/optimizing-a-postgres-query-with-a-large-in)中也提到了: * IN 最慢 * 使用 join values 是很好的 * 資料量太大就建立暫存表,並且加上index,再去join 結論:使用 with values 建立 CTE 再拿去做 join 應該是最簡單又有效的作法。

2017/8/21

在 blogger 貼漂亮 code 的方法(使用 markdown 和 prettyprint)在使用 < 符號時產生的問題

前情提要:http://etrex.blogspot.tw/2017/03/blogger-code-markdown-prettyprint.html

在使用 element.innerHTML 時,會將 < 字元轉換為 &lt; 再輸出

然後 markdown 再度把 &lt; 轉換為 &amp;lt;

所以最後顯示為 &lt;

為了解決這個問題,必須找到一個方法,去取得最原始的html

查了一下發現似乎無法簡單的達成。

https://stackoverflow.com/questions/15419209/getting-raw-text-content-of-html-element-with-html-uninterpreted

https://stackoverflow.com/questions/5998443/how-to-get-raw-html-from-string-in-jquery

結論:必須在取得innerHTML之後做一次html decode

但 html decode 的成本太高,可能只要處理< > &就好。

在前一篇文章裡 Jo 的留言中,提出的解法為:

<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.6.4/showdown.min.js"></script>
<script>
var converter = new showdown.Converter();
var posts = document.querySelectorAll(".post-body");
//定義要替換的字元
var insteadWords = {
    "&gt;": ">",
    "&lt;": "<",
    "&amp;": "&"
};
//loop每一篇文章
Array.prototype.forEach.call(posts, function(el, i){
  /*有在開頭找到 markdown 字眼才處理,把整個文章取出來替換成 html
   * 從文章取出內容時,應該有某些字元早就被轉換過,但因為是寫 markdown,根本不需要轉
   * 所以再寫一段程式把某些特定的字轉回來,暫時只定義了 3 組
   */
  if(el.innerHTML.indexOf("markdown") <= 1){
    var origin = el.innerHTML;
    origin = origin.replace("markdown","");
    for (var key in insteadWords){
        origin = origin.replace(new RegExp(key,'g'),insteadWords[key]);
    };
    //先把特殊字元轉回來再作 markdown 的轉換
    el.innerHTML = converter.makeHtml(origin);
  }
});

var pres = document.querySelectorAll("pre");
Array.prototype.forEach.call(pres, function(el, i){
  el.classList.add("prettyprint");
});
</script>
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=sunburst"></script>

2017/8/20

markdown test

markdown ``` yum list | grep php > /dev/null 2>&1 ```

2017/8/10

以誘導代替強迫

當你想要別人去做某件事,你可能會採取一些手段去做,比方說:

金錢攻勢:「給你錢,快點做」

人情攻勢:「拜託啦~求你~」

情緒勒索:「你不做,我就去死」

勒索:「你不做,我就讓你死」
...

這些手段大概可以被區分為兩類,強迫與誘導。

強迫:對方不甘願的去做了某件事,他會說:「你為什麼要逼我啊~****~」

誘導:對方心甘情願去做了某件事,他會說:「感謝有你,有你真好」


強迫的手段通常不太容易達成效果,而且會把人際關係弄差。


例1:

你看到一個正妹,你跟他說「我想跟你交往,跟我在一起好嗎?」

正妹看你一臉肥宅樣,拒絕了。於是你:

1: 死纏爛打

2: 把自己變成高富帥

選1,很簡單可以執行,但是效果不好,強求的感情也不會幸福。

選2,這是一條困難的路,但是效果會很好,就算這個正妹真的不喜歡你,下一個正妹會喜歡你的。


你必須要思考,要怎麼樣讓別人打從心裡想做那些你想要他們做的事情。


例2:

你覺得醫學系超棒der,你想要讓你的小孩成為醫生,於是你:

1: 跟小孩說:「不管怎樣你就是要給我念醫學系,以後當醫生,乖,聽爸媽的話,以後你會懂der」

2: 在家裡弄一個環境放了一堆醫學相關的東西,提供各種機會讓小孩能接觸醫學方面知識,一段時間之後他會以為他有醫學方面的天賦。

選1,結果小孩醫學系念完不當醫生,或者自殺,慘。

選2,你盡力了,就算最後小孩沒去當醫生,但他有值得更好的。


有一個寓言故事,叫做北風與太陽,我直到今天才知道這個寓言在講什麼。

2017/7/19

chatbot 會以什麼姿態取代 web?

在 chatbot (以下簡稱 bot ) 上,我們沒有足夠大的空間去顯示一整個網頁的資訊,所以我們一次只會顯示網頁的一小部份,就跟做 app 時一樣,但空間更小。而當 web 上的每一個元件都有 bot 的替代方案時,則表示 bot 將可以完全取代 web。

以 line bot 為例:

路由

web:網址解析
bot:語意分析

使用者輸入的每一句話都是一個 request,在此階段是做 route 的工作,這也是語意分析的主要工作。

主選單

web:nav
bot:template buttons 或 imagemap

由於bot無法一次顯示整個網頁的資訊,所以會先從 nav 開始。可以使用多個 template buttons 做出巢狀選單,也可以利用 imagemap 做出比較漂亮的版面。

列表

web:list
bot:text 或 template carousel

有圖或超連結的情況下會使用 template carousel

表單

web:form
bot:conversational form

透過問答的方式填表

總結

像這樣一個個找到 web 元件在 bot 上的實作方案,最終就能取代 web。

大量使用超連結的作法可以迴避掉語意分析,因為除了表單之外不需要打字,進入難度將大大降低,使用者體驗也會比較好。我相信大多數的bot應該都會採用這種較低成本、符合成本效益的做法。

不過,與其說 bot 可以取代 web,不如說開發者將從同時開發 web、app 變成同時開發 web、app、bot,所以將來很可能會有能同時發布到 web、app、bot 上的開發框架。

rails db migrate 寫錯時如何重跑 migrate

markdown 1. 先把開發db跟測試db還原到上一步驟 ``` rails db:rollback rails db:rollback RAILS_ENV=test ``` 2. 修改 migration 檔案 3. 再重新執行 migrate (他會把開發db跟測試db都更新) ``` rails db:migrate ``` 如果一開始忘記跑測試db的 rollback 也沒關係,執行下面的指令就好 ``` rails db:rollback RAILS_ENV=test rails db:migrate RAILS_ENV=test ```

2017/7/17

軟體發展未來趨勢

讓程式以資料的形式存在,就是增加程式彈性最好的方法。

從硬體到軟體

對硬體來說,裡面搭載的軟體是一種資料。早期很多工具是寫死的,甚至於沒有儲存資料的能力。比方算盤,或是特殊型態的計算機。直到現在有很多東西都是把軟體換掉就能得到效能提升的。

從程式到資料

從 web1.0 到 web2.0 可以看出來,最好的例子是BLOG,這是程式到資料的第一步,因為只要做一個BLOG平台網站,資料替換一下,就等於做了N個BLOG。就像我做一隻BOT,如果把很多東西都寫死,結果就只能做出一隻BOT。如果要一次做出N個BOT,那就必須要把寫死的部分都抽出來資料化,讓程式只有一份,只要新增資料,就能夠產生一隻新的BOT,那就是BOT平台。

從BOT到BOT平台,這就是資料化的一個案例。蓋一個購物網站跟蓋一個電商平台的差別也是。大原則其實就是把重複的部分抽出來,把不重複的部分儲存成資料。你當然還可以再抽一層,做個電商平台平台,讓你一次蓋出N個電商平台。(只是沒人要用)

從資料到AI

所以說,已知程式資料化是大趨勢的情況下,資料科學就是必修。需求會是資料的生成過程自動化,應該是由AI來做。所以類神經網路就是AI中最有彈性的一種AI,同時他也是需要最多資料的AI,因為他把邏輯全都資料化了。

如果類神經網路的網路結構最佳化可以由內部自己決定的話,那麼他會需要更多的資料,而且更加強大。

#賺大錢的原則就是去除重複

2017/7/4

FB粉絲團自動邀請按讚程式

有一天,我的好友八里人問我:「幫你卡米狗的貼文按讚的人你都有邀請他嗎?」

經過八里人一番解釋後,發現是FB粉絲團小編可以邀請有按貼文讚,但是沒按粉絲團讚的人去按粉絲團讚,而這個過程是需要粉絲團小編一個個的去點邀請。

操作過程是從這裡點進去按讚清單



然後你會看到某個粉絲是「已說讚」,或者是「邀請」。

當我故意按了取消粉絲團讚之後,就會變成邀請

點擊邀請後對方會收到一則通知。


點擊通知後會看見一個邀請按讚的置頂訊息


會按你貼文讚的人,通常也是高度相關受眾,所以這肯定有搞頭。

可是一個個點耗時又耗力,雖然可以加粉絲數但是太累了。

身為工程師,寫一個自動邀請按讚工具也是很合邏輯的。

於是FB粉絲自動讚就出現了。

https://chrome.google.com/webstore/detail/fb%E7%B2%89%E7%B5%B2%E8%87%AA%E5%8B%95%E8%AE%9A/inmcpfbfiakkmgaahdbjniigaboaopmk

使用方法很簡單,就是點開按讚清單後再去點擴充套件圖示,然後等待完成。



注意:目前只支援繁體中文的FB粉絲團小編使用。
聽說 10萬人以上的粉絲團看不見邀請按鈕,所以無法使用此套件。

版本6 更新內容:
新增運作時將 icon 顏色變紅,再次點擊 icon 可強制停止運作。


2017/6/6

Regex 正規表示式 比對跟前面出現過的那個值相等的方法

markdown 我想要比對跟前面出現過的那個值相等 ,有可能用正規表示式做嗎? 可以的。 [regex維基百科連結](https://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F) 這在術語上稱為向後參照(back-reference) 我想要找兩個相同字元,但是中間卡一個-號,要怎麼寫呢? ``` (.)-\1 ``` 實際案例:[http://rubular.com/r/upTounDuFk](http://rubular.com/r/upTounDuFk) 我想要找兩個連續的不同字元(第二個字跟第一個字不同)要怎麼寫呢? ``` (.)(?!\1) ``` 實際案例:[http://rubular.com/r/JlJx8n2ZCB](http://rubular.com/r/JlJx8n2ZCB) 我想要找某一個字元的下一次出現點呢? ``` (.)((?:(?!\1).)+)\1 ``` 實際案例:[http://rubular.com/r/6pXhub7mOt](http://rubular.com/r/6pXhub7mOt)

2017/4/5

那個美感

我寫字很慢,從小就不喜歡寫字。因為不喜歡寫字、沒練字,所以字也就醜。 一兩年前看到一本書「禮元錄」提到一句話:「字,是一個人的臉面。」 當時看到這句話,我心裡想的是:「哇!那我不就醜爆了?」那還不練嗎? 剛好那時同事正在推一波鋼筆坑,我想說那就入一下坑吧,希望買了筆之後,會讓自己更有動力寫字。 買了筆之後,只寫了些字,當然還是醜,顯然字醜不醜跟用什麼筆來寫,關係不大。 能寫得一手好字的同事,不管他用什麼筆,都能寫出比我好看的字,而那肯定是花時間練出來的。 結果後來還是沒花時間練,現在字還是一樣醜。 最近我學 illustrator 跟 photoshop 時,發現相同的問題又出現了。 illustrator 跟 photoshop 其實只是另一種的高級「筆」,如果沒有去練那個美感,就算學會 illustrator 跟 photoshop 其實也沒搞頭。 回過頭來說寫字,字好不好看很重要。但比起字體本身的美,文字所表達的內涵又更重要。 其實寫程式也是這樣,排版、開發工具、套件、框架、設計模式很重要,但比起那些,可讀性跟效能又更重要。 仔細想想,絕大多數的東西都只是「筆」,只有少數的、最核心的那個美感,那個表達力才是最需要練、最有價值的東西。

2017/3/25

在 Postgresql 使用 uuid 的方法

markdown (以下指令都是在 postgresql cli 輸入) 想要生成uuid的話,只要呼叫 uuid_generate_v4 就可以生成 ``` select uuid_generate_v4() ``` 正常情況下會看到 ``` uuid_generate_v4 -------------------------------------- 98a4f867-8dcd-4982-aa3a-14e1030bcd88 ``` 如果看到 ``` ERROR: function uuid_generate_v4() does not exist ``` 表示你的postgresql 沒有安裝 uuid-ossp 模組 安裝uuid-ossp模組的指令 ``` CREATE EXTENSION "uuid-ossp"; ``` 移除uuid-ossp模組的指令 ``` DROP EXTENSION "uuid-ossp"; ``` 查看目前安裝過的模組 ``` select * from pg_extension; ``` 查看可安裝的模組 ``` select * from pg_available_extensions; ```

2017/3/23

建立一個line bot的所需知識

markdown 架構 * 程式語言:ruby * web server framework:rails * 資料庫:postgresql * 協定:https post * 資料傳輸格式:json 開發環境 * 硬體:macbook * 軟體 * rvm * rails * bundle/gem * sublime text 發布環境 * 硬體(heroku) * 軟體 * git * heroku cli

2017/3/21

rails db & postgresql cli 使用方法

markdown # postgresql 相關指令 查看有哪些資料庫 ``` \l ``` 連線到資料庫 ``` \c db_name ``` 查看有哪些表格 ``` \dt ``` 查看有哪些欄位 ``` \d+ table_name ``` 查看執行過的資料庫遷移 ``` select * from schema_migrations; ``` # rails db 相關指令 開啟含有 rails 環境的 irb ``` rails console ``` 連線到資料庫 ``` rails dbconsole ``` 建立資料庫,如果資料庫已經存在則不做事 ``` rails db:create ``` 刪除資料庫 ``` rails db:drop ``` 根據 db/schema.rb 檔產生對應的資料表(此動作會將資料庫內的資料清空) ``` rails db:schema:load ``` 根據資料庫狀態更新 db/schema.rb 檔 (但只要叫 db:migrate 就會自動執行這個了) ``` rails db:schema:dump ``` 執行db/seeds.rb ``` rails db:seed ``` ##快速功能 ###setup ``` rails db:setup ``` 等於以下指令 ``` rails db:create rails db:schema:load rails db:seed ``` ###reset ``` rails db:reset ``` 等於以下指令 ``` rails db:drop rails db:setup ``` 在這裡要注意的是setup跟reset指令不是重新執行migrate,所以如果你的schema檔是壞的,你下這兩個指令完還是壞的。 如果想要根據migration檔重新建立一個資料庫應該下的指令是 ###migrate:reset ``` rails db:migrate:reset ``` 等於以下指令 ``` rails db:drop rails db:create rails db:migrate ``` 這裡要注意的是, db:migrate:reset 指令並不會執行 db:seed 執行資料庫遷移,會把所有還沒執行過的都執行完,然後自動更新 db/schema.rb 檔 ``` rails db:migrate ``` 查看資料庫遷移結果 ``` rails db:migrate:status ``` 還原上一筆資料庫遷移 ``` rails db:rollback ``` 執行下一筆資料庫遷移 ``` rails db:forward ``` ##參考資料 [RailsGuide Migrations(資料庫遷移)](http://guides.ruby.tw/rails3/migrations.html) # schema 相關 psql 指令 列出所有 schema ``` \dn # List of schemas # Name | Owner #--------+---------- # public | postgres # abc | etrex # (2 rows) ``` 顯示目前所在的 schema ``` SHOW search_path; # search_path #----------------- # "$user", public # (1 row) ``` 切換 schema ``` SET search_path TO abc; # SET SET search_path TO 'abc'; # SET ``` 字串要不要加引號都可以,當 search_path 的值不在 schema 的列表上時不會跳 error,可以想像成連接到一個空的 schema,而這樣並不代表新增了一個 schema。 在 select 的當下使用 schema ``` SELECT * FROM schema_name.table_name; ``` ##參考資料 [https://stackoverflow.com/questions/34098326/how-to-select-a-schema-in-postgres-when-using-psql](https://stackoverflow.com/questions/34098326/how-to-select-a-schema-in-postgres-when-using-psql)

2017/3/20

人生技能配點建議

在玩線上遊戲的時候,職業選擇跟能力發展我們通常都會選擇其中一項特化。比方說玩RO、黑色沙漠,這類型的遊戲都會有配點系統,技能配點和屬性配點是非常重要的,因為點數有限,在配點時不會把點數分配在比較次要或者無關的能力上。 而在實際的生活上,我們把時間看成點數,對某個技能投入時間就像是在點技能。在現實生活中,很少有看到把時間全部投入在同一個技能上的人,而這種人也都強到爆炸。 根據線上遊戲的環境,遊戲平衡的設計不良,就會產生強勢職業跟弱勢職業,可能你玩到一半爬文才發現職業選錯,點數也配錯,選到一個弱勢職業還配點配超爛,完全無法打贏同等級的怪物,此時只能選擇創新角色重練了。 但如果你的人生走在錯誤的道路上,上了錯誤的大學、選錯系、找錯工作,那就不是創新角重練那麼容易。 其實現實世界並不像RO、黑色沙漠,也許現實世界更像FF5、魔力寶貝2。在這些遊戲裏有轉職系統,你一開始是無職業者,你需要做點事情達成轉職條件,甚至有些職業的轉職條件就是數個職業等級到達某個水準。 在李笑來的「七年就是一輩子」書中提到,他認為花2年就可以精熟一個職業,然後花5年利用這個職業去獲利、累積資源,接著就可以轉職學習新的強勢職業。 大多數的人在現實生活中,投在職業技能的時間都是少的,下班之後的時間都拿去點一些奇怪的東西,上班的8小時拿去混水摸魚當個冗員的事情也是常常發生,這樣的人被取代性高也是很合理的。按照李笑來的說法,大多數的人只要用心練個半年一年就可以達到一般水準,兩年就可以精熟。 最近在找工作的時候發現,若想在大公司得到較高的薪水,那麼最好你一輩子只點一個技能,點高點滿。而在小公司,因為資源有限,每個人需要懂的技能是廣的,也許你要身兼數職,所以技能廣度在小公司才有那麼點用處,在大公司則沒有。 很多人沒有考慮過自己的轉職路線。像我,在各種基礎職業轉來轉去,就很少花時間去點高階技能,結果就是得不到好薪水。 這樣算不算浪費技能點呢? Jobs在「史丹佛大學畢業演說」曾提到過,你現在所點的技能,都會被用在未來的某一刻,而那會是現在的你無法想像的。 我覺得不一定是這樣,純粹是看你能不能有效整合、利用手頭上的資源,去打出一個漂亮的combo。 最近在玩遊戲王(Duel links),透過進行遊戲,你可以得到一些寶石,寶石可以拿去抽卡包,決定抽哪些卡包會直接影響你的牌庫強度。 我們可以把寶石看成時間,卡包看成技能,抽卡看成技能配點。這也是款資源分配遊戲。 只要去爬攻略就可以看到很多流派,像是利用卡牌的特性打出漂亮的combo獲勝。或者見招拆招的防禦型獲勝法。你手上的牌庫也許不完整,但你看了別人的combo ,就會知道自己應該要往哪個方向發展,該把石頭拿去抽哪個卡包。 攻略看久之後,也可以根據自己的牌庫,創造出一個最適合自己的流派,打的對面不要不要的。 結論: 需要瞭解世界上的強勢職業有哪些 轉職到另一個基礎職業是容易的 資源整合是困難的 創造出一個新職業去最大化利用目前的技能配點是最佳解

2017/3/16

Swift 使用 dictionary 取代 switch case 的方法

markdown switch 寫法 ``` var a = "a" func funcA(){ print("A") } func funcB(){ print("B") } func funcC(){ print("C") } switch a { case "a": funcA() case "b": funcB() case "C": funcC() default: funcC() } ``` 改為使用 dictionary 的情況 ``` var a = "a" func funcA(){ print("A") } func funcB(){ print("B") } func funcC(){ print("C") } let dic = ["a":funcA,"b":funcB,"c":funcC,] dic[a]?() ``` [關於dictionary 的中括號](https://developer.apple.com/reference/swift/dictionary/1540848-subscript)

2017/3/8

markdown hello world

markdown #hello world ``` var QQ = "QQ"; ``` theme test ``` ```

在 blogger 貼漂亮 code 的方法(使用 markdown 和 prettyprint)

使用套件

markdown
prettyprint

安裝步驟

先到 blogger 版面配置,在最下方找到新增小工具

然後選擇HTML/JavaScript

然後在內容填入以下程式碼
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.6.4/showdown.min.js"></script>
<script>
var converter = new showdown.Converter();
var posts = document.querySelectorAll(".post-body,.snippet-item");
Array.prototype.forEach.call(posts, function(el, i){
  if(el.innerHTML.indexOf("markdown") <= 1){
    el.innerHTML = converter.makeHtml(el.innerHTML.replace("markdown",""));
  }
});

var pres = document.querySelectorAll("pre");
Array.prototype.forEach.call(pres, function(el, i){
  el.classList.add("prettyprint");
});
</script>
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=sunburst"></script>


就完工了。

測試

接著發佈一篇使用markdown語法的新文章
文章內容寫入如下圖:

結果看起來會是

補充

使用Tranquil Heart theme 的 code 寫法為:

<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.6.4/showdown.min.js"></script>
<script>
var converter = new showdown.Converter();
var posts = document.querySelectorAll(".post-body");
Array.prototype.forEach.call(posts, function(el, i){
  if(el.innerHTML.indexOf("markdown") <= 1){
    el.innerHTML = converter.makeHtml(el.innerHTML.replace("markdown",""));
  }
});

var pres = document.querySelectorAll("pre");
Array.prototype.forEach.call(pres, function(el, i){
  el.classList.add("prettyprint");
});
</script>
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>

<link rel="stylesheet" type="text/css" href="https://jmblog.github.io/color-themes-for-google-code-prettify/themes/tranquil-heart.min.css" />

可以成功,但一行程式碼太長時會破版,應該是這個theme的問題。

2017/3/2

ruby 全形轉半形(含英文數字符號)

markdown 寫法: ``` def to_half(str) full = " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~" half = " !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" str.tr(full, half) end ``` 測試: ``` puts to_half("!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~") ```