1
1
Fork 0

Compare commits

..

17 Commits

Author SHA1 Message Date
KenwoodFox 5be67afa54 Add paths 2026-01-06 16:36:35 -05:00
KenwoodFox 3970f9bca7 Add paths 2026-01-06 16:35:34 -05:00
KenwoodFox f46000649c Tada 2025-10-14 17:44:51 -04:00
Kenwood 9c819d6325 Bump ssh 2025-05-25 14:01:00 -04:00
Kenwood a23e71ab5a Just include some new things 2025-05-25 14:00:50 -04:00
Kenwood ce836a568c Bump a few things 2024-09-30 13:32:02 -04:00
Kenwood 23d7c0d52f Bump a few things 2024-04-23 12:19:03 -04:00
Kenwood 129f8ab159 Add new DNS entry for ssh.kitsunehosting.net 2024-01-02 15:22:14 -05:00
Kenwood 4471fe0bb9 Bump some leftovers 2023-12-22 13:00:39 -05:00
Kenwood 8d699bccd6 Add tools from https://wiki.freecad.org/WebTools_Git 2023-09-29 14:19:08 -04:00
Kenwood a99ca6431e Bump 2023-08-20 13:29:06 -04:00
Kenwood d5fd5b8c38 Add new tools 2023-06-05 09:54:33 -04:00
Kenwood 979d769bfb update bosch 2023-06-04 16:38:15 -04:00
Kenwood 08ece46452 copy in default freecad toolbits 2023-06-04 16:38:05 -04:00
Kenwood 4c78b77e60 update gitconfig 2023-05-17 16:19:24 -04:00
Kenwood d3b21fb2f1 Add new ssh hosts 2023-05-14 20:58:10 -04:00
Kenwood ce12e90225 Add discompress 2023-04-18 00:29:59 -04:00
25 changed files with 1000 additions and 37 deletions

View File

@ -0,0 +1,14 @@
{
"version": 2,
"name": "1/8th Drill Bit",
"shape": "drill.fcstd",
"parameter": {
"Chipload": "0.000 in",
"Diameter": "0.125 in",
"Flutes": "0",
"Length": "0.750 in",
"Material": "HSS",
"TipAngle": "135.000 \u00b0"
},
"attribute": {}
}

View File

@ -0,0 +1,16 @@
{
"version": 2,
"name": "3/16 Endmill",
"shape": "endmill.fcstd",
"parameter": {
"Chipload": "0.000 in",
"CuttingEdgeHeight": "0.600 \"",
"Diameter": "0.187 \"",
"Flutes": "0",
"Length": "1.500 \"",
"Material": "HSS",
"ShankDiameter": "0.315 \"",
"SpindleDirection": "Forward"
},
"attribute": {}
}

View File

@ -0,0 +1,14 @@
{
"version": 2,
"name": "45 Deg. Chamfer",
"shape": "chamfer.fcstd",
"parameter": {
"CuttingEdgeAngle": "45.0000 \u00b0",
"CuttingEdgeHeight": "6.3500 mm",
"Diameter": "12.3323 mm",
"Length": "30.0000 mm",
"ShankDiameter": "6.3500 mm",
"TipDiameter": "5.0000 mm"
},
"attribute": {}
}

View File

@ -0,0 +1,14 @@
{
"version": 2,
"name": "5mm-thread-cutter",
"shape": "thread-mill.fcstd",
"parameter": {
"Crest": "0.10 mm",
"Diameter": "5.00 mm",
"Length": "50.00 mm",
"NeckDiameter": "3.00 mm",
"NeckLength": "20.00 mm",
"ShankDiameter": "5.00 mm"
},
"attribute": {}
}

View File

@ -0,0 +1,11 @@
{
"version": 2,
"name": "5mm Drill",
"shape": "drill.fcstd",
"parameter": {
"Diameter": "5.0000 mm",
"Length": "50.0000 mm",
"TipAngle": "119.0000 \u00b0"
},
"attribute": {}
}

View File

@ -0,0 +1,12 @@
{
"version": 2,
"name": "5mm Endmill",
"shape": "endmill.fcstd",
"parameter": {
"CuttingEdgeHeight": "30.0000 mm",
"Diameter": "5.0000 mm",
"Length": "50.0000 mm",
"ShankDiameter": "3.0000 mm"
},
"attribute": {}
}

View File

@ -0,0 +1,14 @@
{
"version": 2,
"name": "60 Deg. V-Bit",
"shape": "v-bit.fcstd",
"parameter": {
"CuttingEdgeAngle": "60.0000 \u00b0",
"Diameter": "10.0000 mm",
"CuttingEdgeHeight": "1.0000 mm",
"TipDiameter": "1.0000 mm",
"Length": "20.0000 mm",
"ShankDiameter": "5.0000 mm"
},
"attribute": {}
}

View File

@ -0,0 +1,12 @@
{
"version": 2,
"name": "6mm Ball End",
"shape": "ballend.fcstd",
"parameter": {
"CuttingEdgeHeight": "40.0000 mm",
"Diameter": "6.0000 mm",
"Length": "50.0000 mm",
"ShankDiameter": "3.0000 mm"
},
"attribute": {}
}

View File

@ -0,0 +1,13 @@
{
"version": 2,
"name": "6 mm Bull Nose",
"shape": "bullnose.fcstd",
"parameter": {
"CuttingEdgeHeight": "40.0000 mm",
"Diameter": "6.0000 mm",
"FlatRadius": "1.5000 mm",
"Length": "50.0000 mm",
"ShankDiameter": "3.0000 mm"
},
"attribute": {}
}

View File

@ -0,0 +1,11 @@
{
"version": 2,
"name": "Probe",
"shape": "probe.fcstd",
"parameter": {
"Diameter": "6.0000 mm",
"Length": "50.0000 mm",
"ShaftDiameter": "4.0000 mm"
},
"attribute": {}
}

View File

@ -0,0 +1,16 @@
{
"version": 2,
"name": "Single Flute 1/8th inch endmill",
"shape": "endmill.fcstd",
"parameter": {
"Chipload": "0.000 in",
"CuttingEdgeHeight": "0.600 \"",
"Diameter": "0.125 \"",
"Flutes": "0",
"Length": "1.000 \"",
"Material": "HSS",
"ShankDiameter": "0.315 \"",
"SpindleDirection": "Forward"
},
"attribute": {}
}

View File

@ -0,0 +1,14 @@
{
"version": 2,
"name": "Slitting Saw",
"shape": "slittingsaw.fcstd",
"parameter": {
"BladeThickness": "3.0000 mm",
"CapHeight": "3.0000 mm",
"CapDiameter": "8.0000 mm",
"Diameter": "76.2000 mm",
"Length": "50.0000 mm",
"ShankDiameter": "19.0500 mm"
},
"attribute": {}
}

View File

@ -0,0 +1,41 @@
{
"tools": [
{
"nr": 1,
"path": "5mm_Endmill.fctb"
},
{
"nr": 2,
"path": "5mm_Drill.fctb"
},
{
"nr": 3,
"path": "6mm_Ball_End.fctb"
},
{
"nr": 4,
"path": "6mm_Bullnose.fctb"
},
{
"nr": 5,
"path": "60degree_Vbit.fctb"
},
{
"nr": 6,
"path": "45degree_chamfer.fctb"
},
{
"nr": 7,
"path": "slittingsaw.fctb"
},
{
"nr": 8,
"path": "probe.fctb"
},
{
"nr": 9,
"path": "5mm-thread-cutter.fctb"
}
],
"version": 1
}

View File

@ -0,0 +1,13 @@
{
"tools": [
{
"nr": 1,
"path": "125_Drill.fctb"
},
{
"nr": 2,
"path": "singleFlute8th_Endmill.fctb"
}
],
"version": 1
}

View File

@ -0,0 +1,88 @@
# Tools
Each tool is stored as a JSON file which has the shape's path and values for all attributes of the shape.
It also includes all additional parameters and their values.
Storing a tool as a JSON file sounds great but eliminates the option of an accurate thumbnail. On the other hand,
storing each tool as a `*.fcstd` file requires more space and does not allow for generating tools. If one has an
extensive tool aresenal they might want to script the generation of tools which is easily done for a `*.json` file but
practically impossible for `*.fcstd` files.
When a tool is instantiated in a job the PDN body is created from the shape and the attributes and constraints are set
according to the values from the JSON file. All additional parameters are created as properties on the object. This
provides the correct shape and dimensions which can be used to generate a point cloud or mesh for advanced
algorithms (and potentially simulation).
# Tool Libraries
Due to each tool being stored in its own file and the storage/organization of those files being quite flexible the
importance of a tool library for organisational purposes is quite diminished. The user is free to organise their tools
in whichever directory hierarchy they see fit and can also name them as best fits their use and organisation. A
_tool library_ is nevertheless a great representation for a physical grouping of tools, such as in an automatic tool
changer.
A tool library is a (JSON) file with a mapping of tool id to the path of the tool file. As a consequence each tool
can be in multiple libraries and doesn't have an `id` of it's own. The `id` is a property of the library.
If a tool from a tool library (or an entire tool library) is added to a job it retains its `id` from the library as a
property. Adding a tool bit directly rsults in the tool getting the next free id assigned.
# Tool Controllers
They largely stay the same as they are today. As an additional feature it should be possible to _copy_ a TC, which
allows for easy feed/speed changes for the same tool.
Above requirement highlights one change though, that the `id` should be a property of the Bit, and not of the TC.
There are two requirements that are currently mapped to a single `id`. There needs to be an identification of which
TC is being used by a certain op, and which tool number to use for a `M6` command.
# Paths and Extensibility
The following directory structure is used for supplied (shipped with FreeCAD) tools:
```
Tools
+ Bit
+ Library
+ Shape
```
Strictly speaking a user is free to store their tools wherever they want and however they want. By default the file
dialog will open the corresponding directory (depending on context), or whichever directory the user opened last.
Above directory structure with the most common default tools shipped with FreeCAD should be installed analogous to
TechDraw's templates.
## How to create a new tool
1. Set the tool's Label, this will show up in the object tree
1. Select a tool shape from the existing shape files. If your tool doesn't exist, you'll have to create a new shape,
see below for details.
1. Each tool bit shape has its own set of parameters, fill them with the tool's values.
1. Select additional parameters
1. Save the tool under path/file that makes sense to you
## How to create a new tool bit Shape
The shape file for a tool bit is expected to contain a PD body which represents the tool as a 3d solid. The PD body
should be parametric based on a PropertyBag object so that, when the properties of the PropertyBag are changed the
solid is updated to the correct representation.
1. Create a new FreeCAD document
1. Open the `PartDesign` workbench, create a body and give the body a label you want to show up in the bit selection.
1. Open the Path workbench and (with the PD body selected) create a PropertyBag,
menu 'Path' -> 'Utils' -> 'Property Bag'
* this creates a PropertyBag object inside the Body (assuming it was selected)
* add properties to which define the tool bit's shape and put those into the group 'Shape'
* add any other properties to the bag which might be useful for the tool bit
1. Construct the body of the tool bit and assign expressions referencing properties from the PropertyBag (in the
`Shape` Group) for all constraints.
* Position the tip of the tool bit on the origin (0,0)
1. Save the document as a new file in the Shape directory
* Before saving the document make sure you have _Save Thumbnail_ selected, and _Add program logo_ deselected in
FreeCAD's preferences.
* Also make sure to switch to _Front View_ and _Fit content to screen_
* Whatever you see when saving the document will end up being the visual representation of tool bits with this shape
Not that 'Shape' is the only property group which has special meaning for tool bits. All other property groups are
copied verbatim to the ToolBit object when one is created.

28
.config/nvim/init.vim Normal file
View File

@ -0,0 +1,28 @@
set number
syntax on
set expandtab shiftwidth=4 tabstop=4
set autoindent
set clipboard=unnamedplus
" I want nvim using a venv for plugins and stuff
let g:python3_host_prog = expand('~/.venvs/nvim/bin/python')
" Plugins with vim-plug
call plug#begin('~/.vim/plugged')
Plug 'psf/black', { 'do': ':!pip install black' }
Plug 'dense-analysis/ale' " For linting and format-on-save
Plug 'vim-python/python-syntax' " Improved Python syntax highlighting
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } " Fuzzy finder
Plug 'junegunn/fzf.vim'
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'} " Better syntax
call plug#end()
" Enable ALE for linting and formatting
let g:ale_fix_on_save = 1
let g:ale_linters = { 'python': ['flake8'] }
let g:ale_fixers = { 'python': ['black'] }
" Keybindings
nnoremap <leader>f :Files<CR> " Fuzzy file search

View File

@ -0,0 +1,2 @@
# LaTeX Import path
export TEXINPUTS=/home/joe/College/SNHU/LaTeX:$(kpsepath tex | tr ':' '\n' | head -n 1):

View File

@ -1,24 +0,0 @@
[/home/joe/.local/share/plasma-vault/Blackmail.enc]
activities=
backend=cryfs
lastError=Unknown device (code: 1)
lastStatus=2
mountPoint=/home/joe/Vaults/Blackmail
name=Blackmail
offlineOnly=false
[/home/joe/.local/share/plasma-vault/NSFW.enc]
activities=
backend=cryfs
lastError=Cannot create the mount point (code: 0)
lastStatus=1
mountPoint=/home/joe/Vaults/NSFW
name=NSFW
offlineOnly=false
[EncryptedDevices]
/home/joe/.local/share/plasma-vault/Blackmail.enc=true
/home/joe/.local/share/plasma-vault/NSFW.enc=true
[UI-notice]
SkipNotice-cryfs-message=false

View File

@ -1,5 +1,5 @@
[user] [user]
email = kenwood364@gmail.com email = joe@kitsunehosting.net
name = KenwoodFox name = KenwoodFox
signingkey = DD5E787D6C678F3F64 signingkey = DD5E787D6C678F3F64
[alias] [alias]
@ -23,3 +23,14 @@
autosetuprebase = always autosetuprebase = always
[safe] [safe]
directory = /opt/flutter directory = /opt/flutter
[protocol "file"]
allow = always
[filter "lfs"]
required = true
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
[diff "fcinfo"]
textconv = ~/.local/bin/fcinfo
[core]
hooksPath = /home/joe/.githooks

44
.githooks/pre-commit Executable file
View File

@ -0,0 +1,44 @@
#!/bin/sh
# Global pre-commit hook: print effective identity and ask to continue.
# Set BYPASS_COMMIT_IDENTITY_CHECK=1 to skip (e.g., in CI).
[ -n "$BYPASS_COMMIT_IDENTITY_CHECK" ] && exit 0
# Resolve effective identity (prefer repo-local config, fall back to global)
name="$(git config --get user.name)"
[ -z "$name" ] && name="$(git config --global --get user.name)"
email="$(git config --get user.email)"
[ -z "$email" ] && email="$(git config --global --get user.email)"
branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo '?')"
remote="$(git remote -v | awk '/\(push\)/{print $2; exit}' | sed 's#^https\?://##; s#git@##' )"
# Optional: block specific identities unless overridden
# Add your alt(s) here, comma-separated (exact match on email or name).
BLOCKED_EMAILS="${BLOCKED_EMAILS:-alt@example.com}"
BLOCKED_NAMES="${BLOCKED_NAMES:-Alt Name}"
is_blocked() {
needle="$1" haystack="$2"
printf '%s' "$haystack" | tr ',' '\n' | grep -Fxq "$needle"
}
printf '\n\033[1;33m⚠ Committing as:\033[0m \033[1m%s\033[0m <\033[1m%s\033[0m>\n' "$name" "$email"
[ -n "$branch" ] && printf ' Branch: %s\n' "$branch"
[ -n "$remote" ] && printf ' Remote: %s\n' "$remote"
printf ' Double-check this is the right account.\n\n'
if is_blocked "$email" "$BLOCKED_EMAILS" || is_blocked "$name" "$BLOCKED_NAMES"; then
printf '\033[1;31mBlocked identity detected.\033[0m Set BYPASS_COMMIT_IDENTITY_CHECK=1 to override just this commit.\n'
exit 1
fi
# Interactive confirm (skip if no TTY, e.g., merge drivers)
if [ -t 0 ]; then
printf 'Continue with commit? [y/N] '
read ans
case "$ans" in
y|Y) ;;
*) echo "Commit aborted."; exit 1 ;;
esac
fi

82
.local/bin/discompress Executable file
View File

@ -0,0 +1,82 @@
#!/bin/bash
#
# Re-encode a video to a target size in MB.
# Example:
# ./this_script.sh video.mp4 15
T_SIZE="$2" # target size in MB
T_FILE="${1%.*}-$2MB.mp4" # filename out
# Original duration in seconds
O_DUR=$(\
ffprobe \
-v error \
-show_entries format=duration \
-of csv=p=0 "$1")
# Original audio rate
O_ARATE=$(\
ffprobe \
-v error \
-select_streams a:0 \
-show_entries stream=bit_rate \
-of csv=p=0 "$1")
# Original audio rate in KiB/s
O_ARATE=$(\
awk \
-v arate="$O_ARATE" \
'BEGIN { printf "%.0f", (arate / 1024) }')
# Target size is required to be less than the size of the original audio stream
T_MINSIZE=$(\
awk \
-v arate="$O_ARATE" \
-v duration="$O_DUR" \
'BEGIN { printf "%.2f", ( (arate * duration) / 8192 ) }')
# Equals 1 if target size is ok, 0 otherwise
IS_MINSIZE=$(\
awk \
-v size="$T_SIZE" \
-v minsize="$T_MINSIZE" \
'BEGIN { print (minsize < size) }')
# Give useful information if size is too small
if [[ $IS_MINSIZE -eq 0 ]]; then
printf "%s\n" "Target size ${T_SIZE}MB is too small!" >&2
printf "%s %s\n" "Try values larger than" "${T_MINSIZE}MB" >&2
exit 1
fi
# Set target audio bitrate
T_ARATE=$O_ARATE
# Calculate target video rate - MB -> KiB/s
T_VRATE=$(\
awk \
-v size="$T_SIZE" \
-v duration="$O_DUR" \
-v audio_rate="$O_ARATE" \
'BEGIN { print ( ( size * 8192.0 ) / ( 1.048576 * duration ) - audio_rate) }')
# Perform the conversion
ffmpeg \
-y \
-i "$1" \
-c:v libx264 \
-b:v "$T_VRATE"k \
-pass 1 \
-an \
-f mp4 \
/dev/null \
&& \
ffmpeg \
-i "$1" \
-c:v libx264 \
-b:v "$T_VRATE"k \
-pass 2 \
-c:a aac \
-b:a "$T_ARATE"k \
$T_FILE

293
.local/bin/fcinfo Executable file
View File

@ -0,0 +1,293 @@
#!/usr/bin/python3
# -*- coding: utf8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2015 Yorik van Havre <yorik@uncreated.net> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
__title__ = "FreeCAD File info utility"
__author__ = "Yorik van Havre"
__url__ = ["http://www.freecad.org"]
__doc__ = """
This utility prints information about a given FreeCAD file (*.FCStd)
on screen, including document properties, number of included objects,
object sizes and properties and values. Its main use is to compare
two files and be able to see the differences in a text-based form.
If no option is used, fcinfo prints the document properties and a list
of properties of each object found in the given file.
Usage:
fcinfo [options] myfile.FCStd
Options:
-h, --help: Prints this help text
-s, --short: Do not print object properties. Only one line
per object is printed, including its size and SHA1.
This is sufficient to see that an object has
changed, but not what exactly has changed.
-vs --veryshort: Only prints the document info, not objects info.
This is sufficient to see if a file has changed, as
its SHA1 code and timestamp will show it. But won't
show details of what has changed.
-g --gui: Adds visual properties too (if not using -s or -vs)
Git usage:
This script can be used as a textconv tool for git diff by
configuring your git folder as follows:
1) add to .gitattributes (or ~/.gitattributes for user-wide):
*.fcstd diff=fcinfo
2) add to .git/config (or ~/.gitconfig for user-wide):
[diff "fcinfo"]
textconv = /path/to/fcinfo
With this, when committing a .FCStd file with Git,
'git diff' will show you the difference between the two
texts obtained by fcinfo
"""
import sys
import zipfile
import xml.sax
import os
import hashlib
import re
class FreeCADFileHandler(xml.sax.ContentHandler):
def __init__(self, zfile, short=0): # short: 0=normal, 1=short, 2=veryshort
xml.sax.ContentHandler.__init__(self)
self.zfile = zfile
self.obj = None
self.prop = None
self.count = "0"
self.contents = {}
self.short = short
def startElement(self, tag, attributes):
if tag == "Document":
self.obj = tag
self.contents = {}
self.contents["ProgramVersion"] = attributes["ProgramVersion"]
self.contents["FileVersion"] = attributes["FileVersion"]
elif tag == "Object":
if "name" in attributes:
name = self.clean(attributes["name"])
self.obj = name
if "type" in attributes:
self.contents[name] = attributes["type"]
elif tag == "ViewProvider":
if "name" in attributes:
self.obj = self.clean(attributes["name"])
elif tag == "Part":
if self.obj:
r = self.zfile.read(attributes["file"])
s = r.__sizeof__()
if s < 1024:
s = str(s) + "B"
elif s > 1048576:
s = str(s / 1048576) + "M"
else:
s = str(s / 1024) + "K"
s += " " + str(hashlib.sha1(r).hexdigest()[:12])
self.contents[self.obj] += " (" + s + ")"
elif tag == "Property":
self.prop = None
# skip "internal" properties, useless for a diff
if attributes["name"] not in [
"Symbol",
"AttacherType",
"MapMode",
"MapPathParameter",
"MapReversed",
"AttachmentOffset",
"SelectionStyle",
"TightGrid",
"GridSize",
"GridSnap",
"GridStyle",
"Lighting",
"Deviation",
"AngularDeflection",
"BoundingBox",
"Selectable",
"ShowGrid",
]:
self.prop = attributes["name"]
elif tag in ["String", "Uuid", "Float", "Integer", "Bool", "Link"]:
if self.prop and ("value" in attributes):
if self.obj == "Document":
self.contents[self.prop] = attributes["value"]
elif self.short == 0:
if tag == "Float":
self.contents[self.obj + "00000000::" + self.prop] = str(
float(attributes["value"])
)
else:
self.contents[self.obj + "00000000::" + self.prop] = attributes["value"]
elif tag in ["PropertyVector"]:
if self.prop and self.obj and (self.short == 0):
val = (
"("
+ str(float(attributes["valueX"]))
+ ","
+ str(float(attributes["valueY"]))
+ ","
+ str(float(attributes["valueZ"]))
+ ")"
)
self.contents[self.obj + "00000000::" + self.prop] = val
elif tag in ["PropertyPlacement"]:
if self.prop and self.obj and (self.short == 0):
val = (
"("
+ str(float(attributes["Px"]))
+ ","
+ str(float(attributes["Py"]))
+ ","
+ str(float(attributes["Pz"]))
+ ")"
)
val += (
" ("
+ str(round(float(attributes["Q0"]), 4))
+ ","
+ str(round(float(attributes["Q1"]), 4))
+ ","
)
val += (
str(round(float(attributes["Q2"]), 4))
+ ","
+ str(round(float(attributes["Q3"]), 4))
+ ")"
)
self.contents[self.obj + "00000000::" + self.prop] = val
elif tag in ["PropertyColor"]:
if self.prop and self.obj and (self.short == 0):
c = int(attributes["value"])
r = float((c >> 24) & 0xFF) / 255.0
g = float((c >> 16) & 0xFF) / 255.0
b = float((c >> 8) & 0xFF) / 255.0
val = str((r, g, b))
self.contents[self.obj + "00000000::" + self.prop] = val
elif tag == "Objects":
self.count = attributes["Count"]
self.obj = None
# Print all the contents of the document properties
items = self.contents.items()
items = sorted(items)
for key, value in items:
key = self.clean(key)
value = self.clean(value)
print(" " + key + " : " + value)
print(" Objects: (" + self.count + ")")
self.contents = {}
def endElement(self, tag):
if (tag == "Document") and (self.short != 2):
items = self.contents.items()
items = sorted(items)
for key, value in items:
key = self.clean(key)
if "00000000::" in key:
key = " " + key.split("00000000::")[1]
value = self.clean(value)
if value:
print(" " + key + " : " + value)
def clean(self, value):
value = value.strip()
return value
if __name__ == "__main__":
if len(sys.argv) < 2:
print(__doc__)
sys.exit()
if ("-h" in sys.argv[1:]) or ("--help" in sys.argv[1:]):
print(__doc__)
sys.exit()
ext = sys.argv[-1].rsplit(".")[-1].lower()
if not ext.startswith("fcstd") and not ext.startswith("fcbak"):
print(__doc__)
sys.exit()
if ("-vs" in sys.argv[1:]) or ("--veryshort" in sys.argv[1:]):
short = 2
elif ("-s" in sys.argv[1:]) or ("--short" in sys.argv[1:]):
short = 1
else:
short = 0
if ("-g" in sys.argv[1:]) or ("--gui" in sys.argv[1:]):
gui = True
else:
gui = False
zfile = zipfile.ZipFile(sys.argv[-1])
if not "Document.xml" in zfile.namelist():
sys.exit(1)
doc = zfile.read("Document.xml")
if gui and "GuiDocument.xml" in zfile.namelist():
guidoc = zfile.read("GuiDocument.xml")
guidoc = re.sub(b"<\?xml.*?-->", b" ", guidoc, flags=re.MULTILINE | re.DOTALL)
# a valid xml doc can have only one root element. So we need to insert
# all the contents of the GUiDocument <document> tag into the main one
doc = re.sub(b"<\/Document>", b"", doc, flags=re.MULTILINE | re.DOTALL)
guidoc = re.sub(b"<Document.*?>", b" ", guidoc, flags=re.MULTILINE | re.DOTALL)
doc += guidoc
s = os.path.getsize(sys.argv[-1])
if s < 1024:
s = str(s) + "B"
elif s > 1048576:
s = str(s / 1048576) + "M"
else:
s = str(s / 1024) + "K"
print("Document: " + sys.argv[-1] + " (" + s + ")")
print(" SHA1: " + str(hashlib.sha1(open(sys.argv[-1], "rb").read()).hexdigest()))
xml.sax.parseString(doc, FreeCADFileHandler(zfile, short))

100
.local/bin/qalctex Executable file
View File

@ -0,0 +1,100 @@
#!/bin/python
import subprocess
import re
# Dictionary for symbol conversion to LaTeX format
latex_symbols = {
"Ω": r"\Omega",
"ohm": r"\Omega",
"A": r"\text{A}",
"V": r"\text{V}",
"milliamperes": r"\text{mA}",
"*": r"\cdot",
"N*m": r"\text{N} \cdot \text{m}",
"in*lb": r"\text{in} \cdot \text{lb}",
"||": r"\|",
"": r"-",
"μ": r"\mu",
"": r"-",
}
def run_qalc(expression):
# Run qalc with the provided expression
result = subprocess.run(["qalc", expression], stdout=subprocess.PIPE, text=True)
output = result.stdout
return output
def format_expression_for_latex(expression):
# Replace the units and special characters in the input expression using the dictionary
for symbol, latex_symbol in latex_symbols.items():
expression = expression.replace(symbol, latex_symbol)
return expression
def format_result_for_latex(output):
# Get the last line of qalc output (the answer)
output = output.strip().split("\n")[-1]
# Check if the result is approximate (contains "≈")
approx_match = "≈" in output
# Extract the value and unit from the result
match = re.search(r"(≈|=)\s*([-\d\.]+)\s*(.*)", output)
if match:
_, value, unit = match.groups()
# Replace the units and special characters using the dictionary
unit = unit.strip()
for symbol, latex_symbol in latex_symbols.items():
unit = unit.replace(symbol, latex_symbol)
# Use = or \approx in LaTeX based on whether the result is approximate
equal_symbol = r"\approx" if approx_match else "="
# Only add \, if there's a unit
if unit:
latex_result = f"{equal_symbol} {value.strip()} \\, {unit}"
else:
latex_result = f"{equal_symbol} {value.strip()}"
return latex_result
return output # Fallback to returning the raw qalc output if no match
def copy_to_clipboard(text):
# Use wl-copy to send the text to the clipboard
subprocess.run(["wl-copy"], input=text, text=True)
def main():
try:
while True:
# Input the qalc expression
expression = input("\nEnter qalc expression (Ctrl+C to exit): ")
# Run qalc and get the result
qalc_output = run_qalc(expression)
# Format the input expression for LaTeX
latex_expression = format_expression_for_latex(expression)
# Format the output result for LaTeX
latex_result = format_result_for_latex(qalc_output)
# Combine both input expression and result for final LaTeX output
final_latex_output = f"{latex_expression} {latex_result}"
# Print and copy to clipboard
print(f"Final LaTeX output:\n{final_latex_output}")
copy_to_clipboard(final_latex_output)
print("LaTeX result copied to clipboard!")
except KeyboardInterrupt:
print("\nExiting...")
if __name__ == "__main__":
main()

View File

@ -8,12 +8,34 @@ Host crawler.kitsunehosting.net
HostName crawler.kitsunehosting.net HostName crawler.kitsunehosting.net
User joe User joe
Host 10.12.33.234 host edge
HostName 10.12.33.234 HostName 10.85.5.52
User will User joe
Host 10.85.3.39 host portainer
HostName 10.85.3.39 HostName 10.85.3.60
User joe
host bitwarden
HostName 10.85.3.83
User joe
host frigate
IdentityFile ~/.ssh/hydroxonium
HostName 10.85.5.20
User joe
host portainer
IdentityFile ~/.ssh/hydroxonium
HostName 10.85.3.60
User joe
host crackheadbot
HostName 10.85.3.182
User joe
host dockerhost
HostName 10.85.3.75
User joe User joe
Host cobalt Host cobalt
@ -26,7 +48,7 @@ Host manganese
User root User root
# R710 # R710
Host magnesium Host nickel
HostName 10.85.3.4 HostName 10.85.3.4
User root User root
@ -37,24 +59,42 @@ Host romi
# My main NAS # My main NAS
Host zinc Host zinc
IdentityFile ~/.ssh/hydroxonium
HostName 10.85.3.120 HostName 10.85.3.120
User joe User joe
# APRS # APRS
Host houston Host houston
IdentityFile ~/.ssh/hydroxonium
HostName 10.85.3.39 HostName 10.85.3.39
User joe User joe
# Steamcache Host deck
Host steamcache HostName 10.85.3.221
HostName 10.85.3.60 User deck
# booru Image Server
Host booru
IdentityFile ~/.ssh/hydroxonium
HostName 10.85.3.71
User joe User joe
# Caddy
Host caddy
IdentityFile ~/.ssh/hydroxonium
HostName 10.85.3.9
User joe
# Robotics # Robotics
# 1721's main NAS # 1721's main NAS
Host flattoaster Host flattoaster
HostName 10.17.21.10 HostName 10.17.21.10
PreferredAuthentications password
IdentityFile none
User root
Host robotics-vps
HostName 50.116.52.250
User root User root
Host lapis Host lapis
@ -74,14 +114,29 @@ Host aur.archlinux.org
User aur User aur
# Personal Git Server # Personal Git Server
Host kitsunehosting.net Host ssh.kitsunehosting.net
Port 2222 Port 2222
IdentityFile ~/.ssh/gitea IdentityFile ~/.ssh/gitea
# Github # Github
Host github.com Host github.com
Hostname ssh.github.com
Port 443
User git
IdentityFile ~/.ssh/github IdentityFile ~/.ssh/github
Host snowsunehost
Hostname 10.85.3.65
User joe
# Also github but, for snowsune
Host github_snowsune
HostName ssh.github.com
User git
Port 443
IdentityFile ~/.ssh/github_snowsune
IdentitiesOnly yes
# Bitbucket # Bitbucket
Host bitbucket.org Host bitbucket.org
IdentityFile ~/.ssh/bitbucket IdentityFile ~/.ssh/bitbucket
@ -91,13 +146,45 @@ Host devserver
HostName 10.12.32.35 HostName 10.12.32.35
User joe User joe
Host bosch
HostName 192.168.0.41
#IdentityFile ~/.ssh/silvertech/ssh_host_dsa_key
#UpdateHostKeys no
Host retropie
HostName 10.19.80.2
User pi
IdentityFile ~/.ssh/silvertech/silvertech
IdentitiesOnly yes
# The little docker host in the closet # The little docker host in the closet
# Runs the vestabot image # Runs the vestabot image
Host stdocker1 Host stdocker1
HostName 10.20.30.225 HostName 10.20.30.225
IdentityFile ~/.ssh/stdocker IdentityFile ~/.ssh/stdocker
# Little mini-pc in the IOT room
Host pioremote
# This is actually a zerotier ip
HostName 10.144.0.15
IdentityFile ~/.ssh/silvertech/silvertech
IdentitiesOnly yes
# Work laptop
Host workLaptop
HostName 10.144.236.234
IdentityFile ~/.ssh/hydroxonium
# Argen pi # Argen pi
Host argen Host argen
HostName 10.20.30.224 HostName 10.20.30.224
Host asterisk
HostName 10.85.3.155
IdentityFile ~/.ssh/hydroxonium
# Pterodactyal stuff
Host wing1.kitsunehosting.net
HostName wing1.kitsunehosting.net
PreferredAuthentications password
IdentityFile none

39
.zshrc
View File

@ -1,12 +1,19 @@
# Joe added this: # Joe added this:
uwufetch uwufetch
echo "" echo ""
fortune fortune -a
# Add my bins to path # Add my bins to path
path+=("$HOME/.local/bin") path+=("$HOME/.local/bin")
path+=("$HOME/Pictures/Furry/Scripts")
export PATH export PATH
# LaTeX Import path
export TEXINPUTS=/home/joe/College/SNHU/LaTeX:$(kpsepath tex | tr ':' '\n' | head -n 1):
# Not sure why but, needed to path these manually for ruby bin
path+=("/home/joe/.local/share/gem/ruby/3.3.0/bin")
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc. # Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
@ -123,6 +130,13 @@ fi
# alias zshconfig="mate ~/.zshrc" # alias zshconfig="mate ~/.zshrc"
# alias ohmyzsh="mate ~/.oh-my-zsh" # alias ohmyzsh="mate ~/.oh-my-zsh"
# https://www.reddit.com/r/archlinux/comments/p0y2hs/flatpak/
alias update="paru -Syu --skipreview; flatpak update; sudo snap refresh"
# Power
alias upshift="powerprofilesctl set performance"
alias downshift="powerprofilesctl set power-saver"
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
export FZF_DEFAULT_COMMAND='fdfind --type f' export FZF_DEFAULT_COMMAND='fdfind --type f'
@ -130,3 +144,26 @@ export FZF_DEFAULT_OPTS="--layout=reverse --inline-info --height=80%"
# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh. # To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
# This is fo cumtanks lol
cumtanks() {
cd /home/joe/git/Snowsune/cumtanks || return 1
EPOCH=$(date +%s)
DATA_JSON="www/data.json"
tmpfile=$(mktemp)
awk -v epoch="$EPOCH" '
BEGIN { added=0 }
/"logs"[ \t]*:[ \t]*\[/ { inlogs=1 }
inlogs && /\]/ && !added {
sub(/\]/, " ,{ \"date\": " epoch ", \"text\": \"\" }\n ]")
added=1
}
{ print }
' "$DATA_JSON" > "$tmpfile" && mv "$tmpfile" "$DATA_JSON"
sed -i 's/,\n ]/\n ]/' "$DATA_JSON"
code -g "$DATA_JSON":$(grep -n '"logs"' "$DATA_JSON" | cut -d: -f1)
}
# For chat GPT
export OPENAI_API_KEY="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"