Pakogi 第一次 meetup 講解 ETH wallet by Nic

最近幾乎所有的團員都有在了解區塊鏈(blockchain)這個東西,事實上它似乎也變成一個很熱門的投資項目,不過大部分的人對於虛擬幣這個東西就只知道找個交易所買賣而已,但更多基本的知識似乎還不夠多。

今天第一次meetup就由師傅兼講師的Nic Lin授課,先來看看講了些什麼囉!

冷錢包V.S熱錢包V.S交易所

先來稍微解釋什麼是錢包,如果你要買虛擬幣就需要虛擬錢包,而對一般人來說最簡單的方法就是去交易所辦一個帳號,他自然會給你虛擬錢包。

虛擬錢包使用的方法就是拿私鑰去打開公鑰,公鑰是眾所皆知的但私鑰則是必須好好小心保管的東西,一但有了錢包的私鑰和公鑰他就能直接動用裡面的錢囉!

保管私鑰的方式有很多種,那冷熱錢包的定義是如何自己如何保管私鑰的方式,所謂的熱錢包就是24小時私鑰擺放的地方都是與網路連接的,例如只要輸入帳號密碼正確就可以拿到正確的私鑰,這就是交易所的錢包,沒錯他是熱錢包,所以也是最不安全的錢包。

反之越不常接觸網路的私鑰就越是偏冷的私鑰,市面上甚至有實體化的冷錢包,他像USB那樣要插上電腦你才可以拿到他的私鑰,這樣一來除非有人要爬進你家裡拿這台冷錢包,不然基本上他可以進入自己錢包的機率是零。

所以換個角度想,越冷的錢包似乎就單純只是保管私鑰的方式有沒有一直在接觸網路,這樣想是對的,但不要對交易所的熱錢包太過於恐慌,因為不論擺在網路的哪,最重要的是放在一個駭客極難入侵的地方就好,這就是為什麼大多交易所都極度建議要有雙重認證的原因。

P.S.這邊就先不贅述公鑰和私鑰是什麼,不只虛擬錢包其實電腦系統很多地方都會用到,上網查就有很多資料。

如何有其他種類的錢包

除了交易所我們如何創造自己的錢包?

其實創造錢包是極其容易而且是可以一直創造的,直接介紹手機和電腦最簡單的工具:

1.在chrome遊覽器的MetaMask

2.在手機app的imToken

如果你真的想了解每一筆交易更多的資訊極度建議可以創造這種錢包放一點小錢去做研究,通常台灣的交易所給的訊息很少,尤其是發送交易的時候不能自己設定Gas fee(後面會提到),但當然不熟操作的可以只放一點點錢就好甚至MetaMask有測試版的以太幣可以領,連結在這邊

如何發起交易廣播

交易廣播其實就是區塊鏈發起每一筆交易會做的事情,因為區塊鏈是全世界一起共同維護的帳本,所以發起的交易一定要是大家都知道才行。

區塊鏈的發起交易很簡單,每個錢包都有自己的地址只要進入自己的錢包後傳給對方的地址就好。

在這途中會發生一件事情是有Gas fee這個東西,剛剛說我們的每一筆交易是全世界維護的,但其實是專門有人下載程式在幫我們跑這些計算,這些人就稱為礦工,他們是要收取手工費(Gas fee)的!

大多的交易所不能設Gas fee,這是蠻重要的一點,當然Gas fee設定的越高交易越容易成功,另外還有一點很重要的是失敗的交易單Gas fee是不退還的,所以當緊急情況例如要大漲或大跌的時候因為一次太多人發起交易廣播會造成礦工來不及算,這就是交易堵塞,此時建議可以將Gas limit 和 Gas Price分別設定150000 和25,機率和速度會改善很多。

上課心得

猜咖啡的環境還不錯~重點這場是Nic親自出錢包的真的是太狂,畢竟他一開始的簡報開宗道明就是希望這方面的智障少一點XDDDD。

不過讓我很驚訝的是整場下來其實都抓得住我的注意力,即使我沒做筆記隔天才寫這篇心得也還記得昨天大多數在講什麼重點,遠端演講可以有這種程度已經很厲害,不愧是有受過講課訓練的人。

後面閒聊之餘還教我們怎麼用DDOS攻擊別人網站,這次算是很圓滿落幕~

[JavaScript]dataURL轉換Blob 並用 formdata上傳

繼上一篇[Vue2]使用vue-avatar-editor套件裁減照片做出大頭貼(Resize image),這次我要做的是用form-data把我的出圖傳上去,但裁剪後得出圖格式是dataURL,而要上傳的格式要是Blob,該如何實現呢?

注意事項:
1.有import jQuery
2.有import axios

dataURL to Blob

var imgURL = $('.someCanvas').toDataURL("image/png");
//直接複製國外的function

dataURItoBlob: function (dataURI) {
    // convert base64 to raw binary data held in a string

    // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this

    var byteString = atob(dataURI.split(',')[1]);

    // separate out the mime component

    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

    // write the bytes of the string to an ArrayBuffer

    var ab = new ArrayBuffer(byteString.length);

    // create a view into the buffer

    var ia = new Uint8Array(ab);

    // set the bytes of the buffer to the correct values

    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    // write the ArrayBuffer to a blob, and you're done

    var blob = new Blob([ab], {type: mimeString});
    return blob;

}
var imgBlob = this.dataURItoBlob(imgURL);
//到這邊我們已經製造好blob,開始製造formdata

var postData =  new FormData();
postData.append('key', imgBlob, 'fileName.jpg' );
//最後一個參數是可以自行設定檔案名稱

axios.post('url', postData, {'content-type': 'multipart/form-data'})
    .then( function (response) {
    //handle succeed

    }).catch(function (error) {
     //handle error

    })

這樣就能利用dataURL上傳Blob格式囉!

參考文件

image 各種型態轉換(blob, dataURL, canvas) in JavaScript

stackoverflow-Blob from DataURL?

stackoverflow-How to give a Blob uploaded as FormData a file name?

[JavaScript]Do not scroll parent element

正常來講滑完子元素的滾輪他會自動滑外面父元素的滾輪,要取消的話只要加上一段js就可以了:

$( '.son' ).on( 'mousewheel', function ( e ) {
    var event = e.originalEvent,
        d = event.wheelDelta || -event.detail;
    
    this.scrollTop += ( d < 0 ? 1 : -1 ) * 10;
    e.preventDefault();
});

比較有趣的是this.scrollTop += ( d < 0 ? 1 : -1 ) * 10;後面的* 10似乎會影響滑動速度,調越高滑越快,還沒有很搞懂這個原理之前先把它記下來。

參考文件
某一個人的Stack overflow

某人的codepen也很值得研究

[Vue2]使用vue-avatar-editor套件裁減照片做出大頭貼(Resize image)

如果對於canvas熟悉的人不一定要使用這個套件,畢竟我是因為這個套件才認識了幾本的canvas用法,畢竟他的文檔沒有更多後續的資訊,vue-avatar-editor的Github

使用前須知:

  1. 不用npm install這個套件只需自行創造這兩個.vue檔案import到使用的地方就好。
  2. 這個團隊似乎沒在維護這個Github了,有個簡單的錯誤tag <canvas> has no matching end tag.也沒修,自行到VueAvatar.vue這個檔案的template裡面幫他加上去</canvas>即可。

如何簡單使用vue-avatar-editor:

他的屬性真的不多,文件上就可以輕鬆掌握,裁減之後會觸發他預設的saveClicked(),他會給我們一個變數名稱是一個canvas的tag,然後呢?然後他的文件就到此為止了XD。

但其實這就是出圖的東西囉!!我們需要把這張圖片變成程式碼格式,其中一種格式只要下var pictureURL = img.toDataURL("image/png");再把他console.log出來會發現是一堆人看不懂的字串,但是電腦是看得懂的!

接著只要創造一個img的tag去裝他就行了!只要下這行$('.picture').attr('src', imgURL);就可以看到才剪出來的圖片了!

直接看範例吧:
p.s:我有用到jQuery喲!
先看html

<div id="app">
     <vue-avatar
       :width=400
       :height=400
       ref="vueavatar"
       @vue-avatar-editor:image-ready="onImageReady"
       image="https://vuejs.org/images/logo.png"
     >
     </vue-avatar>
     <br>
     <vue-avatar-scale
       ref="vueavatarscale"
       @vue-avatar-editor-scale:change-scale="onChangeScale"
       :width=250
       :min=1
       :max=3
       :step=0.02
     >
     </vue-avatar-scale>
     <br>
     <img src="" id="img-1">
     <button v-on:click="saveClicked">Click</button>
     <img src="#" class="picture">
</div>

看看JS

import Vue from 'vue'
import VueAvatar from './components/VueAvatar.vue'
import VueAvatarScale from './components/VueAvatarScale.vue'

let vm = new Vue({
  el: '#app',
  components: {
    VueAvatar,
    VueAvatarScale
  },
  methods:{
    onChangeScale (scale) {
        this.$refs.vueavatar.changeScale(scale)
    },
    saveClicked(){
      var img = this.$refs.vueavatar.getImageScaled()
      // use img

      var pictureURL = img.toDataURL("image/png");
      $('.picture').attr('src', imgURL);
    },
    onImageReady(scale){
      this.$refs.vueavatarscale.setScale(scale)
    }
  }
})

沒意外的話就可以把img做出來了

Canvas與Image可以互相轉換:

這個網站有最簡單的function:

//用<img>製作一個新的<canvas>

// Converts image to canvas; returns new canvas element

function convertImageToCanvas(image) {
    var canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext("2d").drawImage(image, 0, 0);

    return canvas;
}
//用<canvas>製作一個新的<img>

// Converts canvas to an image

function convertCanvasToImage(canvas) {
    var image = new Image();
    image.src = canvas.toDataURL("image/png");
    return image;
}

單純的互相轉換其實沒有這麼複雜,網路上有一堆文章幾乎都寫得大同小異,最常看到應該是使用filereader,filereader可以處理更多種類的檔案還有狀態,但我這裡不需要這麼複雜的操作。

只是因為需要做裁減的動作的話必須熟悉Canvas,但既然我們都沒有這麼多時間的話vue-avatar-editor確實幫我們做好了,所以vue-avatar-editor搭配這個網站的簡述就可以簡易做出大頭貼囉!

參考文章

vue-avatar-editor
Convert an Image to Canvas with JavaScript

element ui form 應用 & 命名小地雷

工作上的應用:

  1. 錯誤訊息動態產生的空間
  2. 驗證自訂規則
  3. 確認密碼的表格
  4. 命名小地雷

錯誤訊息動態產生的空間

在element ui的input裡他是有預留錯誤訊息的空間的,但這讓表單看起來有點空洞,因為輸入欄與輸入欄間距有點大,有點浪費輸入空間,用開發者工具指向出現的錯誤訊息,發現其實很好改動:

.el-form-item__error {
    position: relative;
}

這樣就是動態產生的空間了。

驗證自訂規則

官方文件有寫很基本的寫法,稍微玩過應該就知道怎麼寫,但網路上有很多人使用最精簡的寫法,用正則表示式做驗證,直接看簡單的範例:

4~15碼開頭需要用英文的帳號驗證

someRules: {
    account: [
        { required: true, message: ruleErrorMes.inputAccount, trigger: 'blur' },
        { validator(r,v,b){(/^[a-zA-z]\w{3,15}$/).test(v)?b():b(new Error( errorMessage ))} }
    ]
}

如果單純用正則判斷的話只要開正則的部分就好,剩下就是帶入自己要的errorMessage,只需要改兩個地方。

確認密碼的表格

其實只是簡單的判定兩個變數是不是相等,但我不知道怎麼在rule的function裡面找到我要的變數,所以我跳脫出他的from改用單純的input硬刻,時間上允許的話再回頭研究吧!

命名小地雷

先看簡單又正確的範例

<el-form :model="someModel" :rules="someModelRules" ref="someForm">
    <el-form-item :label="'account'" prop="account">
        <el-input type="text"
                v-model="someModel.account"
                :placeholder="'input here'">
        </el-input>
    </el-form-item>
</el-form>

在js

someModel: {
    account: ''
}
someModelRules: {
    account: [
        { required: true, message: ruleErrorMes.inputAccount, trigger: 'blur' },
        { validator(r,v,b){(/^[a-zA-z]\w{3,15}$/).test(v)?b():b(new Error( errorMessage ))} }
    ]
}

注意!!!!!!!!
Model和Rules兩個物件裡面要驗證的名稱一定要互相對應,不然運作起來會整個一直狂驗證不過!!!

也就是說要驗證model的account,使用的規則名稱也必須是account,這實在很玄,他們應該是不相干的東西但不知道為什麼只要我用不一樣的名稱驗證起來就會一直不過,只有兩個一樣運作才正常。

記錄一下工作上遇到的東西,可能是我哪個環節有問題,歡迎指教~

[Vue2]vue component 裡實作 Account kit 驗證

Account kit可以做到手機或信箱驗證,其實實作起來真的很簡單,但是在Vue的component裡還是要注意一些小地方,這邊把我遇到的問題全部記錄下來。

不過這邊不贅述如何申請開發者帳號和申請應用程式app,他文件上已經夠清楚。

載入後的初始化

首先在html上一定要在header裡就載入sdk,並且在body後端做初始化動作

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Account kit</title>
    <script type="text/javascript" src="https://sdk.accountkit.com/en_US/sdk.js"></script>
</head>
<body>
    <div id="header" ref="header" v-cloak></div>
    <div id="app">
        <router-view></router-view>
    </div>
    <script>
        AccountKit_OnInteractive = function(){
            console.log('Initing signup funciton');
            AccountKit.init(
                {
                    appId:"{{FACEBOOK_APP_ID}}",
                    state:"{{csrf}}",
                    version:"{{ACCOUNT_KIT_API_VERSION}}",
                    fbAppEventsEnabled:true,
                    Redirect:"{{REDIRECT_URL}}"
                }
            );
            console.log('Inited signup funciton');//為什麼下一個console在這後面會提到

        };
    </script>
    <script type="text/javascript" src="/dist/build.js"></script>
</body>
</html>

你會發現文件還有其他三個function,但那個是我要放在component的methods裡面的,在這邊也不贅述build.js裡面有什麼東西,直接寫component.vue的檔案:

P.S:這邊只取簡訊驗證所以不寫emailLogin的東西,兩個邏輯是一樣的。

<template>
    <div>
        <input v-model="countryCode" />
        <input placeholder="phone number" v-model="phoneNumber"/>
        <button @click="smsLogin">Login via SMS</button>
    </div>
</template>

<script>
import Vue from 'vue'
export default {
    name: 'home',
    data: function () {
        return {
        countryCode: '+886',
        phoneNumber: ''
        }
    },
    methods: {
       smsLogin: function () {
           var countryCode = document.getElementById("country_code").value;
           var phoneNumber = document.getElementById("phone_number").value;
           AccountKit.login(
               'PHONE', 
               {countryCode: countryCode, phoneNumber: phoneNumber}, // will use default values if not specified
               this.loginCallback
           );
       },
       loginCallback: function (response) {
           if (response.status === "PARTIALLY_AUTHENTICATED") {
               var code = response.code;
               var csrf = response.state;
               // Send code to server to exchange for access token
           } 
           else if (response.status === "NOT_AUTHENTICATED") {
           // handle authentication failure
           }
           else if (response.status === "BAD_PARAMS") {
           // handle bad parameters
           }
       }
    }
}
</script>
<style lang="scss">
//some...
</style>

正常來講這樣就可以啟動Acoount kit的功能囉!

這邊紀錄一下一些問題以及我的作法:

問題面

account kit 方面

  1. 在html用script載入sdk.js的檔案之後他會執行裡面的function產生AccountKit_OnInteractive這個變數並且watch他,所以在我們下AccountKit_OnInteractive = function () { AccountKit.init() }的時候他自己會執行 AccountKit.init()一次,而且他要抓到正確的AccountKit.init參數
  2. sdk.js載入之後AccountKit裡面有init和login這兩個function要使用login之前一定要執行過init
  3. 執行過AccountKit.init之後再執行一次會報錯。
  4. AccountKit.init的資訊似乎會在暫存裡面,所以刷新頁面如果出現donotlinktosdkdirectly的錯誤代表在抓到真正這次的sdk.js之前已經過早執行AccountKit.init

vue 方面

  1. conponent的methods裡面雖然可以呼叫windows的東西但從外面無法呼叫這個component的methods(或許真的有辦法),這會造成如果account kit function全都寫在windows 的話會造成完成後的function loginCallback執行上的困難。
  2. 雖然可以在component裡面呼叫到window的AccountKit_OnInteractive,但在vue裡面直接下AccountKit.login()他卻找不到正確的AccountKit.init的參數,我在想或許AccountKit在每個component裡面或許都是自己獨立的。
解決方法

問題1,2如何知道sdk.js完整抓下來並且正確的AccountKit.init()一次過,就像我範例中的html上下一段console.log('Inited signup funciton');即可清楚辨別,也可以避免問題3,4的問題。

問題5,6因為我們在html的window init了我們的AccountKit.init,為了讓AccountKit.login抓到window裡正確的參數,指定執行window.AccountKit.login即可。

可能是對很多東西還不是很熟,或許有更棒的做法,但我收尋不太到真正解到我痛點的文章,至少目前這個做法是很ok的,歡迎大家指點。

SONY MDR-1000X使用心得

我是一個寫程式的前端工程師,在安靜的辦公室常常會被我們網紅的叫聲嚇到,就是下面這位:

前陣子剛好師母在北京準備要回來看醫生,一問才知道離飛機剩不到24小時,但還是花了一萬左右的價格弄到了XDDD,先補上兩張開箱文:


接下來使用上的體驗它有分三種模式:

1.環境聲音普通模式:就是還可以清楚聽到外面的聲音
2.環境聲音語音模式:會把人聲留下來其他聲音稍微過濾掉
3.降噪開關:打開後就完全進入自己的世界

最常使用的其實就是降噪模式了,真的是大推!!

在我桌子底下每叫必嚇到我的網紅再開起降噪的時候像是隔壁巷子的狗在叫!

輕輕的壓住右邊的耳罩可以很清楚的聽到外界的聲音

這個耳機是有麥克風的,而且收音也十分良好,聽的音樂也會瞬間被轉的很小聲變成背景音樂繼續播放,可以直接參考官方網站由張鈞甯代言的廣告唷!用起來有鋼鐵人在用的感覺XD。

如果覺得降噪似乎有點不好的話長按降噪的開關鍵他會開始優化程序,他會偵測外界的聲音去做降噪的調整,但我個人是聽不太出來啦~

擁有舒服的音質和音樂操控

我想大家一定會很care音質好不好,音質的方面我不是專家但我覺得已經夠優秀,直接聽大砲進行曲來測試是很ok的唷!

方便的還有剛剛提到按住可以聽到外面聲音的右耳罩,其他功能單指左右滑是換曲子,上下滑是調整音量,連續點兩下歌曲就會暫停和播放囉!!

音量足夠且充電快速

一樣使用USB充電,盒子標榜是可以20個小時,我並沒有實際去測試過,大約經驗如下:

  • 音量約開到iPhone的1/3再高一點左右聽6~8小時會到中電量
  • 使用筆電充電大約兩小時之內就從中電量充到飽

順帶一提這個耳機長按電源鍵是開關機,按一下會報告目前電量。

舒適度在冷氣房可以戴上一整天

說真的台灣真的太熱,我想夏天不可能還可以像張鈞甯一樣在室外戴的這麼優雅跟帥哥眉來眼去再combo個一抹微笑。

我算是長時間戴著工作的(畢竟我沒辦法預測辦公室網紅哪時會叫XD),除了吃飯和午休至少都會戴六個小時以上,有時候回家繼續使用電腦的話很有可能戴上超過10個小時,只要不流汗是沒有感到不舒服喲!只是都聽不到外界的聲音是會有點有自閉的感覺啦。

不會扣分的基本外觀

其實每個人審美觀真的不一樣,但至少這款真的是走比較低調風吧!不會像B牌比較高調,帶著走是很輕鬆自在的,直接附上與師傅的同款耳機照吧XD

以上是我半個多月的使用心得,最後用我辦公室的網紅做個結尾吧!

element ui 移除 el-form-item 上 required 的星號 (米字, *)

其實在網路上真的不好搜尋,也許是我關鍵字下的不好,所以這是我自己想辦法直接硬改css就好XD

簡單解決方法

.el-form-item__label::before {
    content: '' !important;
}
題外話紀錄

el-form-item在官方文件上有一個自己也有一個required的屬性可以寫在html上,有人說這個單純是控制那個星號(米字, *)的跟實際驗證無關,但我自己用是有關聯的!記錄以下幾個狀況:

  1. 不設定他也不給他rule的話預設值是false,所以required的驗證模式是關閉的。
  2. 要設定他的話在html上打:required = 'true',就會開啟驗證模式摟!此時會有星號了。
  3. 如果不設定他但是rule有required這條規則的話也會把星號加上去喔!

[CSS] div 垂直水平置中簡單的兩個方法

繼上次的自製Dimmer突然發現一個問題,如果我的modal要垂直和水平都置中的話怎麼辦呢?

網路上一查就有一堆文章,我喜歡越簡單的越好,就介紹下面兩個:

子元素加上 margin: auto;

直接看範例吧~

<div class="father">
    <div class="son">Hello world!</div>
</div>
.father{
     position: relative;
     background-color: rgba(0, 0, 0, 0.53);
     width: 100%;
     height: 100%;
     position: fixed;
     z-index: 2;
}
.son{
     position: absolute;
     width: 100px;
     height: 50px;
     top: 0;
     right: 0;
     bottom: 0;
     left: 0;
     margin: auto;
     background: #fff;
     z-index: 3;
}

父元素使用 display: flex;

直接看範例吧~

<div class="father">
    <div class="son">Hello world!</div>
</div>
.father{
     display:flex;
     align-items:center;
     justify-content:center;
     background-color: rgba(0, 0, 0, 0.53);
     width: 100%;
     height: 100%;
     position: fixed;
     z-index: 2;
}
.son{
     position: relative;
     width: 100px;
     height: 50px;
     background: #fff;
     z-index: 3;
}

參考文章

CSS 垂直置中的七個方法

[Vue2]vue file scss 使用 & RWD 被覆蓋 小觀念紀錄

專案上的應用

  1. 使用vue-cli webpack-simple
  2. 使用vue-router呈現頁面所以大部份的view由.vue檔案組成
  3. 每個.vue檔案裡面直接在裡面寫自己的css
  4. html還是有引進大家共用的scc(由sass compass出來的css)

.vue檔案裡不能對外部的css檔案使用function

其實這觀念很簡單的,因為我們引入的已經是css檔案,自然.vue檔案不能使用@extend等sass才可以用的function去銜接他XD

但.vue檔案裡面還是能直接使用外部檔案的css喲!

RWD要寫在.vue檔案的最下面

正確寫法:

.someElement {
    display: block;
}
@media only screen and (max-width: 760px) {
    .someElement { display: none; }
}

錯誤寫法:

@media only screen and (max-width: 760px) {
    .someElement { display: none; }
}
.someElement {
    display: block;
}

如果使用錯誤寫法,我們可以在chrome的檢查工具上會發現RWD的東西即使被觸發顯示了,但還是會被下面原本someElement的東西蓋過去哦!
千萬不要太濫用!important這個猛藥!