Aesthetic Programming
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    :::warning **CHANGE LOG**(有任何修改請在此通知) > [name=chia0][time=Tue, Nov 21, 2023 2:02 PM] 註腳標註已修改成跟英文版一樣的了! > [name=andrew] 2023/12/13 10:43pm 已上傳至 [gitlab repo](https://gitlab.com/aesthetic-programming/book/-/tree/master/source.zh_TW/8-QueeryData) ::: ![](https://hackmd.io/_uploads/S1VhwTFxT.png) ## setup() 「查詢」(query)某事物,就是提出與之相關的問題,以檢查其有效性或準確性。查詢資料庫時,我們會以清晰而簡單的方式請求資料,這將讓我們得以選擇要回傳哪些資料,以及回傳的資料該有多少,然而,針對這個操作,我們仍應明確地提出質疑,也就是說,查詢資料這件事,也需要我們去進行「查詢」。 提到聚集內容並根據關鍵字搜尋,以演算法回傳搜尋結果的應用程式,Google 和百度等搜尋引擎便是很好的示例。這類搜尋引擎雖保證會回答我們所有的問題,卻並未揭露它們在選擇要優先顯示哪些答案時的潛在流程(和意識形態)。在查詢驅動的社會中,搜尋引擎已成為一種強大的機制,既能製造真相,又可供我們理解貌似無窮無盡的資料,這些資料以「流」(stream)和饋給(feed)的形式呈現,而我們可從中看到資訊的過度飽和,以及注意力經濟的興起。根據全喜卿的說法,使用者習慣為大數據業務提供了公式。她解釋道:「大數據服務透過使用者的『習慣』,讓他們成為了大數據的機器:使用者以之進行串流、更新、擷取、上傳、共享、打磨、連結、驗證、映射、儲存、刪除和惡意攻擊。」[^chun]舉例來說,他們的搜尋習慣便已轉化為可供儲存、追蹤和分析的資料。 關於程式擷取輸入資料的部分流程,我們已經在第四章〈資料擷取〉中探討,並特別著重於連接到物理裝置的資料,而在本章中,我們將進一步把討論的範圍擴展到線上平台託管的資料。我們將從資料的擷取延伸到儲存,並分析大量擷取的資料(亦即所謂的「大數據」,如果我們將之視為一種男性主義的幻想,甚至可以稱其為「大屌數據」[^bigdick]),進而應用於使用者輪廓分析、目標市場行銷、個人化推薦,以及各種預測和電子商務等面向。在此之後的未來,似乎會如下文所示:「我們無法掌握自己的搜尋實作,反而是搜尋引擎控制著我們,而我們也欣然(儘管大多數時候是無意識地)接受這樣的宰制。」[^netcultures]不過,我們可以說,情況也並不如上文所述的那樣斬釘截鐵,因為這些操作其實是更大的社會技術組合和基礎設施的一部分(其中包括資料、資料結構和人類主體),而上述這些也在不斷發展,並受制於外部條件。 為了讓其中一些彼此互動的實體變得比較好理解,並提供不那麼決定論的資料化願景,本章將著重於如何透過應用程式介面(API,電腦程式不同部分之間的通訊協定,目的為簡化軟體開發)的即時查詢來取得資料。查詢資料是一種雙向的通訊過程,乃是透過「請求和回應的邏輯」[^api]同時進行資訊處理和資料的選擇、提取、傳輸和呈現,在此我們將使用上一章介紹過的 JSON 等結構化資料檔案來幫助理解。處理這些問題的方法有很多,下文則透過一個利用 Google 圖片搜尋 API 的生成藝術作品,演示超越了技術描述範疇的查詢,從而進一步質疑與開放性和可及性相關的一些假設,換句話說,就是要「酷詢資料」[^queering]。上述的文字遊戲,展示了我們希望動搖讓穩定的(性別)表示類別更加牢不可破的規範化資料實踐。 ## start() 網路藝術產生器(net.art generator,nag)[^nag]是一款於網頁瀏覽器中運行的應用程式,用途為產生新的圖片,係由藝術家柯妮莉亞・索弗蘭克(Cornelia Sollfrank)於 1997 年創造,而最新的 5b 版本則為孫詠怡在 2017 年更新並維護。要利用此產生器,使用者須於介面輸入作為搜尋關鍵字標題,以及作為「作者」的名稱。索弗蘭克最初的想法,是透過產生數百個帶有假造的國際女性藝術家簡介的藝術作品項目並提交參賽,來「駭入」一個名為「Extension」的網路藝術(net.art)競賽。用來產生這些藝術項目的程式名為「Female Extension」,本身便是網路藝術的一個隱而不顯的例子,其命名乃是透過諷刺性的女性主義語彙,針砭當時媒體藝術界中女性藝術家人數偏低的現象[^extension]。索弗蘭克不僅捏造了作者名稱,還為每個參賽申請人建立了電子郵件地址、電話號碼和住家地址,以及原創網路藝術作品範例。 如同索弗蘭克先前採訪虛假的女性駭客的紀錄片,以及她所參與的網路女性主義團體名稱「老男孩網路」(Old Boys Network)[^obn],這個作品亦挑戰了我們對於怪咖男性駭客文化的預設觀念。索弗蘭克認為,「聰明的藝術家會利用機器來完成作品」,這樣具有諷刺性的主張(這句話本身就是對勒維特的格言的駭取,如第五章中所述),在此也與本章的論點相關,正如索弗蘭克所言,這乃是用來澄清「藝術作業系統的駭入」。[^hack] 其後,*Female Extension* 演變為網路應用程式「nag」,一種可從現有資料即時產生出圖片的功能性工具,我們可以從而進一步質疑規範化的作者身份和版權,以及藝術製作的一些基礎架構。nag 的最新版本透過使用網路搜尋 API,結合從 Google 傳送的資料,從而產生出圖片。有趣的是,nag 每天設有一百次的 API 請求限制,一旦超過此限,使用者便會看到一個客製化的錯誤頁面,並將無法再檢索圖片。因此,可見性的議題便從再現政治(politics of representation,女性藝術家的資料),轉移到非再現的 API 領域,兼及我們被授予多大權限,得以存取軟體的隱藏層次,而此軟體可以用來查詢可取用的資料,並產生出新的排列方式。 ## 課堂練習 請前往 *net.art generator* 網頁(https://nag.iap.de/),並探索圖片的產生,以及之前創造出來的圖片。請密切注意介面,並勾勒出使用者輸入(例如標題)和相應的輸出(圖片)之間的關係。輸入和輸出之間的過程有哪些?圖片又是如何合成和產生的呢? ![](https://hackmd.io/_uploads/HyhrycYl6.png) *圖 8.1:net.art generator 網頁介面,輸入標題為「queeries」* ## 圖片處理:擷取、載入和呈現 下文包含了這一章的原始碼,是從 *nag* 中擷取的片段,我們可從中了解網路 API 請求和回應的邏輯,請求的資料通過 web API 後,Google 便會利用關鍵語法 `loadJSON()` 回傳相應的資料。在使用 JSON 方面,這章與上一章的主要不同之處,在於 JSON 檔案的位置並不在您的電腦上,也不是由您自行建立,一切都在線上運行。因此,這些資料是在接近即時的狀態下動態產生的。這樣的 JSON 檔案具有更複雜的資料和組織結構。 RunMe:https://aesthetic-programming.gitlab.io/book/p5_SampleCode/ch8_Que(e)ryData/ ![](https://hackmd.io/_uploads/S1XOX5Fe6.gif) *圖 8.2:像素操作過程* ![](https://hackmd.io/_uploads/H1SKQ9Kga.png) *圖 8.3:沃荷的《花》處理狀況* 針對本章的範例程式碼,我們將重點關注搜尋引擎結果中的圖片,並將演示如何以類似於 *nag* 的方式在螢幕上處理及顯示圖片與像素資料。以下為關鍵語法的範例: * `loadJSON()`:[^json] 如上一章所述,此函式可從檔案或網址來載入 JSON 檔案,在這個範例程式碼中,是用來送出網路 API(以網址的形式)的請求,並以 JSON 格式接收回應。回呼函式則是用以將回傳的資料轉換成物件:`loadJSON(request, gotData);`。 * `loadImage()`[^img1] 和 `image()`:[^img2] 兩者都是供載入和顯示圖片之用。聲音、檔案、圖片和影片等資料,皆屬於需要先行載入才能處理的物件。但在此範例程式碼中,我們事先並不知道檔案的位置,因此無法透過 `preload()` 函式來載入。這就是為什麼我們要使用回呼函式來處理圖片的請求和接收之間的時間間隔,例:`loadImage(getImg, img=> {}});`。 * `loadPixels()`:[^pixel] 若您想操控或分析圖片中的資料,可以利用此函式來提取和操作各個圖片像素的資訊,並將資料載入到內建的 `pixels[]` 陣列之中。我們將在下文中更詳細地探討這項功能。 * `line()`:這是用來將選定圖片的像素中提取出的顏色加以視覺化的函式。 * * * ## 原始碼 ```javascript= let url="https://www.googleapis.com/customsearch/v1?"; //註冊:https://developers.google.com/custom-search/json-api/v1/overview let apikey="INPUT YOUR OWN KEY"; //取得搜尋引擎 ID:https://cse.google.com/all(請確保圖片搜尋為開啟狀態) let engineID="INPUT YOUR OWN"; let query = "warhol+flowers"; //搜尋關鍵字 //請檢查其他參數:https://tinyurl.com/googleapiCSE let search Type="image"; let imgSize="medium"; let request;//完整 API let getImg; let loc; let img_x, img_y; let frameBorder = 25; //每一邊 let imgLoaded= false; function setup(){ createCanvas(windowWidth, windowHeight); background(255); frameRate(10); fetchImage(); } function fetchImage(){ request = url + "key=" + apikey + "&cx=" + engineID + "&imgSize=" + imgSize + "&q=" + query + "&searchType=" + searchType; console.log(request); loadJSON(request, gotData); //這是用來進行 API 請求的關鍵語法 } function gotData(data){ getImg = data.items[0].image.thumbnailLink; console.log(getImg); } function draw(){ if (getImg){ //花費時間檢索 API 資料 loadImage(getImg, img=> { //回呼函式 //繪製框架 + 圖片 push(); translate(width/2-img.width-frameBorder, height/2-img.height-frameBorder); scale(2); if (!imgLoaded) { noStroke(); fill(220); rect(0, 0, img.width+frameBorder*2, img.height+frameBorder*2); image(img, frameBorder, frameBorder); imgLoaded = true; }else{ //繪製線條 img.loadPixels(); img_x = floor(random(0, img.width)); img_y = floor(random(0, img.height)); /* 定位像素的公式為:x + y * 寬度, 這表示從圖片的網格中取得一個像素(每個像素陣列包含紅色、綠色、藍色 和 alpha 值)。詳情請參閱此處: https://www.youtube.com/watch?v=nMUMZ5YRxHI */ loc = (img_x+img_y * img.width)*4; strokeWeight(0.7); //rgb 值 stroke(color(img.pixels[loc], img.pixels[loc + 1], img.pixels[loc+2])); line(frameBorder+img_x, frameBorder+img_y, frameBorder+img_x, frameBorder+img.height); } pop(); }); } } ``` ## 練習:(按部就班)存取 web API 上述的原始碼說明了如何從 Google 圖片搜尋 API 中取得靜態圖片(解析 JSON),隨後於螢幕上顯示。正如許多其他 web API 一樣,您必須擁有一個 API 金鑰(一組獨一無二的識別號碼)以便用來授權,讓客戶端程式得以進行 API 呼叫/請求。如此一來,平台便能辨識出取得資料之人的身份,以及他們的流量和使用情況。[^key] 在這個練習中,您將從 Google 取得「金鑰 ID(key ID)」和「引擎 ID(Engine ID)」,從而輸入您自己的一組 ID 並成功執行程式。為了讓程式得以運行並即時擷取線上圖片,這些是必要的資訊。 - **步驟一:** 請建立一個 p5 程式草稿碼,然後複製原始碼並貼到您的程式編輯器中(此處假設您已經擁有 HTML 檔案和 p5 函式庫)。 - **步驟二:** 在第三行程式碼處將 API 金鑰替換為您自己的資訊:`let apikey = "INPUT YOUR OWN KEY";`。 ![](https://hackmd.io/_uploads/SkCg-iYlT.png) *圖 8.4:Google 自訂搜尋頁面* - 如果您沒有 Google 帳戶,請註冊一個(使用 web API 需有 Google 帳戶) - 請登入您的帳戶 - 前往 [Custom Search JSON API](https://developers.google.com/custom-search/v1/overview)[^google1] 並找到 API 金鑰的區塊 - 點按「取得金鑰」的藍色按鍵(參見圖 8.4),然後輸入專案名稱(如「nag-test」)並按下 Enter 鍵,便可建立一個新專案 - 您應可以看到 API 金鑰,只需複製金鑰並貼到您的草稿碼程式中即可 - **步驟三:**在第 5 行程式碼 `let engineID = "INPUT YOUR OWN";` 中,將搜尋引擎 ID(cx)替換為您自己的 ID。 - 前往[程式化搜尋引擎](https://cse.google.com/all)[^google2] - 點按「新增」按鈕以新增搜尋引擎 - 您可以限制搜尋範圍,不過,若想直接進行 Google 全網搜尋,只需輸入「http://www.google.com」即可 - 輸入您的搜尋引擎名稱,例如「nag-test」 - 點按藍色的「建立」按鈕,即表示您同意 Google 的服務條款(當然,您也應該藉此了解您的權益) - 前往控制面板並修改搜尋引擎的設定 - 複製搜尋引擎 ID 並將貼到您的草稿碼中 - **步驟四:** 控制面板設定 - 確定「圖片搜尋」已開啟(切換開關將顯示為藍色,如圖 8.5 所示) - 確定「全網搜索」已開啟(切換開關將顯示為藍色,如圖 8.5 所示) 執行上述步驟後,便完成了設定的調整,現在,您可以開始以自己的 API 金鑰和搜尋引擎 ID 來執行範例程式碼。 ![](https://hackmd.io/_uploads/ryNcVsFlT.png) *圖 8.5:Google 自訂搜尋介面——搜尋設定* ## APIs Net Art Generator 中與 API 相關的程式碼片段如下: ```javascript= let url="https://www.googleapis.com/customsearch/v1?"; //請於下列網址註冊:https://developers.google.com/custom-search/json-api/v1/overview let apikey="INPUT YOUR OWN KEY"; //請於下列網址取得搜尋引擎ID:https://cse.google.com/all(請記得開啟圖片搜尋) let engineID="INPUT YOUR OWN"; let query = "warhol+flowers"; //搜尋關鍵字 //請於下列網址查看其它參數:https://tinyurl.com/googleapiCSE let searchType="image"; let imgSize="medium"; let request;//完整 API function setup(){ … fetchImage(); } function fetchImage(){ request = url + "key=" + apikey + "&cx=" + engineID + "&imgSize=" + imgSize + "&q=" + query + "&searchType=" + searchType; console.log(request); loadJSON(request, gotData); //此為 API 請求的主要語法 } function gotData(data){ getImg = data.items[0].image.thumbnailLink; console.log(getImg); } ``` 為了方便修改,我們將搜尋參數設為全域變數,其中包括所需的 URL、API 金鑰、搜尋引擎 ID、搜尋類型、圖片大小和查詢(參見第 1 至 9 行)。這些參數將用於篩選搜尋結果,若有其他需求,也可以添加更多變數。 Web API 實際上就是一個很長的 URL:`request = url + "key=" + apikey + "&cx=" + engineID + "&imgSize=" + imgSize + "&searchType=" + searchType + "&q=" + query;`,其中包含了所有的憑證以及您想要搜尋的項目和必要篩選條件(URL 看起來像這樣:<https://www.googleapis.com/customsearch/v1?key=APIKEY&cx=SEARCHID&imgSize=medium&searchType=image&q=warhol+flowers>)。 主要語法為 `loadJSON()`(在 `fetchImage()` 函式中的第 21 行),係以 URL 形式向圖片提供者提交「請求」,隨後您必須等待回傳的 JSON 檔案,其中包含搜尋結果列表。回呼函式 `gotData()`(見第 24 行)則是用於進一步處理和查詢回傳的資料。 ### 「酷」詢資料 下文中的圖 8.6 展示了 JSON 檔案格式,但其中含有許多您或許並不需要的資訊。因此,您需要先行理解檔案結構,並找到您想要處理的資料。架構資料的方式會依據提供者和平台而有所不同,酷詢資料的過程因此也必須包含理解回傳的資料檔案。 ![](https://hackmd.io/_uploads/SyzRBjFl6.png) *圖 8.6:Web API 資料結構 I* 在網頁主控台中,請利用您自己的 API 金鑰和搜尋引擎 ID,找出以「https」開頭,並以「warhol+flowers」結尾的 URL(類似於此:<https://www.googleapis.com/customsearch/v1?key=APIKEY&cx=SEARCHID&imgSize=medium&searchType=image&q=warhol+flowers>)。隨後,只需輕點連結,即可在網頁瀏覽器中查看資料如何以 JSON 檔案格式進行架構(參見圖8.6)。若要選擇更具體的資料形式,您還可以設定更多參數,例如圖片大小、圖片顏色類型、圖片主要顏色等等。我們在範例程式碼中使用的 API 只是最基本的設定。[^setting] **跨來源資源共享** 與文本不同,從網域(或影片和字型等多媒體格式)請求、接收和載入圖片會引發安全問題,這在資訊領域中被稱為跨來源資源共享(Cross-Origin Resource Sharing,CORS)。在本章以及相應的示例中,範例程式碼託管於配備區域伺服器,並在 Atom 程式碼編輯器中運行的區域機器上,但 API 請求和對應的資料則是託管於其他地方。與網路請求相關的 CORS 問題旨在防止「不安全的 HTTP 請求」[^w3c]。在產業領域,我們通常會於網頁伺服器端進行配置,從而處理網路請求,但此處為了演示方便,我們使用搜尋提供者產生的縮圖(`data.items[0].image.thumbnailLink;`),而非載入托管於設定各不相同的各種伺服器上的原始網頁圖片(有關資料結構的更多資訊將在下一節中介紹)。只需使用 `createImg()` 或 `loadImage()`(參見圖 8.2 和 8.3)來載入這些圖片即可。 **資料結構** 圖 8.6 示範了如何在 JSON 檔案中指示特定的資料。完整原始碼中有一行程式碼如下:`data.items[0].image.thumbnailLink;`(第 33 行),乃是用於從 JSON 檔案中取得指定的回傳物件(圖片的 URL),而其中的「data」(資料)一詞,則是指涉透過回呼函式 `function gotData(data){}` 回傳的所有物件,而 `items[0]` 指向第一個資料物件,此處使用的是陣列的概念,因此索引序列的編號是從 0 開始。語法裡利用了「點」(.)這個符號,讓您得以導向 `items[0]` 下的 `image` 和 `thumbnailLink` 物件(「data > items[0] > image > thumbnailLink」)。請注意,這個層次結構僅適用於此 API,其它 web API 可能會以不同方式架構資料。 若想了解更多有關 JSON 檔案的資訊,您可以試著導向到其他資料物件,如「queries > request > 0」,這會顯示出圖片搜尋結果的數量、處理的搜尋條件,以及回傳的資料物件的數量等(見圖 8.7)。在範例程式碼中,我們僅列出頭 10 個搜尋項目,但您亦可透過設定 `startIndex` 參數來取得總計 1.1 億張圖片中的最後 10 張。此外,您也能在 JSON 檔案的 `items` 之下,找到每張特定圖片的資料,例如標題和對應的網頁內容片段,而這些資料會以陣列的形式回傳。 ![](https://hackmd.io/_uploads/BJsmvjFea.png) *圖 8.7:Web API 資料結構 II* 現在,我們可以將使用 web API 並從線上平台取得資料的一般過程總結如下: * 了解 web API 的工作流程。 * 了解 API 的規格,這些規格指出了可供使用的資料和參數。 * 了解 web API 回傳的檔案格式(例如 JSON)。 * 註冊並取得 API 金鑰,以及其他所需的額外配置。 以我們在上文中提供的 *nag* 具體示例和範例程式碼為鑑,我們也應該回頭反思越來越普遍的 API 實踐。儘管 Google 提供了取用資料的 API,但也別忘了此 API 的使用次數有限,從企業到非營利組織等所有單位,都只有 100 次免費的 API 請求,此外,實際的資料是從公共領域收集而來,但人們無法取得用來選擇、排序、包含/排除和呈現資料的具體演算法。這引發了人們對關於 API 實踐的開放、透明、可及性和包容性程度的嚴肅質疑。[^soon] ## 課堂練習 ![](https://hackmd.io/_uploads/r1m2Potep.png) *圖 8.8:API 請求和回應邏輯* 1. 參考圖 8.8,您能否總結出透過 web API 請求和取得的內容?或以更概念性的方式來說,web API 進行了哪些形式的控制和交換? 2. 請更改您自己的查詢字串。目前的關鍵字是「warhol flowers」,但請留意,該程式無法理解字符之間的空格,因此關鍵字需寫成「warhol+flowers」。 3. 請回顧上文有關 API 的小節,並觀察使用如「圖片顏色類型」(image color type)等[不同參數](https://developers.google.com/custom-search/v1/cse/list#parameters)[^setting]的搜尋篩選規則,以了解圖片如何分類。URL 參數以「&」符號分隔,如下所示:<https://www.googleapis.com/customsearch/v1?key=APIKEY&cx=SEARCHID&imgSize=medium&searchType=image&q=warhol+flowers>。 4. 請查看 JSON 檔案,以大致了解資料查詢的情況,例如有多少搜尋結果,以及查詢表現等。之後請修改草稿碼程式,以取得其他資料,例如在網頁主控台中顯示,除了圖片 URL 之外的文字。 ## LoadPixels() ![](https://hackmd.io/_uploads/HyDrJ3txp.png) *圖 8.9:由像素組成圖片的示意圖* 在這個圖片檔的示範草稿碼中,程式將只選擇並處理圖片中的一種顏色,這表示程式會隨機定位並選取圖片中的任一像素。而函式 `pixels` 則會分析並檢索所選像素的顏色,亦即用來在螢幕上繪製有色線條的 RGB 顏色值(示意圖見圖 8.9,但實際像素的尺寸比此小上許多)。 有色線條(見圖 8.2 和 8.3)並非隨機繪製,而是基於所選像素的 x 和 y 座標,每條線都沿著該座標點的 y 軸繪製。除了位置外,線條的顏色也是基於所選像素的 RGB 值。結合位置和顏色,就能完成圖片顏色可視化的任務,隨著時間經過,一幅抽象的畫作便漸漸出現在我們眼前。 每個選取的像素都包含顏色資訊,即 R(紅色)、G(綠色)、B(藍色)和 A(透明度) 值。以下呈現資料如何以一維陣列的形式儲存在像素之中: ![](https://hackmd.io/_uploads/SJCZG3Yg6.jpg) *圖 8.10:紐約大學整合數位媒體(Integrated Digital Media,IDM)對每個像素進行細分的圖示。圖片來源: https://idmnyu.github.io/p5.js-image/* [^nyu] 我們現在先來建立一個變數 `loc`,用以儲存像素資料。每個像素的位置都需要明確的定位,如此方能在正確的位置上繪製一條線。跟隨函式 `Pixels()`,每個像素會佔用四個位置:第一個像素具有 RGBA 四個值,第二個像素也具有另外四個 RGBA 值,依此類推: pixels = [p1, p1, p1, p1, p2, p2, p2, p2, p3, p3, p3, p3…] 如上所述,像素由四個不同的位置組成,每個位置會儲存與單個像素有關的單一值。定位特定像素的公式為 `loc = (img_x+img_y * img.width)*4;`。`img.pixels[loc]`、`img.pixels[loc+1]` 和 `img.pixels[loc+2]` 則是透過函式 `pixels[]` 來定位各自的 RGB 值。 ```javascript= function draw(){ if (getImg){ //檢索 API 資料需花費時間 loadImage(getImg, img=> { //回呼函式 //繪製框架 + 圖片 push(); translate(width/2-img.width-frameBorder, height/2-img.height-frameBorder); scale(2); if (!imgLoaded) { noStroke(); fill(220); rect(0, 0, img.width+frameBorder*2, img.height+frameBorder*2); image(img,frameBorder, frameBorder); imgLoaded = true; }else{ //繪製線條 img.loadPixels(); img_x = floor(random(0, img.width)); img_y = floor(random(0, img.height)); /* 定位編號的公式:x+y*width,用來表示一個來自影像網格上的像素點 (每個像素陣列包含紅色,綠色,藍色,和透明度值),詳情請見: https://www.youtube.com/watch?v=nMUMZ5YRxHI */ loc = (img_x+img_y * img.width)*4; strokeWeight(0.7); //rgb 值 stroke(color(img.pixels[loc], img.pixels[loc + 1], img.pixels[loc+2])); line(frameBorder+img_x, frameBorder+img_y, frameBorder+img_x, frameBorder+img.height); } pop(); }); } } ``` 上面的程式碼片段摘錄自與顏色視覺化相關的部分。`draw()` 函式的邏輯,是繪製灰色外框,並以函式 `translate()` 來載入中間的圖片(請參閱程式碼第 6 行)。 條件結構 `if (getImg){}`(見第 2 行)是用來保留足夠的時間,以便載入 JSON 檔案並取得檔案路徑。利用函式 `loadImage()`(第 3 行)和對應的回呼函式 `img` 成功載入圖片後,外框和圖片都將會被繪製在畫布上。 外框和圖片僅會在狀態 `imgLoaded` 更新時隨之繪製(見第 8 行)。針對繪製的每一個外框,程式將使用語法 `loadPixels()` 分析圖片的像素(見第 16 行),選取隨機像素,並利用變數 `img_x` 和 `img_y` 來取得對應像素的 x 和 y 座標。隨後,程式將透過函式 `pixels[]` 自所選像素取得 RGB 色彩值,隨後使用語法 `strokeWeight()`、`stroke()` 和`line()` 繪製彩色線條(請參閱第 24-28 行)。 這一小節包含了像素和顏色元素,展示電腦如何處理圖片並將其儲存成資料的形式,這與人類查看和感知圖片的方式有根本上的不同。[^eckhardt]這也是展示將圖片物件轉換為數字以便進行計算的一種方法,類似於第四章〈資料擷取〉中的臉部追蹤範例,在此例中,像素可以用超出人類感知範圍外的方式定位。這些例子可以幫助您理解當代的各種應用程式,例如追蹤技術等,甚至可以協助了解採用機器學習技術,以圖片作為訓練資料的電腦視覺(我們將在第十章〈機器反學習〉中回頭討論這點)。 ## 不同種類的程式錯誤 1945 年,一隻死掉的蛾被黏貼在葛麗絲・穆雷・霍普(Grace Murray Hopper)的電腦日誌中,記錄了一隻飛蛾導致哈佛大學艾肯繼電器式計算機(Aiken Relay Calculator)Mark II 程式出錯的軼事。[^hopper] 這隻「蟲」(bug,程式錯誤的英文)[^edison] 被困在繼電器接點之間,中斷了這台老式電機式計算機的程式流程。在數位電腦的早期時代,像 ENIAC 這樣的機器使用面板間的接線電纜和開關進行程式編寫,「除錯」(debug)則是透過拔掉電纜來進行的。透過這種方式,人們得以中止運行中的程式並進行除錯。 如今,除錯已成為高級程式語言的重要部分之一,協助程式設計師藉由逐行執行程式碼,從而找出程式錯誤。隨著您程式設計技能的進步,編寫出來的程式將變得越來越複雜,因此到了這個階段,作為除錯過程的一部分[^debug],理解、辨識和定位程式的問題或錯誤非常重要,這將讓您得以編寫出可行的程式碼。 仔細的關注程式錯誤/缺陷,是學習程式設計的重要部分,因為這使程式設計師能深入理解程式的運作,例如程式在哪一點產生非預期的結果並導致失敗。在除錯程式碼時,您能否識別錯誤是來自您自己的程式碼,還是在運行時解析資料錯誤,抑或是來自像圖片搜索引擎這樣的第三方程式?(程式變得更複雜,是因為涉及更多的代理程式)。這些錯誤是次要錯誤還是致命錯誤(使您的程式無法運作的)?它們是語法錯誤、執行階段錯誤還是邏輯錯誤(如下所解釋的)? 廣泛來說,程式錯誤有三大類: 1. **語法錯誤(Syntax error)** 又稱解析錯誤(parsing error),意指語法上出現問題,包含拼字有誤或缺少右括號等情形,通常較容易發現,並可透過解析器(在此情況下為瀏覽器)偵測。 > SyntaxError: missing `)` after argument list(語法錯誤:引數清單後缺少右括號) 2. **執行階段錯誤(Runtime error)**是在語法正確的情況下,於程式執行期間發生的錯誤。想要了解這類錯誤,需前往查看網頁瀏覽器控制台。下面列出兩個執行階段錯誤的例子: 若刪除 `draw()` 函式中的條件檢查 `if (getImg){}`,則程式一開始就將無法載入圖片,這是因為處理 web API 請求需要一些時間。該錯誤將持續顯示在網頁主控台中,直到程式成功解析圖片的 URL。 > > p5.js says: `loadImage()` was expecting `String` for parameter `#0` (zero-based index), received an empty variable instead. If not intentional, this is often a problem with scope: <https://p5js.org/examples/data-variable-scope.html> at about:srcdoc:94:6. <https://github.com/processing/p5.js/wiki/Local-server> Wrong API key sent to the server. It is a more critical error because the program cannot extract the image and display it on the screen: > > p5.js says: It looks like there was a problem loading your json. Try checking if the file path is correct, or running a local server. > > p5.j​​s 說:`loadImage()` 預期參數 `#0`(從零開始的索引)為字串 `String`,但卻收到一個空變數。若非有意如此,這通常是作用域方面的問題:<https://p5js.org/examples/data-variable-scope.html> at about:srcdoc:94:6. <https://github.com/processing/p5.js/wiki/Local-server> 傳送到伺服器的 API 金鑰錯誤。這是一個更嚴重的錯誤,因為程式無法提取圖片並將之顯示在螢幕上: > > p5.j​​s 說:載入您的 json 時似乎出現了問題。請試著檢查檔案路徑是否正確,或執行本機伺服器。 3. **邏輯錯誤(Logical error)** 涉及邏輯而非語法,因此可以說是最難找出的錯誤,出現邏輯錯誤時,程式碼可能仍然可以完美運行,但會跑出非預期的結果。這表示我們認為自己要求電腦執行的操作,與它實際處理指令的方式之間存在差異。想接收錯誤通知或測試程式碼是否能如我們預期運作,可以利用網頁主控台。著手解決錯誤時,重點是要透過函式 `console.log()`(或 p5.js 中的 `print()`)來準確辨識出錯誤發生的位置,亦即是哪個區塊或哪一行程式碼出錯。請逐步測試並運行程式的各個部分,然後試著辨識錯誤類型,並以相應的方式除錯。 ## While () 藉由錯誤的相關討論,我們可以回頭探討「酷詢」的含義:詢問資料等東西是否有效或準確,但在此之前,亦先對有效或準確的定義進行質疑。除非我們能對資料及其執行條件提出進一步的問題,否則這邊恐會有自我實現預言的危險。例如說,當談到大數據時,人們傾向於將非結構化資料視為原始、無媒介的,而在實務中,卻總是會出現一些關於這類資料組成的額外資訊,尤其是從最開始收集資料的方式中獲得的資訊。更具「鑑識性」(forensic)的方法,則會揭示資料是透過何種方式來選擇、預先處理與清理等等。這與艾亞爾・魏茲曼(Eyal Weizman)和湯馬斯・基南(Thomas Keenan)對「鑑識」的定義一致,他們認為,「鑑識」不僅僅是資料收集或擷取的科學方法: > 「當然,鑑識不僅涉及科學,還涉及科學發現的呈現,涉及科學作為一種說服的藝術。這個詞源自拉丁語『forensis』,詞根『forum』(論壇)乃是關於在專業、政治或法律集會中提出論點的實務和技能。古典修辭學中,這樣的技巧關乎讓物件在論壇上發言。因為它們不能自己說話,所以需要在『事物的語言』和人的語言之間進行翻譯、調解或闡釋。」 [^forensis] 使用鑑識這種方式,不僅可以偵測資料的特徵或模式,還可以產生新的形式、形狀或引數:讓資料為自己發聲,就如法庭上的證人般,並揭露資料中不直接可見的方面。這些原則更是魏茲曼所在的「鑑識建築」小組的工作基礎[^FA],其中,鑑識學實務係指在法律和政治過程中產生和呈現建築證據,使得資料可以像人類提供口頭證詞一樣提供作證的能力。在此情況下,知識是以非常精確的方式產生,而非透過以扭曲的方式理解大數據的典型演算法,進行過度簡化的概括。 正如引言中所述,搜尋或饋給等簡單操作,是以企業利益為依歸的明確方式來排序資料並將資訊具體化。這種政治性與安朵涅特・魯夫羅伊(Antoinette Rouvroy)所言之「演算法治理術」(algorithmic governmentality,其中「governmentality」一詞的意義結合了「政府」和「理性」兩個術語)互相呼應,展現出我們的思維是如何被各種技術所塑造。[^Rouvroy]根據魯夫羅伊的說法,使用機器來篩選知識的情況越來越常見,而這些機器又是利用對內容本身或知識如何產生不感興趣的搜尋引擎來篩選知識,因此,有越來越多的知識是以「不含真理」的方式傳遞。令人擔憂的是,演算法更開始定義什麼才算是知識,而這可謂是更深一層的主體化(我們成為主體的過程)案例。魯夫羅伊聲稱:「新出現且即時演化發展的『真理政權』(truth regime)相對於『舊的』權威、等級制度和看似僵化的分類和措施,表面上看來或許是『解放』和『民主』的,但這種真理政權產生的『主體』卻是『大量卻毫無相異性』的。」[^Rouvroy2]在此情況下,人類主體透過積聚大量資料的過程而產生,而這樣的人類主體,乃是關乎演算法對我們的意圖、手勢、行為、習慣、觀點或欲望的理解[^chun],魯夫羅伊稱上述過程為「沒有主體的個人化」,並指出透過演算法治理進行資料探勘和分析的主體化過程才是問題所在,因此,過分關注個人資料相關的憂慮顯然是種失焦。 如果您把這些想法放在心中,本章開頭提及之柯妮莉亞・索弗蘭克(Cornelia Sollfrank)的 *Female Extension* 計畫力量就會變得更加強大,因為它破壞了個人化過程。「藝術作業系統」其實是由男性所宰制,雖然這個系統盲目地相信自己具備自由主義式的包容主張,但這整件事都是假的。談及 Google 及其營運作業,我們可以看到,儘管 Google 提供了可用於實驗的 API,但這是有限制的,API 請求僅限公共和非營利/教育目的,並且僅透露部分可用參數,而其中,透過演算法呈現作為知識的搜尋資料的邏輯仍然不為大眾所知。*nag* 不僅透過資料請求的執行及其回應,更透過對文化「規範」是否永久存在的質疑,強調了資料查詢這件事。例如,薩菲亞・烏莫加·諾布爾(Safiya Umoja Noble)便在《壓迫演算法》(Algorithms of Oppresion)一書中,展示了霸權式的搜尋結果,是如何強化種族主義: > 「搜尋發生在高度商業化的環境中,可以搜尋到的內容是由各種過程所決定;隨後,這些結果經過標準化,成為可信的結果,此外更經常被呈現為事實,並成為我們使用數位技術和電腦的經驗的標準部分,這促使我們相信,這些產生物也因此必須提供可信、準確,同時又去政治化而中立的資訊。」[^noble] 資訊的組織是透過概括過程建構出來的。關於更高階的資料探勘過程和統計建模,亞德里安・麥肯齊(Adrian Mackenzie)談到了工作中推動機器學習發展的各種概括化。[^Mackenzie1]認識到模式辨識和統計的所有技術如何「產生與個人欲望實例相關的陳述和快速行動」,以及這些技術如何對資料進行轉換、建構,並賦予形狀,以便「發現、決定、分類、排名、聚類、推薦、標記或預測」某事物或其他事物[^Mackenzie2]是箇中關鍵。正如麥肯齊所指出的,此處的假設,是存在於世上的一切都可以化約為穩定且獨特的分類:「在所有情況下,預測都取決於分類,而分類本身就假設了類別以及定義類別成員資格的屬性都是存在的。」[^Mackenzie3]這種穩定的類別和分類假設,是我們想在這裡「查詢」的主要問題之一,因為這樣的假設,好像代表著世界就是這樣組織的一般,但顯然並非如此。此處的困難之處,則在於明白模型在多大程度上是準確或有效的。 以這種方式「酷詢」資料,又引發了更進一步的問題:資料是如何被收集、儲存、分析、推薦、排名、選擇和策劃,以便理解更廣泛的社會和政治影響,尤其是性別和種族等分類,是如何被正常化和霸權化。從女性主義的角度質疑材料的權力結構,就是要理解「塑造現實的機制」[^feminist],以及這些機制如何被重新編程。 ## 迷你習作:使用 API 工作(分組) **目標:** * 設計並實作使用 web API 的程式[^Oauth]。 * 學習協作編寫程式碼並構想出程式。 * 反思透過 API 的資料解析過程,並留意資料的定位、可用性、選擇和操縱。 **更多靈感:** * *Queer Motto API* by Winnie Soon and Helen Pritchard (2021) with code example, <http://siusoon.net/queer-motto-api>, <https://editor.p5js.org/siusoon/sketches/7UAv17xw8> * Open Weather(含範例程式碼)<https://www.youtube.com/watch?v=ecT42O6I_WI>. * 其他天氣 API 示例(含程式碼範例)<https://p5js.org/examples/hello-p5-weather.html>. * 《紐約時報》(含程式碼範例)<https://www.youtube.com/watch?v=IMne3LY4bks&list=PLRqwX-V7Uu6a-SQiI4RtIwuOrLJGnel0r&index=9>. * Giphy 圖片(含程式碼範例)<https://www.youtube.com/watch?v=mj8_w11MvH8&index=10&list=PLRqwX-V7Uu6a-SQiI4RtIwuOrLJGnel0r>. * 維基百科 API:<https://www.youtube.com/watch?v=RPz75gcHj18>. * [Twitter API 和 Twitter 機器人](http://shiffman.net/a2z/twitter-bots/)(含程式碼範例)(請留意,Twitter 註冊 API 的規則變得更加嚴格,您需要提出令人信服的提案,而且審查過程可能會很漫長) * 搜尋[各種其它類型的 API](https://www.programmableweb.com/). **任務(RunME):** 這裡將提供一個相對複雜的練習,您要做的事情如下: * 請設計一個程式,其中須使用至少一個 web API,設計時須: * 尋找可用的 web API,以及您想要探索的資料。 * 了解可用資料:資料的檔案格式,以及 API 的規格要求。 * 決定您想選擇的資料欄位,以進行探索和實驗。 * 利用 web API 和您程式中的相應資料(若您的資料是從其它平台取得,註冊過程可能會相當漫長,因此請為此保留更多時間)。 **在您的 ReadMe 檔案中可供思考的問題:** * 這個程式是關於什麼的?您使用了哪個 API?為什麼使用它呢? * 您能否描述並反思您在迷你習作中取得、處理、使用和表示資料的過程? 您對這些資料了解多少,或者說,您想在哪部分了解更多? * 平台提供者如何排序資料,並為您提供所需的資料?所選 API 中的權力關係是什麼?API 在數位文化中又有何重要意義? * 請試著就您若有更多時間,會想進一步研究的 web API 或查詢/解析過程提出相關問題。 ## 指定讀物 * David Gauthier, Audrey Samson, Eric Snodgrass, Winnie Soon, and Magda Tyżlik-Carver, "Executing," in Nanna Thylstrup, Daniela Agostinho, Annie Ring, Catherine D’Ignazio and Kristin Veel, eds., *Uncertain Archives* (Cambridge, MA: MIT Press, 2021). * Daniel Shiffman, "Working with data - p5.js Tutorial," *The Coding Train* (10.1, 10.4 - 10.10), <https://www.youtube.com/playlist?list=PLRqwX-V7Uu6a-SQiI4RtIwuOrLJGnel0r>. * Eric Snodgrass and Winnie Soon, "API practices and paradigms: Exploring the protocological parameters of APIs as key facilitators of sociotechnical forms of exchange]," *First Monday* 24, no.2 (2019), <https://doi.org/10.5210/fm.v24i2.9553>. ## 延伸讀物 * Jonathan Albright, "The Graph API: Key Points in the Facebook and Cambridge Analytica Debacle," *Medium* (2018), <https://medium.com/tow-center/the-graph-api-key-points-in-the-facebook-and-cambridge-analytica-debacle-b69fe692d747>. * Taina Bucher, “Objects of intense feeling: The case of the Twitter API,” in *Computational Culture*, Nov 27 (2013), <http://computationalculture.net/article/objects-of-intense-feeling-the-case-of-the-twitter-api>. * Christoph Raetzsch, Gabriel Pereira, and Lasse S. Vestergaard, "Weaving Seams with Data: Conceptualizing City APIs as Elements of Infrastructures," *Big Data & Society*, Jan (2019), <https://journals.sagepub.com/doi/full/10.1177/2053951719827619>. ## 註釋 [^chun]: Wendy Hui Kyong Chun, *Updating to Remain the Same: Habitual New Media* (Cambridge, MA: MIT Press, 2016). [^bigdick]: 凱瑟琳・狄格納奇歐(Catherine D'Ignazio)和勞倫・克萊因(Lauren Klein)將大數據稱為「大屌數據」,以嘲諷的口吻,稱大數據計畫的特點是「透過資料擷取和分析而實現的男性主義,並總結其統治世界的幻想」,請參閱:"The Numbers Don’t Speak for Themselves," in *Data Feminism* (Cambridge, MA, MIT Press 2020), 151。 [^netcultures]: René König and Miriam Rasch, "Reflect and Act! Introduction to the Society of the Query Reader," in René König and Miriam Rasch, eds. *Society of the Query: Reflections on Web Search* (Amsterdam: The Institute of Network Cultures, 2014), <https://networkcultures.org/query/2014/04/23/reflect-and-act-introduction-to-the-society-of-the-query-reader/>. [^api]: 參見:Ashok K. Chandra and David Harel, "Computer Queries for Relational Data Bases," *Journal of Computer and System Sciences* 21, no.2 (1980): 156-178; Winnie Soon, *Executing Liveness: An Examination of the Live Dimension of Code Inter-actions in Software (Art) Practice*, PhD dissertation, Aarhus University (2016); Eric Snodgrass and Winnie Soon, "API practices and paradigms: Exploring the protocological parameters of APIs as key facilitators of sociotechnical forms of exchange," *First Monday* 24, no.2 (2019)。 [^queering]: 譯註:英文中「查詢」(querying)與「酷兒化」(queering)諧音,此處將「que(e)rying」譯為「酷詢」,代表查詢的同時,仍要質疑規範化的資料。 [^nag]: 自 1997 年以來,七位程式設計師分別在 nag 計畫的各個階段實現了五個不同版本的 nag。2003 年,第五版開始使用來自 Google 搜尋的圖片,但於 2015 年損毀。當前版本 5b 是由孫詠怡於 2017 年更新,為根據規範正式使用 Google 圖片搜尋 API 的版本。請參閱 <http://net.art-generator.com/>。 [^extension]: *Extension* 係由漢堡藝術博物館(Hamburger Kunsthalle)的當代藝術畫廊(Galerie der Gegenwart)贊助。儘管女性藝術家提交的作品數量甚多,但只有男性藝術家晉級決賽,顯然不成比例。決賽名單宣布後,索弗蘭克便公開了此事。關於 *Female Extension* 的一些檔案,請見:<http://www.artwarez.org/femext/index.html>。 [^obn]: Old Boys Network(OBN)被許多人認為是第一個國際性網路女性主義聯盟,1997 年成立於柏林。見 <https://www.obn.org/>。 [^hack]: 索弗蘭克在此使用了湯瑪斯・烏爾芬(Thomas Wulffen)的話,出自 "Hacking the Art Operating System," interviewed by Florian Cramer, Chaos Computer Club, Berlin (2001)。 [^json]: 請見:<https://p5js.org/reference/#/p5/loadJSON>。 [^img1]: 請見:<https://p5js.org/reference/#/p5/loadImage>。 [^img2]: 請見:<https://p5js.org/reference/#/p5/image>。 [^pixel]: 請參閱 `loadPixels()` 的參考指南:<https://p5js.org/reference/#/p5/loadPixels>。 [^key]: 欲從其他圖片相關平台(例如 Giphy 和 Pexels)請求 API 金鑰,請參閱 <https://support.giphy.com/hc/en-us/articles/360020283431-Request-A-GIPHY-API-Key> 和 <https://www.pexels.com/api/>。 [^google1]: 請見:<https://developers.google.com/custom-search/v1/overview>。 [^google2]: 請見:<https://cse.google.com/all>。 [^setting]: 還有其他可選參數,詳情請參閱:<https://developers.google.com/custom-search/json-api/v1/reference/cse/list#parameters>。 [^w3c]: 請參閱 W3C對 CORS 的推薦:<https://www.w3.org/TR/cors/>。 [^soon]: Snodgrass and Soon, "API Practices and Paradigms." [^nyu]: 有關 p5.js 中圖片處理的教學,請參見:<https://idmnyu.github.io/p5.js-image/>。 [^eckhardt]: 1930 年代中期,這種將圖片分解為色階像素的方法也被用於電子電視的傳輸,但資料是由電報員透過電報或無線電手動發送。參見:George H, Eckhardt, *Electronic television* (Chicago: Goodheart-Willcox Company, Incorporated, 1936), 48-50。 [^debug]: 傑森・阿德曼(Jason Alderman)、泰加・布雷恩(Tega Brain)、崔太允(Taeyoon Choi,音譯)和路易莎・皮蕾拉(Luisa Pereira)為 p5.js 貢獻者會議開設了一個程式除錯課程,請參閱:<https://p5js.org/learn/debugging.html>。 [^forensis]: Thomas Keenan and Eyal Weizman, *Mengele's Skull: The Advent of a Forensic Aesthetics* (Berlin: Sternberg Press, 2012); 亦可參閱:Matthew Kirschenbaum, *Mechanisms: New Media and the Forensic Imagination* (Cambridge, MA: MIT Press, 2008)。 [^FA]: 鑑識建築小組由埃亞爾・魏茲曼(Eyal Weizman)領導,是一家隸屬倫敦大學金匠學院的研究機構,與受政治暴力影響的社群和人權組織、國際檢察官、環境正義團體和媒體站在一起,並代表他們對侵犯人權的案件進行先進的空間與媒體調查。請參閱:<https://forensic-architecture.org/>。 [^Rouvroy]:「治理術」(governmentality)的概念源自於米歇爾・傅柯的著作,特別是他於 1982 到 1983 年間在法蘭西學院的演講。2013 年 10 月,魯夫羅伊於網路文化研究所以「演算法治理與批評的終結」(Algorithmic Governmentalities and the End(s) of Critique)為題進行演講,其間她提出如下論點:如果無法更全面地理解知識是如何產生的,那麼批評便不可能實現。 [^Rouvroy2]: 參見:Antoinette Rouvroy, "Technology, Virtuality and Utopia: Governmentality in an Age of Autonomic Computing," in Mireille Hildebrandt and Antoinette Rouvroy, eds., *Autonomic Computing and Transformations of Human Agency* (London: Routledge, 2011)。 [^noble]: Safiya Umoja Noble, *Algorithms of Oppression: How Search Engines Reinforce Racism* (New York: New York University Press, 2018), 24-25. [^Mackenzie1]: Adrian Mackenzie, "The Production of Prediction: What Does Machine Learning Want?" *European Journal of Cultural Studies* 18, nos.4-5 (2015): 431. [^Mackenzie2]: Mackenzie, "The Production of Prediction", 432. [^Mackenzie3]: Mackenzie, "The Production of Prediction", 433. [^feminist]: Cornelia Sollfrank, ed. *Beautiful Warriors: Technofeminist Praxis in the Twenty-First Century* (New York: Autonomedia/Minor Compositions, 2019), 6. [^Oauth]: 針對需要 OAuth 2.0 授權(標準授權協定)的 API,您可能會需要以 Node.js(<https://nodejs.org/en/>)來處理伺服器用戶端驗證。我們建議初學者尋找已註冊 API 金鑰的 web API。欲檢視 15.1 和 15.2 的 Node,請見(<https://www.youtube.com/watch?v=RF5_MPSNAtU&index=1&list=PLRqwX-V7Uu6atTSxoRiVnSuOn6JHnq2yV>),欲了解 Internet Engineering Task Force 在 2012 年提出的 OAuth 2.0 授權框架,請見:<https://tools.ietf.org/html/rfc6749>。 [^edison]: 「bug」一詞是由湯馬斯・愛迪生(Thomas Edison)在 1873 年創造,用來描述技術問題,例如電氣設備連接中的故障。參見:Alexander Magoun and Paul Israel, "Did You Know? Edison Coined the Term 'Bug'," *IEEE Spectrum* (August 1, 2013), <https://spectrum.ieee.org/the-institute/ieee-history/did-you-know-edison-coined-the-term-bug>。 [^hopper]: 該日誌存檔於美國國家歷史博物館:<https://americanhistory.si.edu/collections/search/object/nmah_334663>。 [^w3c]: 請見:<https://w3c.github.io/webappsec-cors-for-developers/>。

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully