20200225のJavaScriptに関する記事は23件です。

TypeScript 3.7のNullish Coalescingで少し嵌った話

概要

TypeScript 3.7で追加されたNullish Coalescingは現場で使用しておりとても重宝しています。
nullとunderstandのみ判定できるので簡単に任意の型にすることが出来るのですが、
今回、愚直に使用した結果、発生した現象がありました。

今回は例文とそれをトランスパイルした実際に実行されたコードも出して解説?したいと思います。
もし、今後同じようなことは起きる人がいた時にこの記事で解決の糸口になれば良いなとって思います。

事象

先ずは実際に判定できなかった時のコードと同等のものになります。

typescript
interface MyFavorite {
  lastName?: string;
  firstName?: string;
}

const myFavorite: MyFavorite = {};

const result = myFavorite.lastName && myFavorite.firstName
  ? myFavorite.lastName + " " +  myFavorite.firstName
  : myFavorite.lastName ?? "" + myFavorite.firstName ?? ""
;

console.log(result )

とします。
この場合、trueの場合は説明するまでもないと思います。

問題なのはfalse判定だった時です。
この場合、実装者(今回は僕)の期待値としては空文字列を期待していました、

しかし実際に出力された文字は"undefined"と表示されてしました。

もうダメだ。。。
救いはないんですか!?

ってなりました。

原因

この現象を見たとき、処理の評価順がどーなっているかを調べました。
TypeScriptをコンパイルしてJavaScriptに変換してみました。

そしたら以下コードになりました。

javaScript
var _a, _b;
const myFavorite = {};
const result = myFavorite.lastName && myFavorite.firstName
    ? myFavorite.lastName + " " + myFavorite.firstName
    : (_b = (_a = myFavorite.lastName, (_a !== null && _a !== void 0 ? _a : "" + myFavorite.firstName)), (_b !== null && _b !== void 0 ? _b : ""));
console.log(result);

となりました。

問題のコードは三項演算子のfalseの部分ですね。

(
  _b = (
    _a = myFavorite.lastName, (_a !== null && _a !== void 0 ? _a : "" + myFavorite.firstName)
  ),
  (_b !== null && _b !== void 0 ? _b : "")
)

これをみた瞬間全てを理解しました。

処理の順番としては
 1. aにmyFavorite.lastNameを代入(_aにはundefined)
 2. _aがnull又はunderstandではない場合、_aはそのまま(今回はこっちではない)
 3. _aがnull又はunderstandだった場合、空文字列とmyFavorite.firstNameを結合して
aに代入 ← ここ
 4. 以下はそのまま(決してめんどくさいわけではない)
 
つまり僕の脳内では

(myFavorite.lastName ?? "") + (myFavorite.firstName ?? "")

このようなイメージでいたのですが実際は

((myFavorite.lastName ?? "") + myFavorite.firstName) ?? ""

このように評価されていたそうです。
間違えていたらこっそり教えてください

これでは空文字列とunderstandを結合していることになる為、
"understand"の文字列を生成しておりました。

確かに遅延評価なので理解はしましたが、納得はちょっと・・・てなりました。
まぁ~サボって愚直な実装した僕が悪いんですけどね・・・

最後に

ちょっと使いなれたからって愚直な実装は良くないですね。
このおかげで学ぶ機会があったので良かったですが、改めて慣れって怖いですね。
皆さんも予期せぬ落とし穴に嵌らないように気を付けましょう!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ブラウザでウェブカメラ映像のタッチのから色をRGBY-BK-WH判別

ブラウザでカメラ映像から色を判別するときに利用したチップスをメモ

ウェブカメラ動画の取得

videoタグ配置しJSでカメラ取得
※localhost,127.0.0.1 や HTTPS の環境がないと動作しないでした。。

<video id="videoInput" width="640" height="480" autoplay></video>
var video = document.getElementById('videoInput')
navigator.mediaDevices.getUserMedia({
  video: {
    facingMode: "environment",
  },
  audio: false,
})
  .then(function (stream) {
    video.srcObject = stream;
    video.play();
  })
  .catch(function (err) {
    console.error(err);
  });

カンバスへ変換(描画)

HTMLでカンバスを設置

<canvas id="canvasOutputVideo" width="640" height="480"></canvas>

IntervalでVideoタグの内容をカンバスへ描画

var canvas = document.getElementById("canvasOutputVideo");
var context = canvas.getContext("2d");
setInterval(updateCap, 100);
function updateCap() {
  context.drawImage(video, 0, 0, 640, 480);
};

タッチ箇所の取得

下記のどれかで取得となるはず

console.log("screen:" + e.screenX + "," + e.screenY);
console.log("client:" + e.clientX + "," + e.clientY);
console.log("offset:" + e.offsetX + "," + e.offsetY);

平均の色を取得

クリック箇所を中心に3*3の9ドットの平均を算出
カンバスから取得

let imageData = document.getElementById("videoCanvas").getContext("2d").getImageData(click.x-1 , click.y-1 , 3, 3);
let rgba = [0, 0, 0, 0];
imageData.data.forEach((v, i) => {
  rgba[i % 4] = rgba[i % 4] + v
});
const r = rgba[0] / (iW * iH);
const g = rgba[1] / (iW * iH);
const b = rgba[2] / (iW * iH);
const a = rgba[3] / (iW * iH);
let resRGBA = [Math.ceil(r), Math.ceil(g), Math.ceil(b), Math.ceil(a)];

RGBをHSVへ変換

色を純粋に判定したい場合はHSVが便利

  • H:色相 RGB的な色を判定に利用
  • S:彩度 白の判定に利用
  • V:明度 黒の判定に利用
function rgb2hsv (rgb) {
  var r = rgb[0] / 255;
  var g = rgb[1] / 255;
  var b = rgb[2] / 255;
  var max = Math.max(r, g, b);
  var min = Math.min(r, g, b);
  var diff = max - min;
  var h = 0;
  switch (min) {
    case max: h = 0; break;
    case r: h = (60 * ((b - g) / diff)) + 180; break;
    case g: h = (60 * ((r - b) / diff)) + 300; break;
    case b: h = (60 * ((g - r) / diff)) + 60; break;
  }
  var s = max == 0 ? 0 : diff / max;
  var v = max;
  return [h, s, v];
}

RGBY,BK,WHに判別

色相0~360、彩度0~1、明度0~1を利用して判別

やんわり力技なので、Sinとか使ってうまいことできないか、模索したが挫折しこの状態へ。。

function checkColor (rgba) {
  var ret = "";
  var hsvRGBA = U.rgb2hsv(rgba);//色相
  var hRGBA = hsvRGBA[0];//色相
  var sRGBA = hsvRGBA[1];//彩度0で白
  var vRGBA = hsvRGBA[2];//明度0で黒
  if (sRGBA < 0.2) {
    ret = "White";
  } else if (vRGBA < 0.2) {
    ret = "Black";
  } else if (
    (315 < hRGBA && hRGBA <= 360) ||
    (0 < hRGBA && hRGBA <= 45)
  ) {
    ret = "Red";
  } else if (
    (45 < hRGBA && hRGBA <= 135)
  ) {
    ret = "Yellow";
  } else if (
    (135 < hRGBA && hRGBA <= 200)
  ) {
    ret = "Green";
  } else if (
    (200 < hRGBA && hRGBA <= 315)
  ) {
    ret = "Blue";
  }
  return ret;
}

参考サイト

HSV色空間
https://www.peko-step.com/html/hsv.html

RGBをHSVに変換する方法
https://lab.syncer.jp/Web/JavaScript/Snippet/66/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GASを試して図書館のサイトをスクレイピングしようとしたけど断念した

概要

GASを試した。
図書館のサイトをスクレイピングしようとしたけど断念した。
なぜか、セッションをキープできない。
fetchのたびにIPが変わっちゃうから?(他に原因がある可能性あり。)

はじめに

GASに興味あって、少し触ってみた。
シンプルなことやってる人のサイトを参考にいくつか試してみた。
前からやりたかった、図書館のサイトのスクレイピングも試してみた。

試しにGoogle SheetsでGAS

試しに、Google SheetsでGAS使う練習をしてみた。

この人のを見て、真似してみる。
【GAS初級者向け】Google Apps Scriptで バイトの給与を予測するアプリを作ろう - Qiita
時間を測りたいわけではないので、イベント名だけ表示する関数にしてみた。

コードはこんな感じ。

code.gs
function myFunction() {
  var objSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var objSheet = objSpreadsheet.getActiveSheet();
  var myCal = CalendarApp.getCalendarById('xx@yy'); 
  var today = new Date();
  var date = today.setDate(1);
  var startDate = new Date(date);
  var endDate = new Date(date);
  endDate.setMonth(endDate.getMonth()+1);
  myEvents = myCal.getEvents(startDate,endDate);

  for (var i in myEvents) {
    var title = myEvents[i].getTitle();
    objSheet.getRange(i+1,1,1,1).setValue(i); 
    objSheet.getRange(i+1,2,1,1).setValue(title); 
  }
}

作業画面はこんな感じ。

image.png

結果はこんな感じ。
なぜか、10行ごとに入力される。なぜに?

image.png

こんな感じで書くと、ちゃんと1行おきに表示されるんやけど、なぜに??

var hoge = [10,11,12,13];
for (var i in hoge){
for (var i=1; i<4; i++){
  objSheet.getRange(i+1,1).setValue(i);
  objSheet.getRange(i+1,2).setValue(hoge[i]);
}

試しにメール送信

初心者でも簡単!Google Apps ScriptでGmailを操作してメールを送る方法

この人のコードをコピペ。
すんなり動いた。

GETしてほしい情報を取得

Google App ScriptでWebスクレイピングしたら楽だった - phicdy devlog
このサイトを参考に、ほしい情報取得した。

JavaScript 正規表現まとめ - Qiita
正規表現は、ここら確認した。

ログインセッションをキープして情報取得

ここらを参考にクッキーを保存して試してみたけれど、うまくいかなかった。

GoogleスプレッドシートでGET/POST通信を行いコンテンツを取得する - ソフラボの技術ブログ
いろいろ試してみたあと、このサイトにたどり着いた。

GoogleAppsScriptは、サーバーサイド言語ですのでサーバー側で実行されます。fetch毎にサーバーのIPアドレスが変わる仕様のようで、セッションを維持する必要のあるサイトへ接続し、一連の処理を行おうとしても、IPアドレスが変わっているため同一セッションと扱われないので注意してください。

これのせいな気がする。ブラウザとサーバーとで、Cookieだけじゃなくて、authenticity_tokenってのをやりとりしてるっぽくて、それが変わっちゃってるんじゃないかと思う。半分、想像やけど。
デバッグ環境がよくわからないので、調査するの大変そう。ということで、諦めた。

一応、試行錯誤の結果のコードをおいておく。

function getKobeLibInfo(){
  var url = 'https://www.lib.city.kobe.jp/opac/opacs/mypage_display';
  var response = UrlFetchApp.fetch(url);
  var html = response.getContentText('UTF-8');

  var reg = /<input type="hidden" name="authenticity_token" value="(\S*)" \/>/i;
  var match = reg.exec(html);

  var cookies = response.getAllHeaders()['Set-Cookie']; 
  session_cookie = cookies[0].split( ';' )[0];
  Logger.log(session_cookie);
  cookies = "locale=ja; cokkie=opac_server2; searchkan=all; " + session_cookie;
  //  Logger.log(match[0]);
  var auth_token = match[1];
  Logger.log(match[1]);

  var payload = {
    'utf8': '',
    'user[login]': 'xxx',
    'user[passwd]': 'yyy',
    'act_login': 'ログイン',
    'nextAction': 'mypage_display',
    'prevAction': '',
    'prevParams': '',
    'kobeid': '',
    'pvolid': '',
    'type': '',
    'shozo_kyk': '',
    'authenticity_token':auth_token
  };

  var headers = {'Cookie' : cookies,
                 'Connection': 'keep-alive',
                 'Content-Type': 'application/x-www-form-urlencoded'
                };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : payload
  };
  response = UrlFetchApp.fetch("https://www.lib.city.kobe.jp/opac/opacs/login", options);
  Logger.log(response);
  var cookies = response.getAllHeaders()['Set-Cookie']; 
  session_cookie = cookies[0].split( ';' )[0];
  Logger.log(session_cookie);
  cookies = "locale=ja; cokkie=opac_server2; searchkan=all; " + session_cookie;
  // Logger.log(response);
  var headers = {'Cookie' : cookies,
                 'Connection': 'keep-alive',
                 'Content-Type': 'application/x-www-form-urlencoded'
                };

  var options = {
    "method" : "get",
    "headers" : headers
  };

  var response = UrlFetchApp.fetch("https://www.lib.city.kobe.jp/opac/opacs/mypage_display", options);

  var html = response.getContentText('UTF-8');

  Logger.log(html);
}

おわりに

結構がんばったけど、やりたいことはできなかった。
まあしょうがないか。
ただ、GAS使えるようになってうれしい。
他にもいろんなことに使えそう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GASを使って図書館のサイトから自分の借りてる本と予約してる本の情報を取得しようとしたけど断念した

概要

GASを試した。
GASを使って図書館のサイトから自分の借りてる本と予約してる本の情報を取得しようとしたけど断念した。
なぜか、セッションをキープできない。
fetchのたびにIPが変わっちゃうから?(他に原因がある可能性あり。)

はじめに

GASに興味あって、少し触ってみた。
シンプルなことやってる人のサイトを参考にいくつか試してみた。
前からやりたかった、図書館のサイトのスクレイピングも試してみた。

試しにGoogle SheetsでGAS

試しに、Google SheetsでGAS使う練習をしてみた。

この人のを見て、真似してみる。
【GAS初級者向け】Google Apps Scriptで バイトの給与を予測するアプリを作ろう - Qiita
時間を測りたいわけではないので、イベント名だけ表示する関数にしてみた。

コードはこんな感じ。

code.gs
function myFunction() {
  var objSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var objSheet = objSpreadsheet.getActiveSheet();
  var myCal = CalendarApp.getCalendarById('xx@yy'); 
  var today = new Date();
  var date = today.setDate(1);
  var startDate = new Date(date);
  var endDate = new Date(date);
  endDate.setMonth(endDate.getMonth()+1);
  myEvents = myCal.getEvents(startDate,endDate);

  for (var i in myEvents) {
    var title = myEvents[i].getTitle();
    objSheet.getRange(i+1,1,1,1).setValue(i); 
    objSheet.getRange(i+1,2,1,1).setValue(title); 
  }
}

作業画面はこんな感じ。

image.png

結果はこんな感じ。
なぜか、10行ごとに入力される。なぜに?

image.png

こんな感じで書くと、ちゃんと1行おきに表示されるんやけど、なぜに??

var hoge = [10,11,12,13];
for (var i in hoge){
for (var i=1; i<4; i++){
  objSheet.getRange(i+1,1).setValue(i);
  objSheet.getRange(i+1,2).setValue(hoge[i]);
}

試しにメール送信

初心者でも簡単!Google Apps ScriptでGmailを操作してメールを送る方法

この人のコードをコピペ。
すんなり動いた。

GETしてほしい情報を取得

Google App ScriptでWebスクレイピングしたら楽だった - phicdy devlog
このサイトを参考に、ほしい情報取得した。

JavaScript 正規表現まとめ - Qiita
正規表現は、ここら確認した。

ログインセッションをキープして情報取得

ここらを参考にクッキーを保存して試してみたけれど、うまくいかなかった。

GoogleスプレッドシートでGET/POST通信を行いコンテンツを取得する - ソフラボの技術ブログ
いろいろ試してみたあと、このサイトにたどり着いた。

GoogleAppsScriptは、サーバーサイド言語ですのでサーバー側で実行されます。fetch毎にサーバーのIPアドレスが変わる仕様のようで、セッションを維持する必要のあるサイトへ接続し、一連の処理を行おうとしても、IPアドレスが変わっているため同一セッションと扱われないので注意してください。

これのせいな気がする。ブラウザとサーバーとで、Cookieだけじゃなくて、authenticity_tokenってのをやりとりしてるっぽくて、それが変わっちゃってるんじゃないかと思う。半分、想像やけど。
デバッグ環境がよくわからないので、調査するの大変そう。ということで、諦めた。

一応、試行錯誤の結果のコードをおいておく。

function getKobeLibInfo(){
  var url = 'https://www.lib.city.kobe.jp/opac/opacs/mypage_display';
  var response = UrlFetchApp.fetch(url);
  var html = response.getContentText('UTF-8');

  var reg = /<input type="hidden" name="authenticity_token" value="(\S*)" \/>/i;
  var match = reg.exec(html);

  var cookies = response.getAllHeaders()['Set-Cookie']; 
  session_cookie = cookies[0].split( ';' )[0];
  Logger.log(session_cookie);
  cookies = "locale=ja; cokkie=opac_server2; searchkan=all; " + session_cookie;
  //  Logger.log(match[0]);
  var auth_token = match[1];
  Logger.log(match[1]);

  var payload = {
    'utf8': '',
    'user[login]': 'xxx',
    'user[passwd]': 'yyy',
    'act_login': 'ログイン',
    'nextAction': 'mypage_display',
    'prevAction': '',
    'prevParams': '',
    'kobeid': '',
    'pvolid': '',
    'type': '',
    'shozo_kyk': '',
    'authenticity_token':auth_token
  };

  var headers = {'Cookie' : cookies,
                 'Connection': 'keep-alive',
                 'Content-Type': 'application/x-www-form-urlencoded'
                };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : payload
  };
  response = UrlFetchApp.fetch("https://www.lib.city.kobe.jp/opac/opacs/login", options);
  Logger.log(response);
  var cookies = response.getAllHeaders()['Set-Cookie']; 
  session_cookie = cookies[0].split( ';' )[0];
  Logger.log(session_cookie);
  cookies = "locale=ja; cokkie=opac_server2; searchkan=all; " + session_cookie;
  // Logger.log(response);
  var headers = {'Cookie' : cookies,
                 'Connection': 'keep-alive',
                 'Content-Type': 'application/x-www-form-urlencoded'
                };

  var options = {
    "method" : "get",
    "headers" : headers
  };

  var response = UrlFetchApp.fetch("https://www.lib.city.kobe.jp/opac/opacs/mypage_display", options);

  var html = response.getContentText('UTF-8');

  Logger.log(html);
}

おわりに

結構がんばったけど、やりたいことはできなかった。
まあしょうがないか。
ただ、GAS使えるようになってうれしい。
他にもいろんなことに使えそう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript メモ

  • ###var → 変数
  • ###function(){} → 関数
  • ###for → 繰り返し(終わりのある)
  • ###console.log → コンソールに表示
  • ###alert() → 警告
  • ###confirm() → 確認
  • ###prompt() → 入力
  • ###if(条件式) {条件式に合致する場合に行われる処理} → もし〜ならば
  • ###else {条件式に合致しない場合に行われる処理} → ifがダメなら
  • ###switch(条件) { case 値1: //処理 break; }

比較演算子

  • ###A > B AはBより大きい
  • ###A >= B AはB以上
  • ###A === B AとBは等しい
  • ###A !== B AとBは等しくない

論理演算子

  • ###A && B AかつB (and)
  • ###A || B AまたはB (or)
  • ### !A Aではない(not)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

chart.jsのyAxes

SNMPのグラフをchart.jsで表示しているのだが、y軸がいまいちいけてない。

filename(1).png

              yAxes: [{
                  ticks: {
                    callback: function(value) { return value + " oct";},
                    min: 0
                  }
              }]

こんな風にしてみた。

              yAxes: [{
                  ticks: {
                    callback: function(value) { if (value == 0) { return value +
 " oct";} else if (value >= 1000000) { return (value / 1000000) + " moct";} else
{return (value / 1000) + " koct";}},
                    min: 0
                  }
              }]

filename(2).png

大きいトラフィックは外すと

filename(3).png

もっと外すと

filename(4).png

もっともっと外すと

filename(5).png

とりあえず今日はこれで良しとしよう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript メモ

var → 変数
function() {}→ 関数
for → 繰り返し(終わりのある)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スクリプト言語 KINX/基本編(1) - プログラム基礎・データ型

はじめに

前回の記事から。シリーズ第一弾は普通に基本編。概要は以下の前回の記事を参照してください。

前回お披露目してみたら★を付けてくださった方がいて、非常に浮かれています。ありがとうございました。温かいお気持ちで行く末を見届けてやってください。
- ここ (https://github.com/Kray-G/kinx) です。

見た目は JavaScript頭脳(中身)は Ruby、(安定感は AC/DC)」でお届けする スクリプト言語 KINX。オブジェクト指向と C 系シンタックスで C 系プログラマになじむ触感 を目指して。

Kinx 基本編(1) - プログラム基礎・データ型

プログラム基礎

hello, world

プログラムはトップレベルから記述可能。

hello.kx
System.println("hello, world.");

hello.kx という名前で保存し、以下のように実行.

$ ./kinx hello.kx
hello, world.

コメント

コメントは C/C++ 形式と Perl のような # 形式と両方利用可能。

/* Comment */
// Comment
# Comment

変数宣言

変数宣言は var で宣言する。

var a = 10;

初期化子を使って初期化するが、初期化子を書かなかった場合は null となる。ちなみに Kinx においては nullundefined は同じ意味(賛否あると思うが)。どちらも a.isUndefined が true となる。

データ型一覧

Kinx は動的型付け言語だが、内部に型を持っている。

Type CheckProperty Example Meaning
Undefined isUndefined null 初期化されていない値。
Integer isInteger, isBigInteger 100, 0x02 整数。演算では自動的に Big Integer と相互変換される。
Double isDouble 1.5 実数。
String isString "aaa", 'bbb' 文字列。
Binary isBinary <1,2,3> バイナリ値。バイトの配列。要素は全て 0x00-0xFF に丸められる。
Array isArray, isObject [1,a,["aaa"]] 配列。扱える型は全て保持可能。
Object isObject { a: 1, b: x } JSON のようなキーバリュー構造。
Function isFunction function(){},
&() => expr
関数。

Undefined 以外であれば isDefined で true が返る。

尚、真偽値としての truefalse は整数の 1、0 のエイリアスでしかないのに注意。
Boolean 型というのは特別に定義されていないが、オブジェクトとして真偽を表す TrueFalse という定数が定義されているので、整数値とどうしても区別したい場合はそちらを使用する。

System.println(True ? 1 : 0);   // 1
System.println(False ? 1 : 0);  // 0

ブロックとスコープ

ブロックはスコープを持ち、内側で宣言された変数は外側のブロックからは参照不可。同じ名前で宣言した場合、外側ブロックの同名変数は隠蔽される。

var a = 10;
{
    var a = 100;
    System.println(a);
}
System.println(a);

この辺が「見た目は JavaScript」であっても中身は JavaScript ではない感じの部分。というか、JavaScript のスコープは変態過ぎて使いづらい。

式(エクスプレッション)は、以下の優先順位で四則演算、関数呼び出し、オブジェクト操作等が可能。

# 要素 演算子例 評価方向
1 要素 変数, 数値, 文字列, ... -
2 後置演算子 ++, --, [], ., () 左から右
3 前置演算子 !, +, -, ++, -- 左から右
4 パターンマッチ =~, !~ 左から右
5 べき乗 ** 右から左
6 乗除 *, /, % 左から右
7 加減 +, - 左から右
8 ビットシフト <<, >> 左から右
9 大小比較 <, >, >=, <= 左から右
10 等値比較 ==, != 左から右
11 ビットAND & 左から右
12 ビットXOR ^ 左から右
13 ビットOR | 左から右
14 論理AND && 左から右
15 論理OR || 左から右
16 三項演算子 ? :, function(){} 左から右
17 代入演算子 =, +=, -=, *=. /=. %=, &=, |=, ^=, &&=, ||= 右から左

いくつか特徴を以下に示す。

演算

演算結果によって型が自動的に結果に適応していく。3/21.5 になる。

num = 3 + 2;    // 5
num = 3 - 2;    // 1
num = 3 * 2;    // 6
num = 3 / 2;    // 1.5
num = 3 % 2;    // 1

インクリメント・デクリメント

前置形式・後置形式があり、C と同様。

var a = 10;
System.println(a++);    // 10
System.println(++a);    // 12
System.println(a--);    // 12
System.println(--a);    // 10

データ型

数値

整数、実数

整数、実数は以下の形式。整数では可読性向上のため任意の場所に _ を挿入可能。_ は単に無視される。

var i = 2;
var j = 100_000_000;
var num = 1.234;

文字列

基本

ダブルクォートとシングルクォートの両方が使えるが、エスケープしなければならないクォート文字が異なるだけでどちらも同じ意味になる。

var a = "\"aaa\", 'bbb'";
var b = '"aaa", \'bbb\'';
System.println(a == b ? "same" : "different");  // same

内部式

%{...} の形式で内部に式を持つことができる。

for (var i = 0; i < 10; ++i) {
    System.println("i = %{i}, i * 2 = %{i * 2}");
}
// i = 0, i * 2 = 0
// i = 1, i * 2 = 2
// i = 2, i * 2 = 4
// i = 3, i * 2 = 6
// i = 4, i * 2 = 8
// i = 5, i * 2 = 10
// i = 6, i * 2 = 12
// i = 7, i * 2 = 14
// i = 8, i * 2 = 16
// i = 9, i * 2 = 18

フォーマッタ

文字列に対する % 演算子はフォーマッタ・オブジェクトを作成する。

var fmt = "This is %1%, I can do %2%.";
System.println(fmt % "Tom" % "cooking");

%1%1 はプレースホルダ番号を示し、% 演算子で適用した順に合わせて整形する。適用場所が順序通りであれば、C の printf と同様の指定の仕方も可能。さらに、C の printf と同じ指定子を使いながら同時にプレースホルダも指定したい場合は、$ の前に位置指定子を書き、'$' で区切って記述する。例えば、16進数で表示したい場合は以下のようにする。

var fmt = "This is %2%, I am 0x%1$02x years old in hex.";
System.println(fmt % 27 % "John");
// This is John, I am 0x1b years old in hex.

フォーマッタ・オブジェクトに後から値を適用していく場合は、%= 演算子で適用していく。

var fmt = "This is %1%, I can do %2%.";
fmt %= "Tom";
fmt %= "cooking";
System.println(fmt);

実際のフォーマット処理は、System.println 等で表示するとき、文字列との加算等が行われるとき、に実際に実行される。

Raw 文字列

文字列内部ではなく、%{...} で文字列を記載することで Raw 文字列を作成することが可能。%-{...} を使うと、先頭と末尾の改行文字をトリミングする。ヒアドキュメントのようにも使えるので、ヒアドキュメントはサポートしていない。また、%<...>%(...)%[...] を使うこともできる。

var a = 100;
var b = 10;
var str = %{
This is a string without escaping control characters.
New line is available in this area.
{ and } can be nested here.
};
System.println(str);
var str = %-{
This is a string without escaping control characters.
New line is available in this area.
But newlines at the beginning and the end are removed when starting with '%-'.
};
System.println(str);

\ でエスケープする必要があるのは、内部式を使う場合 %{% に対するものと、ネストした形にならないケースでのクォート文字である {} に対するものだけとなる。

また、カッコは対応する閉じカッコでクォートするが、以下の文字を使ったクォートも可能である。その場合は、開始文字と終了文字は同じ文字となる。例えば、%|...| のような形で使用する。

  • |, !, ^, ~, _, ., ,, +, *, @, &, $, :, ;, ?, ', ".

正規表現リテラル

正規表現リテラルは /.../ の形式で使う。リテラル内の /\ でエスケープする必要がある。以下が例。

var a = "111/aaa/bbb/ccc/ddd";
while (group = (a =~ /\w+\//)) {
    for (var i = 0, len = group.length(); i < len; ++i) {
        System.println("found[%2d,%2d) = %s"
            % group[i].begin
            % group[i].end
            % a.subString(group[i].begin, group[i].end - group[i].begin));
    }
}

/ を多用するような正規表現の場合、%m プレフィックスを付け、別のクォート文字を使うことで回避できる。例えば %m(...) といった記述が可能。これを使って上記を書き直すと、以下のようになる。

var a = "111/aaa/bbb/ccc/ddd";
while (group = (a =~ %m(\w+/))) {
    for (var i = 0, len = group.length(); i < len; ++i) {
        System.println("found[%2d,%2d) = %s"
            % group[i].begin
            % group[i].end
            % a.subString(group[i].begin, group[i].end - group[i].begin));
    }
}

尚、正規表現リテラルを while 等の条件式に入れることができるが注意点があるので補足しておく。例えば以下のように記述した場合、str の文字列に対してマッチしなくなるまでループを回すことができる(group にはキャプチャ一覧が入る)。その際、最後のマッチまで実行せずに途中で break 等でループを抜けると正規表現リテラルの対象文字列が次回のループで正しくリセットされない、という状況が発生する。

while (group = (str =~ /ab+/)) {
    /* block */
}

正規表現リテラルがリセットされるタイミングは以下の 2 パターン。

  • 初回(前回のマッチが失敗して再度式が評価された場合を含む)。
  • str の内容が変化した場合。

将来改善を検討するかもしれないが、現在は上記の制約があることに注意。

配列

配列は任意の要素を保持するリスト。インデックスでアクセスできる。またインデックスに負の数を与えることで末尾からアクセスすることもできる。

var a = [1,2,3];
var b = [a, 1, 2];
System.println(b[0][2]);    // 3
System.println(a[-1]);      // 3

配列構造は左辺値で使用すると右辺値の配列を個々の変数に取り込むことが可能。これを使用して値のスワップも可能。

[a, b] = [b, a];    // Swap

スプレッド(レスト)演算子を使っての分割も可能。

[a, ...b] = [1, 2, 3, 4, 5];
// a = 1
// b = [2, 3, 4, 5]

尚、以下の書き方はできない。変数は宣言なしで使用できる(最初に代入された時点で生成される)ため、var を付けない形で直接記述することは可能。ただしその際、外部のスコープで定義されていた場合、外側のスコープの変数の内容が書き換わってしまうことに注意。スコープで変数へのアクセス範囲を閉じたい場合は、予め var a, b; と宣言してから使うことで回避可能。

// var [a, ...b] = [1, 2, 3, 4, 5];    // error.
var a = 3, b = [4], x = 3, y = [4];
{
    var a, b;
    [a, ...b] = [1, 2, 3, 4, 5];
    // a = 1
    // b = [2, 3, 4, 5]
    [x, ...y] = [1, 2, 3, 4, 5];
    // x = 1
    // y = [2, 3, 4, 5]
    [z] = [1, 2, 3, 4, 5];
    // okay z = 1, but scoped out...
}
System.println("a = ", a);      // 3
System.println("b = ", b[0]);   // 4
System.println("x = ", x);      // 1
System.println("y = ", y[0]);   // 2

宣言と同時に使えると便利とは思うので、将来改善するかもしれない。

バイナリ

バイナリはバイト配列であり、<...> の形式で記述する。全ての要素は 0x00 ~ 0xFF の範囲にアジャストされ、配列のようにアクセス可能。

バイナリと配列は相互にスプレッド演算子で分割、結合することが可能。

var bin = <0x01, 0x02, 0x03, 0x04>;
var ary = [...bin];
    // ary := [1, 2, 3, 4]

var ary = [10, 11, 12, 257];
var bin = <...ary>;
    // bin := <0x0a, 0x0b, 0x0c, 0x01>

ただし、バイナリになった瞬間に 0x00-0xFF に丸められるので注意。

オブジェクト

いわゆる JSON。ただし、ソースコード上のキー文字列に対してクォートする必要は無い(しても良い)。

var a = { a: 100 };
a.b = 1_000;
a["c"] = 10_000;
System.println(a.a);        // 100
System.println(a.b);        // 1000
System.println(a.c);        // 10000

内部的に実はオブジェクトと配列は同じであり、両方の値を同時に保持できる。

var a = { a: 100 };
a.b = 1_000;
a["c"] = 10_000;
a[1] = 10;
System.println(a[1]);       // 10
System.println(a.a);        // 100
System.println(a.b);        // 1000
System.println(a.c);        // 10000

おわりに

今回はここまで。結構疲れた。

非常に一般的な話ばかりで面白くないのだが、まずはこういうところに触れた上で色々な解説しとかないと土台が良く分からなくなりそうなので頑張ってみた。とりあえず、次は制御構造に触れて、一通りのプログラムが構築できるところまでを目指そう。そこまで行ったら関数とかクラスとかクロージャとか個別の解説をしてみる予定。

例によって★が増えるといいな、と宣伝しておく。

そして書きながらバグを見つけ修正するという...。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonで生徒を当てるアプリをつくる-GUI版

はじめに

以前投稿したpythonで生徒を当てるアプリをつくるをGUIソフトにしたってだけの記事.

プログラム

main.py
data/
  history.txt
  list.txt
  list_raw.txt
web/
  main.html
  css/
    style.css
  js/
    eel.js

main.py
main.py
import locale
import eel
import random
import pickle
import os
import sys
import datetime
from tkinter import filedialog, Tk
import platform
import copy


def main():
    eel.init("web")
    eel.start("main.html")


Student_names = []
Student_FILENAME = "./data/list.txt"
Student_FILENAME_raw = "./data/list_raw.txt"

# Student
@eel.expose
def Student_load():
    with open(select_file(), "r") as f:
        global Student_names
        Student_names = f.read().splitlines()
        Student_save(Student_FILENAME)
        Student_save(Student_FILENAME_raw)


@eel.expose
def Student_reset():
    Student_names_load(Student_FILENAME_raw)


@eel.expose
def Student_show():
    Student_names_load(Student_FILENAME)
    name_ls = ""
    a = 1
    for name in Student_names:
        if a % 5 == 0:
            name_ls = name_ls + name + "<br>"
        else:
            name_ls = name_ls + name + " "
        a += 1
    return name_ls


@eel.expose
def Student_choice():
    Student_names_load(Student_FILENAME)
    global Student_names_raw
    Student_names_raw = copy.deepcopy(Student_names)
    if not Student_names:
        return
    global name
    name = random.choice(Student_names)
    Student_names.remove(name)
    if Student_names == []:
        Student_names_load(Student_FILENAME_raw)
    History_add(name)
    Student_save(Student_FILENAME)
    return name


@eel.expose
def Student_save(FILENAME):
    f = open(FILENAME, 'wb')
    pickle.dump(Student_names, f)


@eel.expose
def Student_names_load(FILENAME):
    f = open(FILENAME, "rb")
    global Student_names
    Student_names = pickle.load(f)


# History
History_FILENAME = "./data/history.txt"
History_data = []


@eel.expose
def History_load():
    with open(History_FILENAME, "r") as f:
        global History_data
        History_data = f.read().splitlines()


@eel.expose
def History_save():
    with open(History_FILENAME, "w") as f:
        for history in History_data:
            print(history, file=f)


@eel.expose
def History_show():
    history_ls = ""
    History_load()
    for history in History_data:
        history_ls = history + "<br>" + history_ls
    return history_ls


locale.setlocale(locale.LC_ALL, '')
@eel.expose
def History_add(name):
    now = datetime.datetime.now()
    History_data.append(f"{now:%m月%d日}:{name}")
    History_save()


@eel.expose
def History_cancel():
    History_data.pop()
    History_save()
    global Student_names
    Student_names = copy.deepcopy(Student_names_raw)
    Student_save(Student_FILENAME)


@eel.expose
def History_clear():
    global History_data
    History_data = []
    History_save()


# 名簿読み込み
# ダイアログ用のルートウィンドウの作成
# (root自体はeelのウィンドウとは関係ないので非表示にしておくのが望ましい)
root = Tk()
# ウィンドウサイズを0にする
root.geometry("0x0")
# ウィンドウのタイトルバーを消す
root.overrideredirect(1)
# ウィンドウを非表示に
root.withdraw()
system = platform.system()


@eel.expose
def select_file():
    # Windowsの場合withdrawの状態だとダイアログも
    # 非表示になるため、rootウィンドウを表示する
    if system == "Windows":
        root.deiconify()
    # macOS用にダイアログ作成前後でupdate()を呼ぶ
    root.update()

    # ダイアログを前面に
    # topmost指定(最前面)
    root.attributes('-topmost', True)
    root.withdraw()
    root.lift()
    root.focus_force()
    path_str = filedialog.askopenfilename()
    root.update()
    if system == "Windows":
        # 再度非表示化(Windowsのみ)
        root.withdraw()
    #path = Path(path_str)
    return path_str


if __name__ == '__main__':
    main()

main.html
main.html
<html>

<head>
  <meta charset="UTF-8">
  <title>生徒当てるヤツ</title>
  <link rel="stylesheet" type="text/css" href="./css/style.css">
  <script type="text/javascript" src="/eel.js"></script>
  <script type="text/javascript">
    async function Student_choice() {
      var demo2 = document.getElementById("div0");
      demo2.innerHTML = "";
      div0.insertAdjacentHTML('afterbegin', '<div id="name"></div>');
      let val = await eel.Student_choice()();
      var doc0 = document.getElementById("name");
      doc0.innerHTML = val;
    }

    async function Student_load() {
      eel.Student_load();
    }

    async function Student_show() {
      let val = await eel.Student_show()();
      var doc0 = document.getElementById("div0");
      doc0.innerHTML = val;
    }

    async function History_show() {
      let val = await eel.History_show()();
      var doc0 = document.getElementById("div0");
      doc0.innerHTML = val;
    }

    async function History_clear() {
      let val = await eel.History_clear()();
      var doc0 = document.getElementById("div0");
      doc0.innerHTML = val;
    }

    async function History_cancel() {
      let val = await eel.History_cancel()();
      var doc0 = document.getElementById("div0");
      doc0.innerHTML = val;
    }
  </script>
</head>

<body>
  <center>
    <div id="div0">
    </div>
    <div class="bottom">
      <a href="#" onclick="Student_choice()" class="btn-square">生徒を当てる</a>
      <a href="#" onclick="History_cancel()" class="btn-square">欠席者を飛ばす</a>
      <a href="#" onclick="Student_show()" class="btn-square">残りの生徒を表示</a>
      <a href="#" onclick="History_show()" class="btn-square">履歴の表示</a>
      <a href="#" onclick="History_clear()" class="btn-square">履歴の消去</a>
      <a href="#" onclick="Student_load()" class="btn-square">名簿を更新</a>
    </div>
  </center>
  <div class='markdown-preview' data-use-github-style>
    <details>
      <summary>名簿の更新方法</summary>
      <div>

        <h1 id="名簿の更新方法">名簿の更新方法</h1>
        <h3 id="1">1</h3>
        <p>任意のファイル名のテキストファイル(*.txt)を作成します.</p>
        <h3 id="2">2</h3>
        <p>その中に<br>
          1.名前<br>
          2.名前<br><br><br><br>
          と入力します.</p>
        <h3 id="3">3</h3>
        <p>名簿を更新をクリックし,テキストファイルを選択する.</p>
      </div>
    </details>
  </div>

</html>

style.css
style.css
.btn-square {
  display: inline-block;
  padding: 0.5em 1em;
  text-decoration: none;
  background: #668ad8;
  /*ボタン色*/
  color: #FFF;
  border-bottom: solid 4px #627295;
  border-radius: 3px;
}

.btn-square:active {
  /*ボタンを押したとき*/
  -webkit-transform: translateY(4px);
  transform: translateY(4px);
  /*下に動く*/
  border-bottom: none;
  /*線を消す*/
}

#div0 {
  height: 300px;
  overflow: scroll;
}

#name {
  margin-top: 50px;
  font-size: 100px;
}

.bottom {}

.markdown-preview:not([data-use-github-style]) {
  padding: 2em;
  font-size: 1.2em;
  color: rgb(197, 200, 198);
  background-color: rgb(29, 31, 33);
  overflow: auto;
}

.markdown-preview:not([data-use-github-style])> :first-child {
  margin-top: 0px;
}

.markdown-preview:not([data-use-github-style]) h1,
.markdown-preview:not([data-use-github-style]) h2,
.markdown-preview:not([data-use-github-style]) h3,
.markdown-preview:not([data-use-github-style]) h4,
.markdown-preview:not([data-use-github-style]) h5,
.markdown-preview:not([data-use-github-style]) h6 {
  line-height: 1.2;
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  color: rgb(255, 255, 255);
}

.markdown-preview:not([data-use-github-style]) h1 {
  font-size: 2.4em;
  font-weight: 300;
}

.markdown-preview:not([data-use-github-style]) h2 {
  font-size: 1.8em;
  font-weight: 400;
}

.markdown-preview:not([data-use-github-style]) h3 {
  font-size: 1.5em;
  font-weight: 500;
}

.markdown-preview:not([data-use-github-style]) h4 {
  font-size: 1.2em;
  font-weight: 600;
}

.markdown-preview:not([data-use-github-style]) h5 {
  font-size: 1.1em;
  font-weight: 600;
}

.markdown-preview:not([data-use-github-style]) h6 {
  font-size: 1em;
  font-weight: 600;
}

.markdown-preview:not([data-use-github-style]) strong {
  color: rgb(255, 255, 255);
}

.markdown-preview:not([data-use-github-style]) del {
  color: rgb(155, 160, 157);
}

.markdown-preview:not([data-use-github-style]) a,
.markdown-preview:not([data-use-github-style]) a code {
  color: white;
}

.markdown-preview:not([data-use-github-style]) img {
  max-width: 100%;
}

.markdown-preview:not([data-use-github-style])>p {
  margin-top: 0px;
  margin-bottom: 1.5em;
}

.markdown-preview:not([data-use-github-style])>ul,
.markdown-preview:not([data-use-github-style])>ol {
  margin-bottom: 1.5em;
}

.markdown-preview:not([data-use-github-style]) blockquote {
  margin: 1.5em 0px;
  font-size: inherit;
  color: rgb(155, 160, 157);
  border-color: rgb(67, 72, 76);
  border-width: 4px;
}

.markdown-preview:not([data-use-github-style]) hr {
  margin: 3em 0px;
  border-top: 2px dashed rgb(67, 72, 76);
  background: none;
}

.markdown-preview:not([data-use-github-style]) table {
  margin: 1.5em 0px;
}

.markdown-preview:not([data-use-github-style]) th {
  color: rgb(255, 255, 255);
}

.markdown-preview:not([data-use-github-style]) th,
.markdown-preview:not([data-use-github-style]) td {
  padding: 0.66em 1em;
  border: 1px solid rgb(67, 72, 76);
}

.markdown-preview:not([data-use-github-style]) code {
  color: rgb(255, 255, 255);
  background-color: rgb(48, 51, 55);
}

.markdown-preview:not([data-use-github-style]) pre.editor-colors {
  margin: 1.5em 0px;
  padding: 1em;
  font-size: 0.92em;
  border-radius: 3px;
  background-color: rgb(39, 41, 44);
}

.markdown-preview:not([data-use-github-style]) kbd {
  color: rgb(255, 255, 255);
  border-width: 1px 1px 2px;
  border-style: solid;
  border-color: rgb(67, 72, 76) rgb(67, 72, 76) rgb(53, 57, 60);
  border-image: initial;
  background-color: rgb(48, 51, 55);
}

.markdown-preview[data-use-github-style] {
  font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
  line-height: 1.6;
  overflow-wrap: break-word;
  padding: 30px;
  font-size: 16px;
  color: rgb(51, 51, 51);
  background-color: rgb(255, 255, 255);
}

.markdown-preview[data-use-github-style]> :first-child {
  margin-top: 0px !important;
}

.markdown-preview[data-use-github-style]> :last-child {
  margin-bottom: 0px !important;
}

.markdown-preview[data-use-github-style] a:not([href]) {
  color: inherit;
  text-decoration: none;
}

.markdown-preview[data-use-github-style] .absent {
  color: rgb(204, 0, 0);
}

.markdown-preview[data-use-github-style] .anchor {
  position: absolute;
  top: 0px;
  left: 0px;
  display: block;
  padding-right: 6px;
  padding-left: 30px;
  margin-left: -30px;
}

.markdown-preview[data-use-github-style] .anchor:focus {
  outline: none;
}

.markdown-preview[data-use-github-style] h1,
.markdown-preview[data-use-github-style] h2,
.markdown-preview[data-use-github-style] h3,
.markdown-preview[data-use-github-style] h4,
.markdown-preview[data-use-github-style] h5,
.markdown-preview[data-use-github-style] h6 {
  position: relative;
  margin-top: 1em;
  margin-bottom: 16px;
  font-weight: bold;
  line-height: 1.4;
}

.markdown-preview[data-use-github-style] h1 .octicon-link,
.markdown-preview[data-use-github-style] h2 .octicon-link,
.markdown-preview[data-use-github-style] h3 .octicon-link,
.markdown-preview[data-use-github-style] h4 .octicon-link,
.markdown-preview[data-use-github-style] h5 .octicon-link,
.markdown-preview[data-use-github-style] h6 .octicon-link {
  display: none;
  color: rgb(0, 0, 0);
  vertical-align: middle;
}

.markdown-preview[data-use-github-style] h1:hover .anchor,
.markdown-preview[data-use-github-style] h2:hover .anchor,
.markdown-preview[data-use-github-style] h3:hover .anchor,
.markdown-preview[data-use-github-style] h4:hover .anchor,
.markdown-preview[data-use-github-style] h5:hover .anchor,
.markdown-preview[data-use-github-style] h6:hover .anchor {
  padding-left: 8px;
  margin-left: -30px;
  text-decoration: none;
}

.markdown-preview[data-use-github-style] h1:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h2:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h3:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h4:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h5:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h6:hover .anchor .octicon-link {
  display: inline-block;
}

.markdown-preview[data-use-github-style] h1 tt,
.markdown-preview[data-use-github-style] h2 tt,
.markdown-preview[data-use-github-style] h3 tt,
.markdown-preview[data-use-github-style] h4 tt,
.markdown-preview[data-use-github-style] h5 tt,
.markdown-preview[data-use-github-style] h6 tt,
.markdown-preview[data-use-github-style] h1 code,
.markdown-preview[data-use-github-style] h2 code,
.markdown-preview[data-use-github-style] h3 code,
.markdown-preview[data-use-github-style] h4 code,
.markdown-preview[data-use-github-style] h5 code,
.markdown-preview[data-use-github-style] h6 code {
  font-size: inherit;
}

.markdown-preview[data-use-github-style] h1 {
  padding-bottom: 0.3em;
  font-size: 2.25em;
  line-height: 1.2;
  border-bottom: 1px solid rgb(238, 238, 238);
}

.markdown-preview[data-use-github-style] h1 .anchor {
  line-height: 1;
}

.markdown-preview[data-use-github-style] h2 {
  padding-bottom: 0.3em;
  font-size: 1.75em;
  line-height: 1.225;
  border-bottom: 1px solid rgb(238, 238, 238);
}

.markdown-preview[data-use-github-style] h2 .anchor {
  line-height: 1;
}

.markdown-preview[data-use-github-style] h3 {
  font-size: 1.5em;
  line-height: 1.43;
}

.markdown-preview[data-use-github-style] h3 .anchor {
  line-height: 1.2;
}

.markdown-preview[data-use-github-style] h4 {
  font-size: 1.25em;
}

.markdown-preview[data-use-github-style] h4 .anchor {
  line-height: 1.2;
}

.markdown-preview[data-use-github-style] h5 {
  font-size: 1em;
}

.markdown-preview[data-use-github-style] h5 .anchor {
  line-height: 1.1;
}

.markdown-preview[data-use-github-style] h6 {
  font-size: 1em;
  color: rgb(119, 119, 119);
}

.markdown-preview[data-use-github-style] h6 .anchor {
  line-height: 1.1;
}

.markdown-preview[data-use-github-style] p,
.markdown-preview[data-use-github-style] blockquote,
.markdown-preview[data-use-github-style] ul,
.markdown-preview[data-use-github-style] ol,
.markdown-preview[data-use-github-style] dl,
.markdown-preview[data-use-github-style] table,
.markdown-preview[data-use-github-style] pre {
  margin-top: 0px;
  margin-bottom: 16px;
}

.markdown-preview[data-use-github-style] hr {
  height: 4px;
  padding: 0px;
  margin: 16px 0px;
  background-color: rgb(231, 231, 231);
  border: 0px none;
}

.markdown-preview[data-use-github-style] ul,
.markdown-preview[data-use-github-style] ol {
  padding-left: 2em;
}

.markdown-preview[data-use-github-style] ul.no-list,
.markdown-preview[data-use-github-style] ol.no-list {
  padding: 0px;
  list-style-type: none;
}

.markdown-preview[data-use-github-style] ul ul,
.markdown-preview[data-use-github-style] ul ol,
.markdown-preview[data-use-github-style] ol ol,
.markdown-preview[data-use-github-style] ol ul {
  margin-top: 0px;
  margin-bottom: 0px;
}

.markdown-preview[data-use-github-style] li>p {
  margin-top: 16px;
}

.markdown-preview[data-use-github-style] dl {
  padding: 0px;
}

.markdown-preview[data-use-github-style] dl dt {
  padding: 0px;
  margin-top: 16px;
  font-size: 1em;
  font-style: italic;
  font-weight: bold;
}

.markdown-preview[data-use-github-style] dl dd {
  padding: 0px 16px;
  margin-bottom: 16px;
}

.markdown-preview[data-use-github-style] blockquote {
  padding: 0px 15px;
  color: rgb(119, 119, 119);
  border-left: 4px solid rgb(221, 221, 221);
}

.markdown-preview[data-use-github-style] blockquote> :first-child {
  margin-top: 0px;
}

.markdown-preview[data-use-github-style] blockquote> :last-child {
  margin-bottom: 0px;
}

.markdown-preview[data-use-github-style] table {
  display: block;
  width: 100%;
  overflow: auto;
  word-break: keep-all;
}

.markdown-preview[data-use-github-style] table th {
  font-weight: bold;
}

.markdown-preview[data-use-github-style] table th,
.markdown-preview[data-use-github-style] table td {
  padding: 6px 13px;
  border: 1px solid rgb(221, 221, 221);
}

.markdown-preview[data-use-github-style] table tr {
  background-color: rgb(255, 255, 255);
  border-top: 1px solid rgb(204, 204, 204);
}

.markdown-preview[data-use-github-style] table tr:nth-child(2n) {
  background-color: rgb(248, 248, 248);
}

.markdown-preview[data-use-github-style] img {
  max-width: 100%;
  box-sizing: border-box;
}

.markdown-preview[data-use-github-style] .emoji {
  max-width: none;
}

.markdown-preview[data-use-github-style] span.frame {
  display: block;
  overflow: hidden;
}

.markdown-preview[data-use-github-style] span.frame>span {
  display: block;
  float: left;
  width: auto;
  padding: 7px;
  margin: 13px 0px 0px;
  overflow: hidden;
  border: 1px solid rgb(221, 221, 221);
}

.markdown-preview[data-use-github-style] span.frame span img {
  display: block;
  float: left;
}

.markdown-preview[data-use-github-style] span.frame span span {
  display: block;
  padding: 5px 0px 0px;
  clear: both;
  color: rgb(51, 51, 51);
}

.markdown-preview[data-use-github-style] span.align-center {
  display: block;
  overflow: hidden;
  clear: both;
}

.markdown-preview[data-use-github-style] span.align-center>span {
  display: block;
  margin: 13px auto 0px;
  overflow: hidden;
  text-align: center;
}

.markdown-preview[data-use-github-style] span.align-center span img {
  margin: 0px auto;
  text-align: center;
}

.markdown-preview[data-use-github-style] span.align-right {
  display: block;
  overflow: hidden;
  clear: both;
}

.markdown-preview[data-use-github-style] span.align-right>span {
  display: block;
  margin: 13px 0px 0px;
  overflow: hidden;
  text-align: right;
}

.markdown-preview[data-use-github-style] span.align-right span img {
  margin: 0px;
  text-align: right;
}

.markdown-preview[data-use-github-style] span.float-left {
  display: block;
  float: left;
  margin-right: 13px;
  overflow: hidden;
}

.markdown-preview[data-use-github-style] span.float-left span {
  margin: 13px 0px 0px;
}

.markdown-preview[data-use-github-style] span.float-right {
  display: block;
  float: right;
  margin-left: 13px;
  overflow: hidden;
}

.markdown-preview[data-use-github-style] span.float-right>span {
  display: block;
  margin: 13px auto 0px;
  overflow: hidden;
  text-align: right;
}

.markdown-preview[data-use-github-style] code,
.markdown-preview[data-use-github-style] tt {
  padding: 0.2em 0px;
  margin: 0px;
  font-size: 85%;
  background-color: rgba(0, 0, 0, 0.04);
  border-radius: 3px;
}

.markdown-preview[data-use-github-style] code::before,
.markdown-preview[data-use-github-style] tt::before,
.markdown-preview[data-use-github-style] code::after,
.markdown-preview[data-use-github-style] tt::after {
  letter-spacing: -0.2em;
  content: " ";
}

.markdown-preview[data-use-github-style] code br,
.markdown-preview[data-use-github-style] tt br {
  display: none;
}

.markdown-preview[data-use-github-style] del code {
  text-decoration: inherit;
}

.markdown-preview[data-use-github-style] pre>code {
  padding: 0px;
  margin: 0px;
  font-size: 100%;
  word-break: normal;
  white-space: pre;
  background: transparent;
  border: 0px;
}

.markdown-preview[data-use-github-style] .highlight {
  margin-bottom: 16px;
}

.markdown-preview[data-use-github-style] .highlight pre,
.markdown-preview[data-use-github-style] pre {
  padding: 16px;
  overflow: auto;
  font-size: 85%;
  line-height: 1.45;
  background-color: rgb(247, 247, 247);
  border-radius: 3px;
}

.markdown-preview[data-use-github-style] .highlight pre {
  margin-bottom: 0px;
  word-break: normal;
}

.markdown-preview[data-use-github-style] pre {
  overflow-wrap: normal;
}

.markdown-preview[data-use-github-style] pre code,
.markdown-preview[data-use-github-style] pre tt {
  display: inline;
  max-width: initial;
  padding: 0px;
  margin: 0px;
  overflow: initial;
  line-height: inherit;
  overflow-wrap: normal;
  background-color: transparent;
  border: 0px;
}

.markdown-preview[data-use-github-style] pre code::before,
.markdown-preview[data-use-github-style] pre tt::before,
.markdown-preview[data-use-github-style] pre code::after,
.markdown-preview[data-use-github-style] pre tt::after {
  content: normal;
}

.markdown-preview[data-use-github-style] kbd {
  display: inline-block;
  padding: 3px 5px;
  font-size: 11px;
  line-height: 10px;
  color: rgb(85, 85, 85);
  vertical-align: middle;
  background-color: rgb(252, 252, 252);
  border-width: 1px;
  border-style: solid;
  border-color: rgb(204, 204, 204) rgb(204, 204, 204) rgb(187, 187, 187);
  border-image: initial;
  border-radius: 3px;
  box-shadow: rgb(187, 187, 187) 0px -1px 0px inset;
}

.markdown-preview[data-use-github-style] a {
  color: rgb(51, 122, 183);
}

.markdown-preview[data-use-github-style] code {
  color: inherit;
}

.markdown-preview[data-use-github-style] pre.editor-colors {
  padding: 0.8em 1em;
  margin-bottom: 1em;
  font-size: 0.85em;
  border-radius: 4px;
  overflow: auto;
}

.markdown-preview pre.editor-colors {
  user-select: auto;
}

.scrollbars-visible-always .markdown-preview pre.editor-colors .vertical-scrollbar,
.scrollbars-visible-always .markdown-preview pre.editor-colors .horizontal-scrollbar {
  visibility: hidden;
}

.scrollbars-visible-always .markdown-preview pre.editor-colors:hover .vertical-scrollbar,
.scrollbars-visible-always .markdown-preview pre.editor-colors:hover .horizontal-scrollbar {
  visibility: visible;
}

.markdown-preview .task-list-item input[type="checkbox"] {
  position: absolute;
  margin: 0.25em 0px 0px -1.4em;
}

.markdown-preview .task-list-item {
  list-style-type: none;
}

.markdown-preview code {
  text-shadow: none;
}

@keyframes RotatingBackground {
  0% {
    background-position-x: 0%;
  }

  100% {
    background-position-x: 100%;
  }
}

.debugger-breakpoint-icon::before,
.debugger-shadow-breakpoint-icon::before {
  font-family: 'Octicons Regular';
  font-weight: normal;
  font-style: normal;
  display: inline-block;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  text-decoration: none;
  font-size: 130%;
  width: 130%;
  height: 130%;
  content: "\f052";
}

.debugger-breakpoint-icon,
.debugger-breakpoint-icon-disabled,
.debugger-breakpoint-icon-unresolved,
.debugger-breakpoint-icon-conditional,
.debugger-shadow-breakpoint-icon {
  text-align: center;
  display: block;
  width: 0.8em;
  cursor: pointer;
}

.debugger-breakpoint-icon-nonconditional {
  color: #5293d8;
}

.debugger-breakpoint-icon-conditional {
  color: #ff982d;
}

.debugger-breakpoint-icon-disabled {
  position: relative;
  top: -4px;
  left: 2px;
}

.debugger-breakpoint-icon-disabled::before {
  font-family: 'Octicons Regular';
  font-weight: normal;
  font-style: normal;
  display: inline-block;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  text-decoration: none;
  font-size: 78%;
  width: 78%;
  height: 78%;
  content: "\f084";
}

.debugger-breakpoint-icon-unresolved {
  position: relative;
  top: -2px;
}

.debugger-breakpoint-icon-unresolved::before {
  font-family: 'Octicons Regular';
  font-weight: normal;
  font-style: normal;
  display: inline-block;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  text-decoration: none;
  font-size: 80%;
  width: 80%;
  height: 80%;
  content: "\f0e8";
}

.debugger-shadow-breakpoint-icon {
  color: rgba(82, 147, 216, 0.4);
}

.debugger-current-line-highlight {
  background: linear-gradient(to bottom, rgba(0, 152, 255, 0.8) 0%, rgba(0, 152, 255, 0.8) 5%, rgba(0, 152, 255, 0.3) 5%, rgba(0, 152, 255, 0.3) 95%, rgba(0, 152, 255, 0.8) 95%, rgba(0, 152, 255, 0.8) 100%);
}

.gutter[gutter-name=diagnostics-gutter] {
  width: 0.7em;
}

.diagnostics-gutter-ui-item {
  display: flex;
}

.diagnostics-gutter-ui-item .icon {
  display: flex;
  width: 0.7em;
  height: 0.7em;
  font-size: 0.7em;
  align-self: center;
}

.diagnostics-gutter-ui-item .icon::before {
  width: 1em;
  height: 1em;
  font-size: 1em;
  margin: 0;
  align-self: center;
}

.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-info,
.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-review {
  color: #5293d8;
}

.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-error {
  color: #c00;
}

.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-action,
.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-warning {
  color: #ff982d;
}

.bracket-matcher .region {
  border-bottom: 1px dotted lime;
  position: absolute;
}

.line-number.bracket-matcher.bracket-matcher {
  color: #c5c8c6;
  background-color: rgba(255, 255, 255, 0.14);
}

.spell-check-misspelling .region {
  border-bottom: 2px dotted rgba(255, 51, 51, 0.75);
}

.spell-check-corrections {
  width: 25em !important;
}

pre.editor-colors {
  background-color: #1d1f21;
  color: #c5c8c6;
}

pre.editor-colors .invisible-character {
  color: rgba(197, 200, 198, 0.2);
}

pre.editor-colors .indent-guide {
  color: rgba(197, 200, 198, 0.2);
}

pre.editor-colors .wrap-guide {
  background-color: rgba(197, 200, 198, 0.1);
}

pre.editor-colors .gutter {
  background-color: #292c2f;
}

pre.editor-colors .gutter .cursor-line {
  background-color: rgba(255, 255, 255, 0.14);
}

pre.editor-colors .line-number.cursor-line-no-selection {
  background-color: rgba(255, 255, 255, 0.14);
}

pre.editor-colors .gutter .line-number.folded,
pre.editor-colors .gutter .line-number:after,
pre.editor-colors .fold-marker:after {
  color: #fba0e3;
}

pre.editor-colors .invisible {
  color: #c5c8c6;
}

pre.editor-colors .cursor {
  border-color: white;
}

pre.editor-colors .selection .region {
  background-color: #444;
}

pre.editor-colors .bracket-matcher .region {
  border-bottom: 1px solid #f8de7e;
  margin-top: -1px;
  opacity: .7;
}

.syntax--comment {
  color: #8a8a8a;
}

.syntax--entity {
  color: #FFD2A7;
}

.syntax--entity.syntax--name.syntax--type {
  text-decoration: underline;
  color: #FFFFB6;
}

.syntax--entity.syntax--other.syntax--inherited-class {
  color: #9B5C2E;
}

.syntax--keyword {
  color: #96CBFE;
}

.syntax--keyword.syntax--control {
  color: #96CBFE;
}

.syntax--keyword.syntax--operator {
  color: #EDEDED;
}

.syntax--storage {
  color: #CFCB90;
}

.syntax--storage.syntax--modifier {
  color: #96CBFE;
}

.syntax--constant {
  color: #99CC99;
}

.syntax--constant.syntax--numeric {
  color: #FF73FD;
}

.syntax--variable {
  color: #C6C5FE;
}

.syntax--invalid.syntax--deprecated {
  text-decoration: underline;
  color: #FD5FF1;
}

.syntax--invalid.syntax--illegal {
  color: #FD5FF1;
  background-color: rgba(86, 45, 86, 0.75);
}

.syntax--string .syntax--source,
.syntax--string .syntax--meta.syntax--embedded.syntax--line {
  color: #EDEDED;
}

.syntax--string .syntax--punctuation.syntax--section.syntax--embedded {
  color: #00A0A0;
}

.syntax--string .syntax--punctuation.syntax--section.syntax--embedded .syntax--source {
  color: #00A0A0;
}

.syntax--string {
  color: #A8FF60;
}

.syntax--string .syntax--constant {
  color: #00A0A0;
}

.syntax--string.syntax--regexp {
  color: #E9C062;
}

.syntax--string.syntax--regexp .syntax--constant.syntax--character.syntax--escape,
.syntax--string.syntax--regexp .syntax--source.syntax--ruby.syntax--embedded,
.syntax--string.syntax--regexp .syntax--string.syntax--regexp.syntax--arbitrary-repetition {
  color: #FF8000;
}

.syntax--string.syntax--regexp.syntax--group {
  color: #C6A24F;
  background-color: rgba(255, 255, 255, 0.06);
}

.syntax--string.syntax--regexp.syntax--character-class {
  color: #B18A3D;
}

.syntax--string .syntax--variable {
  color: #8A9A95;
}

.syntax--support {
  color: #FFFFB6;
}

.syntax--support.syntax--function {
  color: #DAD085;
}

.syntax--support.syntax--constant {
  color: #FFD2A7;
}

.syntax--support.syntax--type.syntax--property-name.syntax--css {
  color: #EDEDED;
}

.syntax--source .syntax--entity.syntax--name.syntax--tag,
.syntax--source .syntax--punctuation.syntax--tag {
  color: #96CBFE;
}

.syntax--source .syntax--entity.syntax--other.syntax--attribute-name {
  color: #FF73FD;
}

.syntax--entity.syntax--other.syntax--attribute-name {
  color: #FF73FD;
}

.syntax--entity.syntax--name.syntax--tag.syntax--namespace,
.syntax--entity.syntax--other.syntax--attribute-name.syntax--namespace {
  color: #E18964;
}

.syntax--meta.syntax--preprocessor.syntax--c {
  color: #8996A8;
}

.syntax--meta.syntax--preprocessor.syntax--c .syntax--keyword {
  color: #AFC4DB;
}

.syntax--meta.syntax--cast {
  color: #676767;
}

.syntax--meta.syntax--sgml.syntax--html .syntax--meta.syntax--doctype,
.syntax--meta.syntax--sgml.syntax--html .syntax--meta.syntax--doctype .syntax--entity,
.syntax--meta.syntax--sgml.syntax--html .syntax--meta.syntax--doctype .syntax--string,
.syntax--meta.syntax--xml-processing,
.syntax--meta.syntax--xml-processing .syntax--entity,
.syntax--meta.syntax--xml-processing .syntax--string {
  color: #8a8a8a;
}

.syntax--meta.syntax--tag .syntax--entity,
.syntax--meta.syntax--tag>.syntax--punctuation,
.syntax--meta.syntax--tag.syntax--inline .syntax--entity {
  color: #FF73FD;
}

.syntax--meta.syntax--tag .syntax--name,
.syntax--meta.syntax--tag.syntax--inline .syntax--name,
.syntax--meta.syntax--tag>.syntax--punctuation {
  color: #96CBFE;
}

.syntax--meta.syntax--selector.syntax--css .syntax--entity.syntax--name.syntax--tag {
  text-decoration: underline;
  color: #96CBFE;
}

.syntax--meta.syntax--selector.syntax--css .syntax--entity.syntax--other.syntax--attribute-name.syntax--tag.syntax--pseudo-class {
  color: #8F9D6A;
}

.syntax--meta.syntax--selector.syntax--css .syntax--entity.syntax--other.syntax--attribute-name.syntax--id {
  color: #8B98AB;
}

.syntax--meta.syntax--selector.syntax--css .syntax--entity.syntax--other.syntax--attribute-name.syntax--class {
  color: #62B1FE;
}

.syntax--meta.syntax--property-group .syntax--support.syntax--constant.syntax--property-value.syntax--css,
.syntax--meta.syntax--property-value .syntax--support.syntax--constant.syntax--property-value.syntax--css {
  color: #F9EE98;
}

.syntax--meta.syntax--preprocessor.syntax--at-rule .syntax--keyword.syntax--control.syntax--at-rule {
  color: #8693A5;
}

.syntax--meta.syntax--property-value .syntax--support.syntax--constant.syntax--named-color.syntax--css,
.syntax--meta.syntax--property-value .syntax--constant {
  color: #87C38A;
}

.syntax--meta.syntax--constructor.syntax--argument.syntax--css {
  color: #8F9D6A;
}

.syntax--meta.syntax--diff,
.syntax--meta.syntax--diff.syntax--header {
  color: #F8F8F8;
  background-color: #0E2231;
}

.syntax--meta.syntax--separator {
  color: #60A633;
  background-color: #242424;
}

.syntax--meta.syntax--line.syntax--entry.syntax--logfile,
.syntax--meta.syntax--line.syntax--exit.syntax--logfile {
  background-color: rgba(238, 238, 238, 0.16);
}

.syntax--meta.syntax--line.syntax--error.syntax--logfile {
  background-color: #751012;
}

.syntax--source.syntax--gfm {
  color: #999;
}

.syntax--gfm .syntax--markup.syntax--heading {
  color: #eee;
}

.syntax--gfm .syntax--link {
  color: #555;
}

.syntax--gfm .syntax--variable.syntax--list,
.syntax--gfm .syntax--support.syntax--quote {
  color: #555;
}

.syntax--gfm .syntax--link .syntax--entity {
  color: #ddd;
}

.syntax--gfm .syntax--raw {
  color: #aaa;
}

.syntax--markdown .syntax--paragraph {
  color: #999;
}

.syntax--markdown .syntax--heading {
  color: #eee;
}

.syntax--markdown .syntax--raw {
  color: #aaa;
}

.syntax--markdown .syntax--link {
  color: #555;
}

.syntax--markdown .syntax--link .syntax--string {
  color: #555;
}

.syntax--markdown .syntax--link .syntax--string.syntax--title {
  color: #ddd;
}

eel.jsは公式githubとかから取得してください
(このコードをそのまま使うなら必要ない)

参考にしたサイト

CSSで作る!押したくなるボタンデザイン100(Web用)
Python eelでファイル選択ダイアログ

動作風景

Screenshot from 2020-02-25 14-39-18.png
Screenshot from 2020-02-25 14-39-33.png
Screenshot from 2020-02-25 14-39-37.png
Screenshot from 2020-02-25 14-39-39.png

exeファイル

exeファイル

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptでcontent-typeを自動で取得する方法

content-typeを自動で取得する方法を探した結果、mime-typesを使うことにしました。

前提条件

  • npmがインストールされていること

インストール

$ npm i --save mime-types

使い方

設定

touchコマンドでファイルを作成します。

$ touch test.js

test.js
mime-typesモジュールの読み込みと、引数にパスを入れてメソッドを使用します。

const mime = require('mime-types')

console.log(mime.lookup('test.json'))
console.log(mime.contentType('test.json'))

実行

nodeコマンドでtest.jsを実行します。

$ node test

出力結果

application/json
application/json; charset=utf-8

参考文献

この記事は以下の情報を参考にして執筆しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

俺得な備忘録

ちょっとしたTipsを留めておく俺得な記事

setInterval系

setIntervalがうまく消えてくれない!!!
=> リストを作成して消せば消える!(日本語雑だけど未来の俺わかるよね?)

// インターバルをストックするメモリ.
var timerList = new Array();

// インターバルをセットする関数.
function funcA() {
  timerList.push(
    setInterval(() => {
      console.log("setInterval");
    }, 100)
  );
}

// インターバルをすべて削除する関数.
function funcB() {
  timerList.forEach((id) => {
    clearInterval(id);
  });
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt.jsの始め方

Nuxt.jsを始めたい方に向けて、導入の仕方をまとめます。
ライフサイクルなど細かい内容は公式ドキュメントをご確認ください。

前提条件

  • npmの5.2.0以降のバージョンがインストールされていること

インストール

プロジェクトディレクトリの作成

$ mkdir test && cd $_

Nuxt.jsフレームワークのインストール

$ npx create-nuxt-app

開発

開発サーバーを起動

$ npm run dev

デプロイ

SSRモードでサーバーを起動

$ npm run build && npm run start

静的HTML生成

$ npm run generate

その他

pug/stylusの導入

pug

pugのモジュールをインストール

$ npm i --save pug pug-loader pug-plain-loader

全*.vueファイルのtemplateタグにlang="pug"を追加する

<!-- <template> -->

<template lang="pug">

stylus

stylusのモジュールをインストール

$ npm i --save stylus stylus-loader

全*.vueファイルのstyleタグにlang="stylus"を追加する
ここの内容を他のスタイルに影響させたくない場合はscopedも追加する

/* <style> */

<style lang="stylus" scoped>

storeの導入

データ定義

store用のファイルを作成

$ touch store/index.js

store/index.js
保持しておきたいデータをstate内にcounterという名前で定義
state内のcounterの数値を1ずつ増やすincrementメソッドを定義

export const state = () => ({
  counter: 0
})

export const mutations = {
  increment (state) {
    state.counter++
  }
}

データへのアクセス

state内のcounterの値を取得

this.$store.state.counter

出力結果

0

データの変更

mutations内のincrementメソッドを実行

this.$store.commit('increment')

transitionタグ

html(pug)の定義

transitionタグを追加して、子要素はv-ifなどで存在確認をさせる

transition
  p(v-if="show") Hello world!

css(stylus)の定義

v-enterv-leave-toで最初(出現時)と最後(消失時)のstyleを定義
そのスタイルにどういうtransitionをかけるかv-enter-activev-leave-activeで定義

.v-enter-active
.v-leave-active
  transition opacity .5s

.v-enter
.v-leave-to
  opacity 0

ページ遷移transition

html(pug)の定義

nuxt-linkタグを追加する

nuxt-link(to="/test/") go to test!

css(stylus)の定義

page-enterpage-leave-toで最初(出現時)と最後(消失時)のstyleを定義
そのスタイルにどういうtransitionをかけるかpage-enter-activepage-leave-activeで定義

.page-enter-active
.page-leave-active
  transition opacity .5s

.page-enter
.page-leave-to
  opacity 0

ページ読み込み時のLoading表示

Loading用のファイルを作成

$ mkdir components/Loading && touch components/Loading/index.vue

components/Loading/index.vue

<template lang="pug">
.loading-page(v-if="loading")
  p Loading...
</template>

<script>
export default {
  data: () => ({
    loading: false
  }),
  methods: {
    start () {
      this.loading = true
    },
    finish () {
      setTimeout(() => {
        this.loading = false
      }, 3000)
    }
  }
}
</script>

<style lang="stylus" scoped></style>

nuxt.config.js
loadingの記述を追加

module.exports = {
  loading: '~/components/Loading/index.vue' // 追記
}

テンプレートレイアウト変更

テンプレート用のファイルを作成

$ touch layouts/another.vue

layouts/another.vue

<template lang="pug">
.l-another
  nuxt
</template>

<script>
export default {}
</script>

<style lang="stylus" scoped></style>

*.vue
layoutのカスタム読み込みをする記述を追加

export default {
  layout: 'another', // 追記
}

エラーページ

エラー用のファイルを作成

$ touch layouts/error.vue

layouts/error.vue

<template lang="pug">
.container
  h1(v-if="error.statusCode === 404") ページが見つかりません
  h1(v-else) エラーが発生しました
  nuxt-link(to="/") ホーム
</template>

<script>
export default {
  props: {
    error: {
      type: Object,
      default: null
    }
  }
}
</script>

<style lang="stylus" scoped></style>

コンソールの削除

nuxt.config.js
build内にdrop_consoleの記述を追加

module.exports = {
  build: {
    terser: {
      terserOptions: {
        compress: { drop_console: true }
      }
    }
  }
}

作業ディレクトリをまとめる

作業ディレクトリの作成、移動

$ mkdir src && mv assets components layouts pages plugins static store middleware src/

nuxt.config.js
srcDirの記述を追加する

module.exports = {
  srcDir: 'src/', // 追記
}

参考文献

この記事は以下の情報を参考にして執筆しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPer脳の人がJavaScriptでループを回す

毎回for文書くたびに調べてるので

配列のforeach

phpだとこんな感じのやつ

$array = [1, 2, 3];

foreach($array as $a){
    echo $a;
}

// 1
// 2
// 3

jsだとこう

const array = [1, 2, 3];

for(let a of array){
    console.log(a);
}

// 1
// 2
// 3

連想配列のforeach

phpだとこんな感じのやつ

$array_assoc = [
    1 => 'one',
    2 => 'two',
    3 => 'three'
];

foreach($array_assoc as $k => $v){
    echo $k . ' is ' . $v . "\n";
}

// 1 is one
// 2 is two
// 3 is three

jsだとこう

const array_assoc = {
    1 : 'one',
    2 : 'two',
    3 : 'three'
};

for(let [k, v] of Object.entries(array_assoc)){
    console.log(k + ' is ' + v + "\n");
}

// 1 is one
// 2 is two
// 3 is three

※まあ、jsのObjectは正確には連想配列ではないけど

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonで生徒を当てるアプリをつくる-GUI版

はじめに

以前投稿したpythonで生徒を当てるアプリをつくるをGUIソフトにしたってだけの記事.

プログラム

main.py
data/
  history.txt
  list.txt
  list_raw.txt
web/
  main.html
  css/
    style.css
  js/
    eel.js

main.py
main.py
import locale
import eel
import random
import pickle
import os
import sys
import datetime
from tkinter import filedialog, Tk
import platform
import copy


def main():
    eel.init("web")
    eel.start("main.html")


Student_names = []
Student_FILENAME = "./data/list.txt"
Student_FILENAME_raw = "./data/list_raw.txt"

# Student
@eel.expose
def Student_load():
    with open(select_file(), "r") as f:
        global Student_names
        Student_names = f.read().splitlines()
        Student_save(Student_FILENAME)
        Student_save(Student_FILENAME_raw)


@eel.expose
def Student_reset():
    Student_names_load(Student_FILENAME_raw)


@eel.expose
def Student_show():
    Student_names_load(Student_FILENAME)
    name_ls = ""
    a = 1
    for name in Student_names:
        if a % 5 == 0:
            name_ls = name_ls + name + "<br>"
        else:
            name_ls = name_ls + name + " "
        a += 1
    return name_ls


@eel.expose
def Student_choice():
    Student_names_load(Student_FILENAME)
    global Student_names_raw
    Student_names_raw = copy.deepcopy(Student_names)
    if not Student_names:
        return
    global name
    name = random.choice(Student_names)
    Student_names.remove(name)
    if Student_names == []:
        Student_names_load(Student_FILENAME_raw)
    History_add(name)
    Student_save(Student_FILENAME)
    return name


@eel.expose
def Student_save(FILENAME):
    f = open(FILENAME, 'wb')
    pickle.dump(Student_names, f)


@eel.expose
def Student_names_load(FILENAME):
    f = open(FILENAME, "rb")
    global Student_names
    Student_names = pickle.load(f)


# History
History_FILENAME = "./data/history.txt"
History_data = []


@eel.expose
def History_load():
    with open(History_FILENAME, "r") as f:
        global History_data
        History_data = f.read().splitlines()


@eel.expose
def History_save():
    with open(History_FILENAME, "w") as f:
        for history in History_data:
            print(history, file=f)


@eel.expose
def History_show():
    history_ls = ""
    History_load()
    for history in History_data:
        history_ls = history + "<br>" + history_ls
    return history_ls


locale.setlocale(locale.LC_ALL, '')
@eel.expose
def History_add(name):
    now = datetime.datetime.now()
    History_data.append(f"{now:%m月%d日}:{name}")
    History_save()


@eel.expose
def History_cancel():
    History_data.pop()
    History_save()
    global Student_names
    Student_names = copy.deepcopy(Student_names_raw)
    Student_save(Student_FILENAME)


@eel.expose
def History_clear():
    global History_data
    History_data = []
    History_save()


# 名簿読み込み
# ダイアログ用のルートウィンドウの作成
# (root自体はeelのウィンドウとは関係ないので非表示にしておくのが望ましい)
root = Tk()
# ウィンドウサイズを0にする
root.geometry("0x0")
# ウィンドウのタイトルバーを消す
root.overrideredirect(1)
# ウィンドウを非表示に
root.withdraw()
system = platform.system()


@eel.expose
def select_file():
    # Windowsの場合withdrawの状態だとダイアログも
    # 非表示になるため、rootウィンドウを表示する
    if system == "Windows":
        root.deiconify()
    # macOS用にダイアログ作成前後でupdate()を呼ぶ
    root.update()

    # ダイアログを前面に
    # topmost指定(最前面)
    root.attributes('-topmost', True)
    root.withdraw()
    root.lift()
    root.focus_force()
    path_str = filedialog.askopenfilename()
    root.update()
    if system == "Windows":
        # 再度非表示化(Windowsのみ)
        root.withdraw()
    #path = Path(path_str)
    return path_str


if __name__ == '__main__':
    main()

main.html
main.html
<html>

<head>
  <meta charset="UTF-8">
  <title>生徒当てるヤツ</title>
  <link rel="stylesheet" type="text/css" href="./css/style.css">
  <script type="text/javascript" src="/eel.js"></script>
  <script type="text/javascript">
    async function Student_choice() {
      var demo2 = document.getElementById("div0");
      demo2.innerHTML = "";
      div0.insertAdjacentHTML('afterbegin', '<div id="name"></div>');
      let val = await eel.Student_choice()();
      var doc0 = document.getElementById("name");
      doc0.innerHTML = val;
    }

    async function Student_load() {
      eel.Student_load();
    }

    async function Student_show() {
      let val = await eel.Student_show()();
      var doc0 = document.getElementById("div0");
      doc0.innerHTML = val;
    }

    async function History_show() {
      let val = await eel.History_show()();
      var doc0 = document.getElementById("div0");
      doc0.innerHTML = val;
    }

    async function History_clear() {
      let val = await eel.History_clear()();
      var doc0 = document.getElementById("div0");
      doc0.innerHTML = val;
    }

    async function History_cancel() {
      let val = await eel.History_cancel()();
      var doc0 = document.getElementById("div0");
      doc0.innerHTML = val;
    }
  </script>
</head>

<body>
  <center>
    <div id="div0">
    </div>
    <div class="bottom">
      <a href="#" onclick="Student_choice()" class="btn-square">生徒を当てる</a>
      <a href="#" onclick="History_cancel()" class="btn-square">欠席者を飛ばす</a>
      <a href="#" onclick="Student_show()" class="btn-square">残りの生徒を表示</a>
      <a href="#" onclick="History_show()" class="btn-square">履歴の表示</a>
      <a href="#" onclick="History_clear()" class="btn-square">履歴の消去</a>
      <a href="#" onclick="Student_load()" class="btn-square">名簿を更新</a>
    </div>
  </center>
  <div class='markdown-preview' data-use-github-style>
    <details>
      <summary>名簿の更新方法</summary>
      <div>

        <h1 id="名簿の更新方法">名簿の更新方法</h1>
        <h3 id="1">1</h3>
        <p>任意のファイル名のテキストファイル(*.txt)を作成します.</p>
        <h3 id="2">2</h3>
        <p>その中に<br>
          1.名前<br>
          2.名前<br><br><br><br>
          と入力します.</p>
        <h3 id="3">3</h3>
        <p>名簿を更新をクリックし,テキストファイルを選択する.</p>
      </div>
    </details>
  </div>

</html>

style.css
style.css
.btn-square {
  display: inline-block;
  padding: 0.5em 1em;
  text-decoration: none;
  background: #668ad8;
  /*ボタン色*/
  color: #FFF;
  border-bottom: solid 4px #627295;
  border-radius: 3px;
}

.btn-square:active {
  /*ボタンを押したとき*/
  -webkit-transform: translateY(4px);
  transform: translateY(4px);
  /*下に動く*/
  border-bottom: none;
  /*線を消す*/
}

#div0 {
  height: 300px;
  overflow: scroll;
}

#name {
  margin-top: 50px;
  font-size: 100px;
}

.bottom {}

.markdown-preview:not([data-use-github-style]) {
  padding: 2em;
  font-size: 1.2em;
  color: rgb(197, 200, 198);
  background-color: rgb(29, 31, 33);
  overflow: auto;
}

.markdown-preview:not([data-use-github-style])> :first-child {
  margin-top: 0px;
}

.markdown-preview:not([data-use-github-style]) h1,
.markdown-preview:not([data-use-github-style]) h2,
.markdown-preview:not([data-use-github-style]) h3,
.markdown-preview:not([data-use-github-style]) h4,
.markdown-preview:not([data-use-github-style]) h5,
.markdown-preview:not([data-use-github-style]) h6 {
  line-height: 1.2;
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  color: rgb(255, 255, 255);
}

.markdown-preview:not([data-use-github-style]) h1 {
  font-size: 2.4em;
  font-weight: 300;
}

.markdown-preview:not([data-use-github-style]) h2 {
  font-size: 1.8em;
  font-weight: 400;
}

.markdown-preview:not([data-use-github-style]) h3 {
  font-size: 1.5em;
  font-weight: 500;
}

.markdown-preview:not([data-use-github-style]) h4 {
  font-size: 1.2em;
  font-weight: 600;
}

.markdown-preview:not([data-use-github-style]) h5 {
  font-size: 1.1em;
  font-weight: 600;
}

.markdown-preview:not([data-use-github-style]) h6 {
  font-size: 1em;
  font-weight: 600;
}

.markdown-preview:not([data-use-github-style]) strong {
  color: rgb(255, 255, 255);
}

.markdown-preview:not([data-use-github-style]) del {
  color: rgb(155, 160, 157);
}

.markdown-preview:not([data-use-github-style]) a,
.markdown-preview:not([data-use-github-style]) a code {
  color: white;
}

.markdown-preview:not([data-use-github-style]) img {
  max-width: 100%;
}

.markdown-preview:not([data-use-github-style])>p {
  margin-top: 0px;
  margin-bottom: 1.5em;
}

.markdown-preview:not([data-use-github-style])>ul,
.markdown-preview:not([data-use-github-style])>ol {
  margin-bottom: 1.5em;
}

.markdown-preview:not([data-use-github-style]) blockquote {
  margin: 1.5em 0px;
  font-size: inherit;
  color: rgb(155, 160, 157);
  border-color: rgb(67, 72, 76);
  border-width: 4px;
}

.markdown-preview:not([data-use-github-style]) hr {
  margin: 3em 0px;
  border-top: 2px dashed rgb(67, 72, 76);
  background: none;
}

.markdown-preview:not([data-use-github-style]) table {
  margin: 1.5em 0px;
}

.markdown-preview:not([data-use-github-style]) th {
  color: rgb(255, 255, 255);
}

.markdown-preview:not([data-use-github-style]) th,
.markdown-preview:not([data-use-github-style]) td {
  padding: 0.66em 1em;
  border: 1px solid rgb(67, 72, 76);
}

.markdown-preview:not([data-use-github-style]) code {
  color: rgb(255, 255, 255);
  background-color: rgb(48, 51, 55);
}

.markdown-preview:not([data-use-github-style]) pre.editor-colors {
  margin: 1.5em 0px;
  padding: 1em;
  font-size: 0.92em;
  border-radius: 3px;
  background-color: rgb(39, 41, 44);
}

.markdown-preview:not([data-use-github-style]) kbd {
  color: rgb(255, 255, 255);
  border-width: 1px 1px 2px;
  border-style: solid;
  border-color: rgb(67, 72, 76) rgb(67, 72, 76) rgb(53, 57, 60);
  border-image: initial;
  background-color: rgb(48, 51, 55);
}

.markdown-preview[data-use-github-style] {
  font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
  line-height: 1.6;
  overflow-wrap: break-word;
  padding: 30px;
  font-size: 16px;
  color: rgb(51, 51, 51);
  background-color: rgb(255, 255, 255);
}

.markdown-preview[data-use-github-style]> :first-child {
  margin-top: 0px !important;
}

.markdown-preview[data-use-github-style]> :last-child {
  margin-bottom: 0px !important;
}

.markdown-preview[data-use-github-style] a:not([href]) {
  color: inherit;
  text-decoration: none;
}

.markdown-preview[data-use-github-style] .absent {
  color: rgb(204, 0, 0);
}

.markdown-preview[data-use-github-style] .anchor {
  position: absolute;
  top: 0px;
  left: 0px;
  display: block;
  padding-right: 6px;
  padding-left: 30px;
  margin-left: -30px;
}

.markdown-preview[data-use-github-style] .anchor:focus {
  outline: none;
}

.markdown-preview[data-use-github-style] h1,
.markdown-preview[data-use-github-style] h2,
.markdown-preview[data-use-github-style] h3,
.markdown-preview[data-use-github-style] h4,
.markdown-preview[data-use-github-style] h5,
.markdown-preview[data-use-github-style] h6 {
  position: relative;
  margin-top: 1em;
  margin-bottom: 16px;
  font-weight: bold;
  line-height: 1.4;
}

.markdown-preview[data-use-github-style] h1 .octicon-link,
.markdown-preview[data-use-github-style] h2 .octicon-link,
.markdown-preview[data-use-github-style] h3 .octicon-link,
.markdown-preview[data-use-github-style] h4 .octicon-link,
.markdown-preview[data-use-github-style] h5 .octicon-link,
.markdown-preview[data-use-github-style] h6 .octicon-link {
  display: none;
  color: rgb(0, 0, 0);
  vertical-align: middle;
}

.markdown-preview[data-use-github-style] h1:hover .anchor,
.markdown-preview[data-use-github-style] h2:hover .anchor,
.markdown-preview[data-use-github-style] h3:hover .anchor,
.markdown-preview[data-use-github-style] h4:hover .anchor,
.markdown-preview[data-use-github-style] h5:hover .anchor,
.markdown-preview[data-use-github-style] h6:hover .anchor {
  padding-left: 8px;
  margin-left: -30px;
  text-decoration: none;
}

.markdown-preview[data-use-github-style] h1:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h2:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h3:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h4:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h5:hover .anchor .octicon-link,
.markdown-preview[data-use-github-style] h6:hover .anchor .octicon-link {
  display: inline-block;
}

.markdown-preview[data-use-github-style] h1 tt,
.markdown-preview[data-use-github-style] h2 tt,
.markdown-preview[data-use-github-style] h3 tt,
.markdown-preview[data-use-github-style] h4 tt,
.markdown-preview[data-use-github-style] h5 tt,
.markdown-preview[data-use-github-style] h6 tt,
.markdown-preview[data-use-github-style] h1 code,
.markdown-preview[data-use-github-style] h2 code,
.markdown-preview[data-use-github-style] h3 code,
.markdown-preview[data-use-github-style] h4 code,
.markdown-preview[data-use-github-style] h5 code,
.markdown-preview[data-use-github-style] h6 code {
  font-size: inherit;
}

.markdown-preview[data-use-github-style] h1 {
  padding-bottom: 0.3em;
  font-size: 2.25em;
  line-height: 1.2;
  border-bottom: 1px solid rgb(238, 238, 238);
}

.markdown-preview[data-use-github-style] h1 .anchor {
  line-height: 1;
}

.markdown-preview[data-use-github-style] h2 {
  padding-bottom: 0.3em;
  font-size: 1.75em;
  line-height: 1.225;
  border-bottom: 1px solid rgb(238, 238, 238);
}

.markdown-preview[data-use-github-style] h2 .anchor {
  line-height: 1;
}

.markdown-preview[data-use-github-style] h3 {
  font-size: 1.5em;
  line-height: 1.43;
}

.markdown-preview[data-use-github-style] h3 .anchor {
  line-height: 1.2;
}

.markdown-preview[data-use-github-style] h4 {
  font-size: 1.25em;
}

.markdown-preview[data-use-github-style] h4 .anchor {
  line-height: 1.2;
}

.markdown-preview[data-use-github-style] h5 {
  font-size: 1em;
}

.markdown-preview[data-use-github-style] h5 .anchor {
  line-height: 1.1;
}

.markdown-preview[data-use-github-style] h6 {
  font-size: 1em;
  color: rgb(119, 119, 119);
}

.markdown-preview[data-use-github-style] h6 .anchor {
  line-height: 1.1;
}

.markdown-preview[data-use-github-style] p,
.markdown-preview[data-use-github-style] blockquote,
.markdown-preview[data-use-github-style] ul,
.markdown-preview[data-use-github-style] ol,
.markdown-preview[data-use-github-style] dl,
.markdown-preview[data-use-github-style] table,
.markdown-preview[data-use-github-style] pre {
  margin-top: 0px;
  margin-bottom: 16px;
}

.markdown-preview[data-use-github-style] hr {
  height: 4px;
  padding: 0px;
  margin: 16px 0px;
  background-color: rgb(231, 231, 231);
  border: 0px none;
}

.markdown-preview[data-use-github-style] ul,
.markdown-preview[data-use-github-style] ol {
  padding-left: 2em;
}

.markdown-preview[data-use-github-style] ul.no-list,
.markdown-preview[data-use-github-style] ol.no-list {
  padding: 0px;
  list-style-type: none;
}

.markdown-preview[data-use-github-style] ul ul,
.markdown-preview[data-use-github-style] ul ol,
.markdown-preview[data-use-github-style] ol ol,
.markdown-preview[data-use-github-style] ol ul {
  margin-top: 0px;
  margin-bottom: 0px;
}

.markdown-preview[data-use-github-style] li>p {
  margin-top: 16px;
}

.markdown-preview[data-use-github-style] dl {
  padding: 0px;
}

.markdown-preview[data-use-github-style] dl dt {
  padding: 0px;
  margin-top: 16px;
  font-size: 1em;
  font-style: italic;
  font-weight: bold;
}

.markdown-preview[data-use-github-style] dl dd {
  padding: 0px 16px;
  margin-bottom: 16px;
}

.markdown-preview[data-use-github-style] blockquote {
  padding: 0px 15px;
  color: rgb(119, 119, 119);
  border-left: 4px solid rgb(221, 221, 221);
}

.markdown-preview[data-use-github-style] blockquote> :first-child {
  margin-top: 0px;
}

.markdown-preview[data-use-github-style] blockquote> :last-child {
  margin-bottom: 0px;
}

.markdown-preview[data-use-github-style] table {
  display: block;
  width: 100%;
  overflow: auto;
  word-break: keep-all;
}

.markdown-preview[data-use-github-style] table th {
  font-weight: bold;
}

.markdown-preview[data-use-github-style] table th,
.markdown-preview[data-use-github-style] table td {
  padding: 6px 13px;
  border: 1px solid rgb(221, 221, 221);
}

.markdown-preview[data-use-github-style] table tr {
  background-color: rgb(255, 255, 255);
  border-top: 1px solid rgb(204, 204, 204);
}

.markdown-preview[data-use-github-style] table tr:nth-child(2n) {
  background-color: rgb(248, 248, 248);
}

.markdown-preview[data-use-github-style] img {
  max-width: 100%;
  box-sizing: border-box;
}

.markdown-preview[data-use-github-style] .emoji {
  max-width: none;
}

.markdown-preview[data-use-github-style] span.frame {
  display: block;
  overflow: hidden;
}

.markdown-preview[data-use-github-style] span.frame>span {
  display: block;
  float: left;
  width: auto;
  padding: 7px;
  margin: 13px 0px 0px;
  overflow: hidden;
  border: 1px solid rgb(221, 221, 221);
}

.markdown-preview[data-use-github-style] span.frame span img {
  display: block;
  float: left;
}

.markdown-preview[data-use-github-style] span.frame span span {
  display: block;
  padding: 5px 0px 0px;
  clear: both;
  color: rgb(51, 51, 51);
}

.markdown-preview[data-use-github-style] span.align-center {
  display: block;
  overflow: hidden;
  clear: both;
}

.markdown-preview[data-use-github-style] span.align-center>span {
  display: block;
  margin: 13px auto 0px;
  overflow: hidden;
  text-align: center;
}

.markdown-preview[data-use-github-style] span.align-center span img {
  margin: 0px auto;
  text-align: center;
}

.markdown-preview[data-use-github-style] span.align-right {
  display: block;
  overflow: hidden;
  clear: both;
}

.markdown-preview[data-use-github-style] span.align-right>span {
  display: block;
  margin: 13px 0px 0px;
  overflow: hidden;
  text-align: right;
}

.markdown-preview[data-use-github-style] span.align-right span img {
  margin: 0px;
  text-align: right;
}

.markdown-preview[data-use-github-style] span.float-left {
  display: block;
  float: left;
  margin-right: 13px;
  overflow: hidden;
}

.markdown-preview[data-use-github-style] span.float-left span {
  margin: 13px 0px 0px;
}

.markdown-preview[data-use-github-style] span.float-right {
  display: block;
  float: right;
  margin-left: 13px;
  overflow: hidden;
}

.markdown-preview[data-use-github-style] span.float-right>span {
  display: block;
  margin: 13px auto 0px;
  overflow: hidden;
  text-align: right;
}

.markdown-preview[data-use-github-style] code,
.markdown-preview[data-use-github-style] tt {
  padding: 0.2em 0px;
  margin: 0px;
  font-size: 85%;
  background-color: rgba(0, 0, 0, 0.04);
  border-radius: 3px;
}

.markdown-preview[data-use-github-style] code::before,
.markdown-preview[data-use-github-style] tt::before,
.markdown-preview[data-use-github-style] code::after,
.markdown-preview[data-use-github-style] tt::after {
  letter-spacing: -0.2em;
  content: " ";
}

.markdown-preview[data-use-github-style] code br,
.markdown-preview[data-use-github-style] tt br {
  display: none;
}

.markdown-preview[data-use-github-style] del code {
  text-decoration: inherit;
}

.markdown-preview[data-use-github-style] pre>code {
  padding: 0px;
  margin: 0px;
  font-size: 100%;
  word-break: normal;
  white-space: pre;
  background: transparent;
  border: 0px;
}

.markdown-preview[data-use-github-style] .highlight {
  margin-bottom: 16px;
}

.markdown-preview[data-use-github-style] .highlight pre,
.markdown-preview[data-use-github-style] pre {
  padding: 16px;
  overflow: auto;
  font-size: 85%;
  line-height: 1.45;
  background-color: rgb(247, 247, 247);
  border-radius: 3px;
}

.markdown-preview[data-use-github-style] .highlight pre {
  margin-bottom: 0px;
  word-break: normal;
}

.markdown-preview[data-use-github-style] pre {
  overflow-wrap: normal;
}

.markdown-preview[data-use-github-style] pre code,
.markdown-preview[data-use-github-style] pre tt {
  display: inline;
  max-width: initial;
  padding: 0px;
  margin: 0px;
  overflow: initial;
  line-height: inherit;
  overflow-wrap: normal;
  background-color: transparent;
  border: 0px;
}

.markdown-preview[data-use-github-style] pre code::before,
.markdown-preview[data-use-github-style] pre tt::before,
.markdown-preview[data-use-github-style] pre code::after,
.markdown-preview[data-use-github-style] pre tt::after {
  content: normal;
}

.markdown-preview[data-use-github-style] kbd {
  display: inline-block;
  padding: 3px 5px;
  font-size: 11px;
  line-height: 10px;
  color: rgb(85, 85, 85);
  vertical-align: middle;
  background-color: rgb(252, 252, 252);
  border-width: 1px;
  border-style: solid;
  border-color: rgb(204, 204, 204) rgb(204, 204, 204) rgb(187, 187, 187);
  border-image: initial;
  border-radius: 3px;
  box-shadow: rgb(187, 187, 187) 0px -1px 0px inset;
}

.markdown-preview[data-use-github-style] a {
  color: rgb(51, 122, 183);
}

.markdown-preview[data-use-github-style] code {
  color: inherit;
}

.markdown-preview[data-use-github-style] pre.editor-colors {
  padding: 0.8em 1em;
  margin-bottom: 1em;
  font-size: 0.85em;
  border-radius: 4px;
  overflow: auto;
}

.markdown-preview pre.editor-colors {
  user-select: auto;
}

.scrollbars-visible-always .markdown-preview pre.editor-colors .vertical-scrollbar,
.scrollbars-visible-always .markdown-preview pre.editor-colors .horizontal-scrollbar {
  visibility: hidden;
}

.scrollbars-visible-always .markdown-preview pre.editor-colors:hover .vertical-scrollbar,
.scrollbars-visible-always .markdown-preview pre.editor-colors:hover .horizontal-scrollbar {
  visibility: visible;
}

.markdown-preview .task-list-item input[type="checkbox"] {
  position: absolute;
  margin: 0.25em 0px 0px -1.4em;
}

.markdown-preview .task-list-item {
  list-style-type: none;
}

.markdown-preview code {
  text-shadow: none;
}

@keyframes RotatingBackground {
  0% {
    background-position-x: 0%;
  }

  100% {
    background-position-x: 100%;
  }
}

.debugger-breakpoint-icon::before,
.debugger-shadow-breakpoint-icon::before {
  font-family: 'Octicons Regular';
  font-weight: normal;
  font-style: normal;
  display: inline-block;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  text-decoration: none;
  font-size: 130%;
  width: 130%;
  height: 130%;
  content: "\f052";
}

.debugger-breakpoint-icon,
.debugger-breakpoint-icon-disabled,
.debugger-breakpoint-icon-unresolved,
.debugger-breakpoint-icon-conditional,
.debugger-shadow-breakpoint-icon {
  text-align: center;
  display: block;
  width: 0.8em;
  cursor: pointer;
}

.debugger-breakpoint-icon-nonconditional {
  color: #5293d8;
}

.debugger-breakpoint-icon-conditional {
  color: #ff982d;
}

.debugger-breakpoint-icon-disabled {
  position: relative;
  top: -4px;
  left: 2px;
}

.debugger-breakpoint-icon-disabled::before {
  font-family: 'Octicons Regular';
  font-weight: normal;
  font-style: normal;
  display: inline-block;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  text-decoration: none;
  font-size: 78%;
  width: 78%;
  height: 78%;
  content: "\f084";
}

.debugger-breakpoint-icon-unresolved {
  position: relative;
  top: -2px;
}

.debugger-breakpoint-icon-unresolved::before {
  font-family: 'Octicons Regular';
  font-weight: normal;
  font-style: normal;
  display: inline-block;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  text-decoration: none;
  font-size: 80%;
  width: 80%;
  height: 80%;
  content: "\f0e8";
}

.debugger-shadow-breakpoint-icon {
  color: rgba(82, 147, 216, 0.4);
}

.debugger-current-line-highlight {
  background: linear-gradient(to bottom, rgba(0, 152, 255, 0.8) 0%, rgba(0, 152, 255, 0.8) 5%, rgba(0, 152, 255, 0.3) 5%, rgba(0, 152, 255, 0.3) 95%, rgba(0, 152, 255, 0.8) 95%, rgba(0, 152, 255, 0.8) 100%);
}

.gutter[gutter-name=diagnostics-gutter] {
  width: 0.7em;
}

.diagnostics-gutter-ui-item {
  display: flex;
}

.diagnostics-gutter-ui-item .icon {
  display: flex;
  width: 0.7em;
  height: 0.7em;
  font-size: 0.7em;
  align-self: center;
}

.diagnostics-gutter-ui-item .icon::before {
  width: 1em;
  height: 1em;
  font-size: 1em;
  margin: 0;
  align-self: center;
}

.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-info,
.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-review {
  color: #5293d8;
}

.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-error {
  color: #c00;
}

.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-action,
.diagnostics-gutter-ui-item.diagnostics-gutter-ui-gutter-warning {
  color: #ff982d;
}

.bracket-matcher .region {
  border-bottom: 1px dotted lime;
  position: absolute;
}

.line-number.bracket-matcher.bracket-matcher {
  color: #c5c8c6;
  background-color: rgba(255, 255, 255, 0.14);
}

.spell-check-misspelling .region {
  border-bottom: 2px dotted rgba(255, 51, 51, 0.75);
}

.spell-check-corrections {
  width: 25em !important;
}

pre.editor-colors {
  background-color: #1d1f21;
  color: #c5c8c6;
}

pre.editor-colors .invisible-character {
  color: rgba(197, 200, 198, 0.2);
}

pre.editor-colors .indent-guide {
  color: rgba(197, 200, 198, 0.2);
}

pre.editor-colors .wrap-guide {
  background-color: rgba(197, 200, 198, 0.1);
}

pre.editor-colors .gutter {
  background-color: #292c2f;
}

pre.editor-colors .gutter .cursor-line {
  background-color: rgba(255, 255, 255, 0.14);
}

pre.editor-colors .line-number.cursor-line-no-selection {
  background-color: rgba(255, 255, 255, 0.14);
}

pre.editor-colors .gutter .line-number.folded,
pre.editor-colors .gutter .line-number:after,
pre.editor-colors .fold-marker:after {
  color: #fba0e3;
}

pre.editor-colors .invisible {
  color: #c5c8c6;
}

pre.editor-colors .cursor {
  border-color: white;
}

pre.editor-colors .selection .region {
  background-color: #444;
}

pre.editor-colors .bracket-matcher .region {
  border-bottom: 1px solid #f8de7e;
  margin-top: -1px;
  opacity: .7;
}

.syntax--comment {
  color: #8a8a8a;
}

.syntax--entity {
  color: #FFD2A7;
}

.syntax--entity.syntax--name.syntax--type {
  text-decoration: underline;
  color: #FFFFB6;
}

.syntax--entity.syntax--other.syntax--inherited-class {
  color: #9B5C2E;
}

.syntax--keyword {
  color: #96CBFE;
}

.syntax--keyword.syntax--control {
  color: #96CBFE;
}

.syntax--keyword.syntax--operator {
  color: #EDEDED;
}

.syntax--storage {
  color: #CFCB90;
}

.syntax--storage.syntax--modifier {
  color: #96CBFE;
}

.syntax--constant {
  color: #99CC99;
}

.syntax--constant.syntax--numeric {
  color: #FF73FD;
}

.syntax--variable {
  color: #C6C5FE;
}

.syntax--invalid.syntax--deprecated {
  text-decoration: underline;
  color: #FD5FF1;
}

.syntax--invalid.syntax--illegal {
  color: #FD5FF1;
  background-color: rgba(86, 45, 86, 0.75);
}

.syntax--string .syntax--source,
.syntax--string .syntax--meta.syntax--embedded.syntax--line {
  color: #EDEDED;
}

.syntax--string .syntax--punctuation.syntax--section.syntax--embedded {
  color: #00A0A0;
}

.syntax--string .syntax--punctuation.syntax--section.syntax--embedded .syntax--source {
  color: #00A0A0;
}

.syntax--string {
  color: #A8FF60;
}

.syntax--string .syntax--constant {
  color: #00A0A0;
}

.syntax--string.syntax--regexp {
  color: #E9C062;
}

.syntax--string.syntax--regexp .syntax--constant.syntax--character.syntax--escape,
.syntax--string.syntax--regexp .syntax--source.syntax--ruby.syntax--embedded,
.syntax--string.syntax--regexp .syntax--string.syntax--regexp.syntax--arbitrary-repetition {
  color: #FF8000;
}

.syntax--string.syntax--regexp.syntax--group {
  color: #C6A24F;
  background-color: rgba(255, 255, 255, 0.06);
}

.syntax--string.syntax--regexp.syntax--character-class {
  color: #B18A3D;
}

.syntax--string .syntax--variable {
  color: #8A9A95;
}

.syntax--support {
  color: #FFFFB6;
}

.syntax--support.syntax--function {
  color: #DAD085;
}

.syntax--support.syntax--constant {
  color: #FFD2A7;
}

.syntax--support.syntax--type.syntax--property-name.syntax--css {
  color: #EDEDED;
}

.syntax--source .syntax--entity.syntax--name.syntax--tag,
.syntax--source .syntax--punctuation.syntax--tag {
  color: #96CBFE;
}

.syntax--source .syntax--entity.syntax--other.syntax--attribute-name {
  color: #FF73FD;
}

.syntax--entity.syntax--other.syntax--attribute-name {
  color: #FF73FD;
}

.syntax--entity.syntax--name.syntax--tag.syntax--namespace,
.syntax--entity.syntax--other.syntax--attribute-name.syntax--namespace {
  color: #E18964;
}

.syntax--meta.syntax--preprocessor.syntax--c {
  color: #8996A8;
}

.syntax--meta.syntax--preprocessor.syntax--c .syntax--keyword {
  color: #AFC4DB;
}

.syntax--meta.syntax--cast {
  color: #676767;
}

.syntax--meta.syntax--sgml.syntax--html .syntax--meta.syntax--doctype,
.syntax--meta.syntax--sgml.syntax--html .syntax--meta.syntax--doctype .syntax--entity,
.syntax--meta.syntax--sgml.syntax--html .syntax--meta.syntax--doctype .syntax--string,
.syntax--meta.syntax--xml-processing,
.syntax--meta.syntax--xml-processing .syntax--entity,
.syntax--meta.syntax--xml-processing .syntax--string {
  color: #8a8a8a;
}

.syntax--meta.syntax--tag .syntax--entity,
.syntax--meta.syntax--tag>.syntax--punctuation,
.syntax--meta.syntax--tag.syntax--inline .syntax--entity {
  color: #FF73FD;
}

.syntax--meta.syntax--tag .syntax--name,
.syntax--meta.syntax--tag.syntax--inline .syntax--name,
.syntax--meta.syntax--tag>.syntax--punctuation {
  color: #96CBFE;
}

.syntax--meta.syntax--selector.syntax--css .syntax--entity.syntax--name.syntax--tag {
  text-decoration: underline;
  color: #96CBFE;
}

.syntax--meta.syntax--selector.syntax--css .syntax--entity.syntax--other.syntax--attribute-name.syntax--tag.syntax--pseudo-class {
  color: #8F9D6A;
}

.syntax--meta.syntax--selector.syntax--css .syntax--entity.syntax--other.syntax--attribute-name.syntax--id {
  color: #8B98AB;
}

.syntax--meta.syntax--selector.syntax--css .syntax--entity.syntax--other.syntax--attribute-name.syntax--class {
  color: #62B1FE;
}

.syntax--meta.syntax--property-group .syntax--support.syntax--constant.syntax--property-value.syntax--css,
.syntax--meta.syntax--property-value .syntax--support.syntax--constant.syntax--property-value.syntax--css {
  color: #F9EE98;
}

.syntax--meta.syntax--preprocessor.syntax--at-rule .syntax--keyword.syntax--control.syntax--at-rule {
  color: #8693A5;
}

.syntax--meta.syntax--property-value .syntax--support.syntax--constant.syntax--named-color.syntax--css,
.syntax--meta.syntax--property-value .syntax--constant {
  color: #87C38A;
}

.syntax--meta.syntax--constructor.syntax--argument.syntax--css {
  color: #8F9D6A;
}

.syntax--meta.syntax--diff,
.syntax--meta.syntax--diff.syntax--header {
  color: #F8F8F8;
  background-color: #0E2231;
}

.syntax--meta.syntax--separator {
  color: #60A633;
  background-color: #242424;
}

.syntax--meta.syntax--line.syntax--entry.syntax--logfile,
.syntax--meta.syntax--line.syntax--exit.syntax--logfile {
  background-color: rgba(238, 238, 238, 0.16);
}

.syntax--meta.syntax--line.syntax--error.syntax--logfile {
  background-color: #751012;
}

.syntax--source.syntax--gfm {
  color: #999;
}

.syntax--gfm .syntax--markup.syntax--heading {
  color: #eee;
}

.syntax--gfm .syntax--link {
  color: #555;
}

.syntax--gfm .syntax--variable.syntax--list,
.syntax--gfm .syntax--support.syntax--quote {
  color: #555;
}

.syntax--gfm .syntax--link .syntax--entity {
  color: #ddd;
}

.syntax--gfm .syntax--raw {
  color: #aaa;
}

.syntax--markdown .syntax--paragraph {
  color: #999;
}

.syntax--markdown .syntax--heading {
  color: #eee;
}

.syntax--markdown .syntax--raw {
  color: #aaa;
}

.syntax--markdown .syntax--link {
  color: #555;
}

.syntax--markdown .syntax--link .syntax--string {
  color: #555;
}

.syntax--markdown .syntax--link .syntax--string.syntax--title {
  color: #ddd;
}

eel.jsは公式githubとかから取得してください

参考にしたサイト

CSSで作る!押したくなるボタンデザイン100(Web用)
Python eelでファイル選択ダイアログ

動作風景

Screenshot from 2020-02-25 14-39-18.png
Screenshot from 2020-02-25 14-39-33.png
Screenshot from 2020-02-25 14-39-37.png
Screenshot from 2020-02-25 14-39-39.png

exeファイル

exeファイル

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

URLのみ書かれたファイルからランダムにURLを10個抽出するPGM

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OwlCarousel2でスムーススライドショー

OwlCarousel2 2.3.4 (https://owlcarousel2.github.io/OwlCarousel2/)
を使った複数枚のスライドショーで、
デフォルトでは、1枚ずつ、画像端に来ると一時停止するようになっており、
要件では、一時停止せず、リニアに動かしたい要望があった。

リニアで調べると、オプションのslideTransitionにLinearを指定すると良いらしい。

slideTransition: 'linear',

しかし、うまく行かない。

さらに調べると、下記にあたった。
https://codepen.io/osingh/pen/wOqrPX
実装済みのようで、ちゃんと思った通りの動きをしていた。
しかし、実際おなじオプションを当ててみると、
うごきがおかしい。

さらに調べた際、
スムーズ ということばがおもいついたので、
それを調べると、Github内のページにあたった。
https://github.com/OwlCarousel2/OwlCarousel2/issues/296

読み進めると、一番最後に、一番知りたい内容が書かれていた。
https://github.com/OwlCarousel2/OwlCarousel2/issues/296#issuecomment-400703465

つまり、

autoplay : true,
slideTransition: 'linear',
autoplayTimeout : 4000,
autoplaySpeed : 400

autoplayTimeoutとautoplaySpeedを同値、
もしくは、autoplaySpeedの方を大きくするとのこと。
これにより、やりたいことが無事に実装できた。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】this

下記のようなクラスがあるとします。

class Person {
    constructor(name,age) {
      this.name = name
      this.age = age
    }
    hello() {
      console.log(`my name is = ${this.name}. ${this.age} years old.`)
    }

関数内でthisを呼び出す場合、下記のような書き方だとTypeError: this.hello is not a functionとなりエラーになります。

    remember(){
      setTimeout(function() { 
          this.hello(); 
      }, 1000);
    }

JavaScriptでは、関数内のthisは関数自体を指すため、hello()なんてないですよと怒られている状態です。
そのため、一度別の定数に退避させる必要があります。

    remember(){
      const self = this 
      setTimeout(function() { 
          self.hello(); 
      }, 1000);
    }

一度退避することで、呼びたいthisを正しく呼び出すことができます。

thisを退避させずに呼び出すには、bindメソッドを使います。

    remember2(){
      // self = thisが不要
      setTimeout(function() { 
          this.hello(); 
      }.bind(this), 1000);
    }

bindは束縛という意味です。

また、アロー関数にしてしまうとさらに短縮できます。

remember3() {
    // self=thisが不要
    setTimeout(()=>{ 
      this.hello();
    }, 1000);
  }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スクロールを一番下にもっていきたい(JavaScript)

コード

sample.js
  let scrollPlace = document.querySelector("スクロールしたい要素");
  scrollPlace.scrollTop = scrollPlace.scrollHeight
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

顔認識していろんなリップを試せるアプリの開発と挫折

概要

作ったものはこちら(https://touchlip.koatech.info/)

対面カメラやアップロードした画像に対し、色々なリップを合わせることができます。
こういったソリューションはPerfect社さんが圧倒的ですが、再発明してみました。

Perfectさんの製品は、CHANELのサイトを見ていただければ明らかですが、ラメやマット感など、リップによって異なる質感をうまく再現しています。僕が作ったのは残念ながら色を塗るだけです。

face-api.jsを使って顔認識も描画も全部クライアントサイドで完結しています。
Netlifyの無料枠がまだまだ余裕なので運用コストも無料です。

以下、頑張ったところをメモ。

リップを塗る処理

  1. 顔認識して顔のパーツのランドマークを取る
  2. どこにLandmarksのindex何番が表示されているのかを特定する

  3. どうlandmarksを繋げば綺麗に唇を描けるかを特定する

  4. canvas上で線を結んで塗りつぶす

1はface-api.jsがやってくれるので2以降を自力で作る必要があります。

const mouthLandmarks = [
  {x: 275.4868933089642, y: 330.9715563375305},
  {x: 282.46803207477615, y: 325.7225076276611},
  {x: 292.1396419831185, y: 320.55676439588774},
  {x: 299.4580142327218, y: 321.12185386007536},
  {x: 306.25136206826255, y: 317.9190892297577},
  {x: 321.9393919535546, y: 321.63006702249754},
  {x: 337.6620153017907, y: 323.5335417110275},
  {x: 325.27621345004127, y: 332.3888464290451},
  {x: 315.2544691391854, y: 338.6371144372772},
  {x: 304.66151045044944, y: 341.4427271205734},
  {x: 295.3428850599198, y: 341.4085681754898},
  {x: 285.4118543394475, y: 338.5544467288803}
]
const __fill = (canvasCtx, points) => {
  canvasCtx.beginPath()
  canvasCtx.moveTo(points[0].x, points[0].y)
  points.splice(0, 1)
  points.forEach((point, i) => {
    // pointを結ぶ線を引く。fill()で塗りつぶされる
    canvasCtx.lineTo(point.x, point.y)
    // pointの座標にindexの数字を配置する(デバッグ用)
    canvasCtx.fillText(i, point.x, point.y)
  })
  canvasCtx.fill()
}
canvasCtx.fillStyle = 'rgba(255,0,22,0.15)'
__fill(canvasCtx, mouthLandmarks)

関数ができたので、Vuexのactionから呼び出します。

draw ({ commit, state }, { canvasCtx, detection, color, transparent }) {
  const __mouthPoints = detection.landmarks.getMouth()
  const upperLip = [
    ...__mouthPoints.slice(0, 7),
    __mouthPoints[16],
    __mouthPoints[15],
    __mouthPoints[14],
    __mouthPoints[13],
    __mouthPoints[12]
  ]
  const lowerLip = [
    ...__mouthPoints.slice(6, 12),
    __mouthPoints[0],
    __mouthPoints[12],
    __mouthPoints[19],
    __mouthPoints[18],
    __mouthPoints[17],
    __mouthPoints[16]
  ]
  canvasCtx.fillStyle = `${color.slice(0, -1)}, ${transparent})`
  __fill(canvasCtx, upperLip)
  __fill(canvasCtx, lowerLip)
},

リップが点滅する

当初の実装と事象

対面カメラの映像にリップを塗るために以下を実装します。

  1. videoの内容をcanvasに表示

  2. 顔認識

  3. 唇のランドマーク取得

  4. リップ描画

  5. 1~4をsetIntervalで繰り返す

すると、前のintervalの4で書き込んだリップは、次のintervalの1で書き込まれたvideoに隠れてしまいます。

つまり、2と3の顔認識でラグればラグるほど、リップをvideoで上書きしてからもう一度リップを描画するまでが遅くなってしまい、ユーザーには、リップが点滅しているように見えてしまいます。

解決方法

唇のランドマークを取得したらその位置をキャッシュし、1の後すぐに描画する。

  1. videoの内容をcanvasに表示
  2. 顔認識結果がキャッシュされてたらリップ描画
  3. 顔認識
  4. 認識結果をキャッシュ
  5. 唇のランドマーク取得
  6. リップ描画
  7. 1~5をsetIntervalで繰り返す

video to canvasがiPhoneでインライン再生できない

canvasだけ表示したいのでvideoにhidden要素を指定して隠していましたが、safariではvideoを隠すと再生できないようになっています。

解決方法

#live-video {
  position: absolute;
  top: 10px; left: 10px;
  object-fit: fill;
  transform-origin: left top;
  transform: scale(.1);
}

canvasの左上にvideoも小さく表示するようにしました。transform: scale(.001)とかにしてしまえば見えないも同然です。

webRTCのアスペクト比がなかなか合わない

解決方法

getUserMediaのconstraintsで設定します。

const constraints = {
  aspectRatio: 0.75
}
const stream = await navigator.mediaDevices.getUserMedia({ video: constraints })

ちなみにこれでもiPhone safariではアスペクト比をいじれませんでした。

気合いで3:4のcanvasに合わせる関数を実装しました。

drawImage ({ commit, state }, { canvasDiv, canvasCtx, imagePath }) {
  const image = new Image()
  image.addEventListener('load', () => {
    let width, height, xOffset, yOffset
    if (image.width * 1.34 > image.height) {
      height = canvasDiv.height
      width = image.width * (canvasDiv.height / image.height)
      xOffset = -(width - canvasDiv.width) / 2
      yOffset = 0
    } else {
      width = canvasDiv.width
      height = image.height * (canvasDiv.width / image.width)
      yOffset = -(height - canvasDiv.width) / 2
      xOffset = 0
    }
    canvasCtx.drawImage(image, xOffset, yOffset, width, height)
  })
  image.src = imagePath
}

ちなみにこれでもダメでした。
方針を切り替え、スマホではカメラモードを使えないようにしてしまいます。
以下のような関数を作ってユーザーのデバイスを取得し、PC以外の端末ではカメラモードを使えないようにしてしまいました。

const getDevice = () => {
  const ua = navigator.userAgent
  if (
    (ua.indexOf('iPhone') > 0 || ua.indexOf('iPod') > 0 || ua.indexOf('Android') > 0) && ua.indexOf('Mobile') > 0) {
    return 'sp'
  } else if (ua.indexOf('iPad') > 0 || ua.indexOf('Android') > 0) {
    return 'tab'
  } else {
    return 'other'
  }
}

export default {
  getDevice,
}

iPhoneで画像アップロードすると回転する

iPhoneの画像はExifと呼ばれるメタデータを持っています。
ファイルサイズ、位置情報、撮影日時、回転情報などがこれに含まれます。
これを描画時に反映させないと意図しない方向に回転して表示されてしまいます。

解決方法

便利なライブラリを使って解決しました。

ライブラリインストール

npm install blueimp-load-image

インポート

import loadImage from 'blueimp-load-image'

実装例

onImageChange (file) {
  if (file !== undefined && file !== null) {
    if (file.name.lastIndexOf('.') <= 0) {
      return
    }
    loadImage.parseMetaData(file, (data) => {
      const options = {
        canvas: true
      }
      if (data.exif) {
        options.orientation = data.exif.get('Orientation')
      }
      loadImage(file, async (canvas) => {
        this.imageUrl = canvas.toDataURL('image/jpeg')
        // 顔認識と描画処理
      }, options)
    })
  } else {
    this.imageUrl = ''
  }
}

リップの製品情報を取得

こんな感じでデータを作っていきます。
公式サイトを訪問し、カラーピッカーで一つ一つリップの色を取得する地獄のような作業でした。
地球上の全ブランドを網羅するぐらいの気概で開発を始めましたが、ここで心折れました。

brands: [
  {
    name: 'THREE',
    items: [
      {
        name: 'THREE Daringly Distinct Lipstick',
        colors: [
          {id: '01', code: 'rgb(198,29,67)'},
          {id: '02', code: 'rgb(189,38,79)'},
          {id: '03', code: 'rgb(208,62,80)'},
          {id: '04', code: 'rgb(221,72,110)'},
          {id: '05', code: 'rgb(218,83,126)'},
          {id: '06', code: 'rgb(232,114,136)'},
          {id: '07', code: 'rgb(233,79,111)'},
          {id: '08', code: 'rgb(232,57,74)'},
          {id: '09', code: 'rgb(234,110,146)'},
        ]
      },
      {
        name: 'THREE Daringly Demure Lipstick',
        colors: [
          {id: '01', code: 'rgb(216,49,105)'},
          {id: '02', code: 'rgb(239,53,66)'},
          {id: '03', code: 'rgb(241,81,105)'},
          {id: '04', code: 'rgb(221,80,97)'},
          {id: '05', code: 'rgb(210,97,97)'},
          {id: '06', code: 'rgb(183,74,111)'},
          {id: '07', code: 'rgb(128,17,33)'},
          {id: '08', code: 'rgb(159,24,48)'},
          {id: '09', code: 'rgb(95,19,24)'},
        ]
      }
    ]
  },
]

終わり

リップの情報を取ってくるのが辛すぎたので、このプロダクトのことは一旦忘れることにしました。
それでも技術的に以下の知見が得られたので作ってよかったです。

  • webRTC
  • canvas
  • 顔認識
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

node.jsインストール直後の状態でpackage.jsonをアップデートする方法 ~npmグローバルインストール一切不要~

package.jsonを更新する場合、npm-check-updatesをグローバルインストールしてncu -uとやることが多いです。ただ、nodebrewなどのnodeバージョン管理システムを使っている場合、node.jsの新バージョンがリリースされるたびにグローバルインストールをやり直す必要があります。この問題、何とかならないでしょうか。実はnpm-check-updatesをnpx経由で呼べば、node.jsインストール直後の状態でもpackage.jsonを更新することができます。

package.jsonを更新する

npx npm-check-updates -u
npm install

解説

npx経由でnpm-check-updatesを呼び出しているだけです。試してみましたが、npx ncu -uとは出来ませんでした。

注意点

環境にもよりますが、上記手順はnpx npm-check-updates -uを実行するたびにnpm-check-updatesをローカル環境のインストールします。連続してnpm-check-updatesを呼びたい場合は、npx経由で呼び出すことはお勧めしません。自分の場合は上記コマンドを呼び出すのは1週間に1回程度なので、時間ロスについてはそこまで気にしていません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPで独自フレームワークを作ってサイトも作ってみた

Lalavelが重いと感じたのでPHP7でフレームワークを作ってサイトも作ってみました
サイトは https://mokuzist.com です

laravelが重いというところから始まったので無駄なものは出来るだけ入れないというスタンスです

Composerも名前空間も使っています
構造はDVECモデルとなっています

Controller、Entity Model、Data Model、Viewです
サイト自体は興味のある事をマッチング出来るサイトとなっています
サイトを使って頂いてバグ等あれば教えて頂けると幸いです

機能的にここがダメとかこれが欲しいという要望も受け付けております
これからの予定としては言語選択出来るようにして英語版も作る
人のフォロー機能もつける
もう少しスマホで使いやすいようにボタンを大きくする
スマホアプリ版も作る
といったような改修を予定しております

レビューありがとうございます
登録するとメールアドレスにhashがついたUrlが飛ぶのでそこにアクセスすると登録完了となります
ちなみにパスワードは某F社のように平文ではなくちゃんとhash化して保存してあり復元は不可能となっております

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPで独自フレームワーク作ってサイトも作ってみた

Lalavelが重いと感じたのでPHPで独自フレームワークを作ってそれでサイトも作ってみました。
https://www.mokuzist.com
というのがサイトです

フレームワーク自体はECDVという構造にしました
Controller、Entity Model、Data Model、viewという構造で余計なものを入れない超シンプル構造です
laravelが重いというところから始まっているので余計なものは一切入れてません

サイト、フレームワーク共にバグがないかテストして頂けると幸いです

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascriptで画像付きツイートを行う

経緯

山手線 Ver.2020 by 東京感動線でWebARから画像付きツイートをすることになり、色々と悪戦苦闘して、動くものができたので残しておきます。ニーズが無いのか、ググってもビンゴの記事がないのですよね。

コード

プラットフォームとして、Oauth.ioを使っています。
ポイントをコメントで残しました。

/* detail : base64エンコード済みの画像データ */
/* tweet_text : ツイート内容 */
function twitter_tweet(detail, tweet_text) {
    var oauth_result;
    OAuth.initialize("***public key***"); /* 各自PUBLIC KEYを設定 */
    OAuth.popup('twitter').then(function(result) {
        oauth_result = result;
    }).fail(function(err){
        /* エラー処理 */;
    });

    /* multipartにするための区切り */
    var bound_text = "------------------------1ae47d990b354d1b00a4eea60e6b5b72";

    var image_src =
        "--" + bound_text + "\r\n" +
        'Content-Disposition: form-data; name="media_data"' + "\r\n" +
        "\r\n" +
        detail + "\r\n" +
        "--" + bound_text + "--\r\n\r\n";

    /* この書き方でOauth署名は正しく作成される模様 */
    var param1 = {
        headers: {
            'Content-Type' : 'multipart/form-data; boundary=' + bound_text
        },
        data: image_src
    };

    /* 画像のアップロード */
    oauth_result.post('https://upload.twitter.com/1.1/media/upload.json', param1).done(function (response) {
        /* 画像のアップロードに成功したら、ツイートと紐づけるために */
        /* 画像データのIDを取得する */
        var media_id_ = response.media_id_string;

        var param2 = {
            data: {
                status: tweet_text,
                media_ids: media_id_
            }
        };

        /* ツイート */
        oauth_result.post('/1.1/statuses/update.json', param2).done(function (response) {
            /* ツイート成功時の処理 */;
        }).fail(function (err) {
            /* ツイート失敗時のエラー処理 */;
        });
    }).fail(function(err) {
        /* 画像アップロード失敗時のエラー処理 */;
    });
}

参考

最後に

あまり親切な文書になってないと思うので、気が向いたら更新します。
ここをもっと書いて欲しいとうのご要望いただけるとありがたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む