diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..735f5bd Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000..20d76ad --- /dev/null +++ b/lombok.config @@ -0,0 +1,11 @@ +## 以当前目录为根目录 +config.stopBubbling=true + +## 默认以链式生成Setter +lombok.accessors.chain=true + +## 默认ToString包含超类 +lombok.tostring.callsuper=call + +## 默认比较器包含超类 +lombok.equalsandhashcode.callsuper=call diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8aa7a53 --- /dev/null +++ b/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.4 + + + com.jetbrains.help + Jetbrains-Help + 0.0.1-SNAPSHOT + Jetbrains-Help + Jetbrains-Help + + 21 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + true + + + + cn.hutool + hutool-all + 5.8.26 + + + + org.bouncycastle + bcpkix-jdk18on + 1.78 + + + org.bouncycastle + bcprov-jdk18on + 1.78 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 0000000..47dca67 Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/java/com/jetbrains/help/JetbrainsHelpApplication.java b/src/main/java/com/jetbrains/help/JetbrainsHelpApplication.java new file mode 100644 index 0000000..20310c3 --- /dev/null +++ b/src/main/java/com/jetbrains/help/JetbrainsHelpApplication.java @@ -0,0 +1,39 @@ +package com.jetbrains.help; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.jetbrains.help.context.*; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Import; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.Collection; +import java.util.List; + +@EnableScheduling +@Import(SpringUtil.class) +@SpringBootApplication +public class JetbrainsHelpApplication { + + public static void main(String[] args) { + SpringApplication.run(JetbrainsHelpApplication.class, args); + } + + @EventListener(ApplicationReadyEvent.class) + public void ready() { + ProductsContextHolder.init(); + PluginsContextHolder.init(); + CertificateContextHolder.init(); + AgentContextHolder.init(); + } + + @Scheduled(cron = "0 0 12 * * ?") + public void refresh() { + PluginsContextHolder.refreshJsonFile(); + } + +} diff --git a/src/main/java/com/jetbrains/help/context/AgentContextHolder.java b/src/main/java/com/jetbrains/help/context/AgentContextHolder.java new file mode 100644 index 0000000..dea6515 --- /dev/null +++ b/src/main/java/com/jetbrains/help/context/AgentContextHolder.java @@ -0,0 +1,96 @@ +package com.jetbrains.help.context; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ZipUtil; +import cn.hutool.crypto.KeyUtil; +import cn.hutool.crypto.PemUtil; +import com.jetbrains.help.util.FileTools; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPublicKey; +import java.util.concurrent.CompletableFuture; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class AgentContextHolder { + + private static final String JA_NETFILTER_FILE_PATH = "static/agent/ja-netfilter"; +// private static final String JA_NETFILTER_FILE_PATH = "static/agent/ja"; + + private static final String POWER_CONF_FILE_NAME = JA_NETFILTER_FILE_PATH + "/config/power.conf"; + + private static File jaNetfilterFile; + + public static void init() { + log.info("Agent context init loading..."); + jaNetfilterFile = FileTools.getFileOrCreat(JA_NETFILTER_FILE_PATH); + if (!powerConfHasInit()) { + log.info("Agent config init loading..."); + loadPowerConf(); + zipJaNetfilter(); + log.info("Agent config init success !"); + } + log.info("Agent context init success !"); + } + + private static boolean powerConfHasInit() { + File powerConfFile = FileTools.getFileOrCreat(POWER_CONF_FILE_NAME); + String powerConfStr; + try { + powerConfStr = IoUtil.readUtf8(FileUtil.getInputStream(powerConfFile)); + } catch (IORuntimeException e) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} File read failed", POWER_CONF_FILE_NAME), e); + } + return CharSequenceUtil.containsAll(powerConfStr, "[Result]", "EQUAL,"); + } + + private static void loadPowerConf() { + CompletableFuture + .supplyAsync(AgentContextHolder::generatePowerConfigRule) + .thenApply(AgentContextHolder::generatePowerConfigStr) + .thenAccept(AgentContextHolder::overridePowerConfFileContent) + .exceptionally(throwable -> { + log.error("agent context init or refresh failed", throwable); + return null; + }).join(); + } + + @SneakyThrows + private static String generatePowerConfigRule() { + X509Certificate crt = (X509Certificate) KeyUtil.readX509Certificate(IoUtil.toStream(CertificateContextHolder.crtFile())); + RSAPublicKey publicKey = (RSAPublicKey) PemUtil.readPemPublicKey(IoUtil.toStream(CertificateContextHolder.publicKeyFile())); + RSAPublicKey rootPublicKey = (RSAPublicKey) PemUtil.readPemPublicKey(IoUtil.toStream(CertificateContextHolder.rootKeyFile())); + BigInteger x = new BigInteger(1, crt.getSignature()); + BigInteger y = BigInteger.valueOf(65537L); + BigInteger z = rootPublicKey.getModulus(); + BigInteger r = x.modPow(publicKey.getPublicExponent(), publicKey.getModulus()); + return CharSequenceUtil.format("EQUAL,{},{},{}->{}", x, y, z, r); + } + + private static String generatePowerConfigStr(String ruleValue) { + return CharSequenceUtil.builder("[Result]", "\n", ruleValue).toString(); + } + + private static void overridePowerConfFileContent(String configStr) { + File powerConfFile = FileTools.getFileOrCreat(POWER_CONF_FILE_NAME); + try { + FileUtil.writeString(configStr, powerConfFile, StandardCharsets.UTF_8); + } catch (IORuntimeException e) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} File write failed", POWER_CONF_FILE_NAME), e); + } + } + + private static void zipJaNetfilter() { + ZipUtil.zip(jaNetfilterFile); + } +} diff --git a/src/main/java/com/jetbrains/help/context/CertificateContextHolder.java b/src/main/java/com/jetbrains/help/context/CertificateContextHolder.java new file mode 100644 index 0000000..bb0c1c7 --- /dev/null +++ b/src/main/java/com/jetbrains/help/context/CertificateContextHolder.java @@ -0,0 +1,110 @@ +package com.jetbrains.help.context; + +import cn.hutool.core.date.DateField; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.crypto.PemUtil; +import cn.hutool.crypto.SecureUtil; +import com.jetbrains.help.util.FileTools; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +import java.io.File; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CertificateContextHolder { + + private static final String ROOT_KEY_FILE_NAME = "certificate/root.key"; + private static final String PRIVATE_KEY_FILE_NAME = "certificate/private.key"; + private static final String PUBLIC_KEY_FILE_NAME = "certificate/public.key"; + private static final String CET_FILE_NAME = "certificate/ca.crt"; + + private static File rootKeyFile; + + private static File privateKeyFile; + + private static File publicKeyFile; + + private static File crtFile; + + public static void init() { + log.info("certificate context init loading..."); + rootKeyFile = FileTools.getFileOrCreat(ROOT_KEY_FILE_NAME); + if (!FileTools.fileExists(PRIVATE_KEY_FILE_NAME) + || !FileTools.fileExists(PUBLIC_KEY_FILE_NAME) + || !FileTools.fileExists(CET_FILE_NAME)) { + log.info("certificate context generate loading..."); + generateCertificate(); + } else { + privateKeyFile = FileTools.getFileOrCreat(PRIVATE_KEY_FILE_NAME); + publicKeyFile = FileTools.getFileOrCreat(PUBLIC_KEY_FILE_NAME); + crtFile = FileTools.getFileOrCreat(CET_FILE_NAME); + } + log.info("certificate context init success !"); + } + + + public static File rootKeyFile() { + return CertificateContextHolder.rootKeyFile; + } + + public static File privateKeyFile() { + return CertificateContextHolder.privateKeyFile; + } + + public static File publicKeyFile() { + return CertificateContextHolder.publicKeyFile; + } + + public static File crtFile() { + return CertificateContextHolder.crtFile; + } + + private static void generateCertificate() { + KeyPair keyPair = SecureUtil.generateKeyPair("RSA", 4096); + PrivateKey privateKey = keyPair.getPrivate(); + PublicKey publicKey = keyPair.getPublic(); + privateKeyFile = FileTools.getFileOrCreat(PRIVATE_KEY_FILE_NAME); + PemUtil.writePemObject("PRIVATE KEY", privateKey.getEncoded(), FileUtil.getWriter(privateKeyFile, StandardCharsets.UTF_8, false)); + publicKeyFile = FileTools.getFileOrCreat(PUBLIC_KEY_FILE_NAME); + PemUtil.writePemObject("PUBLIC KEY", publicKey.getEncoded(), FileUtil.getWriter(publicKeyFile, StandardCharsets.UTF_8, false)); + JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder( + new X500Name("CN=JetProfile CA"), + BigInteger.valueOf(System.currentTimeMillis()), + DateUtil.yesterday(), + DateUtil.date().offset(DateField.YEAR, 100), + new X500Name("CN=Jetbrains-Help"), + SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + try { + ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(privateKey); + Certificate certificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certificateBuilder.build(signer)); + crtFile = FileTools.getFileOrCreat(CET_FILE_NAME); + PemUtil.writePemObject("CERTIFICATE", certificate.getEncoded(), FileUtil.getWriter(crtFile, StandardCharsets.UTF_8, false)); + } catch (OperatorCreationException e) { + throw new IllegalArgumentException("Certificate operator creation exception", e); + } catch (CertificateEncodingException e) { + throw new IllegalArgumentException("The certificate encoding exception", e); + } catch (CertificateException e) { + throw new IllegalArgumentException("The certificate read exception", e); + } + } + + +} diff --git a/src/main/java/com/jetbrains/help/context/LicenseContextHolder.java b/src/main/java/com/jetbrains/help/context/LicenseContextHolder.java new file mode 100644 index 0000000..c1c69e2 --- /dev/null +++ b/src/main/java/com/jetbrains/help/context/LicenseContextHolder.java @@ -0,0 +1,77 @@ +package com.jetbrains.help.context; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.crypto.PemUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SignUtil; +import cn.hutool.crypto.asymmetric.Sign; +import cn.hutool.json.JSONUtil; +import lombok.AccessLevel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.util.List; +import java.util.Set; + +import static cn.hutool.crypto.asymmetric.SignAlgorithm.SHA1withRSA; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class LicenseContextHolder { + + public static String generateLicense(String licensesName, String assigneeName, String expiryDate, Set productCodeSet) { + String licenseId = IdUtil.fastSimpleUUID(); + List products = productCodeSet.stream() + .map(productCode -> new Product() + .setCode(productCode) + .setFallbackDate(expiryDate) + .setPaidUpTo(expiryDate)) + .toList(); + LicensePart licensePart = new LicensePart() + .setLicenseId(licenseId) + .setLicenseeName(licensesName) + .setAssigneeName(assigneeName) + .setProducts(products); + String licensePartJson = JSONUtil.toJsonStr(licensePart); + String licensePartBase64 = Base64.encode(licensePartJson); + PrivateKey privateKey = PemUtil.readPemPrivateKey(IoUtil.toStream(CertificateContextHolder.privateKeyFile())); + PublicKey publicKey = PemUtil.readPemPublicKey(IoUtil.toStream(CertificateContextHolder.publicKeyFile())); + Certificate certificate = SecureUtil.readX509Certificate(IoUtil.toStream(CertificateContextHolder.crtFile())); + Sign sign = SignUtil.sign(SHA1withRSA, privateKey.getEncoded(), publicKey.getEncoded()); + String signatureBase64 = Base64.encode(sign.sign(licensePartJson)); + String certBase64; + try { + certBase64 = Base64.encode(certificate.getEncoded()); + } catch (CertificateEncodingException e) { + throw new IllegalArgumentException("Certificate extraction failed", e); + } + return CharSequenceUtil.format("{}-{}-{}-{}", licenseId, licensePartBase64, signatureBase64, certBase64); + } + + @Data + public static class LicensePart { + + private String licenseId; + private String licenseeName; + private String assigneeName; + private List products; + private String metadata = "0120230914PSAX000005"; + } + + @Data + public static class Product { + private String code; + private String fallbackDate; + private String paidUpTo; + } + +} diff --git a/src/main/java/com/jetbrains/help/context/PluginsContextHolder.java b/src/main/java/com/jetbrains/help/context/PluginsContextHolder.java new file mode 100644 index 0000000..ee4e9da --- /dev/null +++ b/src/main/java/com/jetbrains/help/context/PluginsContextHolder.java @@ -0,0 +1,196 @@ +package com.jetbrains.help.context; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONUtil; +import com.jetbrains.help.util.FileTools; +import lombok.AccessLevel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class PluginsContextHolder { + + private static final String PLUGIN_BASIC_URL = "https://plugins.jetbrains.com"; + + private static final String PLUGIN_LIST_URL = PLUGIN_BASIC_URL + "/api/searchPlugins?max=10000&offset=0&orderBy=name"; + + private static final String PLUGIN_INFO_URL = PLUGIN_BASIC_URL + "/api/plugins/"; + + private static final String PLUGIN_JSON_FILE_NAME = "plugin.json"; + + private static List pluginCacheList; + + private static File pluginsJsonFile; + + public static void init() { + log.info("Plugin context init loading..."); + pluginsJsonFile = FileTools.getFileOrCreat(PLUGIN_JSON_FILE_NAME); + + String pluginJsonArray; + try { + pluginJsonArray = IoUtil.readUtf8(FileUtil.getInputStream(pluginsJsonFile)); + } catch (IORuntimeException e) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} File read failed", PLUGIN_JSON_FILE_NAME), e); + } + if (CharSequenceUtil.isBlank(pluginJsonArray) || !JSONUtil.isTypeJSON(pluginJsonArray)) { + refreshJsonFile(); + } else { + pluginCacheList = JSONUtil.toList(pluginJsonArray, PluginCache.class); + log.info("Plugin context init success !"); + } + } + + public static List pluginCacheList() { + return PluginsContextHolder.pluginCacheList; + } + + public static void refreshJsonFile() { + log.info("Init or Refresh plugin context from 'JetBrains.com' loading..."); + CompletableFuture + .supplyAsync(PluginsContextHolder::pluginList) + .thenApply(PluginsContextHolder::pluginListFilter) + .thenApply(PluginsContextHolder::pluginConversion) + .thenAccept(PluginsContextHolder::overrideJsonFile) + .exceptionally(throwable -> { + log.error("Plugin context init or refresh failed", throwable); + return null; + }); + log.info("Init or Refresh plugin context success !"); + } + + public static void overrideJsonFile(List pluginCaches) { + pluginCacheList.addAll(pluginCaches); + String jsonStr = JSONUtil.toJsonStr(pluginCacheList); + try { + FileUtil.writeString(jsonStr, pluginsJsonFile, StandardCharsets.UTF_8); + } catch (IORuntimeException e) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} File write failed", PLUGIN_JSON_FILE_NAME), e); + } + + } + + public static PluginList pluginList() { + return HttpUtil.createGet(PLUGIN_LIST_URL) + .thenFunction(response -> { + InputStream is = response.bodyStream(); + if (!response.isOk()) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} The request failed = {}", PLUGIN_LIST_URL, response)); + } + return IoUtil.readObj(is, PluginList.class); + }); + } + + public static List pluginListFilter(PluginList pluginList) { + return pluginList.getPlugins() + .stream() + .filter(plugin -> !PluginsContextHolder.pluginCacheList.contains(new PluginCache().setId(plugin.getId()))) + .filter(plugin -> !CharSequenceUtil.equals(plugin.getPricingModel(), "FREE")) + .toList(); + } + + public static List pluginConversion(List pluginList) { + return pluginList + .stream() + .map(plugin -> { + String productCode = pluginInfo(plugin.getId()).getPurchaseInfo().getProductCode(); + return new PluginCache() + .setId(plugin.getId()) + .setProductCode(productCode) + .setName(plugin.getName()) + .setPricingModel(plugin.getPricingModel()) + .setIcon(PLUGIN_BASIC_URL + plugin.getIcon()) + ; + }) + .toList(); + } + + public static PluginInfo pluginInfo(Long pluginId) { + return HttpUtil.createGet(PLUGIN_INFO_URL + pluginId) + .thenFunction(response -> { + InputStream is = response.bodyStream(); + if (!response.isOk()) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} The request failed = {}", PLUGIN_INFO_URL, response)); + } + return IoUtil.readObj(is, PluginInfo.class); + }); + } + + + @Data + public static class PluginCache { + + private Long id; + private String productCode; + private String name; + private String pricingModel; + private String icon; + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof PluginCache that)) return false; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + } + + @Data + public static class PluginInfo { + + private Long id; + + private PurchaseInfo purchaseInfo; + + @Data + public static class PurchaseInfo { + + private String productCode; + } + } + + @Data + public static class PluginList { + + private List plugins; + private Long total; + + + @Data + public static class Plugin { + + private Long id; + private String name; + private String preview; + private Integer downloads; + private String pricingModel; + private String organization; + private String icon; + private String previewImage; + private Double rating; + private VendorInfo vendorInfo; + } + + @Data + public static class VendorInfo { + private String name; + private Boolean isVerified; + } + } +} diff --git a/src/main/java/com/jetbrains/help/context/ProductsContextHolder.java b/src/main/java/com/jetbrains/help/context/ProductsContextHolder.java new file mode 100644 index 0000000..b7a8d55 --- /dev/null +++ b/src/main/java/com/jetbrains/help/context/ProductsContextHolder.java @@ -0,0 +1,54 @@ +package com.jetbrains.help.context; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.json.JSONUtil; +import com.jetbrains.help.util.FileTools; +import lombok.AccessLevel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.util.List; + +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ProductsContextHolder { + + private static final String PRODUCT_JSON_FILE_NAME = "product.json"; + + private static List productCacheList; + + public static void init() { + log.info("Product context init loading..."); + File productJsonFile = FileTools.getFileOrCreat(PRODUCT_JSON_FILE_NAME); + + String productJsonArray; + try { + productJsonArray = IoUtil.readUtf8(FileUtil.getInputStream(productJsonFile)); + } catch (IORuntimeException e) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} File read failed !", PRODUCT_JSON_FILE_NAME), e); + } + if (CharSequenceUtil.isBlank(productJsonArray) || !JSONUtil.isTypeJSON(productJsonArray)) { + log.error("Jetbrains Product data does not exist !"); + } else { + productCacheList = JSONUtil.toList(productJsonArray, ProductCache.class); + log.info("Product context init success !"); + } + } + + public static List productCacheList() { + return ProductsContextHolder.productCacheList; + } + + @Data + public static class ProductCache { + + private String name; + private String productCode; + private String iconClass; + } +} diff --git a/src/main/java/com/jetbrains/help/controller/OpenApiController.java b/src/main/java/com/jetbrains/help/controller/OpenApiController.java new file mode 100644 index 0000000..13b9e42 --- /dev/null +++ b/src/main/java/com/jetbrains/help/controller/OpenApiController.java @@ -0,0 +1,62 @@ +package com.jetbrains.help.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.StrUtil; +import com.jetbrains.help.context.LicenseContextHolder; +import com.jetbrains.help.context.PluginsContextHolder; +import com.jetbrains.help.context.ProductsContextHolder; +import lombok.Data; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@RestController +public class OpenApiController { + + @Data + public static class GenerateLicenseReqBody { + + private String licenseName; + + private String assigneeName; + + private String expiryDate; + + private String productCode; + } + + @PostMapping("generateLicense") + public String generateLicense(@RequestBody GenerateLicenseReqBody body) { + Set productCodeSet; + if (CharSequenceUtil.isBlank(body.getProductCode())) { + List productCodeList = ProductsContextHolder.productCacheList() + .stream() + .map(ProductsContextHolder.ProductCache::getProductCode) + .filter(StrUtil::isNotBlank) + .map(productCode -> CharSequenceUtil.splitTrim(productCode, ",")) + .flatMap(Collection::stream) + .toList(); + List pluginCodeList = PluginsContextHolder.pluginCacheList() + .stream() + .map(PluginsContextHolder.PluginCache::getProductCode) + .filter(StrUtil::isNotBlank) + .toList(); + productCodeSet = CollUtil.newHashSet(productCodeList); + productCodeSet.addAll(pluginCodeList); + }else { + productCodeSet = CollUtil.newHashSet(CharSequenceUtil.splitTrim(body.getProductCode(), ',')); + } + return LicenseContextHolder.generateLicense( + body.getLicenseName(), + body.getAssigneeName(), + body.getExpiryDate(), + productCodeSet + ); + } +} diff --git a/src/main/java/com/jetbrains/help/properties/JetbrainsHelpProperties.java b/src/main/java/com/jetbrains/help/properties/JetbrainsHelpProperties.java new file mode 100644 index 0000000..e60cc23 --- /dev/null +++ b/src/main/java/com/jetbrains/help/properties/JetbrainsHelpProperties.java @@ -0,0 +1,17 @@ +package com.jetbrains.help.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@Configuration +@ConfigurationProperties("help") +public class JetbrainsHelpProperties { + + private String defaultLicenseName; + + private String defaultAssigneeName; + + private String defaultExpiryDate; +} diff --git a/src/main/java/com/jetbrains/help/route/IndexController.java b/src/main/java/com/jetbrains/help/route/IndexController.java new file mode 100644 index 0000000..5e3a0e8 --- /dev/null +++ b/src/main/java/com/jetbrains/help/route/IndexController.java @@ -0,0 +1,51 @@ +package com.jetbrains.help.route; + +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.StrUtil; +import com.jetbrains.help.JetbrainsHelpApplication; +import com.jetbrains.help.context.PluginsContextHolder; +import com.jetbrains.help.context.ProductsContextHolder; +import com.jetbrains.help.properties.JetbrainsHelpProperties; +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class IndexController { + + private final JetbrainsHelpProperties jetbrainsHelpProperties; + + @GetMapping + public String index(Model model) { + List productCacheList = ProductsContextHolder.productCacheList(); + List pluginCacheList = PluginsContextHolder.pluginCacheList(); + model.addAttribute("products", productCacheList); + model.addAttribute("plugins", pluginCacheList); + model.addAttribute("defaults", jetbrainsHelpProperties); + return "index"; + } + + @GetMapping("search") + public String index(@RequestParam(required = false) String search, Model model) { + List productCacheList = ProductsContextHolder.productCacheList(); + List pluginCacheList = PluginsContextHolder.pluginCacheList(); + if (CharSequenceUtil.isNotBlank(search)) { + productCacheList = productCacheList.stream() + .filter(productCache -> CharSequenceUtil.containsIgnoreCase(productCache.getName(), search)) + .toList(); + pluginCacheList = pluginCacheList.stream() + .filter(pluginCache -> CharSequenceUtil.containsIgnoreCase(pluginCache.getName(), search)) + .toList(); + } + model.addAttribute("products", productCacheList); + model.addAttribute("plugins", pluginCacheList); + model.addAttribute("defaults", jetbrainsHelpProperties); + return "index::product-list"; + } +} diff --git a/src/main/java/com/jetbrains/help/util/FileTools.java b/src/main/java/com/jetbrains/help/util/FileTools.java new file mode 100644 index 0000000..0518368 --- /dev/null +++ b/src/main/java/com/jetbrains/help/util/FileTools.java @@ -0,0 +1,33 @@ +package com.jetbrains.help.util; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.text.CharSequenceUtil; +import org.springframework.core.io.ClassPathResource; + +import java.io.File; +import java.io.IOException; + +public interface FileTools { + + static boolean fileExists(String pathOrFile) { + return FileUtil.file(new ClassPathResource(pathOrFile).getPath()).exists(); + } + + static File getFileOrCreat(String pathOrFile) { + File file = FileUtil.file(new ClassPathResource(pathOrFile).getPath()); + if (!file.exists()) { + try { + File parentFile = file.getParentFile(); + if (!parentFile.exists() && !parentFile.mkdir()) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} File directory create Failed", pathOrFile)); + } + if (!file.createNewFile()) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} File create failed", pathOrFile)); + } + } catch (IOException e) { + throw new IllegalArgumentException(CharSequenceUtil.format("{} File create failed", pathOrFile), e); + } + } + return file; + } +} diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store new file mode 100644 index 0000000..53aead6 Binary files /dev/null and b/src/main/resources/.DS_Store differ diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..d2b4e74 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,11 @@ +spring: + application: + name: Jetbrains-Help + thymeleaf: + cache: false +server: + port: 10768 +help: + default-license-name: 光云 + default-assignee-name: 藏柏 + default-expiry-date: 2111-11-11 \ No newline at end of file diff --git a/src/main/resources/certificate/root.key b/src/main/resources/certificate/root.key new file mode 100644 index 0000000..fafaa78 --- /dev/null +++ b/src/main/resources/certificate/root.key @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFOzCCAyOgAwIBAgIJANJssYOyg3nhMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV +BAMMDUpldFByb2ZpbGUgQ0EwHhcNMTUxMDAyMTEwMDU2WhcNNDUxMDI0MTEwMDU2 +WjAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMIICIjANBgkqhkiG9w0BAQEFAAOC +Ag8AMIICCgKCAgEA0tQuEA8784NabB1+T2XBhpB+2P1qjewHiSajAV8dfIeWJOYG +y+ShXiuedj8rL8VCdU+yH7Ux/6IvTcT3nwM/E/3rjJIgLnbZNerFm15Eez+XpWBl +m5fDBJhEGhPc89Y31GpTzW0vCLmhJ44XwvYPntWxYISUrqeR3zoUQrCEp1C6mXNX +EpqIGIVbJ6JVa/YI+pwbfuP51o0ZtF2rzvgfPzKtkpYQ7m7KgA8g8ktRXyNrz8bo +iwg7RRPeqs4uL/RK8d2KLpgLqcAB9WDpcEQzPWegbDrFO1F3z4UVNH6hrMfOLGVA +xoiQhNFhZj6RumBXlPS0rmCOCkUkWrDr3l6Z3spUVgoeea+QdX682j6t7JnakaOw +jzwY777SrZoi9mFFpLVhfb4haq4IWyKSHR3/0BlWXgcgI6w6LXm+V+ZgLVDON52F +LcxnfftaBJz2yclEwBohq38rYEpb+28+JBvHJYqcZRaldHYLjjmb8XXvf2MyFeXr +SopYkdzCvzmiEJAewrEbPUaTllogUQmnv7Rv9sZ9jfdJ/cEn8e7GSGjHIbnjV2ZM +Q9vTpWjvsT/cqatbxzdBo/iEg5i9yohOC9aBfpIHPXFw+fEj7VLvktxZY6qThYXR +Rus1WErPgxDzVpNp+4gXovAYOxsZak5oTV74ynv1aQ93HSndGkKUE/qA/JECAwEA +AaOBhzCBhDAdBgNVHQ4EFgQUo562SGdCEjZBvW3gubSgUouX8bMwSAYDVR0jBEEw +P4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2Zp +bGUgQ0GCCQDSbLGDsoN54TAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkq +hkiG9w0BAQsFAAOCAgEAjrPAZ4xC7sNiSSqh69s3KJD3Ti4etaxcrSnD7r9rJYpK +BMviCKZRKFbLv+iaF5JK5QWuWdlgA37ol7mLeoF7aIA9b60Ag2OpgRICRG79QY7o +uLviF/yRMqm6yno7NYkGLd61e5Huu+BfT459MWG9RVkG/DY0sGfkyTHJS5xrjBV6 +hjLG0lf3orwqOlqSNRmhvn9sMzwAP3ILLM5VJC5jNF1zAk0jrqKz64vuA8PLJZlL +S9TZJIYwdesCGfnN2AETvzf3qxLcGTF038zKOHUMnjZuFW1ba/12fDK5GJ4i5y+n +fDWVZVUDYOPUixEZ1cwzmf9Tx3hR8tRjMWQmHixcNC8XEkVfztID5XeHtDeQ+uPk +X+jTDXbRb+77BP6n41briXhm57AwUI3TqqJFvoiFyx5JvVWG3ZqlVaeU/U9e0gxn +8qyR+ZA3BGbtUSDDs8LDnE67URzK+L+q0F2BC758lSPNB2qsJeQ63bYyzf0du3wB +/gb2+xJijAvscU3KgNpkxfGklvJD/oDUIqZQAnNcHe7QEf8iG2WqaMJIyXZlW3me +0rn+cgvxHPt6N4EBh5GgNZR4l0eaFEV+fxVsydOQYo1RIyFMXtafFBqQl6DDxujl +FeU3FZ+Bcp12t7dlM4E0/sS1XdL47CfGVj4Bp+/VbF862HmkAbd7shs7sDQkHbU= +-----END CERTIFICATE----- diff --git a/src/main/resources/plugin.json b/src/main/resources/plugin.json new file mode 100644 index 0000000..8060bda --- /dev/null +++ b/src/main/resources/plugin.json @@ -0,0 +1,1612 @@ +[ + { + "id": 9269, + "productCode": "PAEMIDE", + "name": "AEM IDE", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/9269/503057/icon/pluginIcon.svg" + }, + { + "id": 9863, + "productCode": "PAEM", + "name": "AEM Support", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/9863/509753/icon/pluginIcon.svg" + }, + { + "id": 21263, + "productCode": "PAICODING", + "name": "AI Coding", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/21263/513630/icon/pluginIcon.svg" + }, + { + "id": 21289, + "productCode": "PCAICOMMITAPP", + "name": "AICommit", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/21289/504423/icon/pluginIcon.svg" + }, + { + "id": 12408, + "productCode": "PBISAA", + "name": "Android Antidecompiler", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/12408/229970/icon/pluginIcon.svg" + }, + { + "id": 15456, + "productCode": "PAPH", + "name": "Android Package Helper", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15456/104869/icon/pluginIcon.svg" + }, + { + "id": 13156, + "productCode": "PWIFIADB", + "name": "Android WiFiADB", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13156/154275/icon/pluginIcon.svg" + }, + { + "id": 9707, + "productCode": "PANSIHIGHLIGHT", + "name": "ANSI Highlighter Premium", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/9707/518674/icon/pluginIcon.svg" + }, + { + "id": 18357, + "productCode": "PCDAPIRUNNER", + "name": "API Runner", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18357/269544/icon/pluginIcon.svg" + }, + { + "id": 16682, + "productCode": "PAPPLETRUNNER", + "name": "Applet Runner", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/16682/506565/icon/pluginIcon.svg" + }, + { + "id": 21566, + "productCode": "PARMADILLO", + "name": "Armadillo", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/21566/354792/icon/pluginIcon.svg" + }, + { + "id": 17699, + "productCode": "PASTOCK", + "name": "AStock", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/17699/468853/icon/pluginIcon.svg" + }, + { + "id": 13016, + "productCode": "PATOMONEDARK", + "name": "Atom One Dark By Mayke", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13016/122178/icon/pluginIcon.svg" + }, + { + "id": 14088, + "productCode": "PGOLANGCODESUGG", + "name": "Auto GOLang Code Suggestions", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14088/191484/icon/pluginIcon.svg" + }, + { + "id": 14070, + "productCode": "PJAVACODESUGG", + "name": "Auto Java Code Suggestions", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14070/191711/icon/pluginIcon.svg" + }, + { + "id": 14166, + "productCode": "PJSCODESUGG", + "name": "Auto Javascript Code Suggestions", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14166/191485/icon/pluginIcon.svg" + }, + { + "id": 14167, + "productCode": "PPHPCODESUGG", + "name": "Auto PHP Code Suggestions", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14167/191710/icon/pluginIcon.svg" + }, + { + "id": 14594, + "productCode": "PPYCODESUGG", + "name": "Auto Python Code Suggestions", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14594/190896/icon/pluginIcon.svg" + }, + { + "id": 14089, + "productCode": "PRUBYCODESUGG", + "name": "Auto Ruby Code Suggestions", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14089/191482/icon/pluginIcon.svg" + }, + { + "id": 10904, + "productCode": "PBRWJV", + "name": "AutoCode for Java", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 23577, + "productCode": "PAUTOLOG", + "name": "AutoLog", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23577/473858/icon/pluginIcon.svg" + }, + { + "id": 14742, + "productCode": "PAWSLAMBDADEPLR", + "name": "AWS Lambda Deployer", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 22319, + "productCode": "PAZD", + "name": "Azd", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22319/517134/icon/pluginIcon.svg" + }, + { + "id": 22194, + "productCode": "PAZURECODING", + "name": "Azure Coding", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22194/355932/icon/pluginIcon.svg" + }, + { + "id": 13841, + "productCode": "PBASHSUPPORTPRO", + "name": "BashSupport Pro", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13841/514417/icon/pluginIcon.svg" + }, + { + "id": 12895, + "productCode": "PBETTERHIGHLIGH", + "name": "Better Highlights", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/12895/514904/icon/pluginIcon.svg" + }, + { + "id": 13538, + "productCode": "PCREVIEW", + "name": "Bitbucket Pull Requests", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13538/516839/icon/pluginIcon.svg" + }, + { + "id": 16222, + "productCode": "PBITRISECI", + "name": "Bitrise Dashboard", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/16222/463944/icon/pluginIcon.svg" + }, + { + "id": 20061, + "productCode": "PBREWBUNDLE", + "name": "Brew Bundle", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20061/471756/icon/pluginIcon.svg" + }, + { + "id": 20985, + "productCode": "PBUILDMON", + "name": "Build Monitor", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/20985/452340/icon/pluginIcon.svg" + }, + { + "id": 17692, + "productCode": "PCAPELASTIC", + "name": "Cap-Elasticsearch", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/17692/256059/icon/pluginIcon.svg" + }, + { + "id": 17785, + "productCode": "PCAPREDIS", + "name": "Cap-Redis", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/17785/256060/icon/pluginIcon.svg" + }, + { + "id": 21314, + "productCode": "PCHATGPTCODING", + "name": "ChatGPT Coding", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/21314/346162/icon/pluginIcon.svg" + }, + { + "id": 19114, + "productCode": "PCIINTG", + "name": "CIclone", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19114/472822/icon/pluginIcon.svg" + }, + { + "id": 15458, + "productCode": "PCIRCLECI", + "name": "CircleCI Dashboard", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15458/463945/icon/pluginIcon.svg" + }, + { + "id": 22813, + "productCode": "PCITRIC", + "name": "Citric", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22813/515382/icon/pluginIcon.svg" + }, + { + "id": 23887, + "productCode": "PCLAI", + "name": "CLAi", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23887/515259/icon/pluginIcon.svg" + }, + { + "id": 12869, + "productCode": "PCMAKEPLUS", + "name": "CMake Plus", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/12869/496990/icon/pluginIcon.svg" + }, + { + "id": 17501, + "productCode": "PISCRATCH", + "name": "Code Note: In IDE Note-Taking, Project Notes", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/17501/509149/icon/pluginIcon.svg" + }, + { + "id": 18394, + "productCode": "PCODEREFACTORAI", + "name": "Code Refactor AI", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18394/153532/icon/pluginIcon.svg" + }, + { + "id": 14896, + "productCode": "PCWMP", + "name": "Code With Me", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 19097, + "productCode": "PWGCODECREATOR", + "name": "codeCreator", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 19578, + "productCode": "PCODEKITS", + "name": "CodeKits", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/19578/302019/icon/pluginIcon.svg" + }, + { + "id": 10811, + "productCode": "PCODEMRBASE", + "name": "CodeMR", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/10811/186959/icon/pluginIcon.svg" + }, + { + "id": 14104, + "productCode": "PVCS", + "name": "commit-template", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14104/250600/icon/pluginIcon.svg" + }, + { + "id": 20293, + "productCode": "PCONNECTUI", + "name": "Connect Api", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/20293/452254/icon/pluginIcon.svg" + }, + { + "id": 21857, + "productCode": "PCUEFY", + "name": "Cuefy", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/21857/428708/icon/pluginIcon.svg" + }, + { + "id": 23561, + "productCode": "PDATABASEBUDDY", + "name": "Database Buddy", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23561/474923/icon/pluginIcon.svg" + }, + { + "id": 16861, + "productCode": "PDATABASE", + "name": "Database Helper", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/16861/500171/icon/pluginIcon.svg" + }, + { + "id": 19161, + "productCode": "PDBDATABASETOOL", + "name": "Database Tool", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19161/514290/icon/pluginIcon.svg" + }, + { + "id": 10925, + "productCode": "PDB", + "name": "Database Tools and SQL for WebStorm", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/10925/511241/icon/pluginIcon.svg" + }, + { + "id": 22472, + "productCode": "PDATAGRAPH", + "name": "DataGraph - JSON, YAML, XML Visualization", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/22472/503936/icon/pluginIcon.svg" + }, + { + "id": 11461, + "productCode": "DC", + "name": "dotCover", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/11461/81836/icon/META-INF_pluginIcon.svg" + }, + { + "id": 11462, + "productCode": "DPN", + "name": "dotTrace", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/11462/81835/icon/META-INF_pluginIcon.svg" + }, + { + "id": 18896, + "productCode": "PDYNAMODB", + "name": "DynamoDB", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18896/503820/icon/pluginIcon.svg" + }, + { + "id": 14512, + "productCode": "PELASTICSEARCH", + "name": "Elasticsearch", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14512/511081/icon/pluginIcon.svg" + }, + { + "id": 18209, + "productCode": "PELSA", + "name": "ElasticSearch-Admin", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 18663, + "productCode": "PEXCELEDITOR", + "name": "ExcelEditor", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/18663/510865/icon/pluginIcon.svg" + }, + { + "id": 15379, + "productCode": "PGODRUNNER", + "name": "Execution God Recorder", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15379/102175/icon/pluginIcon.svg" + }, + { + "id": 20238, + "productCode": "PEXTENSION", + "name": "Extensions Manager", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20238/308627/icon/pluginIcon.svg" + }, + { + "id": 11058, + "productCode": "PEXTRAICONS", + "name": "Extra Icons", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/11058/516273/icon/pluginIcon.svg" + }, + { + "id": 23927, + "productCode": "PEXTRAIDETWEAKS", + "name": "Extra IDE Tweaks", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23927/515986/icon/pluginIcon.svg" + }, + { + "id": 16988, + "productCode": "PFASTREQUEST", + "name": "Fast Request - API Buddy", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/16988/498000/icon/pluginIcon.svg" + }, + { + "id": 18971, + "productCode": "PFASTSHELL", + "name": "FastShell", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/18971/200999/icon/pluginIcon.svg" + }, + { + "id": 23146, + "productCode": "PFEIGNHELPER", + "name": "Feign-Helper", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23146/473643/icon/pluginIcon.svg" + }, + { + "id": 16217, + "productCode": "PFUZYFIPC", + "name": "Find In Files (Favorites)", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/16217/518682/icon/pluginIcon.svg" + }, + { + "id": 23609, + "productCode": "PFIREBASE", + "name": "Firebase Firestore", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23609/503413/icon/pluginIcon.svg" + }, + { + "id": 15189, + "productCode": "PFIREHIGHLIGHT", + "name": "Firebase Rules", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15189/471752/icon/pluginIcon.svg" + }, + { + "id": 23685, + "productCode": "PSCIPIOFTL", + "name": "Flexible Freemarker", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23685/483800/icon/pluginIcon.svg" + }, + { + "id": 14718, + "productCode": "PFLUTTER", + "name": "Flutter Storm", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14718/367205/icon/pluginIcon.svg" + }, + { + "id": 13086, + "productCode": "PGDOC", + "name": "Generate Document", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13086/499172/icon/pluginIcon.svg" + }, + { + "id": 22971, + "productCode": "PGENSETANDSET", + "name": "GenerateSetAndGet", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22971/467619/icon/pluginIcon.svg" + }, + { + "id": 20319, + "productCode": "PGERRYAURORA", + "name": "Gerry Aurora", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20319/435418/icon/pluginIcon.svg" + }, + { + "id": 20246, + "productCode": "PGERRYCHERRY", + "name": "Gerry Cherry", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20246/435417/icon/pluginIcon.svg" + }, + { + "id": 20247, + "productCode": "PGERRYCOFFEE", + "name": "Gerry Coffee", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20247/435420/icon/pluginIcon.svg" + }, + { + "id": 20049, + "productCode": "PGERRYCYBERPUNK", + "name": "Gerry Cyberpunk", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20049/435415/icon/pluginIcon.svg" + }, + { + "id": 20236, + "productCode": "PGERRYNATURE", + "name": "Gerry Nature", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20236/435419/icon/pluginIcon.svg" + }, + { + "id": 20075, + "productCode": "PGERRYSPACE", + "name": "Gerry Space", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20075/435416/icon/pluginIcon.svg" + }, + { + "id": 19668, + "productCode": "PGERRYTHEMESPRO", + "name": "Gerry Themes Pro", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19668/517943/icon/pluginIcon.svg" + }, + { + "id": 10083, + "productCode": "PGITSCOPE", + "name": "Git Scope", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/10083/396420/icon/pluginIcon.svg" + }, + { + "id": 23813, + "productCode": "PGITWORKTREE", + "name": "Git Worktree", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/23813/493642/icon/pluginIcon.svg" + }, + { + "id": 14056, + "productCode": "PGITFLOWPLUS", + "name": "GitFlowPlus", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/14056/506220/icon/pluginIcon.svg" + }, + { + "id": 20144, + "productCode": "PGITHUBCI", + "name": "Github CI Dashboard", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20144/463946/icon/pluginIcon.svg" + }, + { + "id": 15457, + "productCode": "PGITLABCI", + "name": "Gitlab CI Pipeline Dashboard", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15457/463947/icon/pluginIcon.svg" + }, + { + "id": 22202, + "productCode": "PGITLABCICD", + "name": "GitLab CICD - Pipelines \u0026 Jobs, Builds Run Cancel Retry View Log", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22202/517828/icon/pluginIcon.svg" + }, + { + "id": 18689, + "productCode": "PGITLAB", + "name": "GitLab Merge Requests", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18689/516838/icon/pluginIcon.svg" + }, + { + "id": 7499, + "productCode": "PGITTOOLBOX", + "name": "GitToolBox", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/7499/512954/icon/pluginIcon.svg" + }, + { + "id": 19906, + "productCode": "PGOPARSER", + "name": "GoParser", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19906/293012/icon/pluginIcon.svg" + }, + { + "id": 20411, + "productCode": "PWXUFQYRHZCRSEO", + "name": "Gorm", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20411/502598/icon/pluginIcon.svg" + }, + { + "id": 22035, + "productCode": "PGPTASSISTANT", + "name": "GPT Assistant", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22035/510722/icon/pluginIcon.svg" + }, + { + "id": 15535, + "productCode": "PHEROKU", + "name": "Heroku Dashboard", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15535/463948/icon/pluginIcon.svg" + }, + { + "id": 7525, + "productCode": "PHYBRISCOMMERCE", + "name": "Hybris Integration", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/7525/517492/icon/pluginIcon.svg" + }, + { + "id": 12634, + "productCode": "PIEDIS", + "name": "Iedis 2", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/12634/167816/icon/pluginIcon.svg" + }, + { + "id": 22459, + "productCode": "PIMAGETOVECTOR", + "name": "ImageToVector", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22459/376877/icon/pluginIcon.svg" + }, + { + "id": 23859, + "productCode": "PINTELLIPHP", + "name": "IntelliPHP - AI Autocomplete for PHP", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23859/505657/icon/pluginIcon.svg" + }, + { + "id": 20526, + "productCode": "PWAUFKYVHQCRXEO", + "name": "IoGame", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20526/468605/icon/pluginIcon.svg" + }, + { + "id": 11560, + "productCode": "PBISJ", + "name": "Java Antidecompiler", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/11560/367010/icon/pluginIcon.svg" + }, + { + "id": 10828, + "productCode": "PJDCLEANREAD", + "name": "JavaDoc Clean Read", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/10828/375796/icon/pluginIcon.svg" + }, + { + "id": 20888, + "productCode": "PWXUQQYVOXCRSEO", + "name": "JavaOrm", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20888/438337/icon/pluginIcon.svg" + }, + { + "id": 14557, + "productCode": "PVISUALGC", + "name": "JDK VisualGC", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/14557/453632/icon/pluginIcon.svg" + }, + { + "id": 22282, + "productCode": "AIP", + "name": "JetBrains AI Assistant", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/22282/515367/icon/pluginIcon.svg" + }, + { + "id": 21173, + "productCode": "PJETCLIENT", + "name": "JetClient - The Ultimate REST Client", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/21173/515501/icon/pluginIcon.svg" + }, + { + "id": 9238, + "productCode": "PJETFORCER", + "name": "JetForcer | The Smartest Force.com IDE", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 12621, + "productCode": "PJFORMDESIGNER", + "name": "JFormDesigner (Marketplace Edition)", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/12621/516265/icon/pluginIcon.svg" + }, + { + "id": 23812, + "productCode": "PJMETERPLUGINSM", + "name": "JMeter Plugins Manager", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23812/492356/icon/pluginIcon.svg" + }, + { + "id": 23855, + "productCode": "PJMETERRUNNER", + "name": "JMeter Runner", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23855/494217/icon/pluginIcon.svg" + }, + { + "id": 15242, + "productCode": "PJPASQL", + "name": "JPA SQL", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/15242/510410/icon/pluginIcon.svg" + }, + { + "id": 23360, + "productCode": "PJQEXPRESS", + "name": "jqExpress", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23360/492713/icon/pluginIcon.svg" + }, + { + "id": 22597, + "productCode": "POXYJSONSCHGEN", + "name": "JSON Schema Generator", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22597/471041/icon/pluginIcon.svg" + }, + { + "id": 23554, + "productCode": "POXYJSONDIAGRAM", + "name": "JSON Schema Visualizer/Editor", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23554/503415/icon/pluginIcon.svg" + }, + { + "id": 20297, + "productCode": "POXYJSONCONVERT", + "name": "JSON-YAML-XML Converter", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20297/472486/icon/pluginIcon.svg" + }, + { + "id": 18975, + "productCode": "PJSONNETEMLSUP", + "name": "Jsonnet Pro", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18975/458972/icon/pluginIcon.svg" + }, + { + "id": 19297, + "productCode": "PJSONTOANYLANGU", + "name": "JsonToAnyLanguage", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/19297/351202/icon/pluginIcon.svg" + }, + { + "id": 14393, + "productCode": "PJSONTOTS", + "name": "JsonToTypeScript", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/14393/321300/icon/pluginIcon.svg" + }, + { + "id": 22284, + "productCode": "PKAFKA", + "name": "Kafka Client", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22284/428744/icon/pluginIcon.svg" + }, + { + "id": 20111, + "productCode": "PKAFKAIDE", + "name": "Kafkaide", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20111/425515/icon/pluginIcon.svg" + }, + { + "id": 18286, + "productCode": "PKSEXPLORER", + "name": "KS-Explorer", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18286/518701/icon/pluginIcon.svg" + }, + { + "id": 13441, + "productCode": "PLARAVEL", + "name": "Laravel Idea", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13441/507406/icon/pluginIcon.svg" + }, + { + "id": 19661, + "productCode": "PLATTEPRO", + "name": "Latte Pro", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19661/440924/icon/pluginIcon.svg" + }, + { + "id": 15405, + "productCode": "PLEDGER", + "name": "Ledger CLI", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15405/458942/icon/pluginIcon.svg" + }, + { + "id": 17166, + "productCode": "PLEP", + "name": "LeetCode Editor Pro", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/17166/502109/icon/pluginIcon.svg" + }, + { + "id": 22223, + "productCode": "PLOCALSTACK", + "name": "LocalStack Integrator", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/22223/518671/icon/pluginIcon.svg" + }, + { + "id": 20554, + "productCode": "PMAGE", + "name": "Magento and Adobe Commerce PhpStorm by Atwix", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/20554/505887/icon/pluginIcon.svg" + }, + { + "id": 23556, + "productCode": "PSCIPIOMGNL", + "name": "Magnolia CMS Integration", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23556/483799/icon/pluginIcon.svg" + }, + { + "id": 17688, + "productCode": "PRSMGNL", + "name": "Magnolia YAML Assistant", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/17688/511232/icon/pluginIcon.svg" + }, + { + "id": 8006, + "productCode": "PMATERIALUI", + "name": "Material Theme UI", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/8006/518563/icon/pluginIcon.svg" + }, + { + "id": 19308, + "productCode": "PMATERIALCUSTOM", + "name": "Material Theme UI Custom Theme", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19308/384272/icon/pluginIcon.svg" + }, + { + "id": 19250, + "productCode": "PMATERIALEXTRAS", + "name": "Material Theme UI Extras", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19250/384271/icon/pluginIcon.svg" + }, + { + "id": 17456, + "productCode": "PMATERIALHC", + "name": "Material Theme UI High Contrast", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/17456/384270/icon/pluginIcon.svg" + }, + { + "id": 19309, + "productCode": "PMATERIALLANG", + "name": "Material Theme UI Language Additions", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19309/384269/icon/pluginIcon.svg" + }, + { + "id": 19310, + "productCode": "PMATERIALFRAME", + "name": "Material Theme UI Project Frame", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19310/385745/icon/pluginIcon.svg" + }, + { + "id": 13615, + "productCode": "PMRINTEGEE", + "name": "Merge Request Integration EE - Code Review for GitLab", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13615/113000/icon/pluginIcon.svg" + }, + { + "id": 23687, + "productCode": "PMICRONAUTLAUNC", + "name": "Micronaut Launch", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23687/478379/icon/pluginIcon.svg" + }, + { + "id": 13720, + "productCode": "PMINBATIS", + "name": "MinBatis", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13720/116149/icon/pluginIcon.svg" + }, + { + "id": 23999, + "productCode": "PMONGODB", + "name": "Mongo DB", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23999/518250/icon/pluginIcon.svg" + }, + { + "id": 20761, + "productCode": "PMONGOEXPERT", + "name": "Mongo Expert", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20761/510302/icon/pluginIcon.svg" + }, + { + "id": 17465, + "productCode": "PCDMQTTCLIENT", + "name": "MQTT Client", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/17465/308433/icon/pluginIcon.svg" + }, + { + "id": 13905, + "productCode": "PMYBATISLOG", + "name": "MyBatis Log", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13905/447241/icon/pluginIcon.svg" + }, + { + "id": 18389, + "productCode": "PMBCODEHELPPRO", + "name": "Mybatis Smart Code Help Pro", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/18389/516824/icon/pluginIcon.svg" + }, + { + "id": 23478, + "productCode": "PMYBATISCODE", + "name": "MybatisCode", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23478/472229/icon/pluginIcon.svg" + }, + { + "id": 14522, + "productCode": "PMYBATISHELPER", + "name": "MyBatisCodeHelperPro (Marketplace Edition)", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14522/510194/icon/pluginIcon.svg" + }, + { + "id": 22655, + "productCode": "PMYSQLPROXY", + "name": "MySQL Proxy", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/22655/436599/icon/pluginIcon.svg" + }, + { + "id": 18387, + "productCode": "PNEONPRO", + "name": "NEON Nette Support", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18387/479200/icon/pluginIcon.svg" + }, + { + "id": 19977, + "productCode": "PNETLIFY", + "name": "Netlify Dashboard", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19977/463949/icon/pluginIcon.svg" + }, + { + "id": 19963, + "productCode": "PNEXTSKETCH", + "name": "NextSketch", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19963/272018/icon/pluginIcon.svg" + }, + { + "id": 20805, + "productCode": "PNEXTSKETCHTWO", + "name": "NextSketch2", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20805/308349/icon/pluginIcon.svg" + }, + { + "id": 23765, + "productCode": "PNFLUTTER", + "name": "NFlutter", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23765/492994/icon/pluginIcon.svg" + }, + { + "id": 18280, + "productCode": "PNGINX", + "name": "Nginx Configuration Pro", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18280/239000/icon/pluginIcon.svg" + }, + { + "id": 19205, + "productCode": "PNGROK", + "name": "Ngrok", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/19205/510423/icon/pluginIcon.svg" + }, + { + "id": 21833, + "productCode": "PNOSQLNAVMDB", + "name": "NoSQL Navigator For MongoDB", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/21833/433051/icon/pluginIcon.svg" + }, + { + "id": 22128, + "productCode": "PNPMPACKAGEJSON", + "name": "NPM Package Json", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22128/451192/icon/pluginIcon.svg" + }, + { + "id": 13499, + "productCode": "PODOO", + "name": "Odoo", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13499/512679/icon/pluginIcon.svg" + }, + { + "id": 13151, + "productCode": "POFFICEFLOOR", + "name": "OfficeFloor", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13151/131867/icon/pluginIcon.svg" + }, + { + "id": 19889, + "productCode": "POPENAPICRUDWIZ", + "name": "OpenAPI CRUD Wizard", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/19889/478359/icon/pluginIcon.svg" + }, + { + "id": 12887, + "productCode": "POPENAPI", + "name": "OpenAPI Editor", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/12887/512174/icon/pluginIcon.svg" + }, + { + "id": 14371, + "productCode": "PIMAGEVIEWER", + "name": "OpenCV Image Viewer", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/14371/480879/icon/pluginIcon.svg" + }, + { + "id": 12626, + "productCode": "PORCHIDE", + "name": "OrchidE - Ansible Language Support", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 19660, + "productCode": "PAWSQLADVISOR", + "name": "PawSQL Advisor,SQL Audit/Rewrite/Index Advice,Tune SQL by Clicks", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19660/502106/icon/pluginIcon.svg" + }, + { + "id": 17440, + "productCode": "PHPBUILDER", + "name": "PHP Data Object Generator", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/17440/458368/icon/pluginIcon.svg" + }, + { + "id": 18981, + "productCode": "PPHPHOUDINI", + "name": "PHP Houdini", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18981/271233/icon/pluginIcon.svg" + }, + { + "id": 16935, + "productCode": "PHPEAPLUGIN", + "name": "Php Inspections (EA Ultimate)", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 14821, + "productCode": "PPUMLSTUDIO", + "name": "PlantUML Studio", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14821/172312/icon/pluginIcon.svg" + }, + { + "id": 13733, + "productCode": "PPOJOTOJSONSCH", + "name": "POJO to JSON Schema", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13733/95154/icon/pluginIcon.svg" + }, + { + "id": 22429, + "productCode": "PPOLARISTOMCATS", + "name": "Polaris Tomcat Server", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22429/506445/icon/pluginIcon.svg" + }, + { + "id": 21361, + "productCode": "POLYBPMNGDNEXT", + "name": "PolyBPMN visualizer", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/21361/479001/icon/pluginIcon.svg" + }, + { + "id": 14434, + "productCode": "PQMLEDITOR", + "name": "QmlEditor", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14434/314029/icon/pluginIcon.svg" + }, + { + "id": 16405, + "productCode": "PQTSQSSEDITOR", + "name": "Qt Style Sheets Editor", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/16405/193379/icon/pluginIcon.svg" + }, + { + "id": 19027, + "productCode": "PQUARKUSHELPER", + "name": "Quarkus Assistant", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19027/477162/icon/pluginIcon.svg" + }, + { + "id": 18269, + "productCode": "PQUERYFLAG", + "name": "QueryFlag", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18269/508126/icon/pluginIcon.svg" + }, + { + "id": 10080, + "productCode": "PRAINBOWBRACKET", + "name": "Rainbow Brackets", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/10080/509542/icon/pluginIcon.svg" + }, + { + "id": 19316, + "productCode": "PRANCHER", + "name": "Rancher", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19316/367013/icon/pluginIcon.svg" + }, + { + "id": 13838, + "productCode": "PRDFANDSPARQL", + "name": "RDF and SPARQL", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13838/499816/icon/pluginIcon.svg" + }, + { + "id": 9564, + "productCode": "PRNCONSOLE", + "name": "React Native Console", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/9564/514551/icon/pluginIcon.svg" + }, + { + "id": 12820, + "productCode": "PREDIS", + "name": "Redis", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/12820/433300/icon/pluginIcon.svg" + }, + { + "id": 19360, + "productCode": "PREDISCLIHELPER", + "name": "Redis Client", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19360/479210/icon/pluginIcon.svg" + }, + { + "id": 15722, + "productCode": "PREDISMANAGER", + "name": "Redis Manager", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15722/270538/icon/pluginIcon.svg" + }, + { + "id": 19599, + "productCode": "PREDISS", + "name": "Redis Operator", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19599/518569/icon/pluginIcon.svg" + }, + { + "id": 16160, + "productCode": "PREDISTOOLS", + "name": "Redis-Cli", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/16160/286263/icon/pluginIcon.svg" + }, + { + "id": 15433, + "productCode": "PREGEXTOOL", + "name": "Regex Tool", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15433/510718/icon/pluginIcon.svg" + }, + { + "id": 14723, + "productCode": "PRESTKIT", + "name": "RestfulBox", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/14723/464469/icon/pluginIcon.svg" + }, + { + "id": 22726, + "productCode": "PRETROFITASSIT", + "name": "Retrofit Assistant", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22726/514538/icon/pluginIcon.svg" + }, + { + "id": 22428, + "productCode": "PWXUQRYTOXCRSEO", + "name": "RustTool", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22428/513930/icon/pluginIcon.svg" + }, + { + "id": 13668, + "productCode": "PSFCC", + "name": "Salesforce B2C Commerce (SFCC)", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/13668/510847/icon/pluginIcon.svg" + }, + { + "id": 22748, + "productCode": "PSCHEMAREGVIEW", + "name": "Schema Registry Viewer", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22748/496140/icon/pluginIcon.svg" + }, + { + "id": 12108, + "productCode": "PSCIPIO", + "name": "Scipio ERP Integration", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/12108/478355/icon/pluginIcon.svg" + }, + { + "id": 19556, + "productCode": "PSCREENCODEPRO", + "name": "ScreenCodePro", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19556/198086/icon/pluginIcon.svg" + }, + { + "id": 22232, + "productCode": "PSENTRY", + "name": "Sentry", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/22232/514906/icon/pluginIcon.svg" + }, + { + "id": 15945, + "productCode": "PSENTRYINTEG", + "name": "Sentry Integration", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15945/111527/icon/pluginIcon.svg" + }, + { + "id": 8286, + "productCode": "PSEQUENCEDIAGRA", + "name": "SequenceDiagram", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/8286/485614/icon/pluginIcon.svg" + }, + { + "id": 23115, + "productCode": "PSEQDIAORG", + "name": "SequenceDiagram.org", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23115/485275/icon/pluginIcon.svg" + }, + { + "id": 14437, + "productCode": "PSI", + "name": "Shared Project Indexes", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14437/508994/icon/pluginIcon.svg" + }, + { + "id": 7410, + "productCode": "PSWPLUGIN", + "name": "Shopware", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/7410/167127/icon/pluginIcon.svg" + }, + { + "id": 18151, + "productCode": "PBEANCONVERTER", + "name": "Simple Object Copy", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 20243, + "productCode": "PSKOL", + "name": "Skol", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20243/518236/icon/pluginIcon.svg" + }, + { + "id": 14053, + "productCode": "PSMARTJUMP", + "name": "Smart Jump", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14053/274462/icon/pluginIcon.svg" + }, + { + "id": 20565, + "productCode": "PTAILWINDTOOLS", + "name": "Snippet Toolkit for Tailwind CSS", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20565/502104/icon/pluginIcon.svg" + }, + { + "id": 23743, + "productCode": "PSOTERISECURITY", + "name": "Soteri Secret Scanner", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23743/484143/icon/pluginIcon.svg" + }, + { + "id": 22318, + "productCode": "PSOURCESYNCPRO", + "name": "Source Synchronizer Pro", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22318/503948/icon/pluginIcon.svg" + }, + { + "id": 14338, + "productCode": "PSPARQL", + "name": "SPARQL", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/14338/165810/icon/pluginIcon.svg" + }, + { + "id": 22635, + "productCode": "PSPEECHTOTEXT", + "name": "Speech-To-Text (AWS Transcribe)", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22635/388024/icon/pluginIcon.svg" + }, + { + "id": 18622, + "productCode": "PSPRINGBOOTIDEA", + "name": "Spring Boot Helper", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18622/472683/icon/pluginIcon.svg" + }, + { + "id": 22304, + "productCode": "PSRCODEGEN", + "name": "Spring Rest Code Generator", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22304/391163/icon/pluginIcon.svg" + }, + { + "id": 15574, + "productCode": "PFLYINSKYZJBZ", + "name": "spring-assistant-@valueToYml", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15574/412050/icon/pluginIcon.svg" + }, + { + "id": 20534, + "productCode": "PSQLFLUFFLINTER", + "name": "Sqlfluff Linter (Ultimate Edition)", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20534/502715/icon/pluginIcon.svg" + }, + { + "id": 22742, + "productCode": "PSQLFORMATTER", + "name": "SQLFormatter", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 22713, + "productCode": "PDBSSH", + "name": "SSH Tool", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/22713/516730/icon/pluginIcon.svg" + }, + { + "id": 15851, + "productCode": "PSTORMSECTIONS", + "name": "StormSections", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/15851/449282/icon/pluginIcon.svg" + }, + { + "id": 14482, + "productCode": "PSTRKER", + "name": "Stryker", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/14482/134911/icon/pluginIcon.svg" + }, + { + "id": 23458, + "productCode": "PSWISSKITCONVER", + "name": "SwissKit Converter", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23458/469170/icon/pluginIcon.svg" + }, + { + "id": 7219, + "productCode": "PSYMFONYPLUGIN", + "name": "Symfony Support", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/7219/514919/icon/pluginIcon.svg" + }, + { + "id": 10695, + "productCode": "PVLOG", + "name": "SystemVerilog", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/10695/163626/icon/pluginIcon.svg" + }, + { + "id": 14203, + "productCode": "PSVERILOG", + "name": "SystemVerilog Studio", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 22685, + "productCode": "PNEKOCAT", + "name": "TamaCat the Embedded Internet Browser", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/22685/456002/icon/pluginIcon.svg" + }, + { + "id": 18857, + "productCode": "PTERMINAL", + "name": "Terminal Pro", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/18857/505301/icon/pluginIcon.svg" + }, + { + "id": 20050, + "productCode": "PTLDRAI", + "name": "TLDR", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/20050/394140/icon/pluginIcon.svg" + }, + { + "id": 14384, + "productCode": "PTOOLSET", + "name": "Toolset", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/14384/497387/icon/pluginIcon.svg" + }, + { + "id": 20683, + "productCode": "PTRAVISCI", + "name": "Travis CI Dashboard", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/20683/463950/icon/pluginIcon.svg" + }, + { + "id": 18232, + "productCode": "PDJANGOTPLPEP", + "name": "Typed Django Template", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/18232/370564/icon/pluginIcon.svg" + }, + { + "id": 19675, + "productCode": "PUNIAPPSUPPORT", + "name": "Uniapp Support", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/19675/450668/icon/pluginIcon.svg" + }, + { + "id": 21813, + "productCode": "PVERILOGLANGUAG", + "name": "Verilog Language Support", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/21813/472208/icon/pluginIcon.svg" + }, + { + "id": 23086, + "productCode": "PVOQAL", + "name": "Voqal Assistant", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23086/518244/icon/pluginIcon.svg" + }, + { + "id": 18860, + "productCode": "PWIREMOCHA", + "name": "WireMocha", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18860/517127/icon/pluginIcon.svg" + }, + { + "id": 7232, + "productCode": "PWLANG", + "name": "Wolfram Language", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/7232/476166/icon/pluginIcon.svg" + }, + { + "id": 18425, + "productCode": "PXSDVISUALIZER", + "name": "XSD / WSDL Visualizer", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/18425/515020/icon/pluginIcon.svg" + }, + { + "id": 19024, + "productCode": "POXYXSDJSONSCH", + "name": "XSD to JSON Schema", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/19024/472499/icon/pluginIcon.svg" + }, + { + "id": 9739, + "productCode": "PYAOQIANGBPMN", + "name": "Yaoqiang BPMN Editor", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + }, + { + "id": 23693, + "productCode": "PYIIFRAMEWORK", + "name": "Yii2 Framework Support", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/23693/504334/icon/pluginIcon.svg" + }, + { + "id": 12437, + "productCode": "PZENUML", + "name": "ZenUML Support", + "pricingModel": "FREEMIUM", + "icon": "https://plugins.jetbrains.com/files/12437/466910/icon/pluginIcon.svg" + }, + { + "id": 15773, + "productCode": "PZEROCODE", + "name": "Zerocode Scenario Helper", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com/files/15773/155295/icon/pluginIcon.svg" + }, + { + "id": 18341, + "productCode": "PZKA", + "name": "Zookeeper-Admin", + "pricingModel": "PAID", + "icon": "https://plugins.jetbrains.com" + } +] diff --git a/src/main/resources/product.json b/src/main/resources/product.json new file mode 100644 index 0000000..0d10b03 --- /dev/null +++ b/src/main/resources/product.json @@ -0,0 +1,67 @@ +[ + { + "name": "All Jetbrains's Product Or Plugin", + "productCode": "", + "iconClass": "icon-al" + }, + { + "name": "IntelliJ IDEA", + "productCode": "II,PCWMP,PSI", + "iconClass": "icon-ii" + }, + { + "name": "PhpStorm", + "productCode": "PS,PCWMP,PSI", + "iconClass": "icon-ps" + }, + { + "name": "AppCode", + "productCode": "AC,PCWMP,PSI", + "iconClass": "icon-ac" + }, + { + "name": "DataGrip", + "productCode": "DB,PSI,PDB", + "iconClass": "icon-db" + }, + { + "name": "RubyMine", + "productCode": "RM,PCWMP,PSI", + "iconClass": "icon-rm" + }, + { + "name": "WebStorm", + "productCode": "WS,PCWMP,PSI", + "iconClass": "icon-ws" + }, + { + "name": "Rider", + "productCode": "RD,PDB,PSI,PCWMP", + "iconClass": "icon-rd" + }, + { + "name": "CLion", + "productCode": "CL,PSI,PCWMP", + "iconClass": "icon-cl" + }, + { + "name": "PyCharm", + "productCode": "PC,PSI,PCWMP", + "iconClass": "icon-pc" + }, + { + "name": "GoLand", + "productCode": "GO,PSI,PCWMP", + "iconClass": "icon-go" + }, + { + "name": "DataSpell", + "productCode": "DS,PSI,PDB,PCWMP", + "iconClass": "icon-ds" + }, + { + "name": "dotMemory", + "productCode": "DM", + "iconClass": "icon-dm" + } +] \ No newline at end of file diff --git a/src/main/resources/static/.DS_Store b/src/main/resources/static/.DS_Store new file mode 100644 index 0000000..a9fab93 Binary files /dev/null and b/src/main/resources/static/.DS_Store differ diff --git a/src/main/resources/static/agent/.DS_Store b/src/main/resources/static/agent/.DS_Store new file mode 100644 index 0000000..9b5350d Binary files /dev/null and b/src/main/resources/static/agent/.DS_Store differ diff --git a/src/main/resources/static/agent/ja-netfilter/.DS_Store b/src/main/resources/static/agent/ja-netfilter/.DS_Store new file mode 100644 index 0000000..a500b72 Binary files /dev/null and b/src/main/resources/static/agent/ja-netfilter/.DS_Store differ diff --git a/src/main/resources/static/agent/ja-netfilter/config/dns.conf b/src/main/resources/static/agent/ja-netfilter/config/dns.conf new file mode 100644 index 0000000..54de89f --- /dev/null +++ b/src/main/resources/static/agent/ja-netfilter/config/dns.conf @@ -0,0 +1,3 @@ +[DNS] +; put dns filter rules here + diff --git a/src/main/resources/static/agent/ja-netfilter/config/power.conf b/src/main/resources/static/agent/ja-netfilter/config/power.conf new file mode 100644 index 0000000..a245d18 --- /dev/null +++ b/src/main/resources/static/agent/ja-netfilter/config/power.conf @@ -0,0 +1 @@ +[Result] \ No newline at end of file diff --git a/src/main/resources/static/agent/ja-netfilter/config/url.conf b/src/main/resources/static/agent/ja-netfilter/config/url.conf new file mode 100644 index 0000000..6f77e41 --- /dev/null +++ b/src/main/resources/static/agent/ja-netfilter/config/url.conf @@ -0,0 +1,3 @@ +[URL] +; put url filter rules here + diff --git a/src/main/resources/static/agent/ja-netfilter/ja-netfilter.jar b/src/main/resources/static/agent/ja-netfilter/ja-netfilter.jar new file mode 100644 index 0000000..b72565a Binary files /dev/null and b/src/main/resources/static/agent/ja-netfilter/ja-netfilter.jar differ diff --git a/src/main/resources/static/agent/ja-netfilter/plugins/dns.jar b/src/main/resources/static/agent/ja-netfilter/plugins/dns.jar new file mode 100644 index 0000000..113c699 Binary files /dev/null and b/src/main/resources/static/agent/ja-netfilter/plugins/dns.jar differ diff --git a/src/main/resources/static/agent/ja-netfilter/plugins/hideme.jar b/src/main/resources/static/agent/ja-netfilter/plugins/hideme.jar new file mode 100644 index 0000000..a21ed52 Binary files /dev/null and b/src/main/resources/static/agent/ja-netfilter/plugins/hideme.jar differ diff --git a/src/main/resources/static/agent/ja-netfilter/plugins/power.jar b/src/main/resources/static/agent/ja-netfilter/plugins/power.jar new file mode 100644 index 0000000..1acc698 Binary files /dev/null and b/src/main/resources/static/agent/ja-netfilter/plugins/power.jar differ diff --git a/src/main/resources/static/agent/ja-netfilter/plugins/url.jar b/src/main/resources/static/agent/ja-netfilter/plugins/url.jar new file mode 100644 index 0000000..495804e Binary files /dev/null and b/src/main/resources/static/agent/ja-netfilter/plugins/url.jar differ diff --git a/src/main/resources/static/css/index.css b/src/main/resources/static/css/index.css new file mode 100644 index 0000000..046bd39 --- /dev/null +++ b/src/main/resources/static/css/index.css @@ -0,0 +1,530 @@ +.form { + background-color: #15172b; + border-radius: 20px; + box-sizing: border-box; + height: 500px; + padding: 20px; + width: 320px; +} + +.title { + color: #eee; + font-family: sans-serif; + font-size: 36px; + font-weight: 600; + margin-top: 30px; +} + +.subtitle { + color: #eee; + font-family: sans-serif; + font-size: 16px; + font-weight: 600; + margin-top: 10px; +} + +.input-container { + height: 50px; + position: relative; + width: 100%; +} + +.ic1 { + margin-top: 40px; +} + +.ic2 { + margin-top: 30px; +} + +.input { + background-color: #303245; + border-radius: 12px; + border: 0; + box-sizing: border-box; + color: #eee; + font-size: 18px; + height: 100%; + outline: 0; + padding: 4px 20px 0; + width: 100%; +} + +.cut { + background-color: #15172b; + border-radius: 10px; + height: 20px; + left: 20px; + position: absolute; + top: -20px; + transform: translateY(0); + transition: transform 200ms; + width: 76px; +} + +.cut-short { + width: 50px; +} + +.input:focus ~ .cut, +.input:not(:placeholder-shown) ~ .cut { + transform: translateY(8px); +} + +.placeholder { + color: #65657b; + font-family: sans-serif; + left: 20px; + line-height: 14px; + pointer-events: none; + position: absolute; + transform-origin: 0 50%; + transition: transform 200ms, color 200ms; + top: 20px; +} + +.input:focus ~ .placeholder, +.input:not(:placeholder-shown) ~ .placeholder { + transform: translateY(-30px) translateX(10px) scale(0.75); +} + +.input:not(:placeholder-shown) ~ .placeholder { + color: #808097; +} + +.input:focus ~ .placeholder { + color: #dc2f55; +} + +.submit { + background-color: #08d; + border-radius: 12px; + border: 0; + box-sizing: border-box; + color: #eee; + cursor: pointer; + font-size: 18px; + height: 50px; + margin-top: 38px; + text-align: center; + width: 100%; +} + +.submit:active { + background-color: #06b; +} +:root { + --text-grey: #9e9e9e; + --text-main: rgba(0, 0, 0, 0.87); + --spacing: 4px; + --size: 64px; + --radius: 1.5rem; + --accent: #5380f7; + --text-sm: 0.875rem; + --main-bg: #fff; + --card-bg: #fff; + --hover-color: #eee; + --border-color: rgba(0, 0, 0, 0.05); + --grey-400: rgba(0, 0, 0, 0.04); + --grey-600: rgba(0, 0, 0, 0.06); +} + +@media (prefers-color-scheme: dark) { + :root { + --main-bg: rgb(0, 0, 0); + --card-bg: rgb(31, 34, 38); + --text-main: #d9d9d9; + --text-grey: #6e767d; + --accent: #1d9bf0; + --hover-color: rgba(255, 255, 255, 0.07); + --border-color: #4b4648; + } +} + +body { + font-size: 1rem; + line-height: 1.5; + word-wrap: break-word; + font-kerning: normal; + font-family: 'Gotham SSm A', 'Gotham SSm B', 'Arial Unicode MS', Helvetica, sans-serif; + margin: 0; + padding: 0; + -webkit-font-smoothing: antialiased; + background-color: var(--main-bg); +} + +* ul, * ol { + list-style: none; + padding: 0; + margin: 0; +} + +*[role='button'], button { + cursor: pointer; +} + +.color-primary { + color: var(--text-main); +} + + +.mt-0 { + margin-top: 0; +} + + +.radius-1 { + border-radius: var(--radius); +} + +.px-6 { + padding-left: calc(var(--spacing) * 6); + padding-right: calc(var(--spacing) * 6); +} + +.py-6 { + padding-left: calc(var(--spacing)* 6); + padding-right: calc(var(--spacing)* 6); +} + +.py-10 { + padding-top: calc(var(--spacing) * 10); + padding-bottom: calc(var(--spacing) * 10); +} + +.pd-6 { + padding: calc(var(--spacing) * 6); +} + + +.pt-1 { + padding-top: var(--spacing); +} + +.pb-0 { + padding-bottom: 0; +} + +.overflow-hidden { + overflow: hidden; +} + +.flex { + display: flex; +} + +.justify-between { + justify-content: space-between; +} + +.justify-center { + justify-content: center; +} + + +.items-center { + align-items: center; +} + +.shrink-0 { + flex-shrink: 0; +} + +.text-grey { + color: var(--text-grey); +} + +.text-sm { + font-size: 0.875rem; +} + +.bg-card { + background-color: var(--card-bg); +} + +.truncate { + /* display: -webkit-box; */ + /* -webkit-box-orient: vertical; */ + /* -webkit-line-clamp: var(--line, 3); */ + /* overflow: hidden; */ +} + +.truncate-1 { + --line: 1; +} + +.overflow-ellipsis { + text-overflow: ellipsis; +} + +.z-grid { + display: grid; + grid-gap: var(--gutter, 1rem); + grid-template-columns: repeat(auto-fill, minmax(min(var(--space, 10rem), 100%), 1fr)); +} + + +.card { + box-shadow: rgb(0 0 0 / 30%) 0 8px 40px -12px; + border-radius: 1.5rem; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1) 0ms; + width: 90%; + position: relative; + overflow: visible; + background-color: var(--card-bg); + margin: 0 auto; +} + +.card:hover { + transform: translateY(-2px); +} + +.card:hover .mask { + bottom: -1.5rem; +} + +.card:hover .mask-c-1 { + bottom: -2.5rem; +} + +.container { + padding-top: calc(var(--spacing) * 10); +} + +.container p { + position: relative; + cursor: pointer; + transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; +} + +.container p::after { + content: attr(data-content); + position: absolute; + transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + color: transparent; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--radius); +} + +.container p:hover { + color: transparent; +} + +.container p:hover::after { + color: var(--text-main); + background-color: var(--hover-color); +} + +.toggle li { + z-index: 99; + position: relative; + background: transparent; + padding: 0 20px; + color: var(--text-main); + transition: background-color 250ms ease-out; +} + +.toggle li:hover { + background-color: var(--hover-color); +} + +.toggle li.active a { + color: var(--accent); +} + +.toggle li:first-child { + border-top-left-radius: var(--text-sm); + border-top-right-radius: var(--text-sm); +} + +.toggle li:last-child { + border-bottom-left-radius: var(--text-sm); + border-bottom-right-radius: var(--text-sm); +} + +.toggle li:last-child a { + border-bottom: 0; +} + +.toggle li a { + display: block; + border-bottom: 1px solid var(--border-color); + padding: 16px 0; + color: inherit; + text-decoration: none; + white-space: nowrap; +} + +.icon { + background-image: url('../images/icons.svg?t=4567'); + background-size: 64px; + background-position-x: 0; +} + +.icon-al { + background-position-y: -1728px; +} + +.icon-ii { + background-position-y: -448px; +} + +.icon-ps { + background-position-y: -512px; +} + +.icon-ac { + background-position-y: -192px; +} + +.icon-db { + background-position-y: -320px; +} + +.icon-rm { + background-position-y: -896px; +} + +.icon-ws { + background-position-y: -960px; +} + +.icon-rd { + background-position-y: -832px; +} + +.icon-cl { + background-position-y: -256px; +} + +.icon-pc { + background-position-y: -576px; +} + +.icon-go { + background-position-y: -384px; +} + +.icon-ds { + background-position-y: -1792px; +} + +.icon-dc { + background-position-y: -1408px; +} + +.icon-dpn { + background-position-y: -1536px; +} + +.icon-dm { + background-position-y: -1472px; +} + +.mask { + transition: 0.2s; + position: absolute; + z-index: -1; + width: 88%; + height: 100%; + bottom: 0; + border-radius: 1.5rem; + background-color: var(--grey-600); + left: 50%; + transform: translateX(-50%); +} + +.mask-c-1 { + bottom: 0; + width: 72%; + background-color: var(--grey-400); +} + +.avatar-wrapper { + position: relative; + width: var(--size); + height: var(--size); + font-size: 1.25rem; + user-select: none; + transform: translateY(50%); +} + +.avatar-wrapper img, .avatar-wrapper .icon { + width: 100%; + height: 100%; + margin: 0; + background-color: var(--card-bg); + color: transparent; + object-fit: cover; + text-align: center; + text-indent: 10000px; +} + + +header.tip a { + color: var(--accent); + text-decoration: none; +} + +header.tip p { + word-break: break-word; + word-wrap: break-word; +} + + +main hr { + margin: 0; + padding: 0; + background: var(--border-color); + height: 1px; + border: none; +} + +footer { + --_size: 40px; + padding-top: var(--_size); + width: 96%; + margin: calc(var(--spacing) * 10) auto 0; + padding-bottom: var(--_size); + border-top: 1px solid var(--border-color); + -moz-box-align: center; + -webkit-box-pack: justify; +} + +footer .lt-panel p:nth-of-type(1) { + color: inherit; +} +header.tip { + top: 2.3%; + background-color: var(--card-bg); + color: var(--text-main); + z-index: 99; + width: 80%; + margin: 0 auto; + border-radius: 16px; + box-shadow: rgb(0 0 0 / 30%) 0 8px 40px -12px; + transition: transform 250ms ease, box-shadow 250ms ease; +} +.sticky { + position: sticky; +} + + +.parent { + position: relative; +} +.search { + width: 300px; + height: 40px; + border-radius: 18px; + outline: none; + /*border: 1px solid #ccc;*/ + padding-left: 20px; + /*position: absolute;*/ +} \ No newline at end of file diff --git a/src/main/resources/static/images/icons.svg b/src/main/resources/static/images/icons.svg new file mode 100644 index 0000000..2b7ad34 --- /dev/null +++ b/src/main/resources/static/images/icons.svg @@ -0,0 +1,713 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/static/js/index.js b/src/main/resources/static/js/index.js new file mode 100644 index 0000000..4d18a1d --- /dev/null +++ b/src/main/resources/static/js/index.js @@ -0,0 +1,83 @@ +window.submitLicenseInfo = function () { + let licenseeName = document.getElementById('licenseeName').value + let assigneeName = document.getElementById('assigneeName').value + let expiryDate = document.getElementById('expiryDate').value + let licenseInfo = { + licenseeName: licenseeName, + assigneeName: assigneeName, + expiryDate: expiryDate + } + localStorage.setItem('licenseInfo', JSON.stringify(licenseInfo)) + document.getElementById('mask').style.display = 'none' + document.getElementById('form').style.display = 'none' +} +document.getElementById('search').oninput = function (e) { + $("#product-list").load('/search?search=' + e.target.value) +} +window.showLicenseForm = function () { + let licenseInfo = localStorage.getItem('licenseInfo'); + if (licenseInfo !== null) { + licenseInfo = JSON.parse(licenseInfo) + document.getElementById('licenseeName').value = licenseInfo.licenseeName + document.getElementById('assigneeName').value = licenseInfo.assigneeName + document.getElementById('expiryDate').value = licenseInfo.expiryDate + } else { + document.getElementById('licenseeName').value = '光云' + document.getElementById('assigneeName').value = '藏柏' + document.getElementById('expiryDate').value = '2111-11-11' + } + document.getElementById('mask').style.display = 'block' + document.getElementById('form').style.display = 'block' +} +window.showVmoptins = function () { + alert("-javaagent:/(Your Path)/ja-netfilter/ja-netfilter.jar\n" + + "--add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED\n" + + "--add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED") +} +//@see https://zhuanlan.zhihu.com/p/597944027 +const copyText = async (val) => { + if (navigator.clipboard && navigator.permissions) { + await navigator.clipboard.writeText(val) + } else { + const textArea = document.createElement('textArea') + textArea.value = val + textArea.style.width = 0 + textArea.style.position = 'fixed' + textArea.style.left = '-999px' + textArea.style.top = '10px' + textArea.setAttribute('readonly', 'readonly') + document.body.appendChild(textArea) + + textArea.select() + document.execCommand('copy') + document.body.removeChild(textArea) + } +} +window.copyLicense = async function (e) { + + while (localStorage.getItem('licenseInfo') === null) { + document.getElementById('mask').style.display = 'block' + document.getElementById('form').style.display = 'block' + await new Promise(r => setTimeout(r, 1000)); + } + let licenseInfo = JSON.parse(localStorage.getItem('licenseInfo')) + let productCode = e.closest('.card').dataset.productCodes; + let data = { + "licenseeName": licenseInfo.licenseeName, + "assigneeName": licenseInfo.assigneeName, + "expiryDate": licenseInfo.expiryDate, + "productCode": productCode, + } + let resp = await fetch('/generateLicense', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }).then(response => response.text()) + + copyText(resp) + .then(() => { + alert("The activation code has been copied"); + }) +} \ No newline at end of file diff --git a/src/main/resources/static/js/jquery.js b/src/main/resources/static/js/jquery.js new file mode 100644 index 0000000..7f37b5d --- /dev/null +++ b/src/main/resources/static/js/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 + + + + + + Jetbrains-Help + + + + +
+

+ 🇨🇳 Download ja-netfilter.zip , and configure + your JetBrains's vmoptions!
+ 🇨🇳 Also you can Refill license information to customizer your license!
+ 🇨🇳 Please note that this page is only developed and used by + personally! +

+
+ +
+
+
+ + +
+
+
+
+ +
+
+
+
+
+

+

+ ********** +

+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+

+

+ ********** +

+
+
+
+
+
+
+
+ + + + + + \ No newline at end of file