master 9136e85d111d cached
31 files
140.8 KB
36.5k tokens
15 symbols
1 requests
Download .txt
Repository: AppHouseKitchen/AlDente-Battery_Care_and_Monitoring
Branch: master
Commit: 9136e85d111d
Files: 31
Total size: 140.8 KB

Directory structure:
gitextract_8seg_0uv/

├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       ├── feature_request.md
│       └── question-about-aldente.md
├── AlDente/
│   ├── AppDelegate.swift
│   ├── Assets.xcassets/
│   │   ├── AppIcon.appiconset/
│   │   │   └── Contents.json
│   │   ├── Contents.json
│   │   └── menubaricon.imageset/
│   │       └── Contents.json
│   ├── Base.lproj/
│   │   └── Main.storyboard
│   ├── ContentView.swift
│   ├── Helper.swift
│   ├── Info.plist
│   ├── PersistanceManager.swift
│   └── Preview Content/
│       └── Preview Assets.xcassets/
│           └── Contents.json
├── AlDente.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   ├── contents.xcworkspacedata
│   │   ├── xcshareddata/
│   │   │   ├── IDEWorkspaceChecks.plist
│   │   │   └── swiftpm/
│   │   │       └── Package.resolved
│   │   └── xcuserdata/
│   │       └── davidwernhart.xcuserdatad/
│   │           └── UserInterfaceState.xcuserstate
│   └── xcuserdata/
│       └── davidwernhart.xcuserdatad/
│           ├── xcdebugger/
│           │   └── Breakpoints_v2.xcbkptlist
│           └── xcschemes/
│               └── xcschememanagement.plist
├── CODE_OF_CONDUCT.md
├── Common/
│   └── HelperToolProtocol.swift
├── LICENSE
├── README.md
├── SECURITY.md
├── SMJobBlessUtil.py
└── com.davidwernhart.Helper/
    ├── Helper-Info.plist
    ├── Helper-Launchd.plist
    ├── HelperTool.swift
    ├── SMC.swift
    └── main.swift

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug Report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---
**MacBook (please complete the following information):**
 - MacBook Model (https://support.apple.com/en-us/HT201608):
 - macOS Version (https://support.apple.com/en-us/HT201260):
 - Charger Model (Apple, Third Party, Wattage,...):
 - Charging Cable (MagSafe 2, MagSafe 3, USB-C, Apple, Third Party,...):
 - AlDente Pro or AlDente Free:
 - AlDente Version:
 - List or add screenshots of all enabled/disabled settings in AlDente:
 - Please share a debug file the next time this happens so that we can assess this issue better. You can find a guide on How to generate and share a debug file on our blog(https://apphousekitchen.com/how-to-generate-and-share-a-debug-file/).
 - External Monitor connected?
 - MacBook used in Clamshell Mode (with the lid closed)?

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected Behavior**
A clear and concise description of what you expected to happen.

**Screenshots and Screen Recordings**
If applicable, add screenshots or screen recordings of the issue to help explain your problem.

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/ISSUE_TEMPLATE/question-about-aldente.md
================================================
---
name: Question about AlDente
about: Use Discussions section for questions
title: ''
labels: ''
assignees: ''

---

Hi, if you have a question about AlDente, please use the Discussions section of Github: https://github.com/davidwernhart/AlDente/discussions


================================================
FILE: AlDente/AppDelegate.swift
================================================
//
//  AppDelegate.swift
//  AlDente
//
//  Created by David Wernhart on 09.02.20.
//  Copyright © 2020 David Wernhart. All rights reserved.
//

import AppKit
import SwiftUI
import LaunchAtLogin
import Foundation
import IOKit.ps
import IOKit.pwr_mgt

extension ProcessInfo {
        /// Returns a `String` representing the machine hardware name or nil if there was an error invoking `uname(_:)` or decoding the response.
        ///
        /// Return value is the equivalent to running `$ uname -m` in shell.
        var machineHardwareName: String? {
                var sysinfo = utsname()
                let result = uname(&sysinfo)
                guard result == EXIT_SUCCESS else { return nil }
                let data = Data(bytes: &sysinfo.machine, count: Int(_SYS_NAMELEN))
                guard let identifier = String(bytes: data, encoding: .ascii) else { return nil }
                return identifier.trimmingCharacters(in: .controlCharacters)
        }
}

@NSApplicationMain
final class AppDelegate: NSObject, NSApplicationDelegate {

    //var window: NSWindow!
    var statusBarItem: NSStatusItem!
    var popover: NSPopover!
    
    func applicationWillTerminate(_ aNotification: Notification) {
        Helper.instance.enableSleep()
        Helper.instance.enableCharging()
    }

    func applicationDidFinishLaunching(_ aNotification: Notification) {

        let contentView = ContentView()

        // Create the popover
        let popover = NSPopover()
        popover.contentSize = NSSize(width: 400, height: 600)
        popover.behavior = .transient
        popover.contentViewController = NSHostingController(rootView: contentView)
        self.popover = popover

        let statusBar = NSStatusBar.system
        statusBarItem = statusBar.statusItem(withLength: NSStatusItem.squareLength)
        statusBarItem.button?.image = NSImage(named: "menubaricon")!
        statusBarItem.button?.action = #selector(togglePopover(_:))
        
        Helper.instance.setPlatformKey()

        Helper.instance.checkHelperVersion{(foundHelper) in
            if(foundHelper){
                print("helper found!")
            }
            else{
                Helper.instance.installHelper()
            }
        }
        
        LaunchAtLogin.isEnabled = true
        SMCPresenter.shared.loadValue()
        
        Helper.instance.checkCharging()
        
        var actionMsg:String?

        Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { timer in
            if(Helper.instance.isInitialized){
                Helper.instance.getChargingInfo { (Name, Capacity, IsCharging, MaxCapacity) in
                    
                    
                    if(!PersistanceManager.instance.oldKey){
                        if(Capacity < SMCPresenter.shared.value){
                            actionMsg = "NEED TO CHARGE"
                            if(Helper.instance.chargeInhibited){
                                Helper.instance.enableCharging()
                            }
                            Helper.instance.disableSleep()
 
                        }
                        else{
                            actionMsg = "IS PERFECT"
                            if(!Helper.instance.chargeInhibited){
                                Helper.instance.disableCharging()
                            }
                            Helper.instance.enableSleep()
                            
                        }
                        print("TARGET: ",SMCPresenter.shared.value,
                              " CURRENT: ",String(Capacity),
                              " ISCHARGING: ",String(IsCharging),
                              " CHARGE INHIBITED: ",String(Helper.instance.chargeInhibited),
                              " ACTION: ",actionMsg!)
                    }
                    else{
                        print("BCLM MODE ENABLED")
                    }
                    
                    

                }
                DispatchQueue.main.async {
                    Helper.instance.setStatusString()
                }
                
            }
        }
        
    }

    @objc func togglePopover(_ sender: AnyObject?) {
        popover.contentViewController?.view.window?.becomeKey()

        Helper.instance.setStatusString()
        if let button = self.statusBarItem.button {
            if popover.isShown {
                popover.performClose(sender)
            } else {
                popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
            }
        }
    }

}


================================================
FILE: AlDente/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
  "images" : [
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "16x16"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "16x16"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "32x32"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "32x32"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "128x128"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "128x128"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "256x256"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "256x256"
    },
    {
      "filename" : "spaghetti.png",
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "512x512"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "512x512"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: AlDente/Assets.xcassets/Contents.json
================================================
{
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AlDente/Assets.xcassets/menubaricon.imageset/Contents.json
================================================
{
  "images" : [
    {
      "filename" : "aldentelighticon1x.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "dark"
        }
      ],
      "filename" : "aldentedarkicon1x.png",
      "idiom" : "universal",
      "scale" : "1x"
    },
    {
      "filename" : "aldentelighticon2x.png",
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "dark"
        }
      ],
      "filename" : "aldentedarkicon2x.png",
      "idiom" : "universal",
      "scale" : "2x"
    },
    {
      "idiom" : "universal",
      "scale" : "3x"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "dark"
        }
      ],
      "idiom" : "universal",
      "scale" : "3x"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}


================================================
FILE: AlDente/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
    </dependencies>
    <scenes>
        <!--Application-->
        <scene sceneID="JPo-4y-FX3">
            <objects>
                <application id="hnw-xV-0zn" sceneMemberID="viewController">
                    <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
                        <items>
                            <menuItem title="AlDente" id="1Xt-HY-uBw">
                                <modifierMask key="keyEquivalentModifierMask"/>
                                <menu key="submenu" title="AlDente" systemMenu="apple" id="uQy-DD-JDr">
                                    <items>
                                        <menuItem title="About AlDente" id="5kV-Vb-QxS">
                                            <modifierMask key="keyEquivalentModifierMask"/>
                                            <connections>
                                                <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
                                            </connections>
                                        </menuItem>
                                        <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
                                        <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
                                        <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
                                        <menuItem title="Services" id="NMo-om-nkz">
                                            <modifierMask key="keyEquivalentModifierMask"/>
                                            <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
                                        </menuItem>
                                        <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
                                        <menuItem title="Hide AlDente" keyEquivalent="h" id="Olw-nP-bQN">
                                            <connections>
                                                <action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
                                            </connections>
                                        </menuItem>
                                        <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
                                            <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
                                            <connections>
                                                <action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
                                            </connections>
                                        </menuItem>
                                        <menuItem title="Show All" id="Kd2-mp-pUS">
                                            <modifierMask key="keyEquivalentModifierMask"/>
                                            <connections>
                                                <action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
                                            </connections>
                                        </menuItem>
                                        <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
                                        <menuItem title="Quit AlDente" keyEquivalent="q" id="4sb-4s-VLi">
                                            <connections>
                                                <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
                                            </connections>
                                        </menuItem>
                                    </items>
                                </menu>
                            </menuItem>
                            <menuItem title="File" id="dMs-cI-mzQ">
                                <modifierMask key="keyEquivalentModifierMask"/>
                            </menuItem>
                            <menuItem title="Edit" id="5QF-Oa-p0T">
                                <modifierMask key="keyEquivalentModifierMask"/>
                            </menuItem>
                            <menuItem title="Format" id="jxT-CU-nIS">
                                <modifierMask key="keyEquivalentModifierMask"/>
                            </menuItem>
                            <menuItem title="View" id="H8h-7b-M4v">
                                <modifierMask key="keyEquivalentModifierMask"/>
                            </menuItem>
                            <menuItem title="Window" id="aUF-d1-5bR">
                                <modifierMask key="keyEquivalentModifierMask"/>
                            </menuItem>
                            <menuItem title="Help" id="wpr-3q-Mcd">
                                <modifierMask key="keyEquivalentModifierMask"/>
                            </menuItem>
                        </items>
                    </menu>
                    <connections>
                        <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
                    </connections>
                </application>
                <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="AlDente" customModuleProvider="target"/>
                <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
                <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="75" y="0.0"/>
        </scene>
    </scenes>
</document>


================================================
FILE: AlDente/ContentView.swift
================================================
//
//  ContentView.swift
//  AlDente
//
//  Created by David Wernhart on 09.02.20.
//  Copyright © 2020 David Wernhart. All rights reserved.
//

import LaunchAtLogin
import SwiftUI

private struct BlueButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .foregroundColor(configuration.isPressed ? Color.blue : Color.white)
            .background(configuration.isPressed ? Color.white : Color.blue)
            .cornerRadius(6.0)
            .padding()
    }
}

private struct RedButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .foregroundColor(configuration.isPressed ? Color.red : Color.white)
            .background(configuration.isPressed ? Color.white : Color.red)
            .cornerRadius(6.0)
            .padding()
    }
}

private var allowDischarge = true

private struct Settings: View {
    @State private var launchAtLogin = LaunchAtLogin.isEnabled
    @State private var oldKey = PersistanceManager.instance.oldKey
    @ObservedObject private var presenter = SMCPresenter.shared

    var body: some View {
        VStack {
            Spacer().frame(height: 15)
            Text(presenter.status)
            HStack {
                VStack(alignment: .leading) {
                    Toggle(isOn: Binding(
                        get: { launchAtLogin },

                        set: { newValue in
                            launchAtLogin = newValue
                            print("Launch at login turned \(newValue ? "on" : "off")!")
                            LaunchAtLogin.isEnabled = newValue
                        }
                    )) {
                        Text("Launch at login")
                    }
                    
                    if(!Helper.instance.appleSilicon!){
                        Toggle(isOn: Binding(
                            get: { oldKey },

                            set: { newValue in
                                oldKey = newValue
                                PersistanceManager.instance.oldKey = oldKey
                                PersistanceManager.instance.save()
                                Helper.instance.setStatusString()
                                if(newValue){
                                    Helper.instance.enableCharging()
                                    Helper.instance.enableSleep()
                                    //presenter.writeValue()
                                }
                                else{
                                    presenter.setValue(value: 100)
                                }
                            }
                        )) {
                            Text("Use Classic SMC Key (Intel)")
                        }
                    }
                }.padding()

                Spacer()

                Button(action: {
                    Helper.instance.installHelper()
                }) {
                    Text("Reinstall Helper")
                        .frame(maxWidth: 120, maxHeight: 30)
                }.buttonStyle(BlueButtonStyle())
            }

            HStack {
                Spacer().frame(width: 15)
                VStack(alignment: .leading) {
                    let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
                    Text("AlDente \(version ?? "") 🍝").font(.headline)

                    let address = "github.com/davidwernhart/AlDente"
                    Button(action: {
                        openURL("https://" + address)
                    }) {
                        Text(address).foregroundColor(Color(.linkColor))
                    }.buttonStyle(PlainButtonStyle())

                    Text("Cooked up in 2021 by AppHouseKitchen")
//                    Text("AlDente 🍝").font(.title)
//                    Text("Keep your battery just right").font(.subheadline)
                }

                Spacer()

                Button(action: {
                    openURL("https://apphousekitchen.com/aldente/")
                }) {
                    Text("Get Pro 🍜")
                        .frame(maxWidth: 100, maxHeight: 50)
                }
                .buttonStyle(BlueButtonStyle())
            }
        }
        .background(Color(.unemphasizedSelectedContentBackgroundColor))
        .cornerRadius(5)
    }

    private func openURL(_ string: String) {
        let url = URL(string: string)!
        if NSWorkspace.shared.open(url) {
            print("default browser was successfully opened")
        }
    }
}

struct ContentView: View {
    @State private var adaptableHeight = CGFloat(100)
    @State private var showSettings = false

    @ObservedObject private var presenter = SMCPresenter.shared

    init() {
        Helper.instance.delegate = presenter
    }

    var body: some View {
        VStack(alignment: .leading) {

            HStack {
                Text("Max. Battery Charge:").padding(.leading)
                TextField("Number", value: Binding(
                    get: {
                        Float(presenter.value)
                    },
                    set: { newValue in
                        if newValue >= 20 && newValue <= 100 {
                            presenter.setValue(value: newValue)
                        }
                    }
                ), formatter: NumberFormatter())
                .multilineTextAlignment(.center)
                .frame(maxWidth: 50)
                .textFieldStyle(RoundedBorderTextFieldStyle())

                Spacer()

                Button(action: {
                    showSettings.toggle()
                    adaptableHeight = showSettings ? 275 : 100
                }) {
                    Text("Settings")
                        .frame(maxWidth: 70, maxHeight: 30)
                }.buttonStyle(BlueButtonStyle()).padding(.leading, -30)

                Button(action: {
                    NSApplication.shared.terminate(self)
                }) {
                    Text("Quit")
                        .frame(maxWidth: 50, maxHeight: 30)
                }.buttonStyle(RedButtonStyle()).padding(.leading, -30)
            }

            Slider(value: Binding(
                get: {
                     Float(presenter.value)
                },
                set: { newValue in
                    if newValue >= 20 && newValue <= 100 {
                        presenter.setValue(value: newValue)
                    }
                }
            ), in: 20...100).padding(.horizontal).padding(.top, -20)

            Spacer()

            if showSettings {
                Settings()
            }

        }.frame(width: 400, height: adaptableHeight)

    }
}

public final class SMCPresenter: ObservableObject, HelperDelegate {

    static let shared = SMCPresenter()

    @Published var value: UInt8 = 0
    @Published var status: String = ""
    private var timer: Timer?
    private var accuracyTimer: Timer?

    func OnMaxBatRead(value: UInt8) {
        if(PersistanceManager.instance.oldKey){
            DispatchQueue.main.async {
                self.value = value
            }
        }
    }
    
    func updateStatus(status:String){
        DispatchQueue.main.async {
            self.status = status
        }
    }
    
    public func loadValue(){
        PersistanceManager.instance.load()
        self.value = UInt8(PersistanceManager.instance.chargeVal!)
        if(self.value == 0){
            self.value = 50
        }
        print("loaded max charge val: ",self.value," old key:",PersistanceManager.instance.oldKey)
//        if(!Helper.instance.appleSilicon!){
//            Helper.instance.getSMCCharge(withReply: { (smcval) in
//                self.value = UInt8(smcval)
//            })
//        }
        if(PersistanceManager.instance.oldKey){
            writeValue()
        }
    }

    func setValue(value: Float) {
        DispatchQueue.main.async {
            self.value = UInt8(value)
            PersistanceManager.instance.chargeVal = Int(value)
            PersistanceManager.instance.save()
            self.writeValue()
        }
        timer?.invalidate()
        accuracyTimer?.invalidate()        
    }
    
    func writeValue(){
        if(PersistanceManager.instance.oldKey){
            print("should write bclm value: ", self.value)
            Helper.instance.writeMaxBatteryCharge(setVal: self.value)
        }
    }

}


================================================
FILE: AlDente/Helper.swift
================================================
//
//  Helper.swift
//  AlDente
//
//  Created by David Wernhart on 14.02.20.
//  Copyright © 2020 David Wernhart. All rights reserved.
//

import Foundation
import ServiceManagement
import IOKit.pwr_mgt

protocol HelperDelegate {
    func OnMaxBatRead(value: UInt8)
    func updateStatus(status:String)
}

final class Helper {

    static let instance = Helper()

    public var delegate: HelperDelegate?
    
    private var key: String?
    
    private var preventSleepID: IOPMAssertionID?
    
    public var appleSilicon:Bool?
    public var chargeInhibited: Bool = false
    public var isInitialized:Bool = false
    
    public var statusString:String = ""


    lazy var helperToolConnection: NSXPCConnection = {
        let connection = NSXPCConnection(machServiceName: "com.davidwernhart.Helper.mach", options: .privileged)
        connection.remoteObjectInterface = NSXPCInterface(with: HelperToolProtocol.self)

        connection.resume()
        return connection
    }()

    func setPlatformKey() {
        let s:String! = ProcessInfo.init().machineHardwareName
        if(s != nil){
            if(s.elementsEqual("x86_64")){
                print("intel cpu!")
                appleSilicon = false;
            }
            else if(s.elementsEqual("arm64")){
                print("arm cpu!")
                appleSilicon = true;
            }
            
        }
    }
    func setStatusString(){
        checkCharging()
        var sleepDisabled:Bool = !(preventSleepID == nil)
        statusString = ""
        if(PersistanceManager.instance.oldKey){
            statusString = "BCLM Key Mode. Final charge value can differ by up to 5%"
        }
        else{
            statusString = "Charge Inhibit: "+String(chargeInhibited)+" | Prevent Sleep: "+String(sleepDisabled)+" | Helper v"+String(helperVersion)+": \(self.isInitialized ? "found" : "not found")"
        }
        
        
        self.delegate?.updateStatus(status: statusString)
    }

    
    func enableSleep(){
        if(self.preventSleepID != nil){
            print("RELEASING PREVENT SLEEP ASSERTION WITH ID: ",preventSleepID!)
            releaseAssertion(assertionId: self.preventSleepID!)
            self.preventSleepID = nil
        }
    }
    
    func disableSleep(){
        createAssertion(assertion: kIOPMAssertionTypePreventSystemSleep){ id in
            if(self.preventSleepID == nil){
                print("PREVENT SLEEP ASSERTION CREATED! ID: ",id)
                self.preventSleepID = id
            }
        }
    }
    
    func enableCharging(){
        if(appleSilicon!){
            SMCWriteByte(key: "CH0B", value: 00)
        }
        SMCWriteByte(key: "CH0B", value: 00)
        self.chargeInhibited = false
        
    }
    
    func disableCharging(){
        if(appleSilicon!){
            SMCWriteByte(key: "CH0B", value: 02)
        }
        SMCWriteByte(key: "CH0B", value: 02)
        self.chargeInhibited = true
        
    }
    
    func checkCharging(){
        Helper.instance.SMCReadUInt32(key: "CH0B") { value in
            self.chargeInhibited = !(value == 00)
            print("CHARGE INHIBITED: "+String(self.chargeInhibited))
        }
        if(PersistanceManager.instance.oldKey){
            Helper.instance.readMaxBatteryCharge()
        }

    }
    
    func getChargingInfo(withReply reply: (String,Int,Bool,Int) -> Void){
        let snapshot = IOPSCopyPowerSourcesInfo().takeRetainedValue()
        let sources = IOPSCopyPowerSourcesList(snapshot).takeRetainedValue() as Array
        let info = IOPSGetPowerSourceDescription(snapshot, sources[0]).takeUnretainedValue() as! [String: AnyObject]

        if let name = info[kIOPSNameKey] as? String,
            let capacity = info[kIOPSCurrentCapacityKey] as? Int,
            let isCharging = info[kIOPSIsChargingKey] as? Bool,
            let max = info[kIOPSMaxCapacityKey] as? Int {
            reply(name,capacity,isCharging,max)
        }
    }
    
    func getSMCCharge(withReply reply: @escaping (Float)->Void){
        Helper.instance.SMCReadUInt32(key: "BRSC") { value in
            let smcval = Float(value >> 16)
            reply(smcval)
        }
    }
    
    @objc func createAssertion(assertion: String, withReply reply: @escaping (IOPMAssertionID) -> Void){
        let helper = helperToolConnection.remoteObjectProxyWithErrorHandler {
            let e = $0 as NSError
            print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")")
        } as? HelperToolProtocol

        helper?.createAssertion(assertion: assertion, withReply: { id in
            reply(id)
        })
    }
    
    @objc func releaseAssertion(assertionId: IOPMAssertionID){
        let helper = helperToolConnection.remoteObjectProxyWithErrorHandler {
            let e = $0 as NSError
            print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")")
        } as? HelperToolProtocol

        helper?.releaseAssertion(assertionID: assertionId)
    }
    
    @objc func installHelper() {
        print("trying to install helper!")
        var status = noErr
        let helperID = "com.davidwernhart.Helper" as CFString // Prefs.helperID as CFString

        var authItem = kSMRightBlessPrivilegedHelper.withCString {
            AuthorizationItem(name: $0, valueLength: 0, value: nil, flags: 0)
        }
        var authRights = withUnsafeMutablePointer(to: &authItem) {
            AuthorizationRights(count: 1, items: $0)
        }
        let authFlags: AuthorizationFlags = [.interactionAllowed, .preAuthorize, .extendRights]
        var authRef: AuthorizationRef?
        status = AuthorizationCreate(&authRights, nil, authFlags, &authRef)
        if status != errAuthorizationSuccess {
            print(SecCopyErrorMessageString(status, nil) ?? "")
            print("Error: \(status)")
        }

        var error: Unmanaged<CFError>?
        SMJobBless(kSMDomainSystemLaunchd, helperID, authRef, &error)
        if let e = error?.takeRetainedValue() {
            print("Domain: ", CFErrorGetDomain(e) ?? "")
            print("Code: ", CFErrorGetCode(e))
            print("UserInfo: ", CFErrorCopyUserInfo(e) ?? "")
            print("Description: ", CFErrorCopyDescription(e) ?? "")
            print("Reason: ", CFErrorCopyFailureReason(e) ?? "")
            print("Suggestion: ", CFErrorCopyRecoverySuggestion(e) ?? "")
        }
        
        if(error == nil){
            print("helper installed successfully!")
            restart()
        }
    }
    
    func restart(){
        let url = URL(fileURLWithPath: Bundle.main.resourcePath!)
        let path = url.deletingLastPathComponent().deletingLastPathComponent().absoluteString
        let task = Process()
        task.launchPath = "/usr/bin/open"
        task.arguments = [path]
        task.launch()
        exit(0)
    }
    
    @objc func setResetValues(){
        let helper = helperToolConnection.remoteObjectProxyWithErrorHandler {
            let e = $0 as NSError
            print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")")

        } as? HelperToolProtocol
        
        helper?.setResetVal(key: "CH0B", value: 00)
    }

    @objc func writeMaxBatteryCharge(setVal: UInt8) {
        SMCWriteByte(key: "BCLM", value: setVal)

    }

    @objc func readMaxBatteryCharge() {
        SMCReadByte(key: "BCLM") { value in
            print("OLD KEY MAX CHARGE: "+String(value))
            self.delegate?.OnMaxBatRead(value: value)
        }
    }
    
    @objc func enableCharging(enabled: Bool) {
        if(enabled){
            SMCWriteByte(key: "CH0B", value: 00)
        }
        else{
            SMCWriteByte(key: "CH0B", value: 02)
        }

    }

    @objc func checkHelperVersion(withReply reply: @escaping (Bool) -> Void) {
        print("checking helper version")
        let helper = helperToolConnection.remoteObjectProxyWithErrorHandler {
            let e = $0 as NSError
            print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")")
            reply(false)
            return()

        } as? HelperToolProtocol

        helper?.getVersion { version in
            print("helperVersion:", helperVersion, " version from helper:", version)
            if !helperVersion.elementsEqual(version) {
                reply(false)
                return()
            }
            else{
                self.isInitialized = true
                reply(true)
                return()
            }
        }
    }

    @objc func SMCReadByte(key: String, withReply reply: @escaping (UInt8) -> Void) {
        let helper = helperToolConnection.remoteObjectProxyWithErrorHandler {
            let e = $0 as NSError
            print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")")

        } as? HelperToolProtocol

        helper?.readSMCByte(key: key) {
            reply($0)
        }
    }
    
    @objc func SMCReadUInt32(key: String, withReply reply: @escaping (UInt32) -> Void) {
        let helper = helperToolConnection.remoteObjectProxyWithErrorHandler {
            let e = $0 as NSError
            print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")")

        } as? HelperToolProtocol

        helper?.readSMCUInt32(key: key) {
            reply($0)
        }
    }

    @objc func SMCWriteByte(key: String, value: UInt8) {
        let helper = helperToolConnection.remoteObjectProxyWithErrorHandler {
            let e = $0 as NSError
            print("Remote proxy error \(e.code): \(e.localizedDescription) \(e.localizedRecoverySuggestion ?? "---")")

        } as? HelperToolProtocol

        helper?.setSMCByte(key: key, value: value)
    }
}


================================================
FILE: AlDente/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIconFile</key>
	<string></string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
	<key>CFBundleShortVersionString</key>
	<string>$(MARKETING_VERSION)</string>
	<key>CFBundleVersion</key>
	<string>$(CURRENT_PROJECT_VERSION)</string>
	<key>LSApplicationCategoryType</key>
	<string>public.app-category.developer-tools</string>
	<key>LSMinimumSystemVersion</key>
	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
	<key>LSUIElement</key>
	<true/>
	<key>NSHumanReadableCopyright</key>
	<string>Copyright © 2020 David Wernhart. All rights reserved.</string>
	<key>NSMainStoryboardFile</key>
	<string>Main</string>
	<key>NSPrincipalClass</key>
	<string>NSApplication</string>
	<key>NSSupportsAutomaticTermination</key>
	<false/>
	<key>NSSupportsSuddenTermination</key>
	<false/>
	<key>SMPrivilegedExecutables</key>
	<dict>
		<key>com.davidwernhart.Helper</key>
		<string>identifier "com.davidwernhart.Helper" and anchor apple generic and certificate leaf[subject.CN] = "Apple Development: david.wernhart96@gmail.com (GSDX9BQ584)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */</string>
	</dict>
</dict>
</plist>


================================================
FILE: AlDente/PersistanceManager.swift
================================================
//
//  PersistanceManager.swift
//  AlDente
//
//  Created by David Wernhart on 07.02.21.
//  Copyright © 2021 David Wernhart. All rights reserved.
//

import Foundation

class PersistanceManager{
    static let instance = PersistanceManager()
    
    public var launchOnLogin: Bool?
    public var chargeVal: Int?
    public var oldKey: Bool = false
    
    public func load(){
        launchOnLogin = UserDefaults.standard.bool(forKey: "launchOnLogin")
        oldKey = UserDefaults.standard.bool(forKey: "oldKey")
        chargeVal = UserDefaults.standard.integer(forKey: "chargeVal")
    }
    
    public func save(){
        UserDefaults.standard.set(launchOnLogin, forKey: "launchOnLogin")
        UserDefaults.standard.set(chargeVal, forKey: "chargeVal")
        UserDefaults.standard.set(oldKey, forKey: "oldKey")
    }
}


================================================
FILE: AlDente/Preview Content/Preview Assets.xcassets/Contents.json
================================================
{
  "info" : {
    "version" : 1,
    "author" : "xcode"
  }
}

================================================
FILE: AlDente.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 54;
	objects = {

/* Begin PBXBuildFile section */
		505E96C92586211600DAA405 /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 505E96C82586211600DAA405 /* LaunchAtLogin */; };
		9224A08723F1F70600961AC4 /* com.davidwernhart.Helper in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9283741823F1F34400B8AE7A /* com.davidwernhart.Helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
		927DBFC923F5478E00F8BF0D /* HelperToolProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927DBFC823F5478E00F8BF0D /* HelperToolProtocol.swift */; };
		927DBFCA23F5478E00F8BF0D /* HelperToolProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927DBFC823F5478E00F8BF0D /* HelperToolProtocol.swift */; };
		9283741B23F1F34400B8AE7A /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9283741A23F1F34400B8AE7A /* main.swift */; };
		928674C025D07BA300EC79C1 /* PersistanceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 928674BF25D07BA300EC79C1 /* PersistanceManager.swift */; };
		92981EDB23F08D9B00C05424 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92981EDA23F08D9B00C05424 /* AppDelegate.swift */; };
		92981EDD23F08D9B00C05424 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92981EDC23F08D9B00C05424 /* ContentView.swift */; };
		92981EDF23F08D9C00C05424 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92981EDE23F08D9C00C05424 /* Assets.xcassets */; };
		92981EE223F08D9C00C05424 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92981EE123F08D9C00C05424 /* Preview Assets.xcassets */; };
		92981EE523F08D9C00C05424 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92981EE323F08D9C00C05424 /* Main.storyboard */; };
		92ACA12B23F5F822003512DC /* HelperTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 927DBFCB23F54C2C00F8BF0D /* HelperTool.swift */; };
		92ACA12E23F5F861003512DC /* SMC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92ACA12D23F5F861003512DC /* SMC.swift */; };
		92E24B4123F6DC0D00BE41ED /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92E24B4023F6DC0D00BE41ED /* Helper.swift */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
		9224A08623F1F6E300961AC4 /* CopyFiles */ = {
			isa = PBXCopyFilesBuildPhase;
			buildActionMask = 12;
			dstPath = Contents/Library/LaunchServices;
			dstSubfolderSpec = 1;
			files = (
				9224A08723F1F70600961AC4 /* com.davidwernhart.Helper in CopyFiles */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
		927DBFC623F533FB00F8BF0D /* Helper-Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Helper-Launchd.plist"; sourceTree = "<group>"; };
		927DBFC823F5478E00F8BF0D /* HelperToolProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelperToolProtocol.swift; sourceTree = "<group>"; };
		927DBFCB23F54C2C00F8BF0D /* HelperTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelperTool.swift; sourceTree = "<group>"; };
		9283741823F1F34400B8AE7A /* com.davidwernhart.Helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = com.davidwernhart.Helper; sourceTree = BUILT_PRODUCTS_DIR; };
		9283741A23F1F34400B8AE7A /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
		9283741F23F1F38100B8AE7A /* Helper-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Helper-Info.plist"; sourceTree = "<group>"; };
		928674BF25D07BA300EC79C1 /* PersistanceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistanceManager.swift; sourceTree = "<group>"; };
		92981ED723F08D9B00C05424 /* AlDente.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AlDente.app; sourceTree = BUILT_PRODUCTS_DIR; };
		92981EDA23F08D9B00C05424 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
		92981EDC23F08D9B00C05424 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
		92981EDE23F08D9C00C05424 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
		92981EE123F08D9C00C05424 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
		92981EE423F08D9C00C05424 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
		92981EE623F08D9C00C05424 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		92ACA12D23F5F861003512DC /* SMC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMC.swift; sourceTree = "<group>"; };
		92E24B4023F6DC0D00BE41ED /* Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helper.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		92981ED423F08D9B00C05424 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
				505E96C92586211600DAA405 /* LaunchAtLogin in Frameworks */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		927DBFC723F545AF00F8BF0D /* Common */ = {
			isa = PBXGroup;
			children = (
				927DBFC823F5478E00F8BF0D /* HelperToolProtocol.swift */,
			);
			path = Common;
			sourceTree = "<group>";
		};
		9283741923F1F34400B8AE7A /* com.davidwernhart.Helper */ = {
			isa = PBXGroup;
			children = (
				9283741A23F1F34400B8AE7A /* main.swift */,
				9283741F23F1F38100B8AE7A /* Helper-Info.plist */,
				927DBFC623F533FB00F8BF0D /* Helper-Launchd.plist */,
				927DBFCB23F54C2C00F8BF0D /* HelperTool.swift */,
				92ACA12D23F5F861003512DC /* SMC.swift */,
			);
			path = com.davidwernhart.Helper;
			sourceTree = "<group>";
		};
		92981ECE23F08D9B00C05424 = {
			isa = PBXGroup;
			children = (
				927DBFC723F545AF00F8BF0D /* Common */,
				92981ED923F08D9B00C05424 /* AlDente */,
				9283741923F1F34400B8AE7A /* com.davidwernhart.Helper */,
				92981ED823F08D9B00C05424 /* Products */,
			);
			sourceTree = "<group>";
		};
		92981ED823F08D9B00C05424 /* Products */ = {
			isa = PBXGroup;
			children = (
				92981ED723F08D9B00C05424 /* AlDente.app */,
				9283741823F1F34400B8AE7A /* com.davidwernhart.Helper */,
			);
			name = Products;
			sourceTree = "<group>";
		};
		92981ED923F08D9B00C05424 /* AlDente */ = {
			isa = PBXGroup;
			children = (
				92E24B4023F6DC0D00BE41ED /* Helper.swift */,
				92981EDA23F08D9B00C05424 /* AppDelegate.swift */,
				92981EDC23F08D9B00C05424 /* ContentView.swift */,
				92981EDE23F08D9C00C05424 /* Assets.xcassets */,
				92981EE323F08D9C00C05424 /* Main.storyboard */,
				92981EE623F08D9C00C05424 /* Info.plist */,
				92981EE023F08D9C00C05424 /* Preview Content */,
				928674BF25D07BA300EC79C1 /* PersistanceManager.swift */,
			);
			path = AlDente;
			sourceTree = "<group>";
		};
		92981EE023F08D9C00C05424 /* Preview Content */ = {
			isa = PBXGroup;
			children = (
				92981EE123F08D9C00C05424 /* Preview Assets.xcassets */,
			);
			path = "Preview Content";
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
		9283741723F1F34400B8AE7A /* com.davidwernhart.Helper */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 9283741C23F1F34400B8AE7A /* Build configuration list for PBXNativeTarget "com.davidwernhart.Helper" */;
			buildPhases = (
				9283741423F1F34400B8AE7A /* Sources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = com.davidwernhart.Helper;
			productName = com.davidwernhart.Helper;
			productReference = 9283741823F1F34400B8AE7A /* com.davidwernhart.Helper */;
			productType = "com.apple.product-type.tool";
		};
		92981ED623F08D9B00C05424 /* AlDente */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = 92981EEA23F08D9C00C05424 /* Build configuration list for PBXNativeTarget "AlDente" */;
			buildPhases = (
				92981ED323F08D9B00C05424 /* Sources */,
				92981ED423F08D9B00C05424 /* Frameworks */,
				92981ED523F08D9B00C05424 /* Resources */,
				9224A08623F1F6E300961AC4 /* CopyFiles */,
				92E24B4423F847B500BE41ED /* LaunchAtLogin */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = AlDente;
			packageProductDependencies = (
				505E96C82586211600DAA405 /* LaunchAtLogin */,
			);
			productName = AlDente;
			productReference = 92981ED723F08D9B00C05424 /* AlDente.app */;
			productType = "com.apple.product-type.application";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		92981ECF23F08D9B00C05424 /* Project object */ = {
			isa = PBXProject;
			attributes = {
				LastSwiftUpdateCheck = 1130;
				LastUpgradeCheck = 1220;
				ORGANIZATIONNAME = "David Wernhart";
				TargetAttributes = {
					9283741723F1F34400B8AE7A = {
						CreatedOnToolsVersion = 11.3.1;
					};
					92981ED623F08D9B00C05424 = {
						CreatedOnToolsVersion = 11.3.1;
					};
				};
			};
			buildConfigurationList = 92981ED223F08D9B00C05424 /* Build configuration list for PBXProject "AlDente" */;
			compatibilityVersion = "Xcode 12.0";
			developmentRegion = en;
			hasScannedForEncodings = 0;
			knownRegions = (
				en,
				Base,
			);
			mainGroup = 92981ECE23F08D9B00C05424;
			packageReferences = (
				505E96C72586211600DAA405 /* XCRemoteSwiftPackageReference "LaunchAtLogin" */,
			);
			productRefGroup = 92981ED823F08D9B00C05424 /* Products */;
			projectDirPath = "";
			projectRoot = "";
			targets = (
				92981ED623F08D9B00C05424 /* AlDente */,
				9283741723F1F34400B8AE7A /* com.davidwernhart.Helper */,
			);
		};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
		92981ED523F08D9B00C05424 /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				92981EE523F08D9C00C05424 /* Main.storyboard in Resources */,
				92981EE223F08D9C00C05424 /* Preview Assets.xcassets in Resources */,
				92981EDF23F08D9C00C05424 /* Assets.xcassets in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
		92E24B4423F847B500BE41ED /* LaunchAtLogin */ = {
			isa = PBXShellScriptBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			inputFileListPaths = (
			);
			inputPaths = (
			);
			name = LaunchAtLogin;
			outputFileListPaths = (
			);
			outputPaths = (
			);
			runOnlyForDeploymentPostprocessing = 0;
			shellPath = /bin/sh;
			shellScript = "\"${BUILT_PRODUCTS_DIR}/LaunchAtLogin_LaunchAtLogin.bundle/Contents/Resources/copy-helper-swiftpm.sh\"\n";
		};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
		9283741423F1F34400B8AE7A /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				9283741B23F1F34400B8AE7A /* main.swift in Sources */,
				92ACA12B23F5F822003512DC /* HelperTool.swift in Sources */,
				927DBFCA23F5478E00F8BF0D /* HelperToolProtocol.swift in Sources */,
				92ACA12E23F5F861003512DC /* SMC.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		92981ED323F08D9B00C05424 /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				928674C025D07BA300EC79C1 /* PersistanceManager.swift in Sources */,
				927DBFC923F5478E00F8BF0D /* HelperToolProtocol.swift in Sources */,
				92981EDD23F08D9B00C05424 /* ContentView.swift in Sources */,
				92981EDB23F08D9B00C05424 /* AppDelegate.swift in Sources */,
				92E24B4123F6DC0D00BE41ED /* Helper.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXVariantGroup section */
		92981EE323F08D9C00C05424 /* Main.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				92981EE423F08D9C00C05424 /* Base */,
			);
			name = Main.storyboard;
			sourceTree = "<group>";
		};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
		9283741D23F1F34400B8AE7A /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ARCHS = "$(ARCHS_STANDARD)";
				CODE_SIGN_IDENTITY = "-";
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 10;
				DEVELOPMENT_TEAM = 56C2L92EKW;
				ENABLE_HARDENED_RUNTIME = YES;
				EXCLUDED_ARCHS = "";
				"EXCLUDED_ARCHS[sdk=*]" = "";
				INFOPLIST_FILE = "com.davidwernhart.Helper/Helper-Info.plist";
				MACOSX_DEPLOYMENT_TARGET = 11.1;
				MARKETING_VERSION = 4.3;
				OTHER_LDFLAGS = (
					"-sectcreate",
					__TEXT,
					__info_plist,
					"$(SRCROOT)/com.davidwernhart.Helper/Helper-Info.plist",
					"-sectcreate",
					__TEXT,
					__launchd_plist,
					"$(SRCROOT)/com.davidwernhart.Helper/Helper-Launchd.plist",
				);
				PRODUCT_BUNDLE_IDENTIFIER = com.davidwernhart.Helper;
				PRODUCT_MODULE_NAME = AlDenteHelper;
				PRODUCT_NAME = "$(TARGET_NAME)";
				PROVISIONING_PROFILE_SPECIFIER = "";
				SKIP_INSTALL = YES;
				SWIFT_VERSION = 5.0;
			};
			name = Debug;
		};
		9283741E23F1F34400B8AE7A /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ARCHS = "$(ARCHS_STANDARD)";
				CODE_SIGN_IDENTITY = "-";
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 10;
				DEVELOPMENT_TEAM = 56C2L92EKW;
				ENABLE_HARDENED_RUNTIME = YES;
				EXCLUDED_ARCHS = "";
				INFOPLIST_FILE = "com.davidwernhart.Helper/Helper-Info.plist";
				MACOSX_DEPLOYMENT_TARGET = 11.1;
				MARKETING_VERSION = 4.3;
				OTHER_LDFLAGS = (
					"-sectcreate",
					__TEXT,
					__info_plist,
					"$(SRCROOT)/com.davidwernhart.Helper/Helper-Info.plist",
					"-sectcreate",
					__TEXT,
					__launchd_plist,
					"$(SRCROOT)/com.davidwernhart.Helper/Helper-Launchd.plist",
				);
				PRODUCT_BUNDLE_IDENTIFIER = com.davidwernhart.Helper;
				PRODUCT_MODULE_NAME = AlDenteHelper;
				PRODUCT_NAME = "$(TARGET_NAME)";
				PROVISIONING_PROFILE_SPECIFIER = "";
				SKIP_INSTALL = YES;
				SWIFT_VERSION = 5.0;
			};
			name = Release;
		};
		92981EE823F08D9C00C05424 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = dwarf;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				ENABLE_TESTABILITY = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_OPTIMIZATION_LEVEL = 0;
				GCC_PREPROCESSOR_DEFINITIONS = (
					"DEBUG=1",
					"$(inherited)",
				);
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				MACOSX_DEPLOYMENT_TARGET = 11.1;
				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
				MTL_FAST_MATH = YES;
				ONLY_ACTIVE_ARCH = YES;
				SDKROOT = macosx;
				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
			};
			name = Debug;
		};
		92981EE923F08D9C00C05424 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_SEARCH_USER_PATHS = NO;
				CLANG_ANALYZER_NONNULL = YES;
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
				CLANG_CXX_LIBRARY = "libc++";
				CLANG_ENABLE_MODULES = YES;
				CLANG_ENABLE_OBJC_ARC = YES;
				CLANG_ENABLE_OBJC_WEAK = YES;
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
				CLANG_WARN_BOOL_CONVERSION = YES;
				CLANG_WARN_COMMA = YES;
				CLANG_WARN_CONSTANT_CONVERSION = YES;
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
				CLANG_WARN_EMPTY_BODY = YES;
				CLANG_WARN_ENUM_CONVERSION = YES;
				CLANG_WARN_INFINITE_RECURSION = YES;
				CLANG_WARN_INT_CONVERSION = YES;
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
				CLANG_WARN_STRICT_PROTOTYPES = YES;
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
				CLANG_WARN_UNREACHABLE_CODE = YES;
				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
				COPY_PHASE_STRIP = NO;
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
				ENABLE_NS_ASSERTIONS = NO;
				ENABLE_STRICT_OBJC_MSGSEND = YES;
				GCC_C_LANGUAGE_STANDARD = gnu11;
				GCC_NO_COMMON_BLOCKS = YES;
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
				GCC_WARN_UNDECLARED_SELECTOR = YES;
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				MACOSX_DEPLOYMENT_TARGET = 11.1;
				MTL_ENABLE_DEBUG_INFO = NO;
				MTL_FAST_MATH = YES;
				SDKROOT = macosx;
				SWIFT_COMPILATION_MODE = wholemodule;
				SWIFT_OPTIMIZATION_LEVEL = "-O";
			};
			name = Release;
		};
		92981EEB23F08D9C00C05424 /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				CODE_SIGN_IDENTITY = "-";
				CODE_SIGN_STYLE = Automatic;
				COMBINE_HIDPI_IMAGES = YES;
				CURRENT_PROJECT_VERSION = 6;
				DEVELOPMENT_ASSET_PATHS = "\"AlDente/Preview Content\"";
				DEVELOPMENT_TEAM = 56C2L92EKW;
				ENABLE_HARDENED_RUNTIME = YES;
				ENABLE_PREVIEWS = YES;
				INFOPLIST_FILE = AlDente/Info.plist;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/../Frameworks",
				);
				MACOSX_DEPLOYMENT_TARGET = 11.1;
				MARKETING_VERSION = "2.0 Alpha";
				PRODUCT_BUNDLE_IDENTIFIER = com.davidwernhart.AlDente;
				PRODUCT_NAME = "$(TARGET_NAME)";
				PROVISIONING_PROFILE_SPECIFIER = "";
				SWIFT_VERSION = 5.0;
			};
			name = Debug;
		};
		92981EEC23F08D9C00C05424 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				CODE_SIGN_IDENTITY = "-";
				CODE_SIGN_STYLE = Automatic;
				COMBINE_HIDPI_IMAGES = YES;
				CURRENT_PROJECT_VERSION = 6;
				DEVELOPMENT_ASSET_PATHS = "\"AlDente/Preview Content\"";
				DEVELOPMENT_TEAM = 56C2L92EKW;
				ENABLE_HARDENED_RUNTIME = YES;
				ENABLE_PREVIEWS = YES;
				INFOPLIST_FILE = AlDente/Info.plist;
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/../Frameworks",
				);
				MACOSX_DEPLOYMENT_TARGET = 11.1;
				MARKETING_VERSION = "2.0 Alpha";
				PRODUCT_BUNDLE_IDENTIFIER = com.davidwernhart.AlDente;
				PRODUCT_NAME = "$(TARGET_NAME)";
				PROVISIONING_PROFILE_SPECIFIER = "";
				SWIFT_VERSION = 5.0;
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
		9283741C23F1F34400B8AE7A /* Build configuration list for PBXNativeTarget "com.davidwernhart.Helper" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				9283741D23F1F34400B8AE7A /* Debug */,
				9283741E23F1F34400B8AE7A /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		92981ED223F08D9B00C05424 /* Build configuration list for PBXProject "AlDente" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				92981EE823F08D9C00C05424 /* Debug */,
				92981EE923F08D9C00C05424 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		92981EEA23F08D9C00C05424 /* Build configuration list for PBXNativeTarget "AlDente" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				92981EEB23F08D9C00C05424 /* Debug */,
				92981EEC23F08D9C00C05424 /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
		505E96C72586211600DAA405 /* XCRemoteSwiftPackageReference "LaunchAtLogin" */ = {
			isa = XCRemoteSwiftPackageReference;
			repositoryURL = "https://github.com/sindresorhus/LaunchAtLogin";
			requirement = {
				kind = upToNextMajorVersion;
				minimumVersion = 4.0.0;
			};
		};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
		505E96C82586211600DAA405 /* LaunchAtLogin */ = {
			isa = XCSwiftPackageProductDependency;
			package = 505E96C72586211600DAA405 /* XCRemoteSwiftPackageReference "LaunchAtLogin" */;
			productName = LaunchAtLogin;
		};
/* End XCSwiftPackageProductDependency section */
	};
	rootObject = 92981ECF23F08D9B00C05424 /* Project object */;
}


================================================
FILE: AlDente.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
   version = "1.0">
   <FileRef
      location = "self:">
   </FileRef>
</Workspace>


================================================
FILE: AlDente.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>IDEDidComputeMac32BitWarning</key>
	<true/>
</dict>
</plist>


================================================
FILE: AlDente.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
================================================
{
  "object": {
    "pins": [
      {
        "package": "LaunchAtLogin",
        "repositoryURL": "https://github.com/sindresorhus/LaunchAtLogin",
        "state": {
          "branch": null,
          "revision": "0f39982b9d6993eef253b81219d3c39ba1e680f3",
          "version": "4.0.0"
        }
      }
    ]
  },
  "version": 1
}


================================================
FILE: AlDente.xcodeproj/xcuserdata/davidwernhart.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
   uuid = "0B65810B-47FA-44B5-B39C-4D764B29033A"
   type = "1"
   version = "2.0">
   <Breakpoints>
      <BreakpointProxy
         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
         <BreakpointContent
            uuid = "15EAC10E-2093-4C1F-817D-D17853B691FE"
            shouldBeEnabled = "No"
            ignoreCount = "0"
            continueAfterRunningActions = "No"
            filePath = "AlDente/ContentView.swift"
            startingColumnNumber = "9223372036854775807"
            endingColumnNumber = "9223372036854775807"
            startingLineNumber = "37"
            endingLineNumber = "37"
            landmarkName = "Settings"
            landmarkType = "14">
         </BreakpointContent>
      </BreakpointProxy>
   </Breakpoints>
</Bucket>


================================================
FILE: AlDente.xcodeproj/xcuserdata/davidwernhart.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>SchemeUserState</key>
	<dict>
		<key>AlDente Pro.xcscheme_^#shared#^_</key>
		<dict>
			<key>orderHint</key>
			<integer>2</integer>
		</dict>
		<key>AlDente copy.xcscheme_^#shared#^_</key>
		<dict>
			<key>orderHint</key>
			<integer>2</integer>
		</dict>
		<key>AlDente.xcscheme_^#shared#^_</key>
		<dict>
			<key>orderHint</key>
			<integer>1</integer>
		</dict>
		<key>Hall.xcscheme_^#shared#^_</key>
		<dict>
			<key>orderHint</key>
			<integer>0</integer>
		</dict>
		<key>Helper.xcscheme_^#shared#^_</key>
		<dict>
			<key>orderHint</key>
			<integer>2</integer>
		</dict>
		<key>com.davidwernhart.Helper.xcscheme_^#shared#^_</key>
		<dict>
			<key>orderHint</key>
			<integer>0</integer>
		</dict>
	</dict>
</dict>
</plist>


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: Common/HelperToolProtocol.swift
================================================
//
//  HelperToolProtocol.swift
//  AlDente
//
//  Created by David Wernhart on 13.02.20.
//  Copyright © 2020 David Wernhart. All rights reserved.
//

import Foundation
import IOKit.pwr_mgt

let helperVersion: String = "10" //for some reason the integrated version check does not work, so I use this one

@objc(HelperToolProtocol) protocol HelperToolProtocol {
//protocol HelperToolProtocol {
    func getVersion(withReply reply: @escaping (String) -> Void)

    //TODO: more functions for other data types, altough this is sufficient for battery max charge level
    func setSMCByte(key: String, value: UInt8)
    func readSMCByte(key: String, withReply reply: @escaping (UInt8) -> Void)
    func readSMCUInt32(key: String, withReply reply: @escaping (UInt32) -> Void)
    
    func createAssertion(assertion:String, withReply reply: @escaping (IOPMAssertionID) -> Void)
    func releaseAssertion(assertionID:IOPMAssertionID)
    func setResetVal(key:String, value: UInt8)

}


================================================
FILE: LICENSE
================================================
1.	Preamble

The AppHouseKitchenOG, owner: David Wernhart and Matthias Kerbl, located in Obersdorfer Straße 31/5/11, 2120 Wolkerdorf, Austria (hereinafter referred to as "COMPANY") offers the “All-In-One charge limiter app for MacBooks” “AlDente”.

The licence agreement regulates the use of the software "AlDente" (hereinafter referred to as "SOFTWARE") for free if the evaluation license has been selected.

This licence agreement is addressed to persons who wish to use the services for professional purposes, i.e. entrepreneurs in the sense of section 1 Abs 1 Z 1 KSchG („Austrian Customer Protection Act“) but also private customers (consumers in the sense of section 1 Abs Z 2 KSchG) (both together hereinafter referred to as "USER").

For the purpose of better readability, no gender-specific differentiation is made. This is done without any intention of discrimination. All genders are equally addressed.

2.	Scope of application

This Evaluation Licence Agreement defines and regulates the procurement, use and commercial exploitation of the SOFTWARE as well as the related business and administrative activities if the USER uses the SOFTWARE free of charge for the purpose of evaluating the SOFTWARE. However, if the USER concludes a legal transaction against payment, a separate licence agreement shall apply.

3.	Conditions of use

The USER is obliged to provide truthful, comprehensive and correct information within the framework of the business relationship and to keep the specific information up to date at all times. The USER shall treat all data confidentially (this applies in particular to log-in data and passwords). If the USER suspects misuse by third parties, he must inform the COMPANY of this immediately.

The USER shall refrain from all actions which may endanger or impair the technical functionality of the SOFTWARE (including cyber attacks). Such behaviour will be prosecuted.

The USER shall take reasonable precautions to protect the SOFTWARE from unauthorised access by third parties. The USER shall inform its employees or persons similar to employees that the creation of copies beyond the scope of this evaluation licence agreement is not permitted.

The USER is responsible for setting up the necessary infrastructure to ensure the intended operation of the SOFTWARE. The COMPANY is not obliged to provide any further information or advice in this respect.

It is the USER's responsibility to check the compatibility (i.e. the ability to interact with the USER's existing software and hardware infrastructure) and the functional scope of the SOFTWARE before using it against payment.

4.	Copyright

The COMPANY shall provide the USER with the SOFTWARE on a non-exclusive basis and for a unlimited period of time, content and territory, however, only for the evaluation purposes (within the meaning of section 24 (1) sentence 1 of the Austrian Copyright Act "Werknutzungsbewilligung"). The objective purpose of the business relationship is the evaluation of the SOFTWARE for the purpose of trial. Unless expressly agreed otherwise, the SOFTWARE may also be used for commercial purposes. The exclusive right to use and exploit the SOFTWARE (within the meaning of section 24 (1) sentence 2 UrhG "Werknutzungsrecht") shall in any case remain with the COMPANY.

The USER is permitted to use the SOFTWARE exclusively for the evaluation purposes intended by the COMPANY.

Please note that the evaluation license does not grant the USER the right to use the SOFTWARE in its entirety.

Sub-licensing or further licensing is only permitted with the express consent of the COMPANY. 

The right to decompile the SOFTWARE is excluded.

Markings of the SOFTWARE, in particular copyright notices, trademarks, serial numbers or similar may not be removed, changed or made unrecognisable.

The surrender of the source code of the SOFTWARE is not owed. Neither is a user manual owed, nor the performance of training courses.

5.	Use of open source components

The SOFTWARE developed and provided by the COMPANY contains components that are licensed as Open Source Software. The OSS components may only be used under the respective OSS licence conditions. The OSS components are listed in Annex I. The source code of the OSS components (see „Readme“ in Annex I), the respective licence texts, any copyright notices and their disclaimers shall be made available to the CUSTOMER via link in Annex I.

Upon request by the CUSTOMER, the open source code can also be transmitted on a permanent data carrier (e.g. USB stick).

Attention: With regard to the OSS components used, the contractual partner of the CUSTOMER is not the COMPANY, but the respective open source licensor.

Attention: The COMPANY draws attention to the fact that risks are associated with the use of OSS components. As - demonstrative - examples are to be mentioned: Because the source code of the OSS components is public, it is susceptible to security incidents; furthermore, permanent maintenance and use of the OSS components is not ensured; warranty and damage claims are largely excluded.

6.	Restriction of the duty to make available

Since no paid version is owed, the COMPANY is in no way obliged to make the SOFTWARE available. The COMPANY reserves the right to discontinue the SOFTWARE without notice.

7.	Limitation of liability and warranty

Since no paid version is owed, all warranty and liability claims against the COMPANY are excluded in their entirety. This shall not apply in the event of intentional damage.

8.	Right to amend the evaluation licence

The COMPANY shall be entitled to amend this Evaluation Licence Agreement at any time. The COMPANY shall inform the USER of such amendments by sending the amended Evaluation Licence Agreement to the contact details last provided by the USER. The USER shall have the right to object to the amendments. If the USER does not object within 14 days after notification of the amendments, it shall be assumed that the USER has tacitly agreed to the amended evaluation licence agreement.

9.	Data protection and protection of business and trade secrets

The disclosure of data and information to the respective required business partners is permitted to the extent necessary for the fulfilment of the contractual relationship (Art 6 para 1 lit b GDPR). Otherwise, the COMPANY and the USER shall be mutually obliged to maintain secrecy with regard to the circumstances and data relating to the other of which they become aware as a result of the present business relationship and, in particular, to observe data secrecy. These obligations regarding data and business secrecy shall also apply beyond the contractual relationship. The COMPANY and the USER further undertake to instruct and instruct their employees and vicarious agents in this sense.

The contracting parties further undertake to protect mutually disclosed business and trade secrets appropriately within the meaning of section 26b (1) no. 3 of the Austrian UWG.

A violation of the confidentiality obligations may (among other things) result in consequences under criminal law and damages law.

It is pointed out that the source code programmed by the COMPANY constitutes a trade and business secret within the meaning of section 26b UWG. 

The COMPANY informs that data of the USER may be processed for advertising purposes on the basis of legitimate interests (Art 6 para 1 lit f DSGVO). The USER is entitled to object to the processing of his/her data for advertising purposes (Art 21 (2) GDPR).

10.	Reference-Clause

The COMPANY shall be entitled to indicate the fact of the business relationship with the USER by means of a reference on its homepage or business papers. The COMPANY shall be entitled to use the USER's logo in this context. This right to name references also extends beyond the contractual relationship.

11.	Participation in evaluations

For the purpose of evaluating the SOFTWARE, the USER undertakes to provide the COMPANY with information on the user-friendliness and performance of the SOFTWARE to a reasonable extent free of charge upon request by the COMPANY and, if necessary, to communicate any suggestions for improvement.

12.	Blocking access to the SOFTWARE

If the COMPANY has reasonable grounds to believe that the USER or one of its end users is using the SOFTWARE in an unlawful manner, the COMPANY shall be entitled to block access to the SOFTWARE immediately and without prior notice. This shall not affect the possibility of further legal remedies.

13.	Jurisdiction and applicable law

This contractual relationship shall be governed by and construed in accordance with Austrian law. The application of the United Nations Convention on Contracts for the International Sale of Goods (CISG) and of conflict-of-law rules is excluded. 

The exclusive place of jurisdiction is the competent court in Korneuburg, Austria.

14.	Further issues

If any part of this Evaluation Licence Agreement should be invalid, the validity of the remaining conditions shall not be affected thereby. The invalid provision shall be replaced by a valid provision which comes as close as possible to the economic intent of both contracting parties as discernible from the agreement.

The COMPANY recommends the USER to save this licence agreement permanently.


 
ANNEX I Open Source:

sindresorhus/Defaults:

Function	Library to persist user settings
Licence	MIT-License: https://github.com/sindresorhus/Defaults/blob/main/license
Readme	https://github.com/sindresorhus/Defaults
Disclaimer	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyrights	Sindre Sorhus

sindresorhus/LaunchAtLogin:

Function	Provides launch at login functionality
Licence	MIT-License: https://github.com/sindresorhus/LaunchAtLogin/blob/main/license
Readme	https://github.com/sindresorhus/LaunchAtLogin
Disclaimer	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyrights	Sindre Sorhus

sindresorhus/Preferences:

Function	Preference window library
Licence	MIT-License: https://github.com/sindresorhus/Preferences/blob/main/license
Readme	https://github.com/sindresorhus/Preferences
Disclaimer	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyrights	Sindre Sorhus

sparkle-project/Sparkle

Function	Framework for automatic app updates
Licence	https://github.com/sparkle-project/Sparkle/blob/2.x/LICENSE
Readme	https://github.com/sparkle-project/Sparkle
Disclaimer	THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyrights	Copyright (c) 2006-2013 Andy Matuschak.
Copyright (c) 2009-2013 Elgato Systems GmbH.
Copyright (c) 2011-2014 Kornel Lesiński.
Copyright (c) 2015-2017 Mayur Pawashe.
Copyright (c) 2014 C.W. Betts.
Copyright (c) 2014 Petroules Corporation.
Copyright (c) 2014 Big Nerd Ranch.

=================
EXTERNAL LICENSES
=================

bspatch.c and bsdiff.c, from bsdiff 4.3
Copyright (c) 2003-2005 Colin Percival.

sais.c and sais.c, from sais-lite (2010/08/07) 
Copyright (c) 2008-2010 Yuta Mori.

SUSignatureVerifier.m:
Copyright (c) 2011 Mark Hamlin.


Beltex/SMCKit

Function	Interface to access the System Management Controller
Licence	MIT-License: https://github.com/beltex/SMCKit/blob/master/LICENSE
Readme	https://github.com/beltex/SMCKit
Disclaimer	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyrights	beltex



================================================
FILE: README.md
================================================
<div align="center">
    <img src="AlDente/Assets.xcassets/AppIcon.appiconset/512pt_Mac_1x.png" width=200 height=200>
    <h1>AlDente - Battery Care & Monitoring</h1>
</div>

_MacOS menu bar tool to limit maximum charging percentage and improve battery lifespan_

#### Don't overcook your battery! Keep it fresh and chewy with AlDente.

## Why do I need this?
Li-Ion batteries (like the one in your MacBook) last the longest when operating between 20 and 80 percent. Keeping your battery at 100% at all times can shorten the lifespan of your MacBook significantly.
More information can be found at [Battery University](https://batteryuniversity.com/article/bu-415-how-to-charge-and-when-to-charge).

## What’s AlDente Pro?
AlDente Pro is our paid version of AlDente. It has many more features such as Heat Protection, Sailing Mode, Top Up, Calibration Mode,... It offers a better design and has live status icons. If you are interested in getting the most out of your battery, check out our [website](https://apphousekitchen.com/).

AlDente Pro is now available on [Setapp](https://apphousekitchen.com/pricing/) too.

## Features of AlDente Free
* Charge Limiter allows you to set your maximum charging percentage between 20 and 100 percent. You can either set it by using the slide bar or by typing in the desired percentage in the field above and pressing Enter afterwards. Read more about the Charge Limiter feature in this article ["Feature Explanation: Charge Limiter"](https://apphousekitchen.com/feature-explanation-charge-limiter/).
* Discharge - This feature allows your MacBook to run completely on Battery even if it is plugged in. Therefore, you can actively discharge your MacBook to a healthier percentage. Unfortunately, while Discharge is activated, clamshell mode is not supported due to technical limitations. Read more about the Discharge feature in this article ["Feature Explanation: Discharge"](https://apphousekitchen.com/feature-explanation-discharge/).

## Supported MacBook Models (macOS 11 Big Sur or later required)

Check out if your MacBook is supported on our [FAQ page](https://apphousekitchen.com/faq/).

## Download
You can download the app from GitHub: <https://github.com/davidwernhart/AlDente/releases>

## Installation Guide
An installation guide can be found on our website:[Installation Guide](https://apphousekitchen.com/installation-guide/)

## How to use
When the installation is finished, enter your desired max. charging percentage by clicking on the AlDente icon on your menu bar. Usually, the operating system will take a minute or two to register the changes, so be patient. You can check if it's working by setting the max. percentage to e.g., 80%. After a while, clicking on your battery icon will report "Battery is not charging" if you have more than ≈73% left, even though your charger is connected. Notice that in this state, your MacBook is still powered by the charger, but the battery is bypassed and not charging anymore.

IMPORTANT: Keeping your battery at a lower percentage, such as under 80%, for weeks without doing full cycles (100%-0%) can result in a disturbed battery calibration. When this happens, your MacBook might turn off with 40-50% left, or your battery capacity will drop significantly. However, this is only due to a disturbed battery calibration and not because of a faulty or degraded battery. To avoid this issue, we recommend doing at least one full cycle (0%-100%) every two weeks. Even if your battery calibration gets disturbed, doing 4+ full cycles will recalibrate your battery, and the capacity will go up again.

## Support
* Most questions are already answered on our [FAQ page](https://apphousekitchen.com/faq/) or on our [blog](https://apphousekitchen.com/blog/). Check them out!
* E-mail support is only available for AlDente Pro customers. Check out our [support page](https://apphousekitchen.com/support/) if you want to contact us.
* Due to limited resources, we are not able to provide support to AlDente Free users or here on GitHub.

## Other tools used in this project:
* <https://github.com/beltex/SMCKit>
* <https://github.com/sindresorhus/LaunchAtLogin>
* <https://github.com/andreyvit/create-dmg>

## Closed‑Source Notice

This project is no longer open source. Although the GitHub repository contains legacy code and archived releases, the current version of the software is proprietary and closed‑source.

## Disclaimer:
I do not take any responsibility for any sort of damage as a result of using this tool! Although this had no negative side effects for me and thousands of others, AlDente still taps into some very low-level system functions that are not meant to be tampered with. Use it at your own risk!

Copyright(c) 2021 AppHouseKitchen

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

We release security updates for the latest version of **AlDente** here: https://github.com/AppHouseKitchen/AlDente-Charge-Limiter/releases

## Reporting a Vulnerability

We take the security of our software seriously. If you discover a security vulnerability, we appreciate your help in disclosing it to us in a responsible manner.

**How to Report**

- **Email:** Please send an email to [security@apphousekitchen.com](mailto:security@apphousekitchen.com).
- **Subject Line:** Use a clear and descriptive subject line, such as "Security Vulnerability in AlDente-Charge-Limiter".
- **Content:** Provide a detailed description of the vulnerability, including steps to reproduce it, the potential impact, and any suggested fixes.

**What to Expect**

- **Acknowledgment:** We will acknowledge receipt of your report within 48 hours.
- **Investigation:** Our team will investigate the issue and work on a fix.
- **Updates:** We will keep you informed about the progress of the investigation and remediation.
- **Disclosure:** Once the vulnerability is resolved, we will issue a patch and publicly disclose the issue, crediting you for the discovery if you wish.

**Guidelines**

- **Confidentiality:** Please do not disclose the vulnerability publicly until we have addressed it.
- **Legal:** You must not violate any laws or breach any agreements in the course of discovering and reporting vulnerabilities.

Thank you for helping us keep **AlDente** safe and secure for everyone!


================================================
FILE: SMJobBlessUtil.py
================================================
#! /usr/bin/python 
# 
#   File:       SMJobBlessUtil.py
# 
#   Contains:   Tool for checking and correcting apps that use SMJobBless.
# 
#   Written by: DTS
# 
#   Copyright:  Copyright (c) 2012 Apple Inc. All Rights Reserved.
# 
#   Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
#               ("Apple") in consideration of your agreement to the following
#               terms, and your use, installation, modification or
#               redistribution of this Apple software constitutes acceptance of
#               these terms.  If you do not agree with these terms, please do
#               not use, install, modify or redistribute this Apple software.
# 
#               In consideration of your agreement to abide by the following
#               terms, and subject to these terms, Apple grants you a personal,
#               non-exclusive license, under Apple's copyrights in this
#               original Apple software (the "Apple Software"), to use,
#               reproduce, modify and redistribute the Apple Software, with or
#               without modifications, in source and/or binary forms; provided
#               that if you redistribute the Apple Software in its entirety and
#               without modifications, you must retain this notice and the
#               following text and disclaimers in all such redistributions of
#               the Apple Software. Neither the name, trademarks, service marks
#               or logos of Apple Inc. may be used to endorse or promote
#               products derived from the Apple Software without specific prior
#               written permission from Apple.  Except as expressly stated in
#               this notice, no other rights or licenses, express or implied,
#               are granted by Apple herein, including but not limited to any
#               patent rights that may be infringed by your derivative works or
#               by other works in which the Apple Software may be incorporated.
# 
#               The Apple Software is provided by Apple on an "AS IS" basis. 
#               APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
#               WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
#               MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
#               THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
#               COMBINATION WITH YOUR PRODUCTS.
# 
#               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
#               INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
#               TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#               DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
#               OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
#               OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
#               OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
#               OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
#               SUCH DAMAGE.
# 

import sys
import os
import getopt
import subprocess
import plistlib
import operator

class UsageException (Exception):
    """
    Raised when the progam detects a usage issue; the top-level code catches this 
    and prints a usage message.
    """
    pass

class CheckException (Exception):
    """
    Raised when the "check" subcommand detects a problem; the top-level code catches 
    this and prints a nice error message.
    """
    def __init__(self, message, path=None):
        self.message = message
        self.path = path

def checkCodeSignature(programPath, programType):
    """Checks the code signature of the referenced program."""

    # Use the codesign tool to check the signature.  The second "-v" is required to enable 
    # verbose mode, which causes codesign to do more checking.  By default it does the minimum 
    # amount of checking ("Is the program properly signed?").  If you enabled verbose mode it 
    # does other sanity checks, which we definitely want.  The specific thing I'd like to 
    # detect is "Does the code satisfy its own designated requirement?" and I need to enable 
    # verbose mode to get that.

    args = [
        # "false", 
        "codesign", 
        "-v", 
        "-v",
        programPath
    ]
    try:
        subprocess.check_call(args, stderr=open("/dev/null"))
    except subprocess.CalledProcessError, e:
        raise CheckException("%s code signature invalid" % programType, programPath)
    
def readDesignatedRequirement(programPath, programType):
    """Returns the designated requirement of the program as a string."""
    args = [
        # "false", 
        "codesign", 
        "-d", 
        "-r", 
        "-", 
        programPath
    ]
    try:
        req = subprocess.check_output(args, stderr=open("/dev/null"))
    except subprocess.CalledProcessError, e:
        raise CheckException("%s designated requirement unreadable" % programType, programPath)

    reqLines = req.splitlines()
    if len(reqLines) != 1 or not req.startswith("designated => "):
        raise CheckException("%s designated requirement malformed" % programType, programPath)
    return reqLines[0][len("designated => "):]

def readInfoPlistFromPath(infoPath):
    """Reads an "Info.plist" file from the specified path."""
    try:
        info = plistlib.readPlist(infoPath)
    except:
        raise CheckException("'Info.plist' not readable", infoPath)
    if not isinstance(info, dict):
        raise CheckException("'Info.plist' root must be a dictionary", infoPath)
    return info
    
def readPlistFromToolSection(toolPath, segmentName, sectionName):
    """Reads a dictionary property list from the specified section within the specified executable."""
    
    # Run otool -s to get a hex dump of the section.
    
    args = [
        # "false", 
        "otool", 
        "-s", 
        segmentName, 
        sectionName, 
        toolPath
    ]
    try:
        plistDump = subprocess.check_output(args)
    except subprocess.CalledProcessError, e:
        raise CheckException("tool %s / %s section unreadable" % (segmentName, sectionName), toolPath)

    # Convert that hex dump to an property list.
    
    plistLines = plistDump.splitlines()
    if len(plistLines) < 3 or plistLines[1] != ("Contents of (%s,%s) section" % (segmentName, sectionName)):
        raise CheckException("tool %s / %s section dump malformed (1)" % (segmentName, sectionName), toolPath)
    del plistLines[0:2]

    try:
        bytes = []
        for line in plistLines:
            # line looks like this:
            #
            # '0000000100000b80\t3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 '
            columns = line.split("\t")
            assert len(columns) == 2
            for hexStr in columns[1].split():
                bytes.append(int(hexStr, 16))
        plist = plistlib.readPlistFromString(bytearray(bytes))
    except:
        raise CheckException("tool %s / %s section dump malformed (2)" % (segmentName, sectionName), toolPath)

    # Check the root of the property list.
    
    if not isinstance(plist, dict):
        raise CheckException("tool %s / %s property list root must be a dictionary" % (segmentName, sectionName), toolPath)

    return plist
    
def checkStep1(appPath):
    """Checks that the app and the tool are both correctly code signed."""
    
    if not os.path.isdir(appPath):
        raise CheckException("app not found", appPath)
    
    # Check the app's code signature.
        
    checkCodeSignature(appPath, "app")
    
    # Check the tool directory.
    
    toolDirPath = os.path.join(appPath, "Contents", "Library", "LaunchServices")
    if not os.path.isdir(toolDirPath):
        raise CheckException("tool directory not found", toolDirPath)

    # Check each tool's code signature.
    
    toolPathList = []
    for toolName in os.listdir(toolDirPath):
        if toolName != ".DS_Store":
            toolPath = os.path.join(toolDirPath, toolName)
            if not os.path.isfile(toolPath):
                raise CheckException("tool directory contains a directory", toolPath)
            checkCodeSignature(toolPath, "tool")
            toolPathList.append(toolPath)

    # Check that we have at least one tool.
    
    if len(toolPathList) == 0:
        raise CheckException("no tools found", toolDirPath)

    return toolPathList
    
def checkStep2(appPath, toolPathList):
    """Checks the SMPrivilegedExecutables entry in the app's "Info.plist"."""

    # Create a map from the tool name (not path) to its designated requirement.
    
    toolNameToReqMap = dict()
    for toolPath in toolPathList:
        req = readDesignatedRequirement(toolPath, "tool")
        toolNameToReqMap[os.path.basename(toolPath)] = req
    
    # Read the Info.plist for the app and extract the SMPrivilegedExecutables value.
    
    infoPath = os.path.join(appPath, "Contents", "Info.plist")
    info = readInfoPlistFromPath(infoPath)
    if not info.has_key("SMPrivilegedExecutables"):
        raise CheckException("'SMPrivilegedExecutables' not found", infoPath)
    infoToolDict = info["SMPrivilegedExecutables"]
    if not isinstance(infoToolDict, dict):
        raise CheckException("'SMPrivilegedExecutables' must be a dictionary", infoPath)
    
    # Check that the list of tools matches the list of SMPrivilegedExecutables entries.
    
    if sorted(infoToolDict.keys()) != sorted(toolNameToReqMap.keys()):
        raise CheckException("'SMPrivilegedExecutables' and tools in 'Contents/Library/LaunchServices' don't match")
    
    # Check that all the requirements match.
    
    # This is an interesting policy choice.  Technically the tool just needs to match 
    # the requirement listed in SMPrivilegedExecutables, and we can check that by 
    # putting the requirement into tmp.req and then running
    #
    # $ codesign -v -R tmp.req /path/to/tool
    #
    # However, for a Developer ID signed tool we really want to have the SMPrivilegedExecutables 
    # entry contain the tool's designated requirement because Xcode has built a 
    # more complex DR that does lots of useful and important checks.  So, as a matter 
    # of policy we require that the value in SMPrivilegedExecutables match the tool's DR.
    
    for toolName in infoToolDict:
        if infoToolDict[toolName] != toolNameToReqMap[toolName]:
            raise CheckException("tool designated requirement (%s) doesn't match entry in 'SMPrivilegedExecutables' (%s)" % (toolNameToReqMap[toolName], infoToolDict[toolName]))

def checkStep3(appPath, toolPathList):
    """Checks the "Info.plist" embedded in each helper tool."""

    # First get the app's designated requirement.
    
    appReq = readDesignatedRequirement(appPath, "app")

    # Then check that the tool's SMAuthorizedClients value matches it. 
        
    for toolPath in toolPathList:
        info = readPlistFromToolSection(toolPath, "__TEXT", "__info_plist")

        if not info.has_key("CFBundleInfoDictionaryVersion") or info["CFBundleInfoDictionaryVersion"] != "6.0":
            raise CheckException("'CFBundleInfoDictionaryVersion' in tool __TEXT / __info_plist section must be '6.0'", toolPath)

        if not info.has_key("CFBundleIdentifier") or info["CFBundleIdentifier"] != os.path.basename(toolPath):
            raise CheckException("'CFBundleIdentifier' in tool __TEXT / __info_plist section must match tool name", toolPath)

        if not info.has_key("SMAuthorizedClients"):
            raise CheckException("'SMAuthorizedClients' in tool __TEXT / __info_plist section not found", toolPath)
        infoClientList = info["SMAuthorizedClients"]
        if not isinstance(infoClientList, list):
            raise CheckException("'SMAuthorizedClients' in tool __TEXT / __info_plist section must be an array", toolPath)
        if len(infoClientList) != 1:
            raise CheckException("'SMAuthorizedClients' in tool __TEXT / __info_plist section must have one entry", toolPath)
            
        # Again, as a matter of policy we require that the SMAuthorizedClients entry must 
        # match exactly the designated requirement of the app.

        if infoClientList[0] != appReq:
            raise CheckException("app designated requirement (%s) doesn't match entry in 'SMAuthorizedClients' (%s)" % (appReq, infoClientList[0]), toolPath)

def checkStep4(appPath, toolPathList):
    """Checks the "launchd.plist" embedded in each helper tool."""

    for toolPath in toolPathList:
        launchd = readPlistFromToolSection(toolPath, "__TEXT", "__launchd_plist")

        if not launchd.has_key("Label") or launchd["Label"] != os.path.basename(toolPath):
            raise CheckException("'Label' in tool __TEXT / __launchd_plist section must match tool name", toolPath)

        # We don't need to check that the label matches the bundle identifier because 
        # we know it matches the tool name and step 4 checks that the tool name matches 
        # the bundle identifier.

def checkStep5(appPath):
    """There's nothing to do here; we effectively checked for this is steps 1 and 2."""
    pass
    
def check(appPath):
    """Checks the SMJobBless setup of the specified app."""

    # Each of the following steps matches a bullet point in the SMJobBless header doc.
    
    toolPathList = checkStep1(appPath)

    checkStep2(appPath, toolPathList)

    checkStep3(appPath, toolPathList)

    checkStep4(appPath, toolPathList)

    checkStep5(appPath)

def setreq(appPath, appInfoPlistPath, toolInfoPlistPaths):
    """
    Reads information from the built app and uses it to set the SMJobBless setup 
    in the specified app and tool Info.plist source files.
    """

    if not os.path.isdir(appPath):
        raise CheckException("app not found", appPath)

    if not os.path.isfile(appInfoPlistPath):
        raise CheckException("app 'Info.plist' not found", appInfoPlistPath)
    for toolInfoPlistPath in toolInfoPlistPaths:
        if not os.path.isfile(toolInfoPlistPath):
            raise CheckException("app 'Info.plist' not found", toolInfoPlistPath)

    # Get the designated requirement for the app and each of the tools.
    
    appReq = readDesignatedRequirement(appPath, "app")

    toolDirPath = os.path.join(appPath, "Contents", "Library", "LaunchServices")
    if not os.path.isdir(toolDirPath):
        raise CheckException("tool directory not found", toolDirPath)
    
    toolNameToReqMap = {}
    for toolName in os.listdir(toolDirPath):
        req = readDesignatedRequirement(os.path.join(toolDirPath, toolName), "tool")
        toolNameToReqMap[toolName] = req

    if len(toolNameToReqMap) > len(toolInfoPlistPaths):
        raise CheckException("tool directory has more tools (%d) than you've supplied tool 'Info.plist' paths (%d)" % (len(toolNameToReqMap), len(toolInfoPlistPaths)), toolDirPath)
    if len(toolNameToReqMap) < len(toolInfoPlistPaths):
        raise CheckException("tool directory has fewer tools (%d) than you've supplied tool 'Info.plist' paths (%d)" % (len(toolNameToReqMap), len(toolInfoPlistPaths)), toolDirPath)

    # Build the new value for SMPrivilegedExecutables.
    
    appToolDict = {}
    toolInfoPlistPathToToolInfoMap = {}
    for toolInfoPlistPath in toolInfoPlistPaths:
        toolInfo = readInfoPlistFromPath(toolInfoPlistPath)
        toolInfoPlistPathToToolInfoMap[toolInfoPlistPath] = toolInfo
        if not toolInfo.has_key("CFBundleIdentifier"):
            raise CheckException("'CFBundleIdentifier' not found", toolInfoPlistPath)
        bundleID = toolInfo["CFBundleIdentifier"]
        if not isinstance(bundleID, basestring):
            raise CheckException("'CFBundleIdentifier' must be a string", toolInfoPlistPath)
        appToolDict[bundleID] = toolNameToReqMap[bundleID]

    # Set the SMPrivilegedExecutables value in the app "Info.plist".

    appInfo = readInfoPlistFromPath(appInfoPlistPath)
    needsUpdate = not appInfo.has_key("SMPrivilegedExecutables")
    if not needsUpdate:
        oldAppToolDict = appInfo["SMPrivilegedExecutables"]
        if not isinstance(oldAppToolDict, dict):
            raise CheckException("'SMPrivilegedExecutables' must be a dictionary", appInfoPlistPath)
        appToolDictSorted = sorted(appToolDict.iteritems(), key=operator.itemgetter(0))
        oldAppToolDictSorted = sorted(oldAppToolDict.iteritems(), key=operator.itemgetter(0))
        needsUpdate = (appToolDictSorted != oldAppToolDictSorted)
    
    if needsUpdate:
        appInfo["SMPrivilegedExecutables"] = appToolDict
        plistlib.writePlist(appInfo, appInfoPlistPath)
        print >> sys.stdout, "%s: updated" % appInfoPlistPath
    
    # Set the SMAuthorizedClients value in each tool's "Info.plist".

    toolAppListSorted = [ appReq ]      # only one element, so obviously sorted (-:
    for toolInfoPlistPath in toolInfoPlistPaths:
        toolInfo = toolInfoPlistPathToToolInfoMap[toolInfoPlistPath]
        
        needsUpdate = not toolInfo.has_key("SMAuthorizedClients")
        if not needsUpdate:
            oldToolAppList = toolInfo["SMAuthorizedClients"]
            if not isinstance(oldToolAppList, list):
                raise CheckException("'SMAuthorizedClients' must be an array", toolInfoPlistPath)
            oldToolAppListSorted = sorted(oldToolAppList)
            needsUpdate = (toolAppListSorted != oldToolAppListSorted)
        
        if needsUpdate:
            toolInfo["SMAuthorizedClients"] = toolAppListSorted
            plistlib.writePlist(toolInfo, toolInfoPlistPath)
            print >> sys.stdout, "%s: updated" % toolInfoPlistPath

def main():
    options, appArgs = getopt.getopt(sys.argv[1:], "d")
    
    debug = False
    for opt, val in options:
        if opt == "-d":
            debug = True
        else:
            raise UsageException()

    if len(appArgs) == 0:
        raise UsageException()
    command = appArgs[0]
    if command == "check":
        if len(appArgs) != 2:
            raise UsageException()
        check(appArgs[1])
    elif command == "setreq":
        if len(appArgs) < 4:
            raise UsageException()
        setreq(appArgs[1], appArgs[2], appArgs[3:])
    else:
        raise UsageException()

if __name__ == "__main__":
    try:
        main()
    except CheckException, e:
        if e.path is None:
            print >> sys.stderr, "%s: %s" % (os.path.basename(sys.argv[0]), e.message)
        else:
            path = e.path
            if path.endswith("/"):
                path = path[:-1]
            print >> sys.stderr, "%s: %s" % (path, e.message)
        sys.exit(1)
    except UsageException, e:
        print >> sys.stderr, "usage: %s check  /path/to/app" % os.path.basename(sys.argv[0])
        print >> sys.stderr, "       %s setreq /path/to/app /path/to/app/Info.plist /path/to/tool/Info.plist..." % os.path.basename(sys.argv[0])
        sys.exit(1)


================================================
FILE: com.davidwernhart.Helper/Helper-Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleIdentifier</key>
	<string>com.davidwernhart.Helper</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>com.davidwernhart.Helper</string>
	<key>CFBundleVersion</key>
	<string>10</string>
	<key>SMAuthorizedClients</key>
	<array>
		<string>identifier "com.davidwernhart.AlDente" and anchor apple generic and certificate leaf[subject.CN] = "Apple Development: david.wernhart96@gmail.com (GSDX9BQ584)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */</string>
	</array>
</dict>
</plist>


================================================
FILE: com.davidwernhart.Helper/Helper-Launchd.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.davidwernhart.Helper</string>
    <key>MachServices</key>
    <dict>
        <key>com.davidwernhart.Helper.mach</key>
        <true/>
    </dict>
</dict>
</plist>


================================================
FILE: com.davidwernhart.Helper/HelperTool.swift
================================================
//
//  HelperTool.swift
//  com.davidwernhart.Helper
//
//  Created by David Wernhart on 13.02.20.
//  Copyright © 2020 David Wernhart. All rights reserved.
//

import Foundation
import IOKit.pwr_mgt

final class HelperTool: NSObject, HelperToolProtocol {
    
    static let instance = HelperTool()
    
    var modifiedKeys: [String: UInt8] = [:]
    var openAssertions: [IOPMAssertionID] = []
    
    func getVersion(withReply reply: (String) -> Void) {
//        let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString" as String) as? String ?? "(unknown version)"
//        let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String ?? "(unknown build)"
//        reply("v\(version) (\(build))")
        reply(helperVersion)

    }

    func setSMCByte(key: String, value: UInt8) {
        do {
            try SMCKit.open()
        } catch {
            print(error)
            exit(EX_UNAVAILABLE)
        }
        let smcKey = SMCKit.getKey(key, type: DataTypes.UInt8)
        let bytes: SMCBytes = (value, UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
        UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
        UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
        UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
        UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
        UInt8(0), UInt8(0))
        
        if(self.modifiedKeys[key] == nil){
            readSMCByte(key: key) { (originalValue) in
                self.modifiedKeys[key] = originalValue
                _ = try? SMCKit.writeData(smcKey, data: bytes)
            }
        }
        else{
            _ = try? SMCKit.writeData(smcKey, data: bytes)
        }

        
    }

    func readSMCByte(key: String, withReply reply: @escaping (UInt8) -> Void) {
        do {
            try SMCKit.open()
        } catch {
            print(error)
            exit(EX_UNAVAILABLE)
        }

        let smcKey = SMCKit.getKey(key, type: DataTypes.UInt8)
        do {
            let status = try SMCKit.readData(smcKey).0
            reply(status)
        } catch {
            reply(0)
        }
    }
    
    func readSMCUInt32(key: String, withReply reply: @escaping (UInt32) -> Void) {
        do {
            try SMCKit.open()
        } catch {
            print(error)
            exit(EX_UNAVAILABLE)
        }

        let smcKey = SMCKit.getKey(key, type: DataTypes.UInt32)
        do {
            let data = try SMCKit.readData(smcKey)
            reply(UInt32(fromBytes: (data.0, data.1, data.2, data.3)))
        } catch {
            reply(0)
        }
    }
    
    func createAssertion(assertion:String, withReply reply: @escaping (IOPMAssertionID) -> Void){
        var assertionID : IOPMAssertionID = IOPMAssertionID(0)
        let reason:CFString = "AlDente" as NSString
        let cfAssertion:CFString = assertion as NSString
        let success = IOPMAssertionCreateWithName(cfAssertion,
                        IOPMAssertionLevel(kIOPMAssertionLevelOn),
                        reason,
                        &assertionID)
        if success == kIOReturnSuccess {
            openAssertions.append(assertionID)
            reply(assertionID)
        }
        else{
            reply (UInt32(kCFNumberNaN))
        }
    }
    
    func releaseAssertion(assertionID:IOPMAssertionID){
        IOPMAssertionRelease(assertionID)
        openAssertions.remove(at: openAssertions.firstIndex(of: assertionID)!)
    }
    
    func setResetVal(key:String, value: UInt8){
        modifiedKeys[key]=value
    }
    
    func reset(){
        for (key, value) in modifiedKeys{
            setSMCByte(key: key, value: value)
        }
        
        for assertionID in openAssertions{
            releaseAssertion(assertionID: assertionID)
        }
        modifiedKeys.removeAll()
        openAssertions.removeAll()
    }
}


================================================
FILE: com.davidwernhart.Helper/SMC.swift
================================================
//
// SMC.swift
// SMCKit
//
// The MIT License
//
// Copyright (C) 2014-2017  beltex <https://beltex.github.io>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import IOKit
import Foundation
import os

//------------------------------------------------------------------------------
// MARK: Type Aliases
//------------------------------------------------------------------------------

// http://stackoverflow.com/a/22383661

/// Floating point, unsigned, 14 bits exponent, 2 bits fraction
public typealias FPE2 = (UInt8, UInt8)

/// Floating point, signed, 7 bits exponent, 8 bits fraction
public typealias SP78 = (UInt8, UInt8)

public typealias SMCBytes = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
                             UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
                             UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
                             UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
                             UInt8, UInt8, UInt8, UInt8)

//------------------------------------------------------------------------------
// MARK: Standard Library Extensions
//------------------------------------------------------------------------------

extension UInt32 {

    init(fromBytes bytes: (UInt8, UInt8, UInt8, UInt8)) {
        // TODO: Broken up due to "Expression was too complex" error as of
        //       Swift 4.

        let byte0 = UInt32(bytes.0) << 24
        let byte1 = UInt32(bytes.1) << 16
        let byte2 = UInt32(bytes.2) << 8
        let byte3 = UInt32(bytes.3)

        self = byte0 | byte1 | byte2 | byte3
    }
}

extension Bool {

    init(fromByte byte: UInt8) {
        self = byte == 1 ? true : false
    }
}

public extension Int {

    init(fromFPE2 bytes: FPE2) {
        self = (Int(bytes.0) << 6) + (Int(bytes.1) >> 2)
    }

    func toFPE2() -> FPE2 {
        return (UInt8(self >> 6), UInt8((self << 2) ^ ((self >> 6) << 8)))
    }
}

extension Double {

    init(fromSP78 bytes: SP78) {
        // FIXME: Handle second byte
        let sign = bytes.0 & 0x80 == 0 ? 1.0 : -1.0
        self = sign * Double(bytes.0 & 0x7F)    // AND to mask sign bit
    }
}

// Thanks to Airspeed Velocity for the great idea!
// http://airspeedvelocity.net/2015/05/22/my-talk-at-swift-summit/
public extension FourCharCode {

    init(fromString str: String) {
        precondition(str.count == 4)

        self = str.utf8.reduce(0) { sum, character in
            return sum << 8 | UInt32(character)
        }
    }

    init(fromStaticString str: StaticString) {
        precondition(str.utf8CodeUnitCount == 4)

        self = str.withUTF8Buffer { buffer in
            // TODO: Broken up due to "Expression was too complex" error as of
            //       Swift 4.

            let byte0 = UInt32(buffer[0]) << 24
            let byte1 = UInt32(buffer[1]) << 16
            let byte2 = UInt32(buffer[2]) << 8
            let byte3 = UInt32(buffer[3])

            return byte0 | byte1 | byte2 | byte3
        }
    }

    func toString() -> String {
        return String(describing: UnicodeScalar(self >> 24 & 0xff)!) +
               String(describing: UnicodeScalar(self >> 16 & 0xff)!) +
               String(describing: UnicodeScalar(self >> 8  & 0xff)!) +
               String(describing: UnicodeScalar(self       & 0xff)!)
    }
}

//------------------------------------------------------------------------------
// MARK: Defined by AppleSMC.kext
//------------------------------------------------------------------------------

/// Defined by AppleSMC.kext
///
/// This is the predefined struct that must be passed to communicate with the
/// AppleSMC driver. While the driver is closed source, the definition of this
/// struct happened to appear in the Apple PowerManagement project at around
/// version 211, and soon after disappeared. It can be seen in the PrivateLib.c
/// file under pmconfigd. Given that it is C code, this is the closest
/// translation to Swift from a type perspective.
///
/// ### Issues
///
/// * Padding for struct alignment when passed over to C side
/// * Size of struct must be 80 bytes
/// * C array's are bridged as tuples
///
/// http://www.opensource.apple.com/source/PowerManagement/PowerManagement-211/
public struct SMCParamStruct {

    /// I/O Kit function selector
    public enum Selector: UInt8 {
        case kSMCHandleYPCEvent  = 2
        case kSMCReadKey         = 5
        case kSMCWriteKey        = 6
        case kSMCGetKeyFromIndex = 8
        case kSMCGetKeyInfo      = 9
    }

    /// Return codes for SMCParamStruct.result property
    public enum Result: UInt8 {
        case kSMCSuccess     = 0
        case kSMCError       = 1
        case kSMCKeyNotFound = 132
    }

    public struct SMCVersion {
        var major: CUnsignedChar = 0
        var minor: CUnsignedChar = 0
        var build: CUnsignedChar = 0
        var reserved: CUnsignedChar = 0
        var release: CUnsignedShort = 0
    }

    public struct SMCPLimitData {
        var version: UInt16 = 0
        var length: UInt16 = 0
        var cpuPLimit: UInt32 = 0
        var gpuPLimit: UInt32 = 0
        var memPLimit: UInt32 = 0
    }

    public struct SMCKeyInfoData {
        /// How many bytes written to SMCParamStruct.bytes
        //var dataSize: IOByteCount = 0
        var dataSize:UInt32 = 0

        /// Type of data written to SMCParamStruct.bytes. This lets us know how
        /// to interpret it (translate it to human readable)
        var dataType: UInt32 = 0

        var dataAttributes: UInt8 = 0
    }

    /// FourCharCode telling the SMC what we want
    var key: UInt32 = 0

    var vers = SMCVersion()

    var pLimitData = SMCPLimitData()

    var keyInfo = SMCKeyInfoData()

    /// Padding for struct alignment when passed over to C side
    var padding: UInt16 = 0

    /// Result of an operation
    var result: UInt8 = 0

    var status: UInt8 = 0

    /// Method selector
    var data8: UInt8 = 0

    var data32: UInt32 = 0

    /// Data returned from the SMC
    var bytes: SMCBytes = (UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                           UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                           UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                           UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                           UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                           UInt8(0), UInt8(0))
}

//------------------------------------------------------------------------------
// MARK: SMC Client
//------------------------------------------------------------------------------

/// SMC data type information
public struct DataTypes {

    /// Fan information struct
    public static let FDS =
                DataType(type: FourCharCode(fromStaticString: "{fds"), size: 16)
    public static let Flag =
                 DataType(type: FourCharCode(fromStaticString: "flag"), size: 1)
    /// See type aliases
    public static let FPE2 =
                 DataType(type: FourCharCode(fromStaticString: "fpe2"), size: 2)
    /// See type aliases
    public static let SP78 =
                 DataType(type: FourCharCode(fromStaticString: "sp78"), size: 2)
    public static let UInt8 =
                 DataType(type: FourCharCode(fromStaticString: "ui8 "), size: 1)
    public static let UInt32 =
                 DataType(type: FourCharCode(fromStaticString: "ui32"), size: 4)
}

public struct SMCKey {
    let code: FourCharCode
    let info: DataType
}

public struct DataType: Equatable {
    let type: FourCharCode
    let size: IOByteCount
}

public func ==(lhs: DataType, rhs: DataType) -> Bool {
    return lhs.type == rhs.type && lhs.size == rhs.size
}

/// Apple System Management Controller (SMC) user-space client for Intel-based
/// Macs. Works by talking to the AppleSMC.kext (kernel extension), the closed
/// source driver for the SMC.
public struct SMCKit {

    public enum SMCError: Error {

        /// AppleSMC driver not found
        case driverNotFound

        /// Failed to open a connection to the AppleSMC driver
        case failedToOpen

        /// This SMC key is not valid on this machine
        case keyNotFound(code: String)

        /// Requires root privileges
        case notPrivileged

        /// Fan speed must be > 0 && <= fanMaxSpeed
        case unsafeFanSpeed

        /// https://developer.apple.com/library/mac/qa/qa1075/_index.html
        ///
        /// - parameter kIOReturn: I/O Kit error code
        /// - parameter SMCResult: SMC specific return code
        case unknown(kIOReturn: kern_return_t, SMCResult: UInt8)
    }

    /// Connection to the SMC driver
    fileprivate static var connection: io_connect_t = 0

    /// Open connection to the SMC driver. This must be done first before any
    /// other calls
    public static func open() throws {
        let service = IOServiceGetMatchingService(kIOMasterPortDefault,
                                                  IOServiceMatching("AppleSMC"))

        if service == 0 { throw SMCError.driverNotFound }

        let result = IOServiceOpen(service, mach_task_self_, 0,
                                   &SMCKit.connection)
        IOObjectRelease(service)

        if result != kIOReturnSuccess { throw SMCError.failedToOpen }
    }

    /// Close connection to the SMC driver
    @discardableResult
    public static func close() -> Bool {
        let result = IOServiceClose(SMCKit.connection)
        return result == kIOReturnSuccess ? true : false
    }

    /// Get information about a key
    public static func keyInformation(_ key: FourCharCode) throws -> DataType {
        var inputStruct = SMCParamStruct()

        inputStruct.key = key
        inputStruct.data8 = SMCParamStruct.Selector.kSMCGetKeyInfo.rawValue

        let outputStruct = try callDriver(&inputStruct)

        return DataType(type: outputStruct.keyInfo.dataType,
                        size: IOByteCount(outputStruct.keyInfo.dataSize))
    }

    /// Get information about the key at index
    public static func keyInformationAtIndex(_ index: Int) throws ->
                                                                  FourCharCode {
        var inputStruct = SMCParamStruct()

        inputStruct.data8 = SMCParamStruct.Selector.kSMCGetKeyFromIndex.rawValue
        inputStruct.data32 = UInt32(index)

        let outputStruct = try callDriver(&inputStruct)

        return outputStruct.key
    }

    public static func getKey(_ code: String, type: DataType) -> SMCKey {
        let key = SMCKey(code: FourCharCode(fromString: code), info: type)
        return key
    }

    /// Read data of a key
    public static func readData(_ key: SMCKey) throws -> SMCBytes {
        var inputStruct = SMCParamStruct()

        inputStruct.key = key.code
        inputStruct.keyInfo.dataSize = UInt32(IOByteCount(key.info.size))
        inputStruct.data8 = SMCParamStruct.Selector.kSMCReadKey.rawValue

        let outputStruct = try callDriver(&inputStruct)

        return outputStruct.bytes
    }

    /// Write data for a key
    public static func writeData(_ key: SMCKey, data: SMCBytes) throws {
        var inputStruct = SMCParamStruct()

        inputStruct.key = key.code
        inputStruct.bytes = data
        inputStruct.keyInfo.dataSize = UInt32(IOByteCount(key.info.size))
        inputStruct.data8 = SMCParamStruct.Selector.kSMCWriteKey.rawValue

        _ = try callDriver(&inputStruct)
    }

    /// Make an actual call to the SMC driver
    public static func callDriver(_ inputStruct: inout SMCParamStruct,
                        selector: SMCParamStruct.Selector = .kSMCHandleYPCEvent)
                                                      throws -> SMCParamStruct {
        os_log("SMCPARAMSTRUCT SIZE: %d", MemoryLayout<SMCParamStruct>.stride)
        assert(MemoryLayout<SMCParamStruct>.stride == 80, "SMCParamStruct size is != 80")

        var outputStruct = SMCParamStruct()
        let inputStructSize = MemoryLayout<SMCParamStruct>.stride
        var outputStructSize = MemoryLayout<SMCParamStruct>.stride

        let result = IOConnectCallStructMethod(SMCKit.connection,
                                               UInt32(selector.rawValue),
                                               &inputStruct,
                                               inputStructSize,
                                               &outputStruct,
                                               &outputStructSize)

        switch (result, outputStruct.result) {
        case (kIOReturnSuccess, SMCParamStruct.Result.kSMCSuccess.rawValue):
            return outputStruct
        case (kIOReturnSuccess, SMCParamStruct.Result.kSMCKeyNotFound.rawValue):
            throw SMCError.keyNotFound(code: inputStruct.key.toString())
        case (kIOReturnNotPrivileged, _):
            throw SMCError.notPrivileged
        default:
            throw SMCError.unknown(kIOReturn: result,
                                SMCResult: outputStruct.result)
        }
    }
}

//------------------------------------------------------------------------------
// MARK: General
//------------------------------------------------------------------------------

extension SMCKit {

    /// Get all valid SMC keys for this machine
    public static func allKeys() throws -> [SMCKey] {
        let count = try keyCount()
        var keys = [SMCKey]()

        for i in 0 ..< count {
            let key = try keyInformationAtIndex(i)
            let info = try keyInformation(key)
            keys.append(SMCKey(code: key, info: info))
        }

        return keys
    }

    /// Get the number of valid SMC keys for this machine
    public static func keyCount() throws -> Int {
        let key = SMCKey(code: FourCharCode(fromStaticString: "#KEY"),
                         info: DataTypes.UInt32)

        let data = try readData(key)
        return Int(UInt32(fromBytes: (data.0, data.1, data.2, data.3)))
    }

    /// Is this key valid on this machine?
    public static func isKeyFound(_ code: FourCharCode) throws -> Bool {
        do {
            _ = try keyInformation(code)
        } catch SMCError.keyNotFound { return false }

        return true
    }
}

//------------------------------------------------------------------------------
// MARK: Temperature
//------------------------------------------------------------------------------

/// The list is NOT exhaustive. In addition, the names of the sensors may not be
/// mapped to the correct hardware component.
///
/// ### Sources
///
/// * powermetrics(1)
/// * https://www.apple.com/downloads/dashboard/status/istatpro.html
/// * https://github.com/hholtmann/smcFanControl
/// * https://github.com/jedda/OSX-Monitoring-Tools
/// * http://www.opensource.apple.com/source/net_snmp/
/// * http://www.parhelia.ch/blog/statics/k3_keys.html
public struct TemperatureSensors {

    public static let AMBIENT_AIR_0 = TemperatureSensor(name: "AMBIENT_AIR_0",
                                   code: FourCharCode(fromStaticString: "TA0P"))
    public static let AMBIENT_AIR_1 = TemperatureSensor(name: "AMBIENT_AIR_1",
                                   code: FourCharCode(fromStaticString: "TA1P"))
    // Via powermetrics(1)
    public static let CPU_0_DIE = TemperatureSensor(name: "CPU_0_DIE",
                                   code: FourCharCode(fromStaticString: "TC0F"))
    public static let CPU_0_DIODE = TemperatureSensor(name: "CPU_0_DIODE",
                                   code: FourCharCode(fromStaticString: "TC0D"))
    public static let CPU_0_HEATSINK = TemperatureSensor(name: "CPU_0_HEATSINK",
                                   code: FourCharCode(fromStaticString: "TC0H"))
    public static let CPU_0_PROXIMITY =
                                      TemperatureSensor(name: "CPU_0_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "TC0P"))
    public static let ENCLOSURE_BASE_0 =
                                     TemperatureSensor(name: "ENCLOSURE_BASE_0",
                                   code: FourCharCode(fromStaticString: "TB0T"))
    public static let ENCLOSURE_BASE_1 =
                                     TemperatureSensor(name: "ENCLOSURE_BASE_1",
                                   code: FourCharCode(fromStaticString: "TB1T"))
    public static let ENCLOSURE_BASE_2 =
                                     TemperatureSensor(name: "ENCLOSURE_BASE_2",
                                   code: FourCharCode(fromStaticString: "TB2T"))
    public static let ENCLOSURE_BASE_3 =
                                     TemperatureSensor(name: "ENCLOSURE_BASE_3",
                                   code: FourCharCode(fromStaticString: "TB3T"))
    public static let GPU_0_DIODE = TemperatureSensor(name: "GPU_0_DIODE",
                                   code: FourCharCode(fromStaticString: "TG0D"))
    public static let GPU_0_HEATSINK = TemperatureSensor(name: "GPU_0_HEATSINK",
                                   code: FourCharCode(fromStaticString: "TG0H"))
    public static let GPU_0_PROXIMITY =
                                      TemperatureSensor(name: "GPU_0_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "TG0P"))
    public static let HDD_PROXIMITY = TemperatureSensor(name: "HDD_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "TH0P"))
    public static let HEATSINK_0 = TemperatureSensor(name: "HEATSINK_0",
                                   code: FourCharCode(fromStaticString: "Th0H"))
    public static let HEATSINK_1 = TemperatureSensor(name: "HEATSINK_1",
                                   code: FourCharCode(fromStaticString: "Th1H"))
    public static let HEATSINK_2 = TemperatureSensor(name: "HEATSINK_2",
                                   code: FourCharCode(fromStaticString: "Th2H"))
    public static let LCD_PROXIMITY = TemperatureSensor(name: "LCD_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "TL0P"))
    public static let MEM_SLOT_0 = TemperatureSensor(name: "MEM_SLOT_0",
                                   code: FourCharCode(fromStaticString: "TM0S"))
    public static let MEM_SLOTS_PROXIMITY =
                                  TemperatureSensor(name: "MEM_SLOTS_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "TM0P"))
    public static let MISC_PROXIMITY = TemperatureSensor(name: "MISC_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "Tm0P"))
    public static let NORTHBRIDGE = TemperatureSensor(name: "NORTHBRIDGE",
                                   code: FourCharCode(fromStaticString: "TN0H"))
    public static let NORTHBRIDGE_DIODE =
                                    TemperatureSensor(name: "NORTHBRIDGE_DIODE",
                                   code: FourCharCode(fromStaticString: "TN0D"))
    public static let NORTHBRIDGE_PROXIMITY =
                                TemperatureSensor(name: "NORTHBRIDGE_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "TN0P"))
    public static let ODD_PROXIMITY = TemperatureSensor(name: "ODD_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "TO0P"))
    public static let PALM_REST = TemperatureSensor(name: "PALM_REST",
                                   code: FourCharCode(fromStaticString: "Ts0P"))
    public static let PWR_SUPPLY_PROXIMITY =
                                 TemperatureSensor(name: "PWR_SUPPLY_PROXIMITY",
                                   code: FourCharCode(fromStaticString: "Tp0P"))
    public static let THUNDERBOLT_0 = TemperatureSensor(name: "THUNDERBOLT_0",
                                   code: FourCharCode(fromStaticString: "TI0P"))
    public static let THUNDERBOLT_1 = TemperatureSensor(name: "THUNDERBOLT_1",
                                   code: FourCharCode(fromStaticString: "TI1P"))

    public static let all = [AMBIENT_AIR_0.code: AMBIENT_AIR_0,
                             AMBIENT_AIR_1.code: AMBIENT_AIR_1,
                             CPU_0_DIE.code: CPU_0_DIE,
                             CPU_0_DIODE.code: CPU_0_DIODE,
                             CPU_0_HEATSINK.code: CPU_0_HEATSINK,
                             CPU_0_PROXIMITY.code: CPU_0_PROXIMITY,
                             ENCLOSURE_BASE_0.code: ENCLOSURE_BASE_0,
                             ENCLOSURE_BASE_1.code: ENCLOSURE_BASE_1,
                             ENCLOSURE_BASE_2.code: ENCLOSURE_BASE_2,
                             ENCLOSURE_BASE_3.code: ENCLOSURE_BASE_3,
                             GPU_0_DIODE.code: GPU_0_DIODE,
                             GPU_0_HEATSINK.code: GPU_0_HEATSINK,
                             GPU_0_PROXIMITY.code: GPU_0_PROXIMITY,
                             HDD_PROXIMITY.code: HDD_PROXIMITY,
                             HEATSINK_0.code: HEATSINK_0,
                             HEATSINK_1.code: HEATSINK_1,
                             HEATSINK_2.code: HEATSINK_2,
                             MEM_SLOT_0.code: MEM_SLOT_0,
                             MEM_SLOTS_PROXIMITY.code: MEM_SLOTS_PROXIMITY,
                             PALM_REST.code: PALM_REST,
                             LCD_PROXIMITY.code: LCD_PROXIMITY,
                             MISC_PROXIMITY.code: MISC_PROXIMITY,
                             NORTHBRIDGE.code: NORTHBRIDGE,
                             NORTHBRIDGE_DIODE.code: NORTHBRIDGE_DIODE,
                             NORTHBRIDGE_PROXIMITY.code: NORTHBRIDGE_PROXIMITY,
                             ODD_PROXIMITY.code: ODD_PROXIMITY,
                             PWR_SUPPLY_PROXIMITY.code: PWR_SUPPLY_PROXIMITY,
                             THUNDERBOLT_0.code: THUNDERBOLT_0,
                             THUNDERBOLT_1.code: THUNDERBOLT_1]
}

public struct TemperatureSensor {
    public let name: String
    public let code: FourCharCode
}

public enum TemperatureUnit {
    case celius
    case fahrenheit
    case kelvin

    public static func toFahrenheit(_ celius: Double) -> Double {
        // https://en.wikipedia.org/wiki/Fahrenheit#Definition_and_conversions
        return (celius * 1.8) + 32
    }

    public static func toKelvin(_ celius: Double) -> Double {
        // https://en.wikipedia.org/wiki/Kelvin
        return celius + 273.15
    }
}

extension SMCKit {

    public static func allKnownTemperatureSensors() throws ->
                                                           [TemperatureSensor] {
        var sensors = [TemperatureSensor]()

        for sensor in TemperatureSensors.all.values {
            if try isKeyFound(sensor.code) { sensors.append(sensor) }
        }

        return sensors
    }

    public static func allUnknownTemperatureSensors() throws -> [TemperatureSensor] {
        let keys = try allKeys()

        return keys.filter { $0.code.toString().hasPrefix("T") &&
                             $0.info == DataTypes.SP78 &&
                             TemperatureSensors.all[$0.code] == nil }
                   .map { TemperatureSensor(name: "Unknown", code: $0.code) }
    }

    /// Get current temperature of a sensor
    public static func temperature(_ sensorCode: FourCharCode,
                             unit: TemperatureUnit = .celius) throws -> Double {
        let data = try readData(SMCKey(code: sensorCode, info: DataTypes.SP78))

        let temperatureInCelius = Double(fromSP78: (data.0, data.1))

        switch unit {
        case .celius:
            return temperatureInCelius
        case .fahrenheit:
            return TemperatureUnit.toFahrenheit(temperatureInCelius)
        case .kelvin:
            return TemperatureUnit.toKelvin(temperatureInCelius)
        }
    }
}

//------------------------------------------------------------------------------
// MARK: Fan
//------------------------------------------------------------------------------

public struct Fan {
    // TODO: Should we start the fan id from 1 instead of 0?
    public let id: Int
    public let name: String
    public let minSpeed: Int
    public let maxSpeed: Int
}

extension SMCKit {

    public static func allFans() throws -> [Fan] {
        let count = try fanCount()
        var fans = [Fan]()

        for i in 0 ..< count {
            fans.append(try SMCKit.fan(i))
        }

        return fans
    }

    public static func fan(_ id: Int) throws -> Fan {
        let name = try fanName(id)
        let minSpeed = try fanMinSpeed(id)
        let maxSpeed = try fanMaxSpeed(id)
        return Fan(id: id, name: name, minSpeed: minSpeed, maxSpeed: maxSpeed)
    }

    /// Number of fans this machine has. All Intel based Macs, except for the
    /// 2015 MacBook (8,1), have at least 1
    public static func fanCount() throws -> Int {
        let key = SMCKey(code: FourCharCode(fromStaticString: "FNum"),
                                            info: DataTypes.UInt8)

        let data = try readData(key)
        return Int(data.0)
    }

    public static func fanName(_ id: Int) throws -> String {
        let key = SMCKey(code: FourCharCode(fromString: "F\(id)ID"),
                                            info: DataTypes.FDS)
        let data = try readData(key)

        // The last 12 bytes of '{fds' data type, a custom struct defined by the
        // AppleSMC.kext that is 16 bytes, contains the fan name
        let c1  = String(UnicodeScalar(data.4))
        let c2  = String(UnicodeScalar(data.5))
        let c3  = String(UnicodeScalar(data.6))
        let c4  = String(UnicodeScalar(data.7))
        let c5  = String(UnicodeScalar(data.8))
        let c6  = String(UnicodeScalar(data.9))
        let c7  = String(UnicodeScalar(data.10))
        let c8  = String(UnicodeScalar(data.11))
        let c9  = String(UnicodeScalar(data.12))
        let c10 = String(UnicodeScalar(data.13))
        let c11 = String(UnicodeScalar(data.14))
        let c12 = String(UnicodeScalar(data.15))

        let name = c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + c11 + c12

        let characterSet = CharacterSet.whitespaces
        return name.trimmingCharacters(in: characterSet)
    }

    public static func fanCurrentSpeed(_ id: Int) throws -> Int {
        let key = SMCKey(code: FourCharCode(fromString: "F\(id)Ac"),
                                            info: DataTypes.FPE2)

        let data = try readData(key)
        return Int(fromFPE2: (data.0, data.1))
    }

    public static func fanMinSpeed(_ id: Int) throws -> Int {
        let key = SMCKey(code: FourCharCode(fromString: "F\(id)Mn"),
                                            info: DataTypes.FPE2)

        let data = try readData(key)
        return Int(fromFPE2: (data.0, data.1))
    }

    public static func fanMaxSpeed(_ id: Int) throws -> Int {
        let key = SMCKey(code: FourCharCode(fromString: "F\(id)Mx"),
                                            info: DataTypes.FPE2)

        let data = try readData(key)
        return Int(fromFPE2: (data.0, data.1))
    }

    /// Requires root privileges. By minimum we mean that OS X can interject and
    /// raise the fan speed if needed, however it will not go below this.
    ///
    /// WARNING: You are playing with hardware here, BE CAREFUL.
    ///
    /// - Throws: Of note, `SMCKit.SMCError`'s `UnsafeFanSpeed` and `NotPrivileged`
    public static func fanSetMinSpeed(_ id: Int, speed: Int) throws {
        let maxSpeed = try fanMaxSpeed(id)
        if speed <= 0 || speed > maxSpeed { throw SMCError.unsafeFanSpeed }

        let data = speed.toFPE2()
        let bytes: SMCBytes = (data.0, data.1, UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                               UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                               UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                               UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                               UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
                               UInt8(0), UInt8(0))

        let key = SMCKey(code: FourCharCode(fromString: "F\(id)Mn"),
                         info: DataTypes.FPE2)

        try writeData(key, data: bytes)
    }
}

//------------------------------------------------------------------------------
// MARK: Miscellaneous
//------------------------------------------------------------------------------

public struct batteryInfo {
    public let batteryCount: Int
    public let isACPresent: Bool
    public let isBatteryPowered: Bool
    public let isBatteryOk: Bool
    public let isCharging: Bool
}

extension SMCKit {

    public static func isOpticalDiskDriveFull() throws -> Bool {
        // TODO: Should we catch key not found? That just means the machine
        // doesn't have an ODD. Returning false though is not fully correct.
        // Maybe we could throw a no ODD error instead?
        let key = SMCKey(code: FourCharCode(fromStaticString: "MSDI"),
                         info: DataTypes.Flag)

        let data = try readData(key)
        return Bool(fromByte: data.0)
    }

    public static func batteryInformation() throws -> batteryInfo {
        let batteryCountKey =
                            SMCKey(code: FourCharCode(fromStaticString: "BNum"),
                                   info: DataTypes.UInt8)
        let batteryPoweredKey =
                            SMCKey(code: FourCharCode(fromStaticString: "BATP"),
                                   info: DataTypes.Flag)
        let batteryInfoKey =
                            SMCKey(code: FourCharCode(fromStaticString: "BSIn"),
                                   info: DataTypes.UInt8)

        let batteryCountData = try readData(batteryCountKey)
        let batteryCount = Int(batteryCountData.0)

        let isBatteryPoweredData = try readData(batteryPoweredKey)
        let isBatteryPowered = Bool(fromByte: isBatteryPoweredData.0)

        let batteryInfoData = try readData(batteryInfoKey)
        let isCharging = batteryInfoData.0 & 1 == 1 ? true : false
        let isACPresent = (batteryInfoData.0 >> 1) & 1 == 1 ? true : false
        let isBatteryOk = (batteryInfoData.0 >> 6) & 1 == 1 ? true : false

        return batteryInfo(batteryCount: batteryCount, isACPresent: isACPresent,
                           isBatteryPowered: isBatteryPowered,
                           isBatteryOk: isBatteryOk,
                           isCharging: isCharging)
    }
}


================================================
FILE: com.davidwernhart.Helper/main.swift
================================================
//
//  main.swift
//  com.davidwernhart.Helper
//
//  Created by David Wernhart on 10.02.20.
//  Copyright © 2020 David Wernhart. All rights reserved.
//

import Foundation
import AppKit

final class HelperDelegate: NSObject, NSXPCListenerDelegate {
    func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
        newConnection.exportedInterface = NSXPCInterface(with: HelperToolProtocol.self)
        newConnection.exportedObject = HelperTool.instance
        newConnection.resume()
        return true
    }
}

let delegate = HelperDelegate()
let listener = NSXPCListener(machServiceName: "com.davidwernhart.Helper.mach")
listener.delegate = delegate
listener.resume()
var hasChecked = false
Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
    let workspace = NSWorkspace.shared
    let applications = workspace.runningApplications
    var foundApp = false
    for app in applications {
        if(app.bundleIdentifier?.elementsEqual("com.davidwernhart.AlDente") == true){
            foundApp = true
        }
    }
    if(foundApp && hasChecked){
        hasChecked = false
    }
    else if(!foundApp && !hasChecked){
        hasChecked = true
        HelperTool.instance.reset()
        exit(0)
    }
}
RunLoop.current.run()
Download .txt
gitextract_8seg_0uv/

├── .github/
│   └── ISSUE_TEMPLATE/
│       ├── bug_report.md
│       ├── feature_request.md
│       └── question-about-aldente.md
├── AlDente/
│   ├── AppDelegate.swift
│   ├── Assets.xcassets/
│   │   ├── AppIcon.appiconset/
│   │   │   └── Contents.json
│   │   ├── Contents.json
│   │   └── menubaricon.imageset/
│   │       └── Contents.json
│   ├── Base.lproj/
│   │   └── Main.storyboard
│   ├── ContentView.swift
│   ├── Helper.swift
│   ├── Info.plist
│   ├── PersistanceManager.swift
│   └── Preview Content/
│       └── Preview Assets.xcassets/
│           └── Contents.json
├── AlDente.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   ├── contents.xcworkspacedata
│   │   ├── xcshareddata/
│   │   │   ├── IDEWorkspaceChecks.plist
│   │   │   └── swiftpm/
│   │   │       └── Package.resolved
│   │   └── xcuserdata/
│   │       └── davidwernhart.xcuserdatad/
│   │           └── UserInterfaceState.xcuserstate
│   └── xcuserdata/
│       └── davidwernhart.xcuserdatad/
│           ├── xcdebugger/
│           │   └── Breakpoints_v2.xcbkptlist
│           └── xcschemes/
│               └── xcschememanagement.plist
├── CODE_OF_CONDUCT.md
├── Common/
│   └── HelperToolProtocol.swift
├── LICENSE
├── README.md
├── SECURITY.md
├── SMJobBlessUtil.py
└── com.davidwernhart.Helper/
    ├── Helper-Info.plist
    ├── Helper-Launchd.plist
    ├── HelperTool.swift
    ├── SMC.swift
    └── main.swift
Download .txt
SYMBOL INDEX (15 symbols across 1 files)

FILE: SMJobBlessUtil.py
  class UsageException (line 61) | class UsageException (Exception):
  class CheckException (line 68) | class CheckException (Exception):
    method __init__ (line 73) | def __init__(self, message, path=None):
  function checkCodeSignature (line 77) | def checkCodeSignature(programPath, programType):
  function readDesignatedRequirement (line 99) | def readDesignatedRequirement(programPath, programType):
  function readInfoPlistFromPath (line 119) | def readInfoPlistFromPath(infoPath):
  function readPlistFromToolSection (line 129) | def readPlistFromToolSection(toolPath, segmentName, sectionName):
  function checkStep1 (line 175) | def checkStep1(appPath):
  function checkStep2 (line 209) | def checkStep2(appPath, toolPathList):
  function checkStep3 (line 251) | def checkStep3(appPath, toolPathList):
  function checkStep4 (line 283) | def checkStep4(appPath, toolPathList):
  function checkStep5 (line 296) | def checkStep5(appPath):
  function check (line 300) | def check(appPath):
  function setreq (line 315) | def setreq(appPath, appInfoPlistPath, toolInfoPlistPaths):
  function main (line 398) | def main():
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (153K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 1349,
    "preview": "---\nname: Bug Report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n**MacBook (please"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 595,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question-about-aldente.md",
    "chars": 260,
    "preview": "---\nname: Question about AlDente\nabout: Use Discussions section for questions\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nH"
  },
  {
    "path": "AlDente/AppDelegate.swift",
    "chars": 4599,
    "preview": "//\n//  AppDelegate.swift\n//  AlDente\n//\n//  Created by David Wernhart on 09.02.20.\n//  Copyright © 2020 David Wernhart. "
  },
  {
    "path": "AlDente/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 940,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"idiom\" : "
  },
  {
    "path": "AlDente/Assets.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "AlDente/Assets.xcassets/menubaricon.imageset/Contents.json",
    "chars": 995,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"aldentelighticon1x.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n  "
  },
  {
    "path": "AlDente/Base.lproj/Main.storyboard",
    "chars": 5989,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\" version=\"3.0\" t"
  },
  {
    "path": "AlDente/ContentView.swift",
    "chars": 8543,
    "preview": "//\n//  ContentView.swift\n//  AlDente\n//\n//  Created by David Wernhart on 09.02.20.\n//  Copyright © 2020 David Wernhart. "
  },
  {
    "path": "AlDente/Helper.swift",
    "chars": 9903,
    "preview": "//\n//  Helper.swift\n//  AlDente\n//\n//  Created by David Wernhart on 14.02.20.\n//  Copyright © 2020 David Wernhart. All r"
  },
  {
    "path": "AlDente/Info.plist",
    "chars": 1684,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "AlDente/PersistanceManager.swift",
    "chars": 833,
    "preview": "//\n//  PersistanceManager.swift\n//  AlDente\n//\n//  Created by David Wernhart on 07.02.21.\n//  Copyright © 2021 David Wer"
  },
  {
    "path": "AlDente/Preview Content/Preview Assets.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "AlDente.xcodeproj/project.pbxproj",
    "chars": 22505,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "AlDente.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 135,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef"
  },
  {
    "path": "AlDente.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "chars": 238,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "AlDente.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved",
    "chars": 334,
    "preview": "{\n  \"object\": {\n    \"pins\": [\n      {\n        \"package\": \"LaunchAtLogin\",\n        \"repositoryURL\": \"https://github.com/s"
  },
  {
    "path": "AlDente.xcodeproj/xcuserdata/davidwernhart.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
    "chars": 827,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n   uuid = \"0B65810B-47FA-44B5-B39C-4D764B29033A\"\n   type = \"1\"\n   version"
  },
  {
    "path": "AlDente.xcodeproj/xcuserdata/davidwernhart.xcuserdatad/xcschemes/xcschememanagement.plist",
    "chars": 909,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5202,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": "Common/HelperToolProtocol.swift",
    "chars": 978,
    "preview": "//\n//  HelperToolProtocol.swift\n//  AlDente\n//\n//  Created by David Wernhart on 13.02.20.\n//  Copyright © 2020 David Wer"
  },
  {
    "path": "LICENSE",
    "chars": 13565,
    "preview": "1.\tPreamble\n\nThe AppHouseKitchenOG, owner: David Wernhart and Matthias Kerbl, located in Obersdorfer Straße 31/5/11, 212"
  },
  {
    "path": "README.md",
    "chars": 5216,
    "preview": "<div align=\"center\">\n    <img src=\"AlDente/Assets.xcassets/AppIcon.appiconset/512pt_Mac_1x.png\" width=200 height=200>\n  "
  },
  {
    "path": "SECURITY.md",
    "chars": 1520,
    "preview": "# Security Policy\n\n## Supported Versions\n\nWe release security updates for the latest version of **AlDente** here: https:"
  },
  {
    "path": "SMJobBlessUtil.py",
    "chars": 18981,
    "preview": "#! /usr/bin/python \n# \n#   File:       SMJobBlessUtil.py\n# \n#   Contains:   Tool for checking and correcting apps that u"
  },
  {
    "path": "com.davidwernhart.Helper/Helper-Info.plist",
    "chars": 736,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "com.davidwernhart.Helper/Helper-Launchd.plist",
    "chars": 371,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "com.davidwernhart.Helper/HelperTool.swift",
    "chars": 3943,
    "preview": "//\n//  HelperTool.swift\n//  com.davidwernhart.Helper\n//\n//  Created by David Wernhart on 13.02.20.\n//  Copyright © 2020 "
  },
  {
    "path": "com.davidwernhart.Helper/SMC.swift",
    "chars": 31591,
    "preview": "//\n// SMC.swift\n// SMCKit\n//\n// The MIT License\n//\n// Copyright (C) 2014-2017  beltex <https://beltex.github.io>\n//\n// P"
  },
  {
    "path": "com.davidwernhart.Helper/main.swift",
    "chars": 1309,
    "preview": "//\n//  main.swift\n//  com.davidwernhart.Helper\n//\n//  Created by David Wernhart on 10.02.20.\n//  Copyright © 2020 David "
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the AppHouseKitchen/AlDente-Battery_Care_and_Monitoring GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (140.8 KB), approximately 36.5k tokens, and a symbol index with 15 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!