gikoha’s blog

個人的メモがわり

多施設共同研究患者登録システム

多施設共同研究患者登録システムのひな形

github.com

node.js(express) + mysql で書いた 多施設共同研究に使えるかな?というデータベースのフロントエンドです

  • データベースの設定は mysqlConnection.jsに記載
  • データベースの内容は studydb.sql に記載しています
  • 病院の追加、パスワードの変更、ログイン、患者の登録、編集、イベントの登録、編集が可能です
  • パスワードの保存用にbcryptを使っています

セキュリティ上の問題点があれば遠慮なく修正をお願いします。

もともとはdocker用に作っていますので mysqlConnection.js 内でlocal testか dockerかを判断して接続先を変更しています

これで少しでもexcel提出のクソシステムが減るといいなあ

 

今やってること

・患者登録システムをnode.js+mysql+nginx (docker)で作っています  進捗度:30%..
 ログインログアウト、患者データ追加まで作ったが イベント入力や再来院の画面はまだできていない
 TypeScriptはやりたかったけれど面倒で諦めた
 日時入力にVue.jsを使いたい
 CSSデザインセンスがなくて..
・データベースからの解析システムの構築 (Kaplan-Meierなど) 進捗度:0
 R使って自動化できるかどうか
・割り付け君 進捗度:0
 これまでの患者群の年齢、性別、体重、イベント量などのいくつかのパラメータを均一化に向けて割り振る
 optaplannerの出番だと思われる!

OnePlus 7T到着

次期nova3のかわりにOnePlus 7Tを使うことにしました

  • 速い (Snapdragon 855+)
  • カメラはまあまあよい
  • OLEDはきれい
  • 画面内指紋認証
  • まあまあ安い
  • アマゾンにiPhoneがなくなった

以上が理由です

Xiaomi Mi Note 10と迷いましたが、SoCがボロイのと、カメラもいまいちらしい?のでやめています

 

実際に使用してみて

  • カメラはなかなかいいですよ?
  • USBに接続してもPCとやりとりできない→設定>デバイス情報>ビルド番号をタップして開発者モードになり、USBデバッグをON、ディフォルトのUSB設定>ファイル転送に設定すると、MTPでAndroid File Transferが作動
  • pokemon goは90Hzでヌルヌル、しかしモンスターボールPlusに接続できず、Go Plus Companion appを使ったら接続できた
  • 電池の減りは速い気がするが充電が速いので帳消しか
  • wifi親機設定しなおしたら上手くつながるようになった→ならない
  • 満足度はかなり高いです
  • google calenderは使いづらい 予定も 時刻入力のやり方も huaweiのほうがまし→Yahooカレンダーをいれて解決しました
  • 他は気づいたら書いていきます

 

nova3電池交換

去年購入したnova3ですが、また膨れて側面にスキマができてきました

液晶画面も真ん中に青い色の部分が入る(圧迫による?)

年末にhuawei サポートに郵送、年明けに無償修理され返ってきました

液晶画面もきれいになりました(圧迫がとれたから?)

急速充電器のおまけがついていました

・サポートはかなりいい方です

・電池パックが2年以内に膨らむのはhuaweiだけ!しかも2回目(前回P10 Plus)

・廃熱のよいスマホがいいな..

AffiliateMaker

コマンドライン

github.com

ViewControllerのソース

 

//
//  ViewController.swift
//  AffiliateMaker
//
//  Created by Namikare Gikoha on 2020/01/02.
//  Copyright © 2020 gikoha. All rights reserved.
//

import Cocoa
import Alamofire
import CryptoSwift
import SwiftyXMLParser

let associateTag = "gikohadiary-22"
let amazonAccessKey = "XXXXXX自分で置き換えてねXXXXXXXX"
let amazonSecretKey = "XXXXXX自分で置き換えてねXXXXXXXX"

// http://seiya-orz.hatenablog.com/entry/2018/01/21/154249

extension Date
{
    func jpDate(_ format: String = "yyyy/MM/dd") -> String
    {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "ja_JP")
        formatter.dateFormat = format
        return formatter.string(from: self)
    }
}

extension String
{
    func urlAWSQueryEncoding() -> String
    {
        var allowedCharacters = CharacterSet.alphanumerics
        allowedCharacters.insert(charactersIn: "-")
        if let ret = self.addingPercentEncoding(withAllowedCharacters: allowedCharacters )
        {
            return ret
        }
        return ""
    }
    
    func hmac(key: String) -> String
    {
        guard let keyBytes = key.data(using: .utf8)?.bytes, let mesBytes = self.data(using: .utf8)?.bytes else
        {
            return ""
        }
        let hmac = try! HMAC(key: keyBytes, variant: .sha256).authenticate(mesBytes)
        return Data(hmac).base64EncodedString()
    }
}

class ViewController: NSViewController {

	
	@IBOutlet weak var myTextView: NSTextView!
	@IBOutlet weak var sendButton: NSButton!
	@IBOutlet weak var asinTextField: NSTextField!
	
	override func viewDidLoad()
    {
		super.viewDidLoad()

		// Do any additional setup after loading the view.
	}

	override var representedObject: Any?
    {
		didSet
        {
            // Update the view, if already loaded.
		}
	}
	
	@IBAction func sendAction(_sender: Any)
	{
		// parametersはABC順にソートする必要があります
		
		var parameters = "AWSAccessKeyId=" + amazonAccessKey
		parameters += "&AssociateTag=" + associateTag
        parameters += "&ItemId=" + asinTextField.stringValue // "B08247FT3N"
		parameters += "&Operation=" + "ItemLookup"
		parameters += "&Service=" + "AWSECommerceService"
		parameters += "&Timestamp=" + Date().jpDate("yyyy-MM-dd'T'HH:mm:ssZZZZZ").urlAWSQueryEncoding()
		let target = "GET\nwebservices.amazon.co.jp\n/onca/xml\n\(parameters)"
		let signature = target.hmac(key: amazonSecretKey).urlAWSQueryEncoding()
		let url = "https://webservices.amazon.co.jp/onca/xml?\(parameters)&Signature=\(signature)"

		Alamofire.request(url).response { response in
            if let data = response.data
            {
                let xml = try! XML.parse(String(data: data, encoding: .utf8)!)
                if case .failure(let error) =  xml["ItemLookupResponse","Items","Item","ItemAttributes","Title"]
                {
                    let errmsg = xml.ItemLookupResponse.Items.Request.Errors.Error.Message.text!
                    self.myTextView.string = "Error: \(errmsg)"
                }
                else
                {
                    let title = xml.ItemLookupResponse.Items.Item.ItemAttributes.Title.text!
                    let itemurl = xml.ItemLookupResponse.Items.Item.DetailPageURL.text!
                    self.myTextView.string = "<a href=\"\(itemurl)\">\(title)</a>" + "\nerror = \(request)"
                }
            }
            else
            {
                self.myTextView.string = "Error: no data"
            }
		}

	}

}

<

amazon APIを使用してみようとしてわかったこと

1. このブログのアフィが古くなっていたので更新しようとした

2. アフィに使っていたG-Toolsが使えなくなっていた

3. そこでswiftのお勉強も兼ねて自分でアプリを作ってみようとした

4. コマンドライン+SwiftPMによるサブモジュールを試してみたが

AF.request(urlPath, method: .get).response { response in
print(response)
}
sleep(5)
たかだかこれくらいのコードでも動かない
var keepAlive = true
AF.request(urlPath, method: .get).response {
    response in print(response)
    keepAlive=false 
}
let runLoop = RunLoop.current
while keepAlive && runLoop.run(mode: RunLoop.Mode.default, before: Date(timeIntervalSinceNow: 0.1))
{
}
5. 一方コマンドラインでなくアプリにした場合は動作した
 AFでなくAlamofireにする必要があった
Alamofire.request(url).responseString { response in
	self.myTextView.string = response.description
}
アプリ作成はxcodeを使うため、carthageを使った