20210510のJavaScriptに関する記事は19件です。

【JavaScript】DOMからHTMLとCSSを操作して、背景色、文字色、文字サイズを操作せよ。

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>challenge_dom</title> </head> <body> <div id="large"> <div id="box1">文字色は赤、文字サイズは24p</div> <div id="box2">文字色は白、文字サイズはデフォルト</div> </div> <script> // ここに追記 var large = document.getElementById('large'); // id="box1"の要素を取得 var box1 = document.getElementById('box1'); // id="box1"の要素を取得 var box2 = document.getElementById('box2'); // id="box2"の要素を取得 large.style.backgroundColor = 'black'; box1.style.color = 'red'; box1.style.fontSize = "24px"; box2.style.color = 'white'; </script> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】DOM(Document Object Model)からHTMLとCSSを操作して、背景色、文字色、文字サイズを操作せよ。※css不要

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>challenge_dom</title> </head> <body> <div id="large"> <div id="box1">文字色は赤、文字サイズは24p</div> <div id="box2">文字色は白、文字サイズはデフォルト</div> </div> <script> // ここに追記 var large = document.getElementById('large'); // id="box1"の要素を取得 var box1 = document.getElementById('box1'); // id="box1"の要素を取得 var box2 = document.getElementById('box2'); // id="box2"の要素を取得 large.style.backgroundColor = 'black'; box1.style.color = 'red'; box1.style.fontSize = "24px"; box2.style.color = 'white'; </script> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptで連想配列にmapメソッドとfilterメソッドを同時に使う話

最初に 初心者が書いています。個人的メモ程度に思ってみてください。 もし、他の解決法などがあれば教えていただけると嬉しいです。 Markdownの記法に慣れるための練習も兼ねています。 「普通はこういう書き方するよ!」みたいなアドバイスも頂ければ幸いです。 本題 連想配列内の値を同時に複数取り出したい時を考えます。 例えば以下のような連想配列があります。 const inventory = [{ name: "apple", price: 120, category: "fruits" } { name:"bed", price: 3000, category: "furniture" } { name: "chair", price: 400, category: "furniture" }] この中のIDが1と3の時の値を同時に取り出したい時、このように考えます。 const index = [1, 3]; const result = inventory.map(item => item.filter(i => i.id === index)) console.log(result) しかし、この書き方だとエラーを吐きます。 Uncaught TypeError: item.filter is not a function filterが関数として見なされていないそうです。 調べてもよくわかりませんでした。 おそらくですが、mapメソッドの中で他のメソッドが使えないんだと思います。 (違ったら教えてください) いろいろ試した結果、こうやったら動きました。 const result = inventory.filter(item => index.includes(item.id)).map(item => item["name"]); console.log(result) 出力画面 // [object Array] (2) ["apple","chair"] 余談 配列の中から特定の条件を満たす要素を探すときにfindかfilterのどちらを使うべきかという話。 自分の感覚ではfilterを使うべきなのかなと思いました。 というのも、 find : 配列の要素の中から条件を満たす最も前の要素を1つだけ取り出す filter : 配列の要素の中から条件を満たす全ての要素を取り出す findを使うと取りこぼしが発生してしまうのでfilterを使うべきなのかなと。 一つしか入り得ないのならばfindでもいいのかもしれないです。 こちらの方が要素を見つけ次第探索を終了するから処理が少なくなって良いのかな?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptでアラートの表示

alert.html <DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <script src="alert.js"></script> <body> <input type="button" value="CLICK" onclick="myFunction();"/> </body> </html> alert.js function myFunction() { alert("alert!") }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HTML, CSS, JavaScriptで掲示板システムを作ってみた【その2-飾りaタグ禁止】

作成した掲示板システムの概略 こんな感じのメッセージ投稿とアンカー機能を搭載した掲示板システムを作成し昨日初投稿の記事として紹介しました。 【作成した掲示板】 判明した不具合 昨日初めてのWebプログラミング挑戦の一環として掲示板の記事を投稿したのですが、一つ大きなバグがあったので、早くもアップデートが入りました。 この掲示板にはコメントにアンカーをつける機能を搭載しており、>>1などの文字列を正規表現で置き換えることで、リンクにして目立たせる機能を搭載していたのですが、リンク先がないので当然NotFoundエラーが表示されていました。 今回の改良ポイント そもそもリンク用途のaタグを修飾に使うべきではないような気がしたので、普通にspanで囲んで、青色をつけました。 1つ目.js $("#comment").html($("#comment").html().replace(/&gt;&gt;(\d)/g,"<a href=id$1 class='anc'>" + "&gt;&gt;$1" + "</a>")); 1つ目のコードはaタグを利用して修飾しています 2つ目.js $("#comment").html($("#comment").html().replace(/&gt;&gt;(\d)/g,"<span x=id$1 class='anc text-primary id$1'>" + "&gt;&gt;$1" + "</span>")); 二つ目では単にtext-primaryクラスを追加し、bootstrapで修飾しているので、NotFoundエラーは出ません。タグ内の要素はhrefではなく適当にxとおいて互換しています。 さらなる改良 モバイル用のマウスイベントがJavaScriptにあるなんて! 以前はmouseenterがポップ出現条件だったのですが、スマホでは使えないという欠点がありました。今回、リンク不良が治ったためポップ条件をclickにし、PC用ではマウスが離れた時、スマホ用では画面スワイプでポップを削除するようにしました。 改良.js $(".pop" + n).on("mouseleave", function () {//マウスが離れた時削除 $(this).remove(); }) $(".pop" + n).on("touchmove", function () {//画面をスワイプしたとき削除 $(this).remove(); }) 一つ前の記事へ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js 勉強メモ】コンポーネントはLocal登録で使う

はじめに 仕事で使う事になったので1からVue.jsについて学んだ(元々Angularでプロダクト開発をやっていた事はあるがAngularはだめか・・・)。 ちゃんと覚えておかないとまずそうな事を備忘録として1つ1つ残しておく。 コンポーネントはLocal登録で使うべし 前提として、Vue.jsでコンポーネントを定義する方法には以下の2つがある。 # 方法 1 Local登録 2 Global登録 この内、基本的にはLocal登録を用いるようにするべき。 Gobal登録を一般的に用いない理由は、 あまり使用されないコンポーネントなのにファイルに残ってしまいファイルサイズが増加する などの弊害があるため。 ※Local登録・Gobal登録いずれも以下の画像のように描画される。 Local登録の例 sample.html <body> <div id="app"> <my-component></my-component> <my-component></my-component> <my-component></my-component> </div> <script src=" https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> <script> Vue.component('my-component', { data: function () { return { number: 12 } }, template: '<p>いいね({{number}})<button @click="increment">+1</button></p>', methods: { increment: function () { this.number += 1; } } }) new Vue({ el: '#app' }) </script> </body> Global登録の例 sample.html <body> <div id="app"> <my-component></my-component> <my-component></my-component> <my-component></my-component> </div> <script src=" https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> <script> const component = { data: function () { return { number: 12 } }, template: '<p>いいね({{number}})<button @click="increment">+1</button></p>', methods: { increment: function () { this.number += 1; } } } new Vue({ el: '#app', components: { 'my-component': component } }) </script> </body> Vue.jsの勉強メモ一覧記事へのリンク Vue.jsについて勉強した際に書いた勉強メモ記事のリンクを集約した記事。 https://qiita.com/yuta-katayama-23/items/dabefb59d16a83f1a1d4
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js 勉強メモ】コンポーネントはLocal登録で使うのが基本

はじめに 仕事で使う事になったので1からVue.jsについて学んだ(元々Angularでプロダクト開発をやっていた事はあるがAngularはだめか・・・)。 ちゃんと覚えておかないとまずそうな事を備忘録として1つ1つ残しておく。 コンポーネントはLocal登録で使うのが基本 前提として、Vue.jsでコンポーネントを定義する方法には以下の2つがある。 # 方法 1 Local登録 2 Global登録 この内、基本的にはLocal登録を用いるようにするべき。 Gobal登録を一般的に用いない理由は、 あまり使用されないコンポーネントなのにファイルに残ってしまいファイルサイズが増加する などの弊害があるため。 ※Local登録・Gobal登録いずれも以下の画像のように描画される。 Global登録の例 sample.html <body> <div id="app"> <my-component></my-component> <my-component></my-component> <my-component></my-component> </div> <script src=" https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> <script> Vue.component('my-component', { data: function () { return { number: 12 } }, template: '<p>いいね({{number}})<button @click="increment">+1</button></p>', methods: { increment: function () { this.number += 1; } } }) new Vue({ el: '#app' }) </script> </body> Local登録の例 sample.html <body> <div id="app"> <my-component></my-component> <my-component></my-component> <my-component></my-component> </div> <script src=" https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> <script> const component = { data: function () { return { number: 12 } }, template: '<p>いいね({{number}})<button @click="increment">+1</button></p>', methods: { increment: function () { this.number += 1; } } } new Vue({ el: '#app', components: { 'my-component': component } }) </script> </body> Vue.jsの勉強メモ一覧記事へのリンク Vue.jsについて勉強した際に書いた勉強メモ記事のリンクを集約した記事。 https://qiita.com/yuta-katayama-23/items/dabefb59d16a83f1a1d4
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Web Audio APIを使ったブラウザフィンガープリント手法の紹介

Web Audio APIというAPIがあります。 RFC / 日本語訳 ざっくり言うと、ブラウザで音を作ったり出したりできるAPIです。 RFCの時点でフィンガープリントの懸念が大量に書かれてるという有様ですが、実際に実用レベルでブラウザフィンガープリントしている例が存在しました。 FingerprintJSという、そのまんまな名前のライブラリです。 以下は同ライブラリのブログより、How the Web Audio API is used for browser fingerprintingという記事のざっくり紹介です。 How the Web Audio API is used for browser fingerprinting Cookieを使うこともなく、許可を求めることもなく、Webブラウザを識別できることを知っていますか? この技術はブラウザフィンガープリントと呼ばれていて、ブラウザの属性を読み取り、まとめて一つの識別子にすることによって識別します。 ブラウザフィンガープリントの生成方法には色々なものがありますが、今回取り上げる独創的なテクニックが、オーディオフィンガープリントです。 オーディオフィンガープリントは比較的ユニークで、そして安定しているため、貴重な情報源です。 ユニークである理由は、Web Audio APIが複雑で精巧であり、オーディオソースが数学的に生成されたものであるからです。 実装に入る前に、Web Audio APIのアイデアをいくつか理解しておく必要があります。 A brief overview of the Web Audio API Web Audio APIはオーディオの操作を行うパワフルなAPIです。 ひとつのAudioContextで複数のソースや処理をチェーン実行することができます。 ソースとしてはaudio要素、stream、そしてOscillatorから数学的に生成されたインメモリソースなどがあります。 ここではソースとしてOscillatorを使います。 AudioContext AudioContextは処理の全体を表し、複数のノードをリンクして実行を制御します。 AudioContextは最初にひとつだけ生成し、その後はそれを使い回します。 特殊なAudioContextとしてOfflineAudioContextがあり、これは生成した音を再生することなくAudioBufferメモリ上に保存します。 const AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext const context = new AudioContext(1, 5000, 44100) AudioBuffer AudioBufferはメモリに保存された小さな音声ファイルです。 複数のチャンネルを格納することができますが、ここでは1チャンネルだけ利用します。 Oscillator Oscillatorは周期的な波形を生成する最も簡単な方法で、デフォルトは正弦波です。 矩形波、三角波など他の形を生成することも可能です。 Compressor Web Audio APIにはDynamicsCompressorNodeというCompressorが用意されています。 DynamicsCompressorNodeには多くのプロパティがありますが、ここではその一部を利用します。 How the audio fingerprint is calculated 必要な概念が揃ったので、オーディオフィンガープリントを作ってみましょう。 1チャンネル、フレーム数5000、サンプリングレート44100HzのAudioContextを作成します。 これは113ミリ秒の長さになります。 const AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContex const context = new AudioContext(1, 5000, 44100) 次にoscillatorで、音源となる1秒間に1000回の三角波を生成します。 const oscillator = context.createOscillator() oscillator.type = "triangle" oscillator.frequency.value = 1000 さらにCompressorを作成し、信号を変換しましょう。 const compressor = context.createDynamicsCompressor() compressor.threshold.value = -50 compressor.knee.value = 40 compressor.ratio.value = 12 compressor.reduction.value = 20 compressor.attack.value = 0 compressor.release.value = 0.2 それぞれのノードを接続します。 oscillator.connect(compressor) compressor.connect(context.destination); 完成したらoncompleteを使って結果を取得します。 oscillator.start() context.oncomplete = event => { const samples = event.renderedBuffer.getChannelData(0) }; context.startRendering() samplesは音を表す浮動小数の配列です。 ここからひとつの値を生成する必要がありますが、ここでは単純に全ての値を合計してみましょう。 function calculateHash(samples) { let hash = 0 for (let i = 0; i < samples.length; ++i) { hash += Math.abs(samples[i]) } return hash } console.log(getHash(samples)) これでオーディオフィンガープリントの完成です。 101.45647543197447 MacOSのChromeで実行すると、このような数字が出てきました。 オープンソースのライブラリで、実際の実装を確認することができます。 これをSafariで実行すると、別の値が出てきました。 79.58850509487092 Firefoxだとまたさらに別の値になりました。 80.95458510611206 全てのブラウザで、異なる値になりました。 この値は何度計算しても安定していて、シークレットモードにおいても同じ値になります。 この値はハードウェアとOS、ブラウザに依存します。 Why the audio fingerprint varies by browser なぜブラウザによって値が異なるのか見てみましょう。 ChromeとFirefoxで、単一の三角波を出力したときの波形は本来はこのようになるはずです。 しかし実際に出力される形はOSやブラウザによって異なります。 主要なブラウザエンジン(Blink・WebKit・Gecko)は、Googleが2011年ごろに開発したコードをベースにWeb Audio APIを実装しました。 その後ブラウザごとに多くの変更が加わったため、オーディオフィンガープリントにはそれぞれ違いが生じました。 最近の実装は以下で見ることができます。 Blink: oscillator / dynamics compressor WebKit: oscillator / dynamics compressor Gecko: oscillator / dynamics compressor Pitfalls オーディオフィンガープリントの実用にあたって、我々はブラウザの互換性、安定性、パフォーマンスの向上を目指しました。 互換性として、TorやBraveといったプライバシーに特化したブラウザにも注力しました。 OfflineAudioContext OfflineAudioContextはほとんどの環境で利用できますが、一部特別な処理が必要なケースもあります。 まずiOS11以前では、OfflineAudioContextはユーザアクションでのみトリガー可能です。 このバージョンを未だに使っているユーザはほとんどいないので、サポート対象から外しました。 ついでiOS12以降では、ページがバックグラウンドに行ったときに処理が拒否される場合があります。 幸いフォアグラウンドに戻れば再開できるので、context.startRendering()を何度も試みるようにしました。 Tor これはシンプルです。 TorではWeb Audio APIが無効化されているため、オーディオフィンガープリントは使えません。 Brave Braveでの状況は微妙です。 Braveは、Blinkから派生したプライバシー重視のブラウザです。 このブラウザは、サンプリング値をわずかに変動させる仕組みが備わっており、これはfarblingと呼ばれています。 farblingは3レベルがあり、ユーザは好きな設定を選ぶことができます。 Disabled : farblingしない。他のブラウザと同じ。 Standard : デフォルト。セッションごとに決められたランダム値(fudgeと呼ばれる)増減する。 Strict : 音波が疑似乱数に置き換えられる。 fudgeは取得できるので、Standardの設定であればfarblingする前の値に戻すことができます。 Audio fingerprinting is only a small part of the larger identification process. オーディオフィンガープリントは、我々のライブラリがブラウザフィンガープリントを生成するために使用する、多くの情報源のひとつにすぎません。 全てのフィンガープリントを盲目的に受け入れず、それぞれの安定性やカーディナリティを個別に分析し、精度を判断しています。 オーディオフィンガープリントはカーディナリティは高くないものの、安定性が高いため、フィンガープリントの精度を向上することができます。 Try Browser Fingerprinting for Yourself ブラウザフィンガープリントは、訪問者の識別方法として有効です。 特に、Cookieの消去、シークレットモード、VPNの使用などでトラッキングを避けようとする"maliciousな"訪問者を特定することに役立ちます。 我々のオープンソースライブラリを用いて独自にブラウザフィンガープリントを実装することもできます。 我々はまた、さらに高い精度を誇るFingerprintJS Pro APIを開発しました。 月間1000人までは無料で使用できます。 感想 Web Audio APIはパーミッションが不要です。 ユーザリアクションなしに音を出すことは許されていませんが、逆に言えば音さえ出さなければなんでもできるということです。 すなわち、あなたのブラウザは既にこれらの技術で密かにフィンガープリントされているということです。 この技術はあくまでブラウザフィンガープリントであって、ブラウザを識別するためには使えても、それ以上の情報を得ることはできません。 そのブラウザを誰が使っているのか、複数のブラウザの紐付けといった情報なんかはわからないということですね。 だったら安全じゃないか? そのとおりです。 この技術が、単独で使われているかぎりは。 その他の技術と組み合わせることで、一気に危ない技術になります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ZustandとValtioを比較するサンプルコードをcodesandboxで書いてみた

zustandとvaltioはコーディングのスタイルは違いますが、用途は似ています。zustandをimmerとともに使う場合は、valtioの方があっていることが多いと思います。 そこで、簡単な例を書いてみました。 zustand+immerの場合 valtioの場合 どうでしょうか。これだけの比較で判断することは難しいですが、狙いが伝われば幸いです。 「React Fan」というコミュニティのSlackでzustandやvaltioに関する質問や雑談ができますので、よろしければご参加ください。 React開発者向けオンラインサロン「React Fan」の入り口ページ React開発者向けオンラインサロン「React Fan」のTwitterアカウント
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

指定された時間から45分後の時間を得る

指定された時間から、45分後の時間を得る const currentTime = "23:19" const afterTime = currentTime.split(":"); //23時の場合 if (Number(afterTime[0]) === 23) { //23:15分未満の場合 if (Number(afterTime[1]) < 15) { console.log(Number(afterTime[0]) + ":0" + (Number(afterTime[1]) + 45)); } //15分以上25分未満 else if (Number(afterTime[1]) >= 15 && Number(afterTime[1]) < 25) { console.log("0" + ":0" + (Number(afterTime[1]) + 45 - 60)); } else { //25分以上の場合 console.log("0" + ":" + (Number(afterTime[1]) + 45 - 60)); } // 0時から23時の場合 } else if (Number(afterTime[0]) >= 0 && Number(afterTime[0]) < 23) { //15分未満の場合 if (Number(afterTime[1]) < 15) { console.log(Number(afterTime[0]) + ":" + (Number(afterTime[1]) + 45)); } else if (Number(afterTime[1]) >= 15 && Number(afterTime[1] < 25)) { // 15分以上25分未満 console.log(Number(afterTime[0]) + 1 + ":0" + (Number(afterTime[1]) + 45 - 60)); } else { //25分以上の場合 console.log(Number(afterTime[0]) + 1 + ":" + (Number(afterTime[1]) + 45 - 60)); } } 強引すぎるのでいい方法あればお願いします❗️
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VueCLIでpace.jsを使用する

Pace.jsを使ってページローダーを実装する https://codebyzach.github.io/pace/ PACEはファイルを読み込むだけで簡単にプログレスバーが実装できる定番のプラグインです。また、デザインのテーマが豊富に用意されているので様々なローディング画面を演出できます。 publicフォルダ内にPace.jsを配置した後、 public/index.html <head> <!-- 省略 --> <script src="./pace.js"></script> </head> App.vue <style> @import "./assets/styles/loader.css"; </style> loader.css .pace-done #app { opacity: 1; transition: opacity 2s; } .pace-running #app { opacity: 0; } /* 以下略 */ 上記のようにすることで、ページローダーをVueCLIに配置することができます。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Grid.jsで単位ありのsortがしたい。

経緯 Grid.jsのsortオプションでは、以下の関数が動いている if (a > b) { return 1; } else if (b > a) { return -1; } else { return 0; } しかし、これだと200円や10個といった単位付きでの比較はできない。 表示されるDataを変更するオプションは存在するが、a,bには変更後のデータが格納されてしまうため、そこから数値のみを取り出して比較していく。 単位付きのままsortをかけてみる ソースコードは画像の下にあります。 index.js <Grid data={[ {id: '001', fruite: 'りんご', price: 200, sum: 20}, {id: '002', fruite: 'バナナ', price: 150, sum: 10}, {id: '003', fruite: 'ぶどう', price: 800, sum: 3}, {id: '004', fruite: 'メロン', price: 2000, sum: 1}, ]} columns={[ { id: 'id', name: 'ID' }, { id: 'fruite', name: 'フルーツ', sort: false, }, { id: 'price', name: '価格', data: (row)=> row.price + '個', }, { id: 'sum', name: '個数', data: (row)=> row.sum + '個', }, ]} sort={true} search={true} /> 数値のみを取り出してsortをかける index.js <Grid data={[ {id: '001', fruite: 'りんご', price: 200, sum: 20}, {id: '002', fruite: 'バナナ', price: 150, sum: 10}, {id: '003', fruite: 'ぶどう', price: 800, sum: 3}, {id: '004', fruite: 'メロン', price: 2000, sum: 1}, ]} columns={[ { id: 'id', name: 'ID' }, { id: 'fruite', name: 'フルーツ', sort: false, }, { id: 'price', name: '価格', data: (row)=> row.price + '個', sort: { compare: (a,b) => { // a,bから数値のみを取り出す正規表現        // 結果を比較して1, -1, 0のいずれかを返す } } }, { id: 'sum', name: '個数', data: (row)=> row.sum + '個',      sort: { compare: (a,b) => { // a,bから数値のみを取り出す正規表現        // 結果を比較して1, -1, 0のいずれかを返す } } }, ]} sort={true} search={true} /> うまくいくと こうなります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

hermes(JavaScript engine)を C++14 アプリに組み込むメモ

C++ アプリに JavaScript エンジン組み込みたい(JS で制御とか). Duktape もいいけど, グラフィックス処理などでパフォーマンスがほしいときもある. hermes を考えます. C++14 + cmake で依存ライブラリも一緒に入っている + MIT ライセンスで, 自前 C++ アプリに組み込みやすくなっています. 基本 add_subdirectory() でいけます. ただ, hermes の CMakeLists.ext では global な add_definition とかしているので, 自前アプリや他の submodule となにかかち合うかもしれませんので注意しておきましょう. また, hermes ライブラリは add_target_libraries に追加しても, うまくパスとおしてくれないようです. 自前でインクルードパス指定必要です. binary(build)ディレクトリに hermes/Support/Config.h が生成されるのでこれへのパスも通しておきます. # 必要に応じて hermes の cmake オプション設定を上書き(override) # ... add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third_party/hermes hermes) set(EXT_LIBRARIES hermesVMRuntime hermesCompilerDriver hermesConsoleHost hermesAST hermesHBCBackend hermesBackend hermesOptimizer hermesFrontend hermesParser hermesSourceMap hermesSupport dtoa hermesInstrumentation ) # hermes/Support/Config.h target_include_directories(${TARGET} PUBLIC ${CMAKE_BINARY_DIR}/hermes/include) target_include_directories(${TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/third_party/hermes/include) とりあえずはこんな感じでしょうか. あとは $hermes/tools/hermes/ あたりの repl サンプルを参考にすればいけるはず... です!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【GAS入門】Google Driveのファイル一覧を作成する

TL;DR Google Driveのファイル一覧をスプレッドシートに作成する、Google App Scriptを作成しました。 スプレッドシートを自分のフォルダにコピーするだけで使えます。 (画像はテンプレートを表示しています。スクリプトを実行すると自分のファイル一覧が取得できます。) 背景 ファイルの保存先として、Google Driveを使っている企業はかなり存在すると思います。 一方でWikiなどのツールが社内で使われていない場合、Google Driveがドキュメントをまとめる役割を持ちます。Googleの素晴らしい技術により、検索は高速なため困ることはほとんどありませんが、フォルダの階層が多い場合などの一覧性という点では問題があります。 つまり今回のテーマは、「Google Driveにファイルの一覧性を付加する」です。 (ちなみに弊社ではConfluenceを活用しているので、上記の状態には当たりません。しかし所属しているチームでは、Google Driveを多用しているので、今回のツールを作成することとなりました。) ポイント 使いやすさを考え、ユーザーやフォルダ固有の設定が不要な実装としました 簡単に、すぐに動くため、GASの理解にも役立つと考えました 利用方法 ファイル一覧のスプレッドシートを自分のドライブに保存する。(ファイル > コピーを作成) スクリプトを実行 or トリガーを設定する 2.の詳細 一度だけ実行する場合は「スクリプトを実行」を、継続的にフォルダ内のファイルを確認したい場合は「トリガーを設定する」を確認してください。 まずは、スクリプトを開きます。 Spreadsheetを開いて、以下の手順で進めます。 (Spreadsheetのアップデートにより、多少方法が異なることもあります) 新しいバージョン:拡張機能 > Apps Script 古いバージョン:ツール > スクリプトエディタ スクリプトを実行 myFunctionが選択されていることを確認して、実行を押してください! トリガーを設定する 左メニューの目覚まし時計アイコン > トリガー > 右下のトリガーを追加 から、起動時や特定の時間に実行するトリガーを設定。 以上です! 実装詳細 利用するだけなら、上記の手順だけです。 せっかくなので、実装の詳細を説明します。 コード.gs function myFunction() { // 一覧にしたいフォルダの階層を指定してください。 // 0の場合、スプレッドシートが存在するフォルダのみのファイル一覧が表示されます。 const depth = 1; // getActive()で結びついているスプレッドシートを取得 const spreadSheet = SpreadsheetApp.getActive(); const id = spreadSheet.getId(); folderRoot = DriveApp.getFileById(id).getParents().next(); // デフォルトの'シート1'をそのまま利用 const sheet = spreadSheet.getSheetByName('シート1'); // 1行目は見出しなので、2行目以降にファイル一覧を表示 const rowInit = 2; const rowLast = sheet.getLastRow(); // すでにデータがある場合、一旦クリア if (rowLast > 1) { sheet.getRange(rowInit, 1, rowLast - rowInit + 1, 100).clear(); } // depthに合わせてフォルダを探索 digFolders(folderRoot, sheet, depth) } function digFolders(rootFolder, sheet, depth) { // 現在のフォルダのファイル一覧を取得 listFiles(rootFolder, sheet); // depthが0になるまで探索 if (depth > 0) { const folders = rootFolder.getFolders(); while (folders.hasNext()) { const folder = folders.next(); // depthを1減らして、再帰実行 digFolders(folder, sheet, depth - 1) } } } function listFiles(folder, sheet) { const files = folder.getFiles(); let row = sheet.getLastRow() + 1; // 次のファイルが存在する場合、処理を継続 // 1ファイルごとに1行ずつスプレッドシートに書き込み while (files.hasNext()) { const file = files.next(); // ハイパーリンクをそのまま書き込み const folderValue = '=HYPERLINK("' + folder.getUrl() + '","' + folder.getName() + '")'; sheet.getRange(row, 1).setValue(folderValue); const fileValue = '=HYPERLINK("' + file.getUrl() + '","' + file.getName() + '")'; sheet.getRange(row, 2).setValue(fileValue); const fileValueEn = '=HYPERLINK("' + file.getUrl() + '",' + 'GOOGLETRANSLATE("' + file.getName() + '", "ja", "en")' + ')'; sheet.getRange(row, 3).setValue(fileValueEn); sheet.getRange(row, 4).setValue(file.getLastUpdated()); row = row + 1; } } まとめ コピーしてスクリプトを実行するだけなので、ぜひ試してみてください! 便利なGASを使うきっかけになれば、幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DynamoDBクライアントでセッション再利用されるのか実験してみた その2

前回の追加実験です。 Promise.all()したらどうなるのかやってみました。 実験1 まずは前回の実験3の状態に、環境変数AWS_NODEJS_CONNECTION_REUSE_ENABLEDを1にセットした状態で、別々のインスタンスでセッションが共有されることを確認します。 import { DynamoDB } from 'aws-sdk'; import { execSync } from 'child_process'; process.env.AWS_REGION = 'ap-northeast-1'; process.env.AWS_NODEJS_CONNECTION_REUSE_ENABLED = '1'; const TableName = 'test-table'; function getDynamoDB() { return new DynamoDB({ endpoint: 'http://localhost:18005', }); } function printSession() { try { const stdout = execSync('lsof -i@localhost | grep node'); console.log(stdout.toString()); } catch (e) { console.error('null'); } } async function main() { console.log('#0'); printSession(); const cl = getDynamoDB(); console.log('#1'); printSession(); await cl.describeTable({ TableName }).promise(); console.log('#2'); printSession(); await cl.describeTable({ TableName }).promise(); console.log('#3'); printSession(); const cl2 = getDynamoDB(); console.log('#4'); printSession(); await cl2.describeTable({ TableName }).promise(); console.log('#5'); printSession(); } main(); 以下が出力されました。 #0 null #1 null #2 node 6070 user 29u IPv4 0xa83d103bf35ef62d 0t0 TCP localhost:51201->localhost:18005 (ESTABLISHED) #3 node 6070 user 29u IPv4 0xa83d103bf35ef62d 0t0 TCP localhost:51201->localhost:18005 (ESTABLISHED) #4 node 6070 user 29u IPv4 0xa83d103bf35ef62d 0t0 TCP localhost:51201->localhost:18005 (ESTABLISHED) #5 node 6070 user 29u IPv4 0xa83d103bf35ef62d 0t0 TCP localhost:51201->localhost:18005 (ESTABLISHED) インスタンスが違っても共有されてますね。 実験2 main()の最後に以下を追加して実行してみます。 (差分のみ記載) const requests = [cl.describeTable({ TableName }).promise(), cl2.describeTable({ TableName }).promise()]; await Promise.all(requests); console.log('#6'); printSession(); 以下が出力。 #0 null #1 null #2 node 6584 user 29u IPv4 0xa83d103c049d8c4d 0t0 TCP localhost:51367->localhost:18005 (ESTABLISHED) #3 node 6584 user 29u IPv4 0xa83d103c049d8c4d 0t0 TCP localhost:51367->localhost:18005 (ESTABLISHED) #4 node 6584 user 29u IPv4 0xa83d103c049d8c4d 0t0 TCP localhost:51367->localhost:18005 (ESTABLISHED) #5 node 6584 user 29u IPv4 0xa83d103c049d8c4d 0t0 TCP localhost:51367->localhost:18005 (ESTABLISHED) #6 node 6584 user 29u IPv4 0xa83d103c049d8c4d 0t0 TCP localhost:51367->localhost:18005 (ESTABLISHED) node 6584 user 30u IPv4 0xa83d103bf0bcd62d 0t0 TCP localhost:51368->localhost:18005 (ESTABLISHED) 新しいセッションが作られました。 念のため、同じインスタンスだとどうなるのか。 const requests = [cl.describeTable({ TableName }).promise(), cl.describeTable({ TableName }).promise()]; await Promise.all(requests); console.log('#6'); printSession(); 結果は同じでした。 (出力は割愛) まとめ 同時に処理される場合は、リクエストに必要なだけ(不足する分の)セッションが作られました。 (まあ、当たり前と言えば当たり前か) 高速化を狙って並列化しても、却って遅くなることもあるかも知れないです。 それよりも、(ちゃんと)テーブルやクエリを工夫して、リクエスト数を減らす方がよさそうですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「転生したらスライムだった件」の大賢者チャットボットを作ってみた件

チャットボットを制作していたのですが、ボットとの会話が味気ないなと感じ、思案した結果、転スラの大賢者風に話せてみようと作ってみました。 「転スラ」をご存じないという方はこちらを見てください。 https://www.ten-sura.com/ 完成イメージ動画 前回書いた記事 環境 Windows10 Virtualbox v6 Docker AWS CLI Nginx Botpress v12 PHP 参考リンク Botpressインストール 今回はWindows10上にVirtualboxをセットアップしてCentos7をインストール、そのCentos7にDockerを入れてBotpressのコンテナを起動させています。 かなり複雑になってしまった。。。(;^ω^) Botpress設定 全体フロー図 段々とノードが増えていくにつれ、見にくくなっていくので対象のノードを探すのに困っています。このあたり何んとかならないものかな。。。 システムフロー ユーザ→Bopress→API→コマンド実行 FAQ Emulatorをしばらく置いておくとセッションが切れてしまうので面倒でしたが↓で設定できることが分かりました。 最後に Botpressはチャットボットを自分で一からスクラッチ開発出来るので気に入っています。 今回はチャットボットの制作で力尽き、詳細をお伝えできませんがまたその内、更新したいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Webアプリケーション(2)

Webアプリケーション(2) Webアプリケーション(1)の続きです。 XAMPPとVisual Studio Codeがインストール済みを前提としてすすめます。 今回の内容(動画) XAMPPの作業用フォルダを設定する Visual Studio Codeでフォルダを開くを選択 Windosの場合 Cドライブ>XAMPP>htdocs フォルダを選び、下のフォルダーの選択をクリック Macの場合 移動>アプリケーションXAMPP>xamppfiles>htdocs フォルダを選び、下のフォルダーの選択をクリック エクスプローラーにhtdocsの中が表示される 先ほど選択したフォルダの中がエクスプローラー(左)で見えていることを確認してください 次はこちら (次)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Javascript】try・catch・throw・finallyを試してみた

初めに try...catchなどの例外処理について、学習した内容を纏めてみました。 ※内容に間違いなどがある場合はご指摘をよろしくお願いします。 エラーが出そうな関数の処理 例えば以下のような配列の特定の要素を出力する関数があるとします。 const fruits = ['apple', 'banana', 'mango', 'orange']; function getFruitName(num) { num += 1; document.write(fruits[num]); } getFruitName(3); fruitsの4番目はないため、画面に何も表示されません。当たり前ですが、このような場合でもちゃんとエラーが表示するようにしたいことってありますね。 throw throwは意図的に例外を生成することができます。 throw 'エラー発生'; コンソールには赤文字で以下のように表示されます。 しかしこのようなやり方は非推奨で、errorオブジェクトそ生成してからthrowします。 const err = new Error('エラー'); throw err; 先ほどの例に戻ってと意図的に例外を投げてみます。 const fruits = ['apple', 'banana', 'mango', 'orange']; function getFruitName(num) { num += 1; if (fruits[num] != null) { document.write(fruits[num]); } else { const err = new Error('エラー'); throw err; } } getFruitName(3); このようにしてエラーが表示されない場合でも、意図的に表示させることができました。 try...catch エラーが予想される関数などを実行する場合に、そのエラーに対して何らかの処理をするために使われるのがtry...catch構文です。 try { getFruitName(3); } catch (e) { //eにはエラーの内容が格納されている document.write(e); } ブラウザーにはerrorの内容をcatchして画面に表示されます。 catchの引数にはthrow errの戻り値が格納されていて、エラーの内容が入っています。 finally 例外が発生してもしなくても必ず処理したい命令などを扱う場合にはfinallyを使います。 try { getFruitName(3); } catch (e) { document.write(e); } finally { document.write('お疲れ様です') } 参考記事 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/try...catch https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Error https://qiita.com/Tsuyoshi84/items/c50fbbf30a2af387efdf
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【javaScript】エモいマインスイーパ から学ぶ再帰関数

プログラミングの学習のために同僚たちとともにマインスイーパを作る腕試しをしたところ、とてもエモい作品が上がってきたのでご紹介したいと思い、記事にしました。 以下のページで実際に動かすことができます。 MINESWEEPER 本記事の内容はエモいマインスイーパの紹介を通して、 再帰関数の使い方 背景色をじわじわ変えるCSSの方法 を解説します。 デザインコンセプト エモいマインスイーパは、初期画面では真っ黒な背景です。 ゲームを進めていくごとに背景色が徐々に変化していきます。 黒→青→水色… と変化し、成功すると最後は美しいグラデーションでfinishします。 これは夜明けをイメージしています。マインスイーパは地雷除去のゲームなので、平和な世界にしたいというエモい希望が込められています。 背景色が変化する実装は後ほど解説します。 start play1 play2 clear game over アルゴリズム、ロジックのわかりやすい解説 セルの生成と状態管理 ゲームボードはtableタグで、ひとつひとつのセルはtdタグになっています。 セルは、以下のような状態を持つ必要があります。 爆弾があるか 周辺の爆弾の数 旗が立っているか 開いているか、閉じているか エモいマインスイーパはこれらの状態をDOMに保持して管理しています。つまり、tdタグのclass属性であったり、innerTextに数字を持っていたりします。 周辺の爆弾の数の求め方 周辺の爆弾の数を求めるには、周辺のセルにアクセスする必要があります。 エモいマインスイーパはjQueryによるDOM操作で周辺のセルにアクセスします。 // n番目のセルを取得するコード $('#gameBody td').eq(n); tdを配列で全部取得して、配列のn番目を取得しています。 周辺のセルは、上、下、左、右、左上、右上、左下、右下の8箇所あります。それぞれのnを求める必要があります。 起点となるセルのインデックス(i)とゲームボードの列数(w)のふたつを使いnを算出します。 // 左上 let tl = i - w - 1; // 上 let t = i - w; // 右上 let tr = i - w + 1; // 左 let l = i - 1; // 右 let r = i + 1; // 左下 let bl = i + w - 1; // 下 let b = i + w; // 右下 let br = i + w + 1; ただし、角や端のセルは周辺にセルが8箇所あるとは限りません。角かどうか、端かどうかを判定しながら存在する周辺セルのnのみを取得します。 let array = [tl, t, tr, l, r, bl, b, br]; if (i === 0) { // ボードの左上の角 array = [r, b, br] } else if (i === w - 1) { // ボードの右上の角 array = [l, bl, b] } else if (i === w * (h - 1)) { // ボードの左下の角 array = [t, tr, r] } else if (i === w * h - 1) { // ボードの右下の角 array = [tl, t, l] } else if (i < w - 1) { // ボードの1行目(上端) array = [l, r, bl, b, br] } else if (i > w * (h - 1)) { // ボードの最優業(下端) array = [tl, t, tr, l, r] } else if (i % w === 0) { // ボードの1列目(左端) array = [t, tr, r, b, br] } else if (i % w === w - 1) { // ボードの最終列(右端) array = [tl, t, l, bl, b] } return array; これで周辺のセルのnをすべて取得ことができました。 あとは周辺のセルにアクセスして、爆弾があれば集計変数に+1し、起点となるセルに数字を設定します。 爆弾がないセルを一気に開く 開いたセルに爆弾がない場合、上、下、左、右、左上、右上、左下、右下の8方向に数字or旗がないかを判定しならがセルを開いていき、数字or旗が見つかったらセルを開くのをやめる、という実装をします。 このようなロジックには再帰関数を利用することが多いと思います。 再帰関数とは 再帰関数とは自分自身を呼び出す関数のことです。 以下は再帰関数を利用する場合の例です。 function openCell(targetCell) { if (targetCellに数字or旗がある場合) { return; } targetCell.open(); openCell(targetCellの上のcell); openCell(targetCellの下のcell); openCell(targetCellの左のcell); openCell(targetCellの右のcell); openCell(targetCellの左上のcell); openCell(targetCellの右上のcell); openCell(targetCellの左下のcell); openCell(targetCellの右下のcell); } openCell関数からopenCell関数が8回呼び出されています。こうすることで8方向に、数字 or 旗が見つかるまでセルを開き続けることができます。 もちろん再帰関数ではなく、ループを利用しても可能ですが、再帰関数の方がコードの重複が少なくシンプルに書くことができます。 再帰関数を利用する際には注意点があります。 必ず再帰呼び出しを抜けるためのreturnを書くこと 当たり前ですが再帰呼び出しはreturnしないと永遠に(※)呼び出し続けてしまいます。必ずreturnを書くことと、returnに入る条件をミスしないように気をつけましょう。 ※実際には永遠にということはなく、メモリ内のスタックという領域を使い果たしてエラーになります。 相互再帰 エモいマインスイーパは再帰関数の一種である相互再帰が利用されています。相互再帰とは一つの関数内での循環した呼び出しではなく、複数の関数を組み合わせた状態での循環呼び出しです。 こちらが相互再帰を利用したコードです。 function clearCell($el) { if ($el.hasClass('is-flag')){ // 旗が見つかれば終了 return; } // セルを開ける $el.addClass('is-clear'); if ($el.hasClass('is-bomb')) { // 爆弾が見つかればゲームオーバー return gameOver(); } // これは後述 setProgress(); if ($el.hasClass('is-blank')) { // 数字も爆弾もないセルだったら、周辺のセルも調査 clearBlanks($el); } } function clearBlanks($el) { let index = $('#gameBody td').index($el); // 周辺の存在するセルのindex配列 let array = getAroundCell(index); $.each(array, function(){ let $cell = $('#gameBody td').eq(this); if(!$cell.hasClass('is-clear')){ // まだ開いていないセルの場合は開く clearCell($cell); } }); } 背景色が徐々に変わるCSS bodyに付与しているクラスを付け替えることで背景色を変えています。 セルを開くたび、以下の関数が呼び出されます。 function setProgress() { clearCount += 1 // 開いたセルの数 ÷ 爆弾のない全セルの数 × 100 let progress = clearCount / (width * height - bomb) * 100; if (100 <= progress) { $('body').removeClass().addClass('is-morning'); gameClear(); } else if (90 <= progress) { $('body').removeClass().addClass('is-earlyMorning'); } else if (80 <= progress) { $('body').removeClass().addClass('is-sunrise'); } else if (70 <= progress) { $('body').removeClass().addClass('is-dayBreak'); } else if (60 <= progress) { $('body').removeClass().addClass('is-lateNight'); } else if (50 <= progress) { $('body').removeClass().addClass('is-midNight'); } else if (40 <= progress) { $('body').removeClass().addClass('is-deepNight'); } else if (30 <= progress) { $('body').removeClass().addClass('is-silentNight'); } else if (20 <= progress) { $('body').addClass('is-night'); } else { $('body').removeClass(); } } 進捗に応じてクラスを付け替えています。 色はCSSで以下のように設定されています。真夜中から朝にかけて、徐々に明るくなり、朝はlinear-gradientを利用して3色のグラデーション背景になっています。 body { width: 100%; min-height: 100vh; background: black; } body.is-night { background: #141418; } body.is-silentNight { background: #181620; } body.is-deepNight { background: #181621; } body.is-midNight { background: #12162b; } body.is-lateNight { background: #0d2246; } body.is-dayBreak { background: #0c3864; } body.is-sunrise { background: #0c5a8c; } body.is-earlyMorning { background: #498eb6; } body.is-morning { background: linear-gradient(180deg, #498eb6 0%, #b7dfc2 75%, #ffe1b2 100%); } これだけでは、クラスが付与された瞬間、急激に色が変わってしまうため、じわっと変化をするアニメーションを設定する必要があります。これもCSSで可能です。 * { transition: background 1s, color .6s, opacity .6s; } 上記のCSSは、すべての要素に対して、 背景(background)の変化に1秒をかける 文字色(color)の変化に0.6秒をかける 透明度(opacity)の変化に0.6秒をかける という指定になっています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む