はてなキーワード: constとは
俺:
javascript言語で、現在時刻のタイムスタンプからMD5のハッシュ値を出力する関数、timeToMd5 を作ってください
JavaScriptでは、次のような関数を作成することができます。
function timeToMd5() { // 現在時刻のタイムスタンプを取得します const timestamp = Date.now(); // ハッシュ値を出力するために、MD5ライブラリをロードします const md5 = require('md5'); // timestampを文字列に変換し、それをMD5ハッシュ値に変換して出力します const hash = md5(timestamp.toString()); return hash; }
このような関数を作成することで、現在時刻のタイムスタンプからMD5のハッシュ値を出力することができます。
ご参考までに。
俺:
nodeコマンドで実行しましたが、"Error: Cannot find module 'md5'" というエラーになってしまいました。なにか解決方法がありますか?
ご質問のように、JavaScriptで定義した関数を実行すると、"Error: Cannot find module 'md5'" というエラーが発生しているようです。
このエラーが発生する原因は、JavaScriptのコード内で、MD5ライブラリをロードしようとしたときに、そのライブラリがインストールされていないためです。
JavaScriptのコードで、MD5ライブラリを利用するには、まず、そのライブラリをインストールする必要があります。
インストールするには、次のように、nodeコマンドを実行します。
$ npm install md5
このコマンドを実行することで、MD5ライブラリがインストールされ、JavaScriptのコードから利用することができるようになります。
また、JavaScriptのコードを実行するには、次のようにnodeコマンドを使用します。
$ node [JavaScriptのファイル名]
このようにすることで、JavaScriptのコードを実行することができます。
ご参考までに。
俺:
ありがとうございます。実行できました😁
おめでとうございます!ご質問いただいた内容について、正しく解決されたようで嬉しいです。
もしまだご質問があるようでしたら、お気軽にお問い合わせください。今後とも、Assistantをご利用いただけますよう、よろしくお願いいたします。
これまだ1/2だとか言っている人がいるので、本当に2/3かどうかプログラミングで確かめれば良い。
// 「ある夫婦に2人子供がいる」 // 1. 男or女 である確率は 1/2 (トランスジェンダーなどは考えない) function child() { return ["男", "女"][Math.round(Math.random())]; } // 2. 100000組の二人の子がいる夫婦を作る const families = Array(100000).fill(null).map(function () { return [child(), child()] }); // 「片方の子が男であるとき」 // 3. その中で少なくとも一人が男である夫婦を選ぶ const families_have_son = families.filter(function (children) { return ~children.indexOf("男"); }); // 「もう片方が女である確率は?」 // 4. 3の総数が母数である const total = families_have_son.length; // 5. 3の中で、女のいる夫婦を選ぶ const families_have_son_and_dauter = families_have_son.filter(function (children) { return ~children.indexOf("女") }); // 6. 5を母数で割る console.log(families_have_son_and_dauter.length / total);
私の環境では 0.6674999002778923 になった。
2/3が正しそうだ。
実際には、このコードを書いている時点で答えは明確になってしまう。
コードに落とし込むことによって隠された前提をつまびらかにする必要が出るため、実行ボタンを押す以前にはっきりする事がある。
ちなみに 1/2 にしたければ、
// 「片方の子が男であるとき」 // 3. その中で「はじめの子」が男である夫婦を選ぶ(間違い) const families_first_is_son = families.filter(function (children) { return children[0] === "男" }); const total = families_first_is_son.length; // 5. 3の中で、「次の子が」女である夫婦を選ぶ const families_first_is_son_and_second_is_dauter = families_have_son.filter(function (children) { return children[1] === "女"; }); // 6. 5を母数で割る console.log(families_first_is_son_and_second_is_dauter.length / total);
のようにすれば予想通り 0.49868384317792047...(1/2に近似する) のようになる。
自動で安価をつけて返信するプログラムでもこんなに長く複雑になる(一部抜粋)
/**************************************
以下のCSV_DIR, FILE_PATHS, SETTINGSを書き換えてね。 <h3>o- *************************************/</h3>
//CSVファイルが置かれてるディレクトリのパス。投稿前にエラー出たら大体ここの設定ミス。 例:"C:\\Users\\sakuraimasahiro\\Documents\\iMacros\\Macros\\rentou\\";
'C:\\Users\\USER\\Desktop\\iMacros\\Macros\\rentou\\';
//ファイルのパス。CSVは絶対パスで、拡張子も必要。iimは相対パスでよく、拡張子不要。
const FILE_PATHS = {
textCsv: CSV_DIR + 'textNoAnker.csv',
//レス用投稿文が書かれたCSV。通常とレス用で分けないなら同じファイルを使えばいい。
replyTextCsv: CSV_DIR + 'textReply.csv',
};
baseWaitTime: 5,
//baseWaitTime+0~waitTimeRange(ランダム)だけ待つ
waitTimeRange: 5,
//連投しすぎだと忠告された場合に処理を一時停止させる時間(秒)
waitTimeForAvoidingPunishment: 60 * 30,
//メール
mail: 'sage',
//名前設定
name: '',
//以下、偽装ワッチョイ設定。浪人でワッチョイを非表示にしてるときだけtrueにしてね。
//妙なニックネーム(ワッチョイ、アウアウウーなど)をランダムで決めて付加するかどうか。true=付加する。false=付加しない。
//妙なニックネームの後に付く8桁の文字列をランダムで決めて付加するかどうか。
},
//アンカー無し投稿をするならtrue。しないならfalse。noAnkerPostかreplyPostのどちらかはtrueにすること(両方trueでもOK)。
//アンカー付き投稿(返信)をするならtrue。しないならfalse。もしnoAnkerPostとreplyPostの両方がtrueの場合、投稿は返信が優先され、返信対象が見つからなくなったらアンカー無し投稿をする。
//最初に取得するアンカー無し投稿文CSVファイルの行番号。もし返信用と同じCSVファイルを使うなら-1と入力。
noAnkerPostTextCsvStartRow: 1,
//最初に取得する返信用投稿文CSVファイルの行番号。もしアンカー無しと同じCSVファイルを使うなら-1と入力。
//テキストCSV/返信用テキストCSVの取得行が最終行に達したら最初の行まで戻るかどうか。true=戻る。false=マクロ終了。
//返信する場合、これより小さなレス番には返信しない。返信を投稿すると、この数値は前回の返信先のレス番に更新される。
minAnker: 895,
//返信する場合、名前に以下の文字列を含む投稿にアンカーをつけて返信する(ワッチョイやIPなど名前フィールドにあるものならなんでも可)。配列で複数指定可能。指定無しなら空配列([])。filterNamesとfilterNamesNotIncluded共に無指定ならレス番1から順に返信していく(minAnkerが設定されてればそこから順に)。以下のfilter系は全て併用可能。
//↑とは逆に、名前に以下の文字列を含まない投稿にアンカーをつけて返信する。↑と併用も可能。
//返信する場合、本文に以下の文字列を含む投稿にアンカーをつけて返信する。
filterText: ['自演かな', '自演わらわら', 'スクリプト使うの', '安価ガバ', '>>660', '自演で擁護', '最後' ,'あいうえお', 'かきくけこ', 'さしすせそ', 'なにぬねの', 'はひふへほ', 'まみむめも', 'やいゆえよ', 'やゆよ', 'らりるれろ', 'わいうえを', 'わをん', 'わいうえをん'],
},
//自分のIPアドレスの確認。VPNとかでIPを変更してマクロを動かしてるとき、突然VPNが作動しなくなってIPが元に戻ったときにマクロを止めるためのもの。
//以下の文字列が自分の現在のIPアドレスに含まれている場合、マクロを一時停止する。基本的に自分の本当のIPアドレスを入力。
},
//浪人設定。最後に動作を確認したのは5年くらい前で、今も同じように動作するかは、浪人を持ってないから確認できずわからない。
//浪人にログインしてるかどうかをチェックするかどうか。trueならする。falseならしない。trueにしていてもし浪人にログインしていないことを確認したらログインしにいく。
password: '1234',
},
};
/**************************************
設定箇所終わり。
https://info.5ch.net/index.php/%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%82%81%E3%81%AA%E3%81%84%E6%99%82%E3%81%AE%E6%97%A9%E8%A6%8B%E8%A1%A8 <h3>o- *************************************/</h3>
/**************************************
・NULL演算子(??)は使えない。論理積(&&)は使える。
・オブジェクトの分割代入はできない。
・importはできない。 <h3>o- *************************************/</h3>
/**************************************
関数 <h3>o- *************************************/</h3>
/**
* ここから始まる。
*/
checkSettings();
var _TextCsvCursors = new TextCsvCursors(
SETTINGS.postSettings.noAnkerPostTextCsvStartRow > 0
? SETTINGS.postSettings.noAnkerPostTextCsvStartRow - 1
: SETTINGS.postSettings.noAnkerPostTextCsvStartRow,
SETTINGS.postSettings.textCsvLoop,
),
SETTINGS.postSettings.replyPostTextCsvStartRow > 0
? SETTINGS.postSettings.replyPostTextCsvStartRow - 1
: SETTINGS.postSettings.replyPostTextCsvStartRow,
SETTINGS.postSettings.textCsvLoop,
),
);
var _LoopStatuses = new LoopStatuses(0, SETTINGS.postSettings.minAnker);
const _MyPosterName = new MyPosterName({
name: SETTINGS.nameSettings.name,
});
const _ThreadUrl = openPromptThreadUrl();
//ループ
while (true) {
SETTINGS.ipSettings.checkIp && checkCurrentIpNotTheIp();
//スレを開く
openUrl(_ThreadUrl.fullUrlHttps());
//浪人にログインする設定なら、浪人にログインしているかどうかを確認し、していなければログインしにいく。
if (SETTINGS.roninSettings.checkLogin) {
}
}
if (SETTINGS.postSettings.replyPost) {
const targetAnkerNumber = createPostDOMList()
.filterPostnumberHigher(_LoopStatuses.currentMinAnker())
.filterByPostername(SETTINGS.postSettings.filterNames)
.filterByPosternameNotIncluded(
SETTINGS.postSettings.filterNamesNotIncluded,
)
.filterByText(SETTINGS.postSettings.filterText)
if (targetAnkerNumber !== null) {
const r = _TextCsvCursors.takeNextRowTextAsReply(targetAnkerNumber);
messageDisplay(`返信対象有り。アンカー先: ${targetAnkerNumber}`);
return {
...r,
updatedLoopStatuses:
_LoopStatuses.updateMinAnker(targetAnkerNumber),
};
}
}
if (SETTINGS.postSettings.noAnkerPost) {
//返信対象無し、或いは返信しない設定の場合。アンカー無し投稿文を作る。
const r = _TextCsvCursors.takeNextRowTextAsNoAnker();
messageDisplay('返信対象無し。アンカー無し投稿。');
return {
...r,
updatedLoopStatuses: _LoopStatuses,
};
}
return null;
})();
if (p) {
//投稿。
nickname: SETTINGS.nameSettings.nickname,
korokoro: SETTINGS.nameSettings.korokoro,
area: SETTINGS.nameSettings.area,
}),
SETTINGS.mail,
p.text,
);
//_TextCsvCursorsと_LoopStatusesを更新。
_TextCsvCursors = p.updatedTextCsvCursors;
_LoopStatuses = p.updatedLoopStatuses.incrementPostCount();
`投稿回数: ${_LoopStatuses.currentPostCount()}`,
`minAnker: ${_LoopStatuses.currentMinAnker()}`,
`今回アンカー無し投稿取得行: ${_TextCsvCursors.currentRows().noAnker}`,
`今回アンカー有り投稿取得行: ${_TextCsvCursors.currentRows().reply}`,
]);
} else {
`返信対象が現われるのを待機中...。`,
`投稿回数: ${_LoopStatuses.currentPostCount()}`,
`minAnker: ${_LoopStatuses.currentMinAnker()}`,
`今回アンカー無し投稿取得行: ${_TextCsvCursors.currentRows().noAnker}`,
`今回アンカー有り投稿取得行: ${_TextCsvCursors.currentRows().reply}`,
]);
}
wait(SETTINGS.baseWaitTime + randomRange(0, SETTINGS.waitTimeRange));
}
}
/**
* 投稿処理と投稿結果を見てリトライしたりマクロ終了したり。
* @param {string} serverName サーバー名
* @param {MyPosterName} _MyPosterName
* @param {string} postMail メール
*/
serverName,
postMail,
_MyText,
retryTimes = 0,
) {
const r =
retryTimes === 0
? new ValuesOfPost(serverName, _MyPosterName, postMail, _MyText).post(
postTo5chTread,
)
serverName,
postMail,
_MyText,
).postSubstring(retryTimes, postTo5chTread, postConfirm);
if (r) {
back();
return;
}
wait(7);
const error = createPostErrorMessage().analyze();
messageDisplay(error.message);
if (error.order === 'KILL') {
kill();
} else if (error.order === 'SKIP') {
return;
} else if (error.order === 'TRUNCATE') {
back();
serverName,
postMail,
_MyText,
retryTimes + 1,
);
} else if (error.order === 'WAIT') {
wait(SETTINGS.waitTimeForAvoidingPunishment);
serverName,
postMail,
_MyText,
retryTimes,
);
} else if (error.order === 'LOGIN') {
serverName,
postMail,
_MyText,
retryTimes,
);
}
return;
}
/**
* 現在のIPアドレスに、SETTINGS.ipSettings.avoidTheIpの値が含まれていないことを確認する。含まれていたらマクロを一時停止。
* @returns
*/
function checkCurrentIpNotTheIp() {
openUrl('https://www.cman.jp/network/support/go_access.cgi');
const _IpAdress = createIpAdressFromCMan();
if (_IpAdress.includes(SETTINGS.ipSettings.avoidTheIp)) {
pause('現在のIPに指定した値が含まれていることを確認。');
}
return;
}
/**
* @returns
*/
if (
SETTINGS.postSettings.noAnkerPost === false &&
SETTINGS.postSettings.replyPost === false
) {
return kill('設定エラー。noAnkerPostとreplyPost両方ともfalseになってる。');
}
if (
SETTINGS.postSettings.noAnkerPostTextCsvStartRow < 0 &&
SETTINGS.postSettings.replyPostTextCsvStartRow < 0
) {
return kill(
'設定エラー。noAnkerPostTextCsvStartRowとreplyPostTextCsvStartRow両方とも-1になってる。',
);
}
if (
SETTINGS.postSettings.noAnkerPostTextCsvStartRow === 0 ||
SETTINGS.postSettings.replyPostTextCsvStartRow === 0
) {
return kill(
'設定エラー。noAnkerPostTextCsvStartRow/replyPostTextCsvStartRowの初期値は-1或いは1以上で。',
);
}
}
/**
* 入力フォームを表示して入力されたスレのURLを受け取る。
*/
function openPromptThreadUrl() {
const url = prompt('スレURLを入力');
}
/**
* 開いてるスレのレス全て読み取ってPostListインスタンスを作って返す。
* 重すぎるので使うのやめ。どうやらインスタンスの大量生成が原因な模様。
*/
const posts = window.document.getElementsByClassName('post');
return new PostList(Array.from(posts).map((e) => new Post(e)));
}
/**
* 開いてるスレのレス全て取得してPostDOMListに格納して返す。
* @returns
*/
function createPostDOMList() {
const posts = window.document.getElementsByClassName('post');
for (let index = 0; index < posts.length; index++) {
//HTMLCollectionからElementを1つずつ抽出して配列に。
arrPostDOMList.push(posts.item(index));
}
return new PostDOMList(arrPostDOMList);
}
/**
* 開いてる投稿結果画面に表示されてるエラーを読み取ってPostErrorMessageインスタンスを作って返す。
*/
function createPostErrorMessage() {
window.document
今はもう let と const が主流で var は使わないんだよ
const list = [0,1,2,3,4,5,6,7,8,9]; const a = list.splice(Math.floor( Math.random() * 10), 1); // 0~9のインデックスをランダムに得てそのインデックスの値を取りだす、その要素を配列から削除。 const b = list.splice(Math.floor( Math.random() * 9), 1); // 0~8のインデックスをランダムに得て(ry const c = list.splice(Math.floor( Math.random() * 8), 1); // 0~7の(ry
const inhtml = document.getElementById('problem_text').innerHTML.replace('この白を探せ!<br>#', 'col_'); const el = document.getElementsByClassName("alternatives"); let idd = ''; for( let i = 0 ; i < el.length ; i ++ ) { idd=el[i].getAttribute("id"); if(inhtml == idd){ var clickMe = document.getElementById(idd); if( /*@cc_on ! @*/ false ) { clickMe.fireEvent("onclick"); } else { var event = document.createEvent( "MouseEvents" ); event.initEvent("click", false, true); clickMe.dispatchEvent(event); } } }
例えばJavaScriptでリストをコピーするとき
const newList = list.slice();
しかし、
「なんで const newList = listじゃダメなんですか?」
と聞かれると非常に困る。
例えばconst a = 123と入っているときに、bにコピーしたかったらconst b=aで良い。
プリミティブと配列の違いとして覚えてもらう、という方法もあるけれど
じゃぁ文字列はどうなんですか?となると非常に困る。
JavaScriptだけを教えるならそれでも問題ないかもしれないが、Pythonも一緒に教えるとかなるとカオスになる。
結局のところ、コンピュータの仕組みを理解してもらって、メモリのアドレスとかポインタを知ってもらい
それからプリミティブや配列の話をしないと根本的には説明できない。
単純なプログラミング教育ってこの辺が破綻してると思っているので、結局はPCの構造と機械語・アセンブリ言語・C言語と順番に教える必要があると思っている。
ニコニコプレミアムアワードのランキング、某んがすランキングになっていて鬱陶しいので、ふにん某を非表示にするスクリプトを書いた。
Tempermonkeyとかで使ってくれ。文字実体参照は適宜置き換えること。
// ==UserScript== // @name New Userscript // @namespace http://tampermonkey.net/ // @version 0.1 // @description try to take over the world! // @author masuda // @match https://site.nicovideo.jp/premiumaward/* // @icon https://www.google.com/s2/favicons?sz=64&domain=nicovideo.jp // @grant none // ==/UserScript== const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const blockList = [ "ふにんがす", "なのそん", "Among us", "Among Us", "アモアス", ]; (async function() { 'use strict'; await sleep(100); const list = document.querySelectorAll("li.game"); for (const elem of list) { const title = elem.getElementsByClassName("title")[0].innerText; if (blockList.some((word) => title.includes(word))) { elem.remove(); } } })();
正直動けばいいと思うので、現状でも問題ないと思うけれどちょっとだけ気になった点。
$$使ってる時点で、デベロッパーツール前提なのは分かるけど、 javascriptで動かしたいのか、デベロッパーツールで動かしたいのか、どっちつかずな書き方になっている。
$$('.hatena-star-inner-count').map(a => a.click()); let data = {}; Array.from($$('.entry-comment-contents')).forEach(x => {const userName = x.querySelector('.entry-comment-username a').href.split('/')[3];const comment = x.querySelector('.entry-comment-text').innerText;const stars = Array.from(x.querySelectorAll('.list-star-container a.hatena-star-star')).map(y => y.href.split('/')[3]);data[userName] = [comment, stars];}); console.info(Object.entries(data).map(x => { return ['|', `b:id:${x[0]}`, '|', x[1][0], '|', x[1][1].join(','), '|'].join(' '); }).join("92;n"));
デペロッパーツールだけで動くだけでいいなら、3行目のArray.fromがなくても動く。多分、forEachをmapに書き換えても動く。個人的にはforEachに統一したいけど、そこは好みレベルの問題だと思う。
$$('.hatena-star-inner-count').map(a => a.click()); let data = {}; $$('.entry-comment-contents').forEach(x => {const userName = x.querySelector('.entry-comment-username a').href.split('/')[3];const comment = x.querySelector('.entry-comment-text').innerText;const stars = Array.from(x.querySelectorAll('.list-star-container a.hatena-star-star')).map(y => y.href.split('/')[3]);data[userName] = [comment, stars];}); console.info(Object.entries(data).map(x => { return ['|', `b:id:${x[0]}`, '|', x[1][0], '|', x[1][1].join(','), '|'].join(' '); }).join("92;n"));
逆に、javascriptで動かしたいなら1行目と3行目はquerySelectorAllに書き換えれる。
document.querySelectorAll('.hatena-star-inner-count').forEach((a)=>{a.click()}); let data = {}; document.querySelectorAll('.entry-comment-contents').forEach(x => {const userName = x.querySelector('.entry-comment-username a').href.split('/')[3];const comment = x.querySelector('.entry-comment-text').innerText;const stars = Array.from(x.querySelectorAll('.list-star-container a.hatena-star-star')).map(y => y.href.split('/')[3]);data[userName] = [comment, stars];}); console.info(Object.entries(data).map(x => { return ['|', `b:id:${x[0]}`, '|', x[1][0], '|', x[1][1].join(','), '|'].join(' '); }).join("92;n"));
これも好みの問題だけど、途中のconstの宣言は一回しか使ってないので、宣言せずにそのまんま入れてもいいんじゃないかと思った。
document.querySelectorAll('.hatena-star-inner-count').forEach((a)=>{a.click()}); let data = {}; document.querySelectorAll('.entry-comment-contents').forEach(x => {data[x.querySelector('.entry-comment-username a').href.split('/')[3]] = [x.querySelector('.entry-comment-text').innerText, Array.from(x.querySelectorAll('.list-star-container a.hatena-star-star')).map(y => y.href.split('/')[3])];}); console.info(Object.entries(data).map(x => { return ['|', `b:id:${x[0]}`, '|', x[1][0], '|', x[1][1].join(','), '|'].join(' '); }).join("&#92;n")); |<<
でもよー、それJavaScriptだろ?
const sode = []; // 袖が存在しない! const swing = sode.every(it => it.canSwing); // 振れるだろ? console.log(swing); //=> true(振れるぜ)
だぜ。
aa ʕ•̫͡•ʕ•̫͡•ʕ•̫͡•ʕ•̫͡•ʕ•̫͡•ʕ•̫͡•ʔ
じゃなくて
aa ʕ•̫͡•ʕ•̫͡•ʔ•̫͡•ʔ•̫͡•ʕ•̫͡•ʔ•̫͡•ʔ
にしたい
javascript:(function (d, lowerThan, count) { const MinimumRequiredLength = 33; let currentCount = count(); const elem = d.querySelectorAll(".bookmarkadd-comment-form")[0]; if (!elem) { return; } if (lowerThan(count(), MinimumRequiredLength)) { if (elem.value.slice(-1) !== " ") { elem.value += " "; currentCount += 1; } } if (lowerThan(count(), MinimumRequiredLength)) { const kumas = ['ʕ•̫͡•', 'ʔ•̫͡•']; const indexes = '001101'; for (let i = 0; i === 0 || (lowerThan(currentCount + i * 5, MinimumRequiredLength) || currentCount + i * 5 === MinimumRequiredLength); i++) { elem.value += kumas[indexes[i % 6]]; } elem.value += 'ʔ'; elem.dispatchEvent(new Event("input")); } })(document, function(a, b) { return Math.floor(b / a) !== 0 }, function() { return Number(document.querySelectorAll('.js-bookmarkadd-comment-count')[0].innerText) || 0 } ); //add bear
こういう、特定の URL で特定の bookmarklet を呼び出す extension とか欲しい。これは用途に合わないけれど、クマを消すやつは自動で実行されてほしいものだろうし
クマが30匹程度では建設的と判定されないことがあるようなので、そんな時は
const MinimumRequiredLength = 30;
の部分を変えてみてください。
その際は、ドラッグし直すのでなく、
追加済みのブックマークレットを右クリック→「編集」で、30の部分だけ書き換えればOKです。
追記ここまで
https://anond.hatelabo.jp/20210803012020
に刺激を受けて作りました。
https://b.hatena.ne.jp/entry/4706344345181168386/comment/new3
で、書き込み時の自動クマ補完について書かれてたので、それを実装しました。
以下の文字列を選択して、Chromeのブックマークバーにドラッグしてください。
javascript:(function () { const MinimumRequiredLength = 30; const currentCount = Number(document.querySelectorAll(".js-bookmarkadd-comment-count")[0].innerText); if (Math.floor(MinimumRequiredLength / currentCount) !== 0) { const elem = document.querySelectorAll(".bookmarkadd-comment-form")[0]; if (elem.value.slice(-1) !== " ") { elem.value += " "; } const loopNum = Math.ceil((MinimumRequiredLength - currentCount) / 5); for (let i = 0; i !== loopNum; i++) { elem.value += "ʕ•̫͡•"; } elem.value += "ʔ"; elem.dispatchEvent(new Event("input")); } })();
「_5)」みたいな変な名前で追加されるので、右クリック→「編集」から好きな名前に変えてください。(addBearとか)
はてブのコメント書き込み画面でブックマークレットをクリックしてください。
これで追加したクマを、コメント一覧画面で削除するためのブックマークレットは、
javascript:(function () { document.querySelectorAll(".entry-comment-text").forEach(function (e) { e.innerText = e.innerText.replace(/[ʕ•̫͡•ʔ]+$/, ""); }); })();
です。
セットでお使いください。(名前はremoveBear?)
私はクマで埋めることはしないのですが、埋めたい人もいるでしょうから、道具としてはあればよいと思いました。
最後のクマだけ左頬のパーツを変えて……、など10秒くらい掛けてると思うのです。
その間、「ああ……またこんな作業をして……私ったら承認欲求の塊なのかしら、いやらしいわ」と自己嫌悪してたら可哀想なので、
少しでもネガティブな時間が短くなるよう、活用してみてください。
https://github.com/kokorohamoe/OpenProfile/blob/master/700_sample/Java/Jurina/reader.cpp
int main(int argc,const char*argv[]){
int v;
char buffer[1024];
while(1){
printf("input\n");
scanf("%s%d",buffer,&v);
if(strcmp(buffer,"print")==0)
fprintf(stderr, "public class base{\n"
"public static void main(String[] args){\n"
"int i = %d;\n"
"System.out.println(i);}}\n",v);
}
return 0;
}
https://b.hatena.ne.jp/entry/s/qiita.com/Yametaro/items/621bfd8c894f8fd36539
https://www.google.com/search?q=site%3Aqiita.com+%E3%83%91%E3%83%91
5歳娘「パパ、余分なpropsいっぱい書くんだね!」
4歳娘「パパ、具体的な名前をつけないで?」
5歳娘「パパ、変なAPIを作らないで?」
5歳娘「パパ、型はドキュメントだよ?」
5歳娘「パパ、依存性を注入して?」
4歳娘「パパ、懐かしいJavaScript書いてるね!」
5歳娘「パパ、型ガードって何?」
0歳娘「パパ、型を作る関数はないの?」
4歳娘「パパ、Promiseやasync/awaitって何?」
4歳娘「パパ、具体的な名前をつけないで?」
const array1 = [1,2,3,1,3,5];
const reducer = (accumulator, currentValue,idx) =>{
if(!(currentValue in accumulator)){
accumulator[currentValue]=[idx];
}else{
accumulator[currentValue].push(idx);
}
return accumulator;
};
console.log(array1.reduce(reducer,{}));
何だせっかく考えたのに
(https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
プログラミングはセンスです。センスの無い人がプログラマになると、他のすべての人に迷惑がかかります。だから、センスの無い人は絶対にプログラマにならないで下さい。
プログラミングのセンスが無い人や、プログラミングをやったことの無い人は、知識を得たり経験を積んだりすれば、誰でも「良いプログラマ」になれると思っているようですが、無理です。
というのも、センスの無いプログラマの問題は、知識や経験の不足ではないからです。センスの無いプログラマの救いようの無い問題は「頭がおかしいこと」なのです。
題材は何でもいいのですが、具体的なコードを見た方がイメージがつきやすいと思いますので、とりあえず以下の問題を考えます。
住民のリストが与えられるので、背の低い順に男女ペアにしたリストを作って下さい。ただし、男女の数は同数であるとします。
const makePair = (persons) => { const males = persons.filter(person => person.sex === MALE) const females = persons.filter(person => person.sex === FEMALE) const compareHeight = (a, b) => a.height - b.height males.sort(compareHeight) females.sort(compareHeight) return males.map((male, idx) => [male, females[idx]]) // 男女の数は同数 }
この例はJavaScriptなので高階関数を使っていますが、仮にそういう機能が無かったとしても、
一方、センスの無いゴミプログラマは、以下のような名状しがたきコードを書いてきます。
function pair(psns) { var i = -1; var cnt = 0; var flg = psns[0] &amp;&amp; psns[0].sex; var j = -1; var tmp = null; for(i = 0; i < psns.length; i++) { //console.log('■■■■■■■■■■■■■■■■■■■■ BEGIN ■■■■■■■■■■■■■■■■■■■■') //console.log(psns, 'i=' + i, 'cnt=' + cnt, 'flg=' + flg); if(psns[i].sex == flg) { //console.log('cnt: ' + cnt + '->' + (cnt+1)); cnt++; } else { j = i - cnt + 1; //console.log('swap ' + i + '<-->' + j); tmp = psns[j]; psns[j] = psns[i]; psns[i] = tmp; i = j - 1; // <- 理由は分からないが、i = jだと上手くいかない(by XXXX)。 cnt = 0; flg = flg == MALE ? FEMALE : MALE; while(j > 1) { if(psns[j].height < psns[j-2].height) { //console.log('swap ' + j + '<-->' + (j-2)); tmp = psns[j-2]; psns[j-2] = psns[j]; psns[j] = tmp; } j -= 2; } } //console.log(psns, 'i=' + i, 'cnt=' + cnt, 'flg=' + flg); //console.log('■■■■■■■■■■■■■■■■■■■■ END ■■■■■■■■■■■■■■■■■■■■') //console.log('') } for(i = 0; i < psns.length; i++) { //console.log('■■■■■■■■■■■■■■■■■■■■ BEGIN ■■■■■■■■■■■■■■■■■■■■') j = Math.floor(i / 2); //console.log(psns, 'i=' + i, 'j=' + j); tmp = psns[i]; if(!(i % 2)) { psns[j] = [null, null]; } if(tmp.sex == MALE) { psns[j][0] = tmp; psns[j][1] = psns[i+1]; } else { psns[j][0] = psns[i+1]; psns[j][1] = tmp; } i++; //console.log(psns, 'i=' + i, 'j=' + j); //console.log('■■■■■■■■■■■■■■■■■■■■ END ■■■■■■■■■■■■■■■■■■■■') } psns.splice(psns.length / 2, psns.length); }
こんなコードのメンテナンスは御免被りたいです。一見して配列の要素を入れ替えていることが分かるだけで、実装を全て読まなければ(いや読んでも)処理の意図が全く分かりません。また、たとえば「i = j - 1」が間違って「i = j」などと書かれていてバグを起こしたとしても、原因を突き止めるのは困難を極めます。
さて、このコードは具体的に何がいけないのでしょうか。長すぎることがいけないのしょうか。変数名が分かりにくいのがいけないのでしょうか。引数を破壊的に変更しているのがいけないのでしょうか。不要なコメントが残っているのがいけないのでしょうか。よく見ると、ソート処理で車輪の再発明をしていたり、「j」や「tmp」などが場所によって意味が違うカメレオン変数になっていたりしますが、それがいけないのでしょうか。どれも正しいですが、それらを逐一直したところで、本質的な解決にはならないでしょう。
後者のコードはもはや「ここを直したら良くなる」とかいうレベルを超えています。たしかに、問題を具体的に挙げることはできます。このコードの致命的な問題が、凝集度の低さと、単一責任の原則(SRP)違反にあるのは間違いありません。しかし、後者のコードを書いてくる人に、
「住民リストを男女に分ける処理や、リストをソートをする処理、2つのリストをまとめる処理は、この問題とは独立して意味のある操作だから、別の関数として抽出しましょう。その方がコードの見通しがよくなるし、一部の処理を修正したときの影響も小さくなるし、単体テストも書きやすくなります」
なんて言ったって聞く耳を持たないでしょう。
そもそも、こういうコードを書く人は、この処理自体を「pair」なんて関数に抽出すらしません。まだこの問題では入出力のフォーマットが明確に定義されているので、他人が1から書き直せますが、実際のプロダクトでは、無数の副作用を起こす数千行のコードの迷路を彼の脳内フォーマットのデータが通るわけです。もちろん、テストコードなんてありません。
つまり、指摘をしても絶対に直らないのです。いくら言語の優れた機能やベストプラクティスを紹介しても、馬の耳に念仏。それらの利点を理解できるだけの脳みそが足りていないのです。
どうして、同じ処理を実装するのに、ここまでの違いが生じるのでしょうか。
これは、プログラミングの技術の問題ではありません。既に述べた通り、ふつうの人なら、特定の機能の有無とか知識の程度にかかわらず、ふつうのコードを書くのです。なぜなら、ふつうの人にはそちらの方が楽だからです。つまり、前者のコードは別に何か卓越した技術を身につけた結果書けるようになるものではなく、まともな感覚さえ持っていれば、プログラミング初心者にとっても前者のコードの方が書きやすいのです。
つまり、後者のようなコードを書いてくる奴というのは、現実世界の捉え方が常人とは著しくずれているのです。要するに、「頭がおかしい」のです。この病気はもう直りません。だから、センスの無い人は絶対にプログラマにはならないで下さい。
Bluetooth端末で動作する。(CC0 License)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>A10 Cyclone SA easy controller</title> </head> <body> <span id="status">initializing...</span> <script> let status = document.querySelector('span#status'); let device, characteristic; const connect = async _ => { try { device = await navigator.bluetooth.requestDevice({ filters: [{ services: ['40ee1111-63ec-4b7f-8ce7-712efd55b90e'] }], }); status.textContent = 'connecting...'; let server = await device.gatt.connect(); let service = await server.getPrimaryService('40ee1111-63ec-4b7f-8ce7-712efd55b90e'); characteristic = await service.getCharacteristic('40ee2222-63ec-4b7f-8ce7-712efd55b90e'); } catch (e) { status.textContent = `failed to connect: ${e.message}`; return; } document.addEventListener('pointermove', evt => { evt.preventDefault(); let y = evt.y / innerHeight * 2 - 1; let data = Math.abs(y) * 0x7f | (y < 0 ? 0x80 : 0x00); characteristic.writeValue(new Int8Array([0x01, 0x01, data])); }); status.textContent = 'swipe up and down to move'; document.removeEventListener('click', connect); } document.addEventListener('click', connect); status.textContent = 'tap screen to connect'; </script> </body> </html>