はてなキーワード: csvとは
システムエンジニアをしているけどお客の自称大企業のシステム管理経験ありの役職者が要求仕様で意気揚々とExcel方眼紙で資料出してきて頭抱えている。
せめて内容がまともなら良いが書かれている内容も要求仕様からは程遠いメモ書きでこちらから細かい質問を投げては社内で確認して回答貰うメッセンジャーにしかなっていない。これで社内システムの責任者?
ほんとマジでExcel方眼紙は止めろ。餅は餅屋で表計算だけにしろ。馬鹿でExcel方眼紙しか出来ないならPDFに出力してよこせ。どうせファイル名馬鹿みたいに日付とリビジョン付けんだろうな。
ExcelはA4横に綺麗に罫線ひいて見栄えよく書類作るツールじゃないわ。あとcsvをExcelで開くな。Excelに合わせてShift-JISに文字コード要求すんな。システム担当がUTF-8のファイルをExcelで開いて「文字化けしてます。バグですね!」とか言うな。あと郵便番号データ開いて0消してはがきデータ印刷で失敗して焦んな。
こんなこと書くと何故かExcel方眼紙肯定派が出てくるけど一度も納得できる理由を聞いたことが無い。結局馬鹿が色んなツール覚えられないだけでしょ。そういう人はシステムの仕事から離れろよ。Office365もまともに使えない奴がいっちょ前にシステムエンジニアに意見言うな。レガシーシステムの改変に文句言うな。工数に口出すな。っていうかこっちが言ってること大半理解せず金の時だけ発言すんな。あとアジャイルなんでそんなに好き?アジャイルの前に自社の業務理解しろ。そのうえでExcel方眼紙やめろ。
virtualdjで出力したcueシートを、csv形式に変換するpythonスクリプトを実装してください
```python
import csv
def convert_cue_to_csv(cue_file, csv_file):
cue_data = []
with open(cue_file, 'r') as f:
# cueシートの各行を処理する
for line in f:
if line.startswith(' TRACK'):
track_data = {}
# トラック番号を取得する
track_num = line.split()[1]
track_data['Track Number'] = track_num
track_type = line.split()[2]
track_data['Track Type'] = track_type
# 次の行を処理する
# トラック名を取得する
track_name = line.split('"')[1]
track_data['Track Name'] = track_name
# 次の行を処理する
# トラックの長さを取得する
track_length = line.split()[3]
track_data['Track Length'] = track_length
cue_data.append(track_data)
with open(csv_file, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['Track Number', 'Track Type', 'Track Name', 'Track Length'])
# ヘッダーを書き込む
writer.writeheader()
convert_cue_to_csv(cue_file, csv_file)
```
このスクリプトは、cueシートのファイルを開き、トラック情報を取得して、CSVファイルに書き込みます。トラック情報は、トラック
関係ないっちゃないけどw
あちこちのクレカとか電気ガスとか電話とかのWebサイトでCSV形式の明細書ダウンロードって機能が、いまだに邪悪なShift_JISエンコーディングで出してくるの、いい加減にヤメろや!
WebサイトのHTMLとかは、ほぼほぼ100%ちかくunicode(UTF-8)なのに。
ちょっと前まで、MacのクイックルックでそのCSV化け化けで見づらくてしょうがなかったんで、数10年ぶりにAppleScript書いてフォルダアクションに文字コード変換仕込んだりするハメになったやんかw VenturaになったらShift_JISでも正常にクイックルックできたけどww
ちなみに、Gmail前提の話。
GASでGmailのonCreateDraft的なトリガーとかイベントがあれば楽だったんだけど、無かった。○uck!!
Googleコンタクトで敬称を設定できるんだけど、スマート作成とかスマートリプライとかで候補に出てくるかっていうと出てきたり出てこなかったりする。○uck!!
テンプレートで変数埋め込みとかもできないみたい。○uck!!厳密にはできるんだけど、結構workaroundな感じですぐ使えなくなりそうだし他人にお勧めできない。
てかそもそも、こんなことのためにわざわざGAS使うのがおかしい。
ここまでで1時間くらい使った。まあ勉強にはなったけどそんな回り道をした俺に○uck!!
とりあえず、あなたはコピペしてるってことなんで、それ前提でちょっとした効率化を考えてみた。
下準備が面倒だけど。
まず、Googleコンタクトで敬称・会社・役職などを設定する。
連絡先がたくさんあるなら、CSVでエクスポートしてExcelかスプシで開いて、「Name Suffix」(敬称)「Organization 1 - Name」(会社)「Organization 1 - Title」(役職)の列を一括変更してインポートするのが楽。ちなみに「Name Prefix」はSirとかMr.とか入れるところ。
これで下準備は終わり。
Gmailでメールを作成するときなど、宛先メールアドレスの脇にそのアイコンや名前が出てくる。
で、アイコンや名前にカーソルを合わせて1秒ほど待つと、↓みたいなポップアップが(Googleコンタクトに登録されていれば)敬称付きの名前・会社・役職と一緒に出てくる。
https://ferret-one.akamaized.net/images/623a863585ad34000174a1e6/large.png
Googleコンタクトに姓名をどっちも入れると「田中太郎様」ってなるので、そこは名を抜かすなど臨機応変に。
連絡先を全部変更する前に、1件だけ試しでやってみるのをオススメする。
Thunderbirdの方も、Googleコンタクトを同期させれば似たような使い方ができるかもしれない。
俺はThunderbirdまともに使ったことないので、有識者に指示を仰いでください。
今は、これが精一杯。
追記:
一回のコピペで済ませたいならGoogleコンタクトにメモって項目があるので、それでも良いかもしれない。
ただ、ポップアップを表示させた後「詳細表示を開く」ってボタンを押して出てきた右ペインを一番下までスクロールしないとメモが出てこないので、一長一短という感じ。
まああとは色々やってみてくれ。
俺の仕事の話。
俺にメールしてくるのはお客さんじゃないので、「この度はお世話になります。〇〇社△△部xxと申します」とか「お忙しい中大変恐縮ですが、何卒ご検討のほどよろしくお願い致します」とかかましてきやがったら「自動差し込みとかでない限りそういうのいらないんで。俺からは一切しません」って開口一番に言う。
そういう仕事をしてる。
令和だけど令和っぽくないソフトばかりだが許してくれ、 あとURL書きすぎたら投稿できなかったので気になったのあったら調べてくれ
とりあえずファイルの中身を見るためにこういった汎用のエディタは持っておきたい。
定番が古いので乗り換え先を色々試した結果これに落ち着いた。
これだけあれば世の中の大半のソフトは解凍できるのでLhaと頭についてるソフトを使ってるひとは乗り換えよう。
Massigraから乗り換えるのに丁度よかったので是非。
軽いPDFビューア。
PDFを見るだけならこれでいいと思う。
LinuxでMPD使ってる人は入れてみてもいいけど、全くMPDを知らない人は導入クソ面倒だし操作も面倒なので入れなくていいです。
MPDクライアント。
とある地方の市役所は,自治体DXの進んだ自治体らしい。国だかなんかからも表彰とかもされているらしい。
けど,実態はクソ。
まずなにより,職員が業務で使うPCが令和対応できないまま令和になって2年以上放置されてたの。下手したらまだ対応してないPCが少なからずあるんじゃないか。役所なんて一番和暦を使うとこなのに,エクセルとかセルの書式設定で無理やり令和にしてたの。日付の書式を和暦にするんじゃなくて,日付を年と月日に分けて年の方に「"令和"」って入るようにするってことね。それが2年以上だよ。
それでも,RPAやらなにやら新しいものには手を出すから,DXの推進してる市ですとか対外的にはなってるの。うける。
市役所内でブーイングが出ないかと言われたら,出るんだけど評価する側の部署はさっさと新しくするけど,その他の部署は放置。外局や支所に至っては存在しない扱い。だから数年放置。評価する部署も,聞いたところで疎いから(頭が悪いから)へーそうなんだくらいにしか思わないわけ。だって自分たちは実務してないしさっさとアップデートしたから困った経験ないし。
当然Windowsのアップデートなんて「え?なにそれおいしいの?」って状態。サポート切れてますけど。でも,表彰されるの。
DXとかも,人力で機械様に都合のいいように相当数時間をかけて調整して,機械様がやってるとこだけを取り出して「これだけ効率化されました」とか発表したり取材させたり。そんな切り取られた部分しか表には出てこない。
RPAだってRPAを使うのが目的になってるから,継続利用できているのがほぼゼロ。複数のアプリケーションにまたがって使うならわからなくもないけど,集計につかってるの。説明会に参加した超大手企業の担当者も,RPAを使って各支店がCSVでダウンロードした売上データを分析の集計してんだって。「まじか,日本は大丈夫なわけ?」って聞いてて思ったよね。管理画面作るかCSVをダウンロードする際にその機能を提供してあげたほうがよっぽど効率化じゃないですかね…。行政にはわからんだろうという舐めた営業トークと思いたいけども,実際それで行政が導入してるわけだし営業トークとしては間違ってないんだろう。
そんなこんなで,業務改革のために各部局でRPAを導入しろって方針が出て,もう頭痛いの通り越したよね…。さすがにICTに詳しい非主流派から相当な突き上げ(というか単にどこも継続利用できてないと現実を開示しただけ)があったけど,もう対外的に先進地です〜ってなってるからどうにもできない状態。
なんでそうなるかって,まぁ(本当は知識のない)担当が上の人のお気に入りっていうのが一番で,かつ,担当も実態とは合わないけど財政部局の都合のいいことを言うから,財政部局も便利なんだよね。で,虚栄心の塊だから対外的に見栄えのするデジタル事業だけ金つっこみデジタルインフラ?なにそれ?状態でアップデートもできてないPCが溜まっていきネットワークも貧弱。修理や機器更新もせず壊れるの待ち。システム導入にするにしても同じ機能なんだから統一すればいいのに各部署でバラバラに導入。さらに,うんこみたいなシステムを導入する。これ行政相手じゃなかったら売り物になってないよね?っていうのが多数。
話がそれるけど,今だにIEのみ対応,画面遷移するたびに数秒またされるみたいなのを最近導入してんの。昔からあるならまだ許されるけど,最近ですよ。ほぼ全職員が使うシステムで画面遷移ごとに数秒待たされる損失ってどんなもんじゃい。業務改革とは?って思うけどまぁわからないよね。上の人たちには。で,先に書いたとおり,詳しい人達は邪魔だから非主流派になっていくの。
すげーな組織ってこう壊れていいくんだなと思って抜けさせてもらいました。
まぁ,組織が壊れたところで市役所がなくなることはないけども,行政サービスは落ちるだろうし中にいる人も一部以外は疲弊して優秀な人は抜けていくっていう負のスパイラルに陥るんだろうな。DX推進によって地方創生と逆の道をたどっていくのが皮肉というかなんというか。
でも,DXに限らず地方はそうやってずっと衰退いったのかもなって今は思ったりする。
新型コロナウイルスの「第7波」が続くなか、衆院厚生労働委員会は19日、閉会中審査を開いた。医療機関の負担となっている患者の「全数把握」の見直しなどのコロナ対策について与野党が政府の対応をただした。
新型コロナの場合、診察した医師が患者の氏名や連絡先といった基本情報を「発生届」としてシステムに入力する負担が生じており、見直しを求める声が日本医師会や全国知事会などから上がっている。
:
診察が終わった後に,医師がいちいち患者の氏名やら何十ある項目を手入力するのって面倒だよね。しかも,入力する項目って診察時に診た項目でしょ?
陽性の患者情報にフラグを付けて診察時の情報をそのまま参照データを貼り付けるようにできるようにすれば解決だよね?
特定のデータをCSVファイルにして,新型コロナウイルス感染者等情報把握・管理支援システム(HER-SYS)に取り込めるようにすればいいのにね。
手法の問題なのにそれを解決しないで全数把握を見直すだなんて本末転倒だ
そもそもHER-SYSの要件定義,仕様の作成時に現場を知らない人たちが作っちゃったからじゃないかな?
よくあることだよね。手間とか処理時間を考えないのは
書式なしテキストとして貼り付け
「csvを読み込んで~、該当列を指定してsumifs関数を使ったんですけど~、0になるんですよ~」
「ああ、たぶん金額のところがテキストになっているから、csvを読み込みなおして、数値に変換するか、クエリ自体をコピペして別のシートに書式なしテキストとして張り付けて、該当行をvalue関数で変換してからsumifsをつかってやるといいよ」
わたしは聞くに堪えないと思い、説明している最中の同僚の胸倉をつかみ、頬を2回叩いた
「round関数が~」、「マクロで~」、「ピボットを~」、それでも同僚は話すのを止めないので、同僚の髪の後ろの主電源を切ったのち、電源を入れなおす
蛍光灯が明滅し、セミの鳴き声が逆再生され、私の思考も溶けていく
「あたいが読み込まれる~」と新人がつまんねえことを言いながら窓を突き破り、宙へ飲み込まれていく
世界は再起動され、0と1が書き込まれ、新世界が想像されていく
自動で安価をつけて返信するプログラムでもこんなに長く複雑になる(一部抜粋)
/**************************************
以下の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