end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

blender 2.93 で、Mirror による左右反転コピー

以下のように cubeを x座標に対し、Mirror による左右反転コピーを行います。

f:id:end0tknr:20210912201353p:plain

step 1 - 左右反転の基準となる原点を設定

(x,y,z)=(0,0,0)に設置した3dカーソルを原点とすることで、x座標を基準に mirror します。

objectモード画面で、Object → Set Origin → Origin to 3D Cursor を 実行することで、この原点設定ができます。

f:id:end0tknr:20210912201422p:plain

step 2 - Mirror Modifier 追加

Modifier Properties → Add Modifier → Mirror

f:id:end0tknr:20210912201444p:plain

f:id:end0tknr:20210912201456p:plain

step 3 - Mirror Modifier の設定変更

反転の軸や、クリッピングを設定。

Clipping=ONでは、頂点移動時に反転位置をはみ出さないよう制限してくれます。

f:id:end0tknr:20210912201508p:plain

blender 2.93 で、円から、段付き円柱を作成

以下を作成します。

f:id:end0tknr:20210912133114p:plain

STEP 1 - 円を追加

Objectモードで、Add → Mesh → Circle

f:id:end0tknr:20210912133123p:plain

STEP 2 - 円を円柱化

Editモードで、Extrude Region ( or E )→ Z → マウスドラッグ

f:id:end0tknr:20210912133133p:plain

STEP 3 - 円柱にリム?を追加

E → S →マウスドラッグ

f:id:end0tknr:20210912133156p:plain

STEP 4 - 円柱を追加

E → Z → マウスドラッグ

f:id:end0tknr:20210912133206p:plain

STEP 5 - 表面の平滑化

Objectモードで、Object → Shade Smooth

f:id:end0tknr:20210912133216p:plain

blender2.9における下絵追加

「F3」でコマンド検索できますが、F3ではたどり着きづらく、 version毎に画面構成が変更される為、メモ

STEP 1 - Add → Image → Reference で、画像追加

f:id:end0tknr:20210905065745p:plain

STEP 2 - Opacity(不透明度)を下げ、透過

下絵で、Objectが隠れることを緩和する為

f:id:end0tknr:20210905070958p:plain

owasp zap におけるログイン設定

以前、 OWASP ZAP 2.8.0 で BASIC認証サイトへの脆弱性SCAN - end0tknr's kipple - web写経開発 にて、owasp zapにおける basic認証手順は記載しましたが、 basic認証 + form認証のサイトに対するowasp zapを行う為、メモ。

STEP 1 - サイト一覧へ、ログインurlを追加

まず、owasp zapのproxy経由で firefox等からログイン操作をすることで、 ログインurlをここへ追加します。

次に、追加されたログインurlを右クリックし、 「Flas as Context→既定コンテキスト: Form-based Auth Login Request」を選択し 「セッション・プロパティ」画面を表示します。

f:id:end0tknr:20210829113456p:plain

STEP 2 - 「セッション・プロパティ > 認証」画面 の編集

以下のような画面が表示されますので、必要があれば、修正して下さい。 ( 私の場合、Username Parameter , Password Parameter を修正しました )

f:id:end0tknr:20210829113507p:plain

STEP 3 - 「セッション・プロパティ > ユーザ」画面 の編集

以下のような画面が表示されますので、ログイン可能な ID / PW を追加して下さい。

以上、owasp zapが、spiderやscan時にログインできるはずです

firefoxブラウザに、owasp zapの自己証明書をinstall

owasp zapをproxyとした上で、firefoxで、サイトをアクセスしたところ、 以下のように 外部参照している https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js を 読み込めないエラーが発生。

f:id:end0tknr:20210829103617p:plain

どうやら、owasp zapで「ツール→オプション→ダイナミックSSL証明書」画面で、 証明書を保存(エクスポート)したものを、ブラウザへ、インポートする必要があるらしい。

その他、owasp zapの自己証明書には、1年の有効期間がありますので、 この期間を超えた場合、新しい「ルートCA証明書」の生成と、 再度のエクスポート&インポートが必要です。

f:id:end0tknr:20210829103627p:plain

Seleniumを使ってChromium版EdgeのIEモードを動かしてみた - python版

Seleniumを使ってChromium版EdgeのIEモードを動かしてみた - Qiita

上記urlを selenium for python版。

何となく動作します

#!python
# -*- coding: utf-8 -*-
import getopt
import os
import re
import sys
import time
from selenium import webdriver
from selenium.webdriver.ie.options  import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support     import expected_conditions
from selenium.webdriver.support.ui  import WebDriverWait

CONF = {
    "edge":{
        # download from
        # https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/#downloads
        'web_driver':"c:/Users/end0t/tmp/IE11_to_EDGE/msedgedriver.exe",
        'window_size':[1300,1100],
    },
    "ie": {
        # download from https://selenium-release.storage.googleapis.com/index.html
        'web_driver':"c:/Users/end0t/tmp/IE11_to_EDGE/IEDriverServer_Win32_3.150.1.exe",
        # 2021/8時点で最新のver.3.150.2では、find_elements_~()が動作しない
        #'web_driver':"c:/Users/end0t/tmp/IE11_to_EDGE/IEDriverServer_Win32_3.150.2.exe",
        'msedge_cmd':"c:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe",
        'window_size':[1300,1100],
    },
    'sleep'          : 2, # sec
    "implicitly_wait": 2, # sec
    'out_dir'        : "out",
    }

SCREEN_CAPTURE_URLS = [
    "https://www.yahoo.co.jp/",
    "https://www.google.co.jp/" ]


def main():
    # selenium によりbrowser起動.
    # 対象ブラウザに応じ、以下をcomment解除
    #browser = init_browser_edge()
    #browser = init_browser_edge_ie()
    browser = init_browser_ie()
    
    browser.implicitly_wait(CONF["implicitly_wait"])

    test_manipulate_elements(browser)   # test対象画面を操作
    test_screen_captures(browser)       # test対象urlを連続画面キャプチャ

    browser.close()                     # seleniumの終了処理
    browser.quit()


def my_sleep(*sec):
    if len(sec):
        time.sleep( sec[0] )
        return
    time.sleep( CONF["sleep"] )

def my_browser_wait(browser):
    try:
        WebDriverWait(browser, CONF["implicitly_wait"]).until(
            expected_conditions.presence_of_all_elements_located)
        return True
    except Exception as e:
        print(e)
        return False

    
def test_manipulate_elements(browser):

    browser.get("https://www.yahoo.co.jp/")
    my_browser_wait(browser)

    input_elms = browser.find_elements_by_css_selector("input[type=search]")
    print( input_elms )
    input_elms[0].send_keys("今日の天気")
    
    # input_elms[0].send_keys(Keys.ENTER)

    # 画面表示の倍率によっては
    # find_elements_by_css_selector()できても、click()できない気がします。
    btn_elms = browser.find_elements_by_css_selector("button[type=submit]")
    print( btn_elms )
    btn_elms[0].click()
    
    my_browser_wait(browser)
    
    
def test_screen_captures(browser):

    for test_url in SCREEN_CAPTURE_URLS:
        browser.get( test_url )
        my_browser_wait(browser)

        # 画面キャプチャを取得 & file保存
        save_img_path = calc_img_path( test_url )
        print( "save screen capture to "+save_img_path )
        browser.save_screenshot( save_img_path )

    
def calc_img_path(req_url):
    img_path = req_url
    img_path = re.sub('https?://', '',  img_path)
    img_path = re.sub('[\?/:.]',   '_', img_path)
    return CONF["out_dir"] + "/" + img_path + ".png"


def init_browser_edge_ie():
    # 以下により、内部的に msedge.exe --ie-mode-force が実行
    opts = Options()
    opts._options["ie.edgechromium"] = True
    opts._options["ie.edgepath"] = CONF["ie"]['msedge_cmd']
    opts._options["ignoreProtectedModeSettings"] = True

    browser = webdriver.Ie(CONF["ie"]['web_driver'], options=opts)
    browser.set_window_size(CONF["ie"]["window_size"][0],
                            CONF["ie"]["window_size"][1])
    return browser

def init_browser_ie():
    browser = webdriver.Ie(CONF["ie"]['web_driver'])
    browser.set_window_size(CONF["ie"]["window_size"][0],
                            CONF["ie"]["window_size"][1])
    return browser

def init_browser_edge():
    browser = webdriver.Edge(CONF["edge"]['web_driver'])
    browser.set_window_size(CONF["edge"]["window_size"][0],
                            CONF["edge"]["window_size"][1])
    return browser
    

if __name__ == '__main__':
    main()

msedge.exe --ie-mode-force

WIN + R キーで「ファイル名を指定して実行」画面を表示し

msedge.exe --ie-mode-force

を実行すると、強制的に edgeをieモードで起動できます。

ただし、前提条件として、

Edgeの「IEモード」を、サポートが終了するIE代わりに使う方法:Tech TIPS - @IT にある 「IEモードの設定と有効化」が完了しており、また、アドレスバーにおいて

edge://compat/enterprise

で表示されるサイトは、空である必要があるようです。

visual studio 2019 community edition で console app の project 作成

以下の画面で見当たらない場合、「さらにツールと機能をインストールする」リンクをクリック。

f:id:end0tknr:20210822163155p:plain

次に、以下の画面で「.NET クラスプラットフォーム開発」を選択して下さい。

f:id:end0tknr:20210822163205p:plain

すると、以下のように「コンソール アプリケーション」が現れます。

f:id:end0tknr:20210822163213p:plain

hands-on three.js - display 3d models - gltf形式

hands-on three.js - display 3d models - end0tknr's kipple - web写経開発

先程の上記entryのきです。

今回の場合、

に記載されている gltf 形式の3Dモデルの表示です。

threejsfundamentals.org の説明は分かりやすいのですが、 sketchfab.com のサンプルGLTFが、よくできているおかげだと思います。

その他、次のurlも参考になるかもしれません。

Three.js_Tips_GLTFモデルを表示する – しめじのネタ帳

https://end0tknr.github.io/sandbox/threejs_obj_gltf/test_threejs_gltf.html

f:id:end0tknr:20210822102457p:plain

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Hello Three.js</title>
  <style>
    html, body { margin: 0; height: 100%; }
    #c { width: 100%; height: 100%; display: block; }
  </style>
</head>
<body>
  <canvas id="c"></canvas>
  
  <script type="module">
    import * as THREE from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/build/three.module.js';
    import {OrbitControls} from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/controls/OrbitControls.js';
    import {GLTFLoader} from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/loaders/GLTFLoader.js';
    import {GUI} from
    'https://threejsfundamentals.org/threejs/../3rdparty/dat.gui.module.js';
    
    function main() {
        const canvas = document.querySelector('#c');
        const renderer = new THREE.WebGLRenderer({canvas});
        renderer.shadowMap.enabled = true;
        
        const fov = 45;
        const aspect = 2;  // the canvas default
        const near = 0.1;
        const far = 100;
        const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
        camera.position.set(0, 10, 20);
        
        const controls = new OrbitControls(camera, canvas);
        controls.target.set(0, 5, 0);
        controls.update();
        
        const scene = new THREE.Scene();
        scene.background = new THREE.Color('#DEFEFF');

        {
            const planeSize = 40;
            
            const loader = new THREE.TextureLoader();
            const texture = loader.load('https://threejsfundamentals.org/threejs/resources/images/checker.png');
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.magFilter = THREE.NearestFilter;
            const repeats = planeSize / 2;
            texture.repeat.set(repeats, repeats);
            
            const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
            const planeMat = new THREE.MeshPhongMaterial({
                map: texture,
                side: THREE.DoubleSide,
            });
            const mesh = new THREE.Mesh(planeGeo, planeMat);
            mesh.rotation.x = Math.PI * -.5;
            scene.add(mesh);
        }
        
        {
            const skyColor = 0xB1E1FF;  // light blue
            const groundColor = 0xB97A20;  // brownish orange
            const intensity = 1;
            const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
            scene.add(light);
        }
        
        {
            const color = 0xFFFFFF;
            const intensity = 1;
            const light = new THREE.DirectionalLight(color, intensity);
            light.castShadow = true;
            light.position.set(-250, 800, -850);
            light.target.position.set(-550, 40, -450);
            
            light.shadow.bias = -0.004;
            light.shadow.mapSize.width = 2048;
            light.shadow.mapSize.height = 2048;
            
            scene.add(light);
            scene.add(light.target);
            const cam = light.shadow.camera;
            cam.near = 1;
            cam.far = 2000;
            cam.left = -1500;
            cam.right = 1500;
            cam.top = 1500;
            cam.bottom = -1500;
            
            const cameraHelper = new THREE.CameraHelper(cam);
            scene.add(cameraHelper);
            cameraHelper.visible = false;
            const helper = new THREE.DirectionalLightHelper(light, 100);
            scene.add(helper);
            helper.visible = false;
            
            function makeXYZGUI(gui, vector3, name, onChangeFn) {
                const folder = gui.addFolder(name);
                folder.add(vector3, 'x', vector3.x - 500, vector3.x + 500).onChange(onChangeFn);
                folder.add(vector3, 'y', vector3.y - 500, vector3.y + 500).onChange(onChangeFn);
                folder.add(vector3, 'z', vector3.z - 500, vector3.z + 500).onChange(onChangeFn);
                folder.open();
            }
            
            function updateCamera() {
                // update the light target's matrixWorld because it's needed by the helper
                light.updateMatrixWorld();
                light.target.updateMatrixWorld();
                helper.update();
                // update the light's shadow camera's projection matrix
                light.shadow.camera.updateProjectionMatrix();
                // and now update the camera helper we're using to show the light's shadow camera
                cameraHelper.update();
            }
            updateCamera();
            
            class DimensionGUIHelper {
                constructor(obj, minProp, maxProp) {
                    this.obj = obj;
                    this.minProp = minProp;
                    this.maxProp = maxProp;
                }
                get value() {
                    return this.obj[this.maxProp] * 2;
                }
                set value(v) {
                    this.obj[this.maxProp] = v /  2;
                    this.obj[this.minProp] = v / -2;
                }
            }
            
            class MinMaxGUIHelper {
                constructor(obj, minProp, maxProp, minDif) {
                    this.obj = obj;
                    this.minProp = minProp;
                    this.maxProp = maxProp;
                    this.minDif = minDif;
                }
                get min() {
                    return this.obj[this.minProp];
                }
                set min(v) {
                    this.obj[this.minProp] = v;
                    this.obj[this.maxProp] = Math.max(this.obj[this.maxProp], v + this.minDif);
                }
                get max() {
                    return this.obj[this.maxProp];
                }
                set max(v) {
                    this.obj[this.maxProp] = v;
                    this.min = this.min;  // this will call the min setter
                }
            }
            
            class VisibleGUIHelper {
                constructor(...objects) {
                    this.objects = [...objects];
                }
                get value() {
                    return this.objects[0].visible;
                }
                set value(v) {
                    this.objects.forEach((obj) => {
                        obj.visible = v;
                    });
                }
            }
            
            const gui = new GUI();
            gui.close();
            gui.add(new VisibleGUIHelper(helper, cameraHelper), 'value').name('show helpers');
            gui.add(light.shadow, 'bias', -0.1, 0.1, 0.001);
            {
                const folder = gui.addFolder('Shadow Camera');
                folder.open();
                folder.add(new DimensionGUIHelper(light.shadow.camera, 'left', 'right'), 'value', 1, 4000)
                    .name('width')
                    .onChange(updateCamera);
                folder.add(new DimensionGUIHelper(light.shadow.camera, 'bottom', 'top'), 'value', 1, 4000 )
                    .name('height')
                    .onChange(updateCamera);
                const minMaxGUIHelper = new MinMaxGUIHelper(light.shadow.camera, 'near', 'far', 0.1);
                folder.add(minMaxGUIHelper, 'min', 1, 1000, 1).name('near').onChange(updateCamera);
                folder.add(minMaxGUIHelper, 'max', 1, 4000, 1).name('far').onChange(updateCamera);
                folder.add(light.shadow.camera, 'zoom', 0.01, 1.5, 0.01).onChange(updateCamera);
            }
            
            makeXYZGUI(gui, light.position, 'position', updateCamera);
            makeXYZGUI(gui, light.target.position, 'target', updateCamera);
        }
        
        function frameArea(sizeToFitOnScreen, boxSize, boxCenter, camera) {
            const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
            const halfFovY = THREE.MathUtils.degToRad(camera.fov * .5);
            const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
            // compute a unit vector that points in the direction the camera is now
            // in the xz plane from the center of the box
            const direction = (new THREE.Vector3())
                  .subVectors(camera.position, boxCenter)
                  .multiply(new THREE.Vector3(1, 0, 1))
                  .normalize();
            
            // move the camera to a position distance units way from the center
            // in whatever direction the camera was from the center already
            camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
            
            // pick some near and far values for the frustum that
            // will contain the box.
            camera.near = boxSize / 100;
            camera.far = boxSize * 100;
            
            camera.updateProjectionMatrix();
            
            // point the camera to look at the center of the box
            camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
        }
        
        let curve;
        let curveObject;
        {
            const controlPoints = [
                [1.118281, 5.115846, -3.681386],
                [3.948875, 5.115846, -3.641834],
                [3.960072, 5.115846, -0.240352],
                [3.985447, 5.115846, 4.585005],
                [-3.793631, 5.115846, 4.585006],
                [-3.826839, 5.115846, -14.736200],
                [-14.542292, 5.115846, -14.765865],
                [-14.520929, 5.115846, -3.627002],
                [-5.452815, 5.115846, -3.634418],
                [-5.467251, 5.115846, 4.549161],
                [-13.266233, 5.115846, 4.567083],
                [-13.250067, 5.115846, -13.499271],
                [4.081842, 5.115846, -13.435463],
                [4.125436, 5.115846, -5.334928],
                [-14.521364, 5.115846, -5.239871],
                [-14.510466, 5.115846, 5.486727],
                [5.745666, 5.115846, 5.510492],
                [5.787942, 5.115846, -14.728308],
                [-5.423720, 5.115846, -14.761919],
                [-5.373599, 5.115846, -3.704133],
                [1.004861, 5.115846, -3.641834],
            ];
            const p0 = new THREE.Vector3();
            const p1 = new THREE.Vector3();
            curve = new THREE.CatmullRomCurve3(
                controlPoints.map((p, ndx) => {
                    p0.set(...p);
                    p1.set(...controlPoints[(ndx + 1) % controlPoints.length]);
                    return [
                        (new THREE.Vector3()).copy(p0),
                        (new THREE.Vector3()).lerpVectors(p0, p1, 0.1),
                        (new THREE.Vector3()).lerpVectors(p0, p1, 0.9),
                    ];
                }).flat(),
                true,
            );
            {
                const points = curve.getPoints(250);
                const geometry = new THREE.BufferGeometry().setFromPoints(points);
                const material = new THREE.LineBasicMaterial({color: 0xff0000});
                curveObject = new THREE.Line(geometry, material);
                curveObject.scale.set(100, 100, 100);
                curveObject.position.y = -621;
                curveObject.visible = false;
                scene.add(curveObject);
            }
        }
        
        const cars = [];
        {
            const gltfLoader = new GLTFLoader();
            gltfLoader.load(
                'https://threejsfundamentals.org/threejs/resources/models/cartoon_lowpoly_small_city_free_pack/scene.gltf',
                (gltf) => {
                    const root = gltf.scene;
                    scene.add(root);
                    
                    root.traverse((obj) => {
                        if (obj.castShadow !== undefined) {
                            obj.castShadow = true;
                            obj.receiveShadow = true;
                        }
                    });
                    
                    const loadedCars = root.getObjectByName('Cars');
                    const fixes = [
                        { prefix: 'Car_08', y: 0,  rot: [Math.PI * .5, 0, Math.PI * .5], },
                        { prefix: 'CAR_03', y: 33, rot: [0, Math.PI, 0], },
                        { prefix: 'Car_04', y: 40, rot: [0, Math.PI, 0], },
                    ];
                    
                    root.updateMatrixWorld();
                    for (const car of loadedCars.children.slice()) {
                        const fix = fixes.find(fix => car.name.startsWith(fix.prefix));
                        const obj = new THREE.Object3D();
                        car.position.set(0, fix.y, 0);
                        car.rotation.set(...fix.rot);
                        obj.add(car);
                        scene.add(obj);
                        cars.push(obj);
                    }
                    
                    // compute the box that contains all the stuff
                    // from root and below
                    const box = new THREE.Box3().setFromObject(root);
                    
                    const boxSize = box.getSize(new THREE.Vector3()).length();
                    const boxCenter = box.getCenter(new THREE.Vector3());
                    
                    // set the camera to frame the box
                    frameArea(boxSize * 0.5, boxSize, boxCenter, camera);
                    
                    // update the Trackball controls to handle the new size
                    controls.maxDistance = boxSize * 10;
                    controls.target.copy(boxCenter);
                    controls.update();
                });
        }
        
        function resizeRendererToDisplaySize(renderer) {
            const canvas = renderer.domElement;
            const width = canvas.clientWidth;
            const height = canvas.clientHeight;
            const needResize = canvas.width !== width || canvas.height !== height;
            if (needResize) {
                renderer.setSize(width, height, false);
            }
            return needResize;
        }
        
        // create 2 Vector3s we can use for path calculations
        const carPosition = new THREE.Vector3();
        const carTarget = new THREE.Vector3();
        
        function render(time) {
            time *= 0.001;  // convert to seconds
            
            if (resizeRendererToDisplaySize(renderer)) {
                const canvas = renderer.domElement;
                camera.aspect = canvas.clientWidth / canvas.clientHeight;
                camera.updateProjectionMatrix();
            }
            
            {
                const pathTime = time * .01;
                const targetOffset = 0.01;
                cars.forEach((car, ndx) => {
                    // a number between 0 and 1 to evenly space the cars
                    const u = pathTime + ndx / cars.length;
                    
                    // get the first point
                    curve.getPointAt(u % 1, carPosition);
                    carPosition.applyMatrix4(curveObject.matrixWorld);
                    
                    // get a second point slightly further down the curve
                    curve.getPointAt((u + targetOffset) % 1, carTarget);
                    carTarget.applyMatrix4(curveObject.matrixWorld);
                    
                    // put the car at the first point (temporarily)
                    car.position.copy(carPosition);
                    // point the car the second point
                    car.lookAt(carTarget);
                    
                    // put the car between the 2 points
                    car.position.lerpVectors(carPosition, carTarget, 0.5);
                });
            }
            
            renderer.render(scene, camera);
            
            requestAnimationFrame(render);
        }
        
        requestAnimationFrame(render);
    }
    
    main();
  </script>
</body>
</html>

hands-on three.js - display 3d models - obj形式

今回は、

  • STEP 1 - blend 形式の3D モデルを blender で、obj 形式に変換
  • STEP 2 - obj形式のファイルを three.js で表示

します。

前回のentryまで、 Three.js – しめじのネタ帳 を写経していましたが、 今回は、説明が分かりやすい以下を、写経しています。

Three.jsでOBJファイルを読み込む

STEP 1 - blend 形式の3D モデルを blender で、obj 形式に変換

3Dモデルのファイルは、様々なところで配布されています。 今回は、建築家(バウハウス) 3d model - Free3D から blend 形式の3Dモデルをダウンロードし、これを blenderで、obj形式にexportします。

特に難しい点はない為、詳細までは記載しません。

STEP 2 - obj形式のファイルを three.js で表示

f:id:end0tknr:20210822064341p:plain

https://end0tknr.github.io/sandbox/threejs_obj_gltf/test_threejs_obj.html

以下の通りです。

ちなみに以前のentryと異なり、javascript es6の importを使用する為、

<script type="module"></script>

で jsを記載しています。

Three.jsでOBJファイルを読み込む

の説明は分かりやすいのですが、

Three.js – しめじのネタ帳

にある obj形式のentryと併せて、確認することをお勧めします。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Hello Three.js</title>
  <style>
    html, body { margin: 0; height: 100%; }
    #c { width: 100%; height: 100%; display: block; }
  </style>
</head>
<body>
  <canvas id="c"></canvas>
  <script type="module">
    import * as THREE from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/build/three.module.js';
    import {OrbitControls} from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/controls/OrbitControls.js';
    import {OBJLoader} from
    'https://threejsfundamentals.org/threejs/resources/threejs/r127/examples/jsm/loaders/OBJLoader.js';

    function main() {
        const canvas = document.querySelector('#c');
        const renderer = new THREE.WebGLRenderer({canvas});
        
        const fov = 45;
        const aspect = 2;  // the canvas default
        const near = 0.1;
        const far = 100;
        const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
        camera.position.set(0, 10, 20);
        
        const controls = new OrbitControls(camera, canvas);
        controls.target.set(0, 5, 0);
        controls.update();
        
        const scene = new THREE.Scene();
        scene.background = new THREE.Color('black');
        
        {
            const planeSize = 40;
            
            const loader = new THREE.TextureLoader();
            const texture = loader.load('https://threejsfundamentals.org/threejs/resources/images/checker.png');
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.magFilter = THREE.NearestFilter;
            const repeats = planeSize / 2;
            texture.repeat.set(repeats, repeats);
            
            const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
            const planeMat = new THREE.MeshPhongMaterial({
                map: texture,
                side: THREE.DoubleSide,
            });
            const mesh = new THREE.Mesh(planeGeo, planeMat);
            mesh.rotation.x = Math.PI * -.5;
            scene.add(mesh);
        }
        
        {
            const skyColor = 0xB1E1FF;  // light blue
            const groundColor = 0xB97A20;  // brownish orange
            const intensity = 1;
            const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
            scene.add(light);
        }
        
        {
            const color = 0xFFFFFF;
            const intensity = 1;
            const light = new THREE.DirectionalLight(color, intensity);
            light.position.set(0, 10, 0);
            light.target.position.set(-5, 0, 0);
            scene.add(light);
            scene.add(light.target);
        }
        
        {
            const objLoader = new OBJLoader();
            objLoader.load(
                './bauhaus.obj',
                // 'https://threejsfundamentals.org/threejs/resources/models/windmill/windmill.obj',
                (root) => {
                    root.scale.set(3, 3, 3);
                    scene.add(root);
                });
        }
        
        function resizeRendererToDisplaySize(renderer) {
            const canvas = renderer.domElement;
            const width = canvas.clientWidth;
            const height = canvas.clientHeight;
            const needResize = canvas.width !== width || canvas.height !== height;
            if (needResize) {
                renderer.setSize(width, height, false);
            }
            return needResize;
        }
        
        function render() {
            
            if (resizeRendererToDisplaySize(renderer)) {
                const canvas = renderer.domElement;
                camera.aspect = canvas.clientWidth / canvas.clientHeight;
                camera.updateProjectionMatrix();
            }
            
            renderer.render(scene, camera);
            
            requestAnimationFrame(render);
        }
        
        requestAnimationFrame(render);
    }
    
    main();
  </script>
</body>
</html>

install Greenbone Vulnerability Manager 21 (GVM, 旧OpenVAS) from source to ubuntu20

以前の上記entryの ver.21版です。

前回同様、

Install and Setup GVM 20.08 on Ubuntu 20.04 - kifarunix.com

を参考に進めようとしましたが、 インストールできたものの、OpenVASが起動せず断念しました。

なので、

を参考にインストールしました。

Building GVM 21.04 — Greenbone Documentation documentationコマンドラインまで、丁寧に記載されていますので、楽に進めることができます。

ただ、

$ sudo apt install postgresql-server-dev-11

は、パッケージがないようでしたので

$ sudo apt install postgresql-server-dev-12

としました。

また、自動起動

ExecStart=/usr/local/sbin/gsad --listen=127.0.0.1 --port=9392 --http-only

だと、localのブラウザからしかアクセスできず、私の場合、都合が悪いので

ExecStart=/usr/local/sbin/gsad --listen=0.0.0.0 --port=9392 --http-only

としています。