2021년 5월 22일 토요일

[Bootstrap] Board Template

 1. Board Template


<head>
<title>home</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="./css/bootstrap-3.3.2.css" >
</head>
<body>

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Brand</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu" role="menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li class="divider"></li>
            <li><a href="#">Separated link</a></li>
            <li class="divider"></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <form class="navbar-form navbar-left" role="search">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
      <ul class="nav navbar-nav navbar-right">
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu" role="menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li class="divider"></li>
            <li><a href="#">Separated link</a></li>
          </ul>
        </li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>


<div class="panel panel-primary" style="margin: 25px 25px 25px 25px;">
  <div class="panel-heading">Panel heading</div>
  <div class="panel-body">
    <p>...</p>
	<table class="table table-bordered table-striped" border='0'>
		<thead><tr class="info">
			<th>element1</th>
			<th>data</th>
			<th>junk here</th>
			<th>last column</th>
		</tr></thead>
		<tbody><tr>
			<td class="shrink">elem</td>
			<td class="shrink">more data</td>
			<td class="shrink">other stuff</td>
			<td class="expand">again, last column</td>
		</tr>
		<tr>
			<td class="shrink">more</td>
			<td class="shrink">of </td>
			<td class="shrink">these</td>
			<td class="expand"><center><span class="label label-primary">Primary</span></center></td>
		</tr></tbody>
	</table>
	
	<div style="display: flex; justify-content: flex-end"> 
	<nav>
	  <ul class="pagination">
		<li>
		  <a href="#" aria-label="Previous">
			<span aria-hidden="true">&laquo;</span>
		  </a>
		</li>
		<li><a href="#">1</a></li>
		<li><a href="#">2</a></li>
		<li><a href="#">3</a></li>
		<li><a href="#">4</a></li>
		<li><a href="#">5</a></li>
		<li>
		  <a href="#" aria-label="Next">
			<span aria-hidden="true">&raquo;</span>
		  </a>
		</li>
	  </ul>
	</nav>
	</div>
  </div>
</div>


<script src="./js/jquery-3.6.0.js" ></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" ></script>
<script src="./js/bootstrap-3.3.2.js" ></script>
</body>
</html>

2021년 4월 15일 목요일

[Python] Flask Example

1. File Server

fileserver.py

import logging
import time
import os

import requests
from flask import Flask, url_for, render_template, request, redirect, session
from flask_sqlalchemy import SQLAlchemy
from flask import send_from_directory

ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])
home_dir = r"D:\Temp"
app = Flask(__name__, instance_path=home_dir)
db = SQLAlchemy(app)

#
# FILE SERVER
#
        
def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

def strip_root(filename):
    if len(filename) == 0: return ""
    elif len(filename) == 1: return "" if filename[0] == '/' else filename
    else: return filename[1:] if filename[0] == '/' else filename
        
def send_list_directory(file_path):
    dirs  = []
    files = []
    abs_path = os.path.join( home_dir, file_path )
    if len(file_path) > 0:
        if file_path[0] != '/':  file_path = "/" + file_path
        if file_path[-1] != '/': file_path = file_path + "/"
    else:
        file_path = "/"
    dirs.append( ("..", 0) ) 
    for f in os.listdir( abs_path ):
        full_name = os.path.join( abs_path, f )
        size = os.path.getsize( full_name )
        date = time.strftime( "%Y-%m-%d %H:%M:%S", time.localtime(os.path.getctime( full_name )))
        if os.path.isdir(full_name): dirs.append( (f, size, date) )
        else: files.append( (f, size, date) )
    print('send_list_directory [', file_path, ']', dirs, files)
    return render_template("fileserver.html", folder=file_path, dirs=dirs, files=files)

@app.route('/home', methods=['GET', 'POST'])
@app.route('/', methods=['GET', 'POST'])
def Home():
    if not session.get('logged_in'):
        return render_template('login.html')
    if request.method == 'GET':
        return send_list_directory("")
 
@app.route('/upload', methods=['POST'])
def Upload():
    if not session.get('logged_in'):
        return render_template('login.html')
    file = request.files['file']
    folder = strip_root(request.form['folder'])
    if file and allowed_file(file.filename):
        file.save(os.path.join( home_dir, folder, file.filename))
    return send_list_directory(folder)
        
@app.route('/delete', methods=['GET'])
def Delete():
    if not session.get('logged_in'):
        return render_template('login.html')
    file = strip_root(request.args['file'])
    folder = strip_root(os.path.dirname(file))
    full_path = os.path.join( home_dir, file)
    if file and allowed_file(file):
        print( full_path, home_dir, file )
        os.remove(full_path)
    else:
        print(f"permission error : delete {full_path}")
    return send_list_directory(folder)
 
@app.route('/<path:filePath>', methods=['GET'])
def ServeFile(filePath):
    if not session.get('logged_in'):
        return render_template('login.html')
    print('ServeFile()', filePath)
    if os.path.isdir(os.path.join(home_dir,filePath)):
        return send_list_directory(filePath)
    else:
        return send_from_directory(home_dir, filePath)

def warning(text):
    logger.warning(text)


#
# SESSION
#

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    password = db.Column(db.String(80))
    def __init__(self, username, password):
        self.username = username
        self.password = password

def create_user(username,password):
    new_user = User(username=username, password=password)
    db.session.add(new_user)
    db.session.commit()
    print(User.query.filter_by(username=username, password=password).first())
      
@app.route('/login', methods=['GET', 'POST'])
def login():
    if not session.get('logged_in'):
        if request.method == 'GET':
            return render_template('login.html')
        username = request.form['username']
        password = request.form['password']
        print( '/login', username, password )
        try:
            data = User.query.filter_by(username=username, password=password).first()
            if data is not None:
                #if username == 'admin' and password == 'admin1234':
                session['logged_in'] = True
                return redirect(url_for('Home'))
            else:
                return  render_template('login.html', message="Login Fail [1] !")
        except:
            return  render_template('login.html', message="Login Fail [2] !")
    else:
        return send_list_directory("")

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        new_user = User(username=request.form['username'], password=request.form['password'])
        db.session.add(new_user)
        db.session.commit()
        return render_template('login.html')
    return render_template('register.html')

@app.route("/logout")
def logout():
    session['logged_in'] = False
    return redirect(url_for('Home'))

#
# Application
#
    
if __name__ == "__main__":
    app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024    
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///fileserver.db'
    app.secret_key = "3123"
    db.create_all()
    logger = logging.getLogger(__name__)
    #create_user(username='admin', password='admin1234')
    app.run(debug=True, host="0.0.0.0", port=8000) 


fileserver.html

<!DOCTYPE html>
<html>
    <head>
        <title>home</title>
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">        
    </head>
    <body>
        <div style="margin-right:50px" width="600">
            <div style="float: right"><a href="/logout"> logout </a></div>
            <h1>UpLoad</h1>
            <!--div style="border: 3px solid gold; float: left; height: auto; width: 200px; margin: 15px 25px 15px 0px;"-->
            <table border='1' class="table table-dark" style="margin: 25px 25px 25px 25px; width:600px;" >
            {% autoescape false %}
              <form action = "/upload" method = "POST"
                  enctype = "multipart/form-data">
              <tr>
              <td><input type = "file" name = "file" />
              <input type = "hidden" name = "folder" value="{{folder}}" /></td>
              <td><input type = "submit"/></td>
              </tr>
            </form> 
            {% endautoescape %}
            </table>
        <h1>File List</h1>
        <div style="margin-left:25px"> <h4> {% block title %}  {{folder}}{% endblock %} </h4></div>
        <table border='1' class="table table-striped table-responsive" style="margin: 25px 25px 25px 25px;"> <!-- border='1'  -->
            <thead><tr> <th width="1%" style="text-align: center;"> File/Dir </th>
                 <th style="text-align: center;"> Filename </th> 
                 <th width="1%" style="text-align: center;"> Size </th> 
                 <th width="200px" style="text-align: center;"> Date </th>
                 <th width="1%" style="text-align: center;"> Operation </th>
             </tr></thead><tbody>
        {% if dirs %}
            {% for dirName in dirs %}
                <tr>
                <td>[DIR]</td> 
                <!--td onclick="window.location='{{folder}}{{dirName[0]}}';" style='cursor: pointer;'-->
                <td><a href="{{folder}}{{dirName[0]}}">[ {{ dirName[0] }} ]</a></td> 
                <td style="text-align: right;"> {{ dirName[1] }} </td>
                <td style="text-align: center;"> {{ dirName[2] }} </td>
                <td></td>
                </tr>
            {% endfor %}
        {% endif %}
        {% if files %}
            {% for fileName in files %}
                <tr>
                <td>[FILE]</td>
                <!--td onclick="window.location='{{folder}}{{fileName[0]}}';" style='cursor: pointer;'-->
                <td><a href="{{folder}}{{fileName[0]}}"> {{ fileName[0] }}</td> 
                <td style="text-align: right;">{{ fileName[1] }} </a></td>
                <td style="text-align: center;"> {{ fileName[2] }} </td>
                <td style="text-align: center;"> <a href="/delete?file={{folder}}{{fileName[0]}}">Delete</a></td>
                </tr>
            {% endfor %}
        {% endif %}
        </tbody></table>
        </div>
        <p />
        <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>        
    </body>
</html>

base.html

<html>
<head>
<title>home</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" >
</head>
<body>
{% block content %}{% endblock %}
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" ></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" ></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" ></script>
</body>
</html>

register.html

{% extends "base.html" %}
{% block content %}
{% if session['logged_in'] %}
<p>Oh no Dont show page</p>
{% else %}
<h2>Register</h2>
<form action="/register" method="POST">
  <input type="username" name="username" placeholder="Username">
  <input type="password" name="password" placeholder="Password">
  <input type="submit" value="Log in">
</form>
{% endif %}
{% endblock %}

login.html

{% extends "base.html" %}
{% block content %}
{% if session['logged_in'] %}
<script>window.location.href = "/"</script>
{% else %}
<center>
<h2>Login</h2>
<form action="/login" method="POST">
  <input type="username" name="username" placeholder="Username">
  <input type="password" name="password" placeholder="Password">
  <input type="submit" value="Log in">
</form>
<div><font color="red"> {{message}} </font></div>
</center>
{% endif %}
{% endblock %}

2021년 3월 4일 목요일

[Jython] JavaFx Chart Image Creation

JavaFx Chart Image Creation

import sys
from java.io import *
from java.util import *
from javax.imageio import ( ImageIO )
from javafx.application import Application
from javafx.scene import Scene
from javafx.scene.chart import ( LineChart, AreaChart, BarChart, ScatterChart, StackedBarChart, XYChart, NumberAxis, CategoryAxis )
from javafx.scene.chart import PieChart
from javafx.scene.chart.PieChart import Data
from javafx.scene.image import ( WritableImage )
from javafx.collections import FXCollections
from javafx.embed.swing import SwingFXUtils;

#
# Fx Chart
#

class FxVars():
    def __init__(self):
        self.handler = None
        self.outfile = None

__fx_vars = FxVars()

class FxMain(Application):
    def __init__(self): 
        print('__init__()', self)
    def start(self, stage): 
        try:
            image = __fx_vars.handler()
            ImageIO.write( SwingFXUtils.fromFXImage(image, None)
                    , "png"
                    , File(__fx_vars.outfile))
        except Exception as e:
            print(e)
        sys.exit(0);
    def run(self):
        self.launch(self.class, [])
        #return chart.snapshot(SnapshotParameters(), null)
    def set_handler(self,handler):
        __fx_vars.handler = handler
    def set_outfile(self,outfile):
        __fx_vars.outfile = outfile
        
#
# Application
#
            

def getPieData():
    return FXCollections.observableArrayList(
        PieChart.Data("Peachs", 13),
        PieChart.Data("Oranges", 25),
        PieChart.Data("Plums", 10),
        PieChart.Data("Pears", 22),
        PieChart.Data("Apples", 30))

def getPieChart(title, width, height, data):
    chart = PieChart(data)
    scene = Scene(chart, width, height)
    chart.setTitle(title);
    return scene.snapshot(None);

def PieChartHandler():
    return getPieChart("Fruits",640,480,getPieData());

def getXyChartData():
        title  = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
        value1 = [ 23, 14, 15, 24, 34, 36, 22, 45, 43, 17, 29, 25, ]
        value2 = [ 33, 34, 25, 44, 39, 16, 55, 54, 48, 27, 37, 29, ]
        series1 = XYChart.Series()
        series1.setName("Data 1");
        for i in range(len(title)):
            series1.getData().add(XYChart.Data( title[i], value1[i] ))
        series2 = XYChart.Series()
        series2.setName("Data 2")
        for i in range(len(title)):
            series2.getData().add(XYChart.Data( title[i], value2[i] ))
        #lineChartData = ArrayList()
        #lineChartData.add(series1)
        #lineChartData.add(series2)
        return [ series1, series2 ]

def getXyChartDataH():
        title  = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
        value1 = [ 23, 14, 15, 24, 34, 36, 22, 45, 43, 17, 29, 25, ]
        value2 = [ 33, 34, 25, 44, 39, 16, 55, 54, 48, 27, 37, 29, ]
        series1 = XYChart.Series()
        series1.setName("Data 1");
        for i in range(len(title)):
            series1.getData().add(XYChart.Data( value1[i], title[i] ))
        series2 = XYChart.Series()                        
        series2.setName("Data 2")                         
        for i in range(len(title)):                       
            series2.getData().add(XYChart.Data( value2[i], title[i] ))
        return [ series1, series2 ]
        
def getXyChart(title, width, height, data, chart_type="line"):
    xAxis = CategoryAxis()
    yAxis = NumberAxis()
    if   chart_type == "area": chart = AreaChart(xAxis,yAxis)
    elif chart_type == "line": chart = LineChart(xAxis,yAxis)
    elif chart_type == "stackedbar": chart = StackedBarChart(xAxis,yAxis)
    elif chart_type == "bar": chart = BarChart(xAxis,yAxis)
    elif chart_type == "scatter": chart = ScatterChart(xAxis,yAxis)
    elif chart_type == "hbar": 
        chart = BarChart(yAxis,xAxis)
        xAxis.setTickLabelRotation(90)
    else: return None
    xAxis.setLabel("Number of Month")
    xAxis.setAnimated(False)
    xAxis.setTickLabelsVisible(True)
    yAxis.setLabel("Values")
    yAxis.setAnimated(False)
    yAxis.setTickLabelsVisible(True)
    chart.setTitle(title)
    #chart.getData().addAll(data.toArray(XYChart.Series[data.size()]))
    chart.getData().addAll(data)
    scene = Scene(chart, width, height);
    return scene.snapshot(None)
    
def LineChartHandler():        
    return getXyChart("Annunal Trend",640,480,getXyChartData(),chart_type="line")

def AreaChartHandler():        
    return getXyChart("Annunal Trend",640,480,getXyChartData(),chart_type="area")

def BarChartHandler():        
    return getXyChart("Annunal Trend",640,480,getXyChartData(),chart_type="bar")

def HBarChartHandler():        
    return getXyChart("Annunal Trend",640,480,getXyChartDataH(),chart_type="hbar")

def StackedBarChartHandler():        
    return getXyChart("Annunal Trend",640,480,getXyChartData(),chart_type="stackedbar")

def ScatterChartHandler():        
    return getXyChart("Annunal Trend",640,480,getXyChartData(),chart_type="scatter")

if __name__ == "__main__":
    fx = FxMain()
    #fx.set_handler(PieChartHandler); fx.set_outfile(r"D:\pie.png")
    #fx.set_handler(LineChartHandler); fx.set_outfile(r"D:\line.png")
    #fx.set_handler(AreaChartHandler); fx.set_outfile(r"D:\area.png")
    #fx.set_handler(BarChartHandler); fx.set_outfile(r"D:\bar.png")
    #fx.set_handler(HBarChartHandler); fx.set_outfile(r"D:\hbar.png")
    #fx.set_handler(StackedBarChartHandler); fx.set_outfile(r"D:\stackedbar.png")
    fx.set_handler(ScatterChartHandler); fx.set_outfile(r"D:\scatter.png")
    
    fx.run()
    
    

[Jython] Compile py to java class

Compile py to java class

def compile_dir(directory):
	import compileall
	compileall.compile_dir(directory, force=True)

def compile_file(file):
    import py_compile
    py_compile.compile(file)

if __name__ == "__main__":
    import sys
    import os
    if len(sys.argv) < 2:
        print("Usage: compile.py <file|dir>")
    if os.path.isdir(sys.argv[1]):
        compile_dir(sys.argv[1])
    else:
        compile_file(sys.argv[1])

2021년 2월 25일 목요일

[Jython] JavaFx Icon Library

 JavaFx Icon Library

import base64
from javafx.embed.swing import SwingFXUtils
from java.io import *
from java.lang import *
from java.awt.image import *
from javax.imageio import *

exit_png  = "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"
clock_png = "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"

def FileToBase64(filename):
    bi      = ImageIO.read(File(filename)) # -> BufferedImage
    baos    = ByteArrayOutputStream()
    ImageIO.write(bi, "png", baos)
    image   = baos.toByteArray()
    image64 = base64.b64encode(image)
    print(image64)
       
def Base64ToFile(image64): 
    image_b = base64.b64decode(image64)
    image_o = ImageIO.read(ByteArrayInputStream(image_b))
    ImageIO.write(image_o, "png", File(filename+".png"))

def Base64ToImage(image64):
    image_b = base64.b64decode(image64)
    return ImageIO.read(ByteArrayInputStream(image_b))

def GetExitImage(): 
    image = Base64ToImage(clock_png)
    return SwingFXUtils.toFXImage(image,None)