Build matrix result

This commit is contained in:
2023-06-30 08:50:41 +09:00
parent a3853af59e
commit ef264faeaf
20 changed files with 380 additions and 138 deletions

View File

@@ -0,0 +1,13 @@
//
// ArrayDecodable.swift
// KissMe
//
// Created by ened-book-m1 on 2023/06/30.
//
import Foundation
public protocol ArrayDecodable {
init(array: [String], source: String.SubSequence) throws
}

View File

@@ -332,114 +332,6 @@ public func valueToString(_ any: Any) -> String {
}
extension Array where Element: PropertyIterable {
public func mergeCsv(toFile file: URL, merging: (_ this: [Element], _ file: [Element]) -> [Element], localized: Bool) throws where Element: ArrayDecodable {
guard file.isFileExists == true else {
try writeCsv(toFile: file, localized: localized)
return
}
let oldData = try Self.readCsv(fromFile: file, verifyHeader: true)
let finalData = merging(self, oldData)
try finalData.writeCsv(toFile: file, localized: localized)
}
public func writeCsv(toFile file: URL, appendable: Bool = false, localized: Bool) throws {
if appendable, file.isFileExists == true {
try appendAtEnd(ofCsv: file)
}
else {
try overwrite(toCsv: file, localized: localized)
}
return
// Nested function
func appendAtEnd(ofCsv file: URL) throws {
let oldHeader = try String.readCsvHeader(fromFile: file)
var stringCsv = ""
for item in self {
let all = try item.allProperties()
if stringCsv.isEmpty {
let header = all.map{ $0.0 }
if oldHeader != header {
let (_, field) = oldHeader.getDiff(from: header) ?? (-1, "")
throw GeneralError.incorrectCsvHeaderField(field)
}
}
let values = all.map{ valueToString($0.1) }.joined(separator: ",").appending("\n")
stringCsv.append(values)
}
try stringCsv.writeAppending(toFile: file.path)
}
// Nested function
func overwrite(toCsv file: URL, localized: Bool) throws {
var stringCsv = ""
for item in self {
let all = try item.allProperties()
if stringCsv.isEmpty {
let header = all.map { prop in
localized ? localizeString(prop.0): prop.0
}.joined(separator: ",").appending("\n")
stringCsv.append(header)
}
let values = all.map{ valueToString($0.1) }.joined(separator: ",").appending("\n")
stringCsv.append(values)
}
try stringCsv.write(toFile: file.path, atomically: true, encoding: .utf8)
}
}
public static func readCsv(fromFile: URL, verifyHeader: Bool = true) throws -> [Element] where Element: ArrayDecodable {
let stringCsv = try String(contentsOfFile: fromFile.path, encoding: .utf8)
return try parseCsv(stringCsv: stringCsv, verifyHeader: verifyHeader, filePath: fromFile.path)
}
private static func parseCsv(stringCsv: String, verifyHeader: Bool, filePath: String) throws -> [Element] where Element: ArrayDecodable {
let items = stringCsv.split(separator: "\n")
guard items.count > 0 else {
return []
}
var headerItems = [String]()
var elements = [Element]()
for (index, item) in items.enumerated() {
if index == 0 {
headerItems = item.split(separator: ",", omittingEmptySubsequences: false).map { String($0) }
continue
}
let array = item.split(separator: ",", omittingEmptySubsequences: false).map { String($0) }
//print("index: \(index), \(fromFile.path)")
let element = try Element(array: array, source: item)
if index == 1, verifyHeader {
// Validate property with header
let properties = try element.allProperties()
for (label, _) in properties {
if false == headerItems.contains(where: { $0 == label }) {
printError("index: \(index), \(filePath)")
throw GeneralError.headerNoFiendName(label)
}
}
}
elements.append(element)
}
return elements
}
public static func readCsvTop(fromFile: URL, verifyHeader: Bool = true, by rowCount: Int) throws -> [Element] where Element: ArrayDecodable {
let stringCsv = try String(rowCount+1, lineOfFile: fromFile.path)
return try parseCsv(stringCsv: stringCsv, verifyHeader: verifyHeader, filePath: fromFile.path)
}
}
public func printError(_ items: Any..., separator: String = " ", terminator: String = "\n") {
let output = items.map { "*\($0)" }.joined(separator: separator).appending("\n")
FileHandle.standardError.write(Data(output.utf8))

View File

@@ -0,0 +1,28 @@
//
// GeneralError.swift
// KissMe
//
// Created by ened-book-m1 on 2023/06/30.
//
import Foundation
public enum GeneralError: Error {
case noServerJsonFile
case invalidInstance
case invalidAccessToken
case invalidAccountNo
case unsupportedQueryAtMockServer
case emptyData(String)
case cannotReadFile
case cannotWriteFile
case cannotReadFileLine
case cannotReadFileToConvertString
case incorrectArrayItems(String, Int, Int)
case headerNoFiendName(String)
case noCsvFile
case invalidCandleCsvFile(String)
case incorrectCsvHeaderField(String)
case noData
}

View File

@@ -33,6 +33,109 @@ public extension PropertyIterable {
}
public protocol ArrayDecodable {
init(array: [String], source: String.SubSequence) throws
extension Array where Element: PropertyIterable {
public func mergeCsv(toFile file: URL, merging: (_ this: [Element], _ file: [Element]) -> [Element], localized: Bool) throws where Element: ArrayDecodable {
guard file.isFileExists == true else {
try writeCsv(toFile: file, localized: localized)
return
}
let oldData = try Self.readCsv(fromFile: file, verifyHeader: true)
let finalData = merging(self, oldData)
try finalData.writeCsv(toFile: file, localized: localized)
}
public func writeCsv(toFile file: URL, appendable: Bool = false, localized: Bool) throws {
if appendable, file.isFileExists == true {
try appendAtEnd(ofCsv: file)
}
else {
try overwrite(toCsv: file, localized: localized)
}
return
// Nested function
func appendAtEnd(ofCsv file: URL) throws {
let oldHeader = try String.readCsvHeader(fromFile: file)
var stringCsv = ""
for item in self {
let all = try item.allProperties()
if stringCsv.isEmpty {
let header = all.map{ $0.0 }
if oldHeader != header {
let (_, field) = oldHeader.getDiff(from: header) ?? (-1, "")
throw GeneralError.incorrectCsvHeaderField(field)
}
}
let values = all.map{ valueToString($0.1) }.joined(separator: ",").appending("\n")
stringCsv.append(values)
}
try stringCsv.writeAppending(toFile: file.path)
}
// Nested function
func overwrite(toCsv file: URL, localized: Bool) throws {
var stringCsv = ""
for item in self {
let all = try item.allProperties()
if stringCsv.isEmpty {
let header = all.map { prop in
localized ? localizeString(prop.0): prop.0
}.joined(separator: ",").appending("\n")
stringCsv.append(header)
}
let values = all.map{ valueToString($0.1) }.joined(separator: ",").appending("\n")
stringCsv.append(values)
}
try stringCsv.write(toFile: file.path, atomically: true, encoding: .utf8)
}
}
public static func readCsv(fromFile: URL, verifyHeader: Bool = true) throws -> [Element] where Element: ArrayDecodable {
let stringCsv = try String(contentsOfFile: fromFile.path, encoding: .utf8)
return try parseCsv(stringCsv: stringCsv, verifyHeader: verifyHeader, filePath: fromFile.path)
}
private static func parseCsv(stringCsv: String, verifyHeader: Bool, filePath: String) throws -> [Element] where Element: ArrayDecodable {
let items = stringCsv.split(separator: "\n")
guard items.count > 0 else {
return []
}
var headerItems = [String]()
var elements = [Element]()
for (index, item) in items.enumerated() {
if index == 0 {
headerItems = item.split(separator: ",", omittingEmptySubsequences: false).map { String($0) }
continue
}
let array = item.split(separator: ",", omittingEmptySubsequences: false).map { String($0) }
//print("index: \(index), \(fromFile.path)")
let element = try Element(array: array, source: item)
if index == 1, verifyHeader {
// Validate property with header
let properties = try element.allProperties()
for (label, _) in properties {
if false == headerItems.contains(where: { $0 == label }) {
printError("index: \(index), \(filePath)")
throw GeneralError.headerNoFiendName(label)
}
}
}
elements.append(element)
}
return elements
}
public static func readCsvTop(fromFile: URL, verifyHeader: Bool = true, by rowCount: Int) throws -> [Element] where Element: ArrayDecodable {
let stringCsv = try String(rowCount+1, lineOfFile: fromFile.path)
return try parseCsv(stringCsv: stringCsv, verifyHeader: verifyHeader, filePath: fromFile.path)
}
}

View File

@@ -26,25 +26,6 @@ extension Method: CustomStringConvertible {
}
}
public enum GeneralError: Error {
case noServerJsonFile
case invalidInstance
case invalidAccessToken
case invalidAccountNo
case unsupportedQueryAtMockServer
case emptyData(String)
case cannotReadFile
case cannotWriteFile
case cannotReadFileLine
case cannotReadFileToConvertString
case incorrectArrayItems(String, Int, Int)
case headerNoFiendName(String)
case noCsvFile
case invalidCandleCsvFile(String)
case incorrectCsvHeaderField(String)
case noData
}
public enum QueryError: Error {
case invalidUrl

View File

@@ -39,3 +39,16 @@ public struct KissIndexResult: Codable {
self.output = output
}
}
public struct KissMatrixResult: Codable {
public let code: Int
public let kmis: [String]
public let output: [KissIndexResult.Output]
public init(code: Int, kmis: [String], output: [KissIndexResult.Output]) {
self.code = code
self.kmis = kmis
self.output = output
}
}

View File

@@ -0,0 +1,34 @@
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "KissMeGolder",
platforms: [
.macOS(.v13), .iOS(.v14), .tvOS(.v14)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.executable(
name: "KissMeGolder",
targets: ["KissMeGolder"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
//.package(url: "../KissMe", from: "1.0.0"),
.package(path: "../KissMe"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.executableTarget(
name: "KissMeGolder",
dependencies: ["KissMe"],
path: "Sources"),
//.testTarget(
// name: "KissMeGolderTests",
// dependencies: ["KissMeGolder"],
// path: "Tests"),
]
)

View File

@@ -0,0 +1,16 @@
//
// KissGolder.swift
// KissMeGolder
//
// Created by ened-book-m1 on 2023/06/30.
//
import Foundation
class KissMatrix {
func run() {
print("hello..")
}
}

View File

@@ -7,5 +7,4 @@
import Foundation
print("Hello, World!")
KissMatrix().run()

View File

@@ -12,6 +12,10 @@ import KissMe
extension KissIndex {
func indexSet_0005(date: Date, config: String?, kmi: KissIndexType) {
if productsCount == 0 {
loadShop(url: KissIndex.shopProductsUrl)
}
let belongs: [BelongClassCode] = [.averageVolume, .volumeIncreaseRate, .averageVolumeTurnoverRate, .transactionValue, .averageTransactionValueTurnoverRate]
do {

View File

@@ -82,7 +82,7 @@ class KissIndex: KissMe.ShopContext {
//print(jsonString)
FileHandle.standardOutput.write(jsonData)
} catch {
assertionFailure(error.localizedDescription)
printError(error)
}
}

View File

@@ -0,0 +1,34 @@
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "KissMeMatrix",
platforms: [
.macOS(.v13), .iOS(.v14), .tvOS(.v14)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.executable(
name: "KissMeMatrix",
targets: ["KissMeMatrix"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
//.package(url: "../KissMe", from: "1.0.0"),
.package(path: "../KissMe"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.executableTarget(
name: "KissMeMatrix",
dependencies: ["KissMe"],
path: "Sources"),
//.testTarget(
// name: "KissMeMatrixTests",
// dependencies: ["KissMeMatrix"],
// path: "Tests"),
]
)

View File

@@ -96,7 +96,7 @@ class KissMatrix {
let semaphore = DispatchSemaphore(value: 0)
Task {
let indexResult = try await withThrowingTaskGroup(of: KissIndexResult?.self, returning: [KissIndexResult].self) { taskGroup in
let results = try await withThrowingTaskGroup(of: KissIndexResult?.self, returning: [KissIndexResult].self) { taskGroup in
for indexSet in model.indexSets {
guard let (runUrl, args) = indexSet.build(date: runDate) else {
print("Cannot get command from \(indexSet.name)")
@@ -121,9 +121,7 @@ class KissMatrix {
return taskResult
}
//for result in indexResult {
// print(result)
//}
mergeResult(results)
semaphore.signal()
}
semaphore.wait()
@@ -181,6 +179,40 @@ class KissMatrix {
}
private func mergeResult(_ results: [KissIndexResult]) {
let indexCount = results.count
var mergedOutput = [String: [KissIndexResult.Output]]()
for result in results {
for item in result.output {
if let _ = mergedOutput[item.shortCode] {
mergedOutput[item.shortCode]!.append(item)
}
else {
mergedOutput[item.shortCode] = [item]
}
}
}
var normalized = [KissIndexResult.Output]()
for (productNo, output) in mergedOutput {
let weight = output.reduce(0.0, { $0 + $1.weight }) / Double(indexCount)
let output = KissIndexResult.Output(shortCode: productNo, productName: output.first?.productName, weight: weight)
normalized.append(output)
}
normalized.sort(by: { $0.weight > $1.weight })
let kmis = results.map { $0.kmi }
let matrixResult = KissMatrixResult(code: 200, kmis: kmis, output: normalized)
do {
let jsonData = try JSONEncoder().encode(matrixResult)
try FileHandle.standardOutput.write(contentsOf: jsonData)
} catch {
printError(error)
}
}
private func loadModel(_ jsonFile: String) -> Model? {
do {
let configUrl = URL.currentDirectory().appending(path: jsonFile)

View File

@@ -25,6 +25,7 @@ Command | 설명
WIP `modify (PNO) (ONO) (가격) (수량)` | 주문 내역을 변경. (수량) 에 -82 로 입력하면 전체수량.
`open bag` | 보유 종목 열람. 보유 주식은 **data/account-stocks.csv** 파일로 저장. 잔고 상황은 **data/account-amount.csv** 파일로 저장.
`now [PNO]` | 종목의 현재가 열람. PNO 은 생략 가능. **data/(PNO)/price/prices-(yyyyMM01).csv** 파일로 저장.
`now all` | 모든 종목의 현재가를 열람. **data/(PNO)/price/prices-(yyyyMM01).csv** 파일로 저장.
`candle [PNO]` | 종목의 분봉 열람. PNO 은 생략 가능. **data/(PNO)/min/candle-(yyyyMMdd).csv** 파일로 저장.
`candle all [resume]` | 모든 종목의 분봉 열람. cron job 으로 돌리기 위해서 추가. **data/(PNO)/min/candle-(yyyyMMdd).csv** 파일로 저장. (resume) 을 기입하면, 이미 받은 파일은 검사하여, 데이터에 오류가 있으면 다시 받고 오류가 없으면 새롭게 열람하지 않음.
`candle day [PNO]` | 종목의 최근 250일 동안의 일봉 열람. PNO 은 생략 가능. **data/(PNO)/day/candle-(yyyyMMdd).csv** 파일로 저장.

View File

@@ -8,6 +8,8 @@
/* Begin PBXBuildFile section */
340A4DBD2A4C34BE005A1FBA /* IndexContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340A4DBC2A4C34BE005A1FBA /* IndexContext.swift */; };
340A4DC42A4E4345005A1FBA /* ArrayDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340A4DC32A4E4345005A1FBA /* ArrayDecodable.swift */; };
340A4DC82A4E43C5005A1FBA /* GeneralError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340A4DC72A4E43C5005A1FBA /* GeneralError.swift */; };
341F5EB02A0A80EC00962D48 /* KissMe.docc in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EAF2A0A80EC00962D48 /* KissMe.docc */; };
341F5EB62A0A80EC00962D48 /* KissMe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 341F5EAB2A0A80EC00962D48 /* KissMe.framework */; };
341F5EBB2A0A80EC00962D48 /* KissMeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341F5EBA2A0A80EC00962D48 /* KissMeTests.swift */; };
@@ -55,6 +57,8 @@
/* Begin PBXFileReference section */
340A4DBC2A4C34BE005A1FBA /* IndexContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndexContext.swift; sourceTree = "<group>"; };
340A4DC32A4E4345005A1FBA /* ArrayDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayDecodable.swift; sourceTree = "<group>"; };
340A4DC72A4E43C5005A1FBA /* GeneralError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralError.swift; sourceTree = "<group>"; };
341F5EAB2A0A80EC00962D48 /* KissMe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KissMe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
341F5EAE2A0A80EC00962D48 /* KissMe.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KissMe.h; sourceTree = "<group>"; };
341F5EAF2A0A80EC00962D48 /* KissMe.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; name = KissMe.docc; path = ../KissMe.docc; sourceTree = "<group>"; };
@@ -201,6 +205,8 @@
341F5F0E2A15223A00962D48 /* SeibroRequest.swift */,
341F5F102A1685E700962D48 /* ShopRequest.swift */,
341F5F022A11A2BC00962D48 /* Credential.swift */,
340A4DC72A4E43C5005A1FBA /* GeneralError.swift */,
340A4DC32A4E4345005A1FBA /* ArrayDecodable.swift */,
341F5F062A14634F00962D48 /* Foundation+Extensions.swift */,
34D3680E2A2AA0BE005E6756 /* PropertyIterable.swift */,
);
@@ -359,6 +365,8 @@
buildActionMask = 2147483647;
files = (
341F5EFB2A10909D00962D48 /* LoginResult.swift in Sources */,
340A4DC42A4E4345005A1FBA /* ArrayDecodable.swift in Sources */,
340A4DC82A4E43C5005A1FBA /* GeneralError.swift in Sources */,
341F5F0B2A15115400962D48 /* KissShop.swift in Sources */,
3435A7F72A35D82000D604F1 /* DomesticShortSelling.swift in Sources */,
341F5F072A14634F00962D48 /* Foundation+Extensions.swift in Sources */,

View File

@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
340A4DCC2A4E4C37005A1FBA /* KissGolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340A4DCB2A4E4C37005A1FBA /* KissGolder.swift */; };
3498435C2A24DC1300E85B08 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3498435B2A24DC1300E85B08 /* main.swift */; };
349843642A24DC7800E85B08 /* KissMe.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 349843632A24DC7800E85B08 /* KissMe.framework */; };
349843652A24DC7800E85B08 /* KissMe.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 349843632A24DC7800E85B08 /* KissMe.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -36,6 +37,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
340A4DCB2A4E4C37005A1FBA /* KissGolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KissGolder.swift; sourceTree = "<group>"; };
349843582A24DC1300E85B08 /* KissMeGolder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KissMeGolder; sourceTree = BUILT_PRODUCTS_DIR; };
3498435B2A24DC1300E85B08 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
349843632A24DC7800E85B08 /* KissMe.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KissMe.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -74,6 +76,7 @@
isa = PBXGroup;
children = (
3498435B2A24DC1300E85B08 /* main.swift */,
340A4DCB2A4E4C37005A1FBA /* KissGolder.swift */,
);
name = KissMeGolder;
path = ../../KissMeGolder/Sources;
@@ -146,6 +149,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
340A4DCC2A4E4C37005A1FBA /* KissGolder.swift in Sources */,
3498435C2A24DC1300E85B08 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "349843572A24DC1300E85B08"
BuildableName = "KissMeGolder"
BlueprintName = "KissMeGolder"
ReferencedContainer = "container:KissMeGolder.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "YES"
customWorkingDirectory = "$(SRCROOT)/../../bin"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
viewDebuggingEnabled = "No">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "349843572A24DC1300E85B08"
BuildableName = "KissMeGolder"
BlueprintName = "KissMeGolder"
ReferencedContainer = "container:KissMeGolder.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "349843572A24DC1300E85B08"
BuildableName = "KissMeGolder"
BlueprintName = "KissMeGolder"
ReferencedContainer = "container:KissMeGolder.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -9,6 +9,7 @@ THIS_PATH=`dirname "$0"`
${THIS_PATH}/build_any.sh KissMeConsole
${THIS_PATH}/build_any.sh KissMeIndex
${THIS_PATH}/build_any.sh KissMeMatrix
#${THIS_PATH}/build_any.sh KissMeBatch
#${THIS_PATH}/build_any.sh KissGram

View File

@@ -14,7 +14,7 @@ cd ${CONSOLE_APP}
rm -rf .build
swift build -c release
swift build -c release --enable-dead-strip
cp ./.build/release/${CONSOLE_APP} ../bin