mirror of
				https://github.com/smartfrigde/armcord.git
				synced 2024-08-14 23:56:58 +00:00 
			
		
		
		
	
						commit
						92aed29861
					
				
					 10 changed files with 7877 additions and 2626 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +1,2 @@ | ||||||
| node_modules | node_modules | ||||||
|  | out/ | ||||||
							
								
								
									
										10
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,3 +1,4 @@ | ||||||
|  | 
 | ||||||
| # ArmCord 🦾🔌 | # ArmCord 🦾🔌 | ||||||
| Armcord is a custom Discord client for ARM Linux. It's goal is to bring a custom Discord client to ARM Architecture. It uses [GooseMod](https://goosemod.com) for custom themes and plugins! | Armcord is a custom Discord client for ARM Linux. It's goal is to bring a custom Discord client to ARM Architecture. It uses [GooseMod](https://goosemod.com) for custom themes and plugins! | ||||||
| 
 | 
 | ||||||
|  | @ -20,3 +21,12 @@ Alternative (npm, nodejs required): | ||||||
|  -Yes! ArmCord should work normally under Windows, Mac OS, Linux as long as it has NodeJS, npm and Electron support.    |  -Yes! ArmCord should work normally under Windows, Mac OS, Linux as long as it has NodeJS, npm and Electron support.    | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | # Credits | ||||||
|  | [ArmCord Loading Screen](https://github.com/kckarnige)    | ||||||
|  | [GooseMod](https://github.com/GooseMod/GooseMod)    | ||||||
|  | [GooseMod-Chrome](https://github.com/AAGaming00/GooseMod-chrome)     | ||||||
|  | [update.rocks](https://www.update.rocks)    | ||||||
|  | [electron-discord-webapp](https://github.com/SpacingBat3/electron-discord-webapp)     | ||||||
|  | [custom-electron-titlebar](https://github.com/AlexTorresSk/custom-electron-titlebar)     | ||||||
|  | [electron-localshortcut](https://github.com/parro-it/electron-localshortcut)     | ||||||
|  | [electron-forge](https://www.npmjs.com/package/electron-forge)     | ||||||
|  |  | ||||||
|  | @ -1 +0,0 @@ | ||||||
| GooseMod for Chrome |  | ||||||
|  | @ -80,11 +80,7 @@ | ||||||
|   <p>Loading...</p> |   <p>Loading...</p> | ||||||
|     <h1>Cord</h1> |     <h1>Cord</h1> | ||||||
| </div> | </div> | ||||||
|     <script type=" text/javascript"> | 
 | ||||||
|       document.getElementById("myButton").onclick = function () { |  | ||||||
|       location.href = "https://discordbotclient.jtmaveryk.repl.co"; |  | ||||||
|       }; |  | ||||||
|     </script> |  | ||||||
| </body> | </body> | ||||||
| 
 | 
 | ||||||
| </html> | </html> | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								main.js
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								main.js
									
										
									
									
									
								
							|  | @ -2,10 +2,9 @@ | ||||||
| const { app, BrowserWindow, session } = require('electron') | const { app, BrowserWindow, session } = require('electron') | ||||||
| const path = require('path') | const path = require('path') | ||||||
| require("v8-compile-cache"); | require("v8-compile-cache"); | ||||||
| require("update-electron-app")(); | require("./utils/updater"); | ||||||
| let mainWindow | let mainWindow | ||||||
| require("./menu.js") | require("./menu.js") | ||||||
| 
 |  | ||||||
| function createWindow() { | function createWindow() { | ||||||
|   mainWindow = new BrowserWindow({ |   mainWindow = new BrowserWindow({ | ||||||
|     width: 800, |     width: 800, | ||||||
|  | @ -13,13 +12,14 @@ function createWindow() { | ||||||
|     icon: __dirname + '/discord.ico', |     icon: __dirname + '/discord.ico', | ||||||
|     frame: false, |     frame: false, | ||||||
|     webPreferences: { |     webPreferences: { | ||||||
|       preload: path.join(__dirname, 'preload.js'), |       preload: path.join(__dirname, "preload.js"), | ||||||
|       enableRemoteModule: true, |       enableRemoteModule: true, | ||||||
|       nodeIntegration: false, |       nodeIntegration: false, | ||||||
|     } |     }, | ||||||
|   }) |   }); | ||||||
| 
 |   mainWindow.webContents.userAgent = | ||||||
|   mainWindow.loadFile('index.html') |     "Mozilla/5.0 (X12; TempleOS MIPS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"; //to set
 | ||||||
|  |   mainWindow.loadFile("index.html"); | ||||||
|   mainWindow.webContents.on("new-window", function (e, url) { |   mainWindow.webContents.on("new-window", function (e, url) { | ||||||
|     e.preventDefault(); |     e.preventDefault(); | ||||||
|     require("electron").shell.openExternal(url); |     require("electron").shell.openExternal(url); | ||||||
|  | @ -27,9 +27,9 @@ function createWindow() { | ||||||
|   // Open the DevTools.
 |   // Open the DevTools.
 | ||||||
|   // mainWindow.webContents.openDevTools()
 |   // mainWindow.webContents.openDevTools()
 | ||||||
| 
 | 
 | ||||||
|   mainWindow.on('closed', () => { |   mainWindow.on("closed", () => { | ||||||
|     mainWindow = null |     mainWindow = null; | ||||||
|   }) |   }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // This method will be called when Electron has finished
 | // This method will be called when Electron has finished
 | ||||||
|  | @ -38,7 +38,17 @@ function createWindow() { | ||||||
| app.whenReady().then(() => { | app.whenReady().then(() => { | ||||||
|   createWindow() |   createWindow() | ||||||
|   session.defaultSession.loadExtension(`${require('electron').app.getAppPath()}/goosemod/`) |   session.defaultSession.loadExtension(`${require('electron').app.getAppPath()}/goosemod/`) | ||||||
|  |   session | ||||||
|  |     .fromPartition("some-partition") | ||||||
|  |     .setPermissionRequestHandler((webContents, permission, callback) => { | ||||||
|  |       const url = webContents.getURL(); //unused?
 | ||||||
| 
 | 
 | ||||||
|  |       if (permission === "notifications") { | ||||||
|  |         // Approves the permissions request
 | ||||||
|  |         callback(true); | ||||||
|  |        | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|   app.on('activate', function () { |   app.on('activate', function () { | ||||||
|     // On macOS it's common to re-create a window in the app when the
 |     // On macOS it's common to re-create a window in the app when the
 | ||||||
|     // dock icon is clicked and there are no other windows open.
 |     // dock icon is clicked and there are no other windows open.
 | ||||||
|  |  | ||||||
							
								
								
									
										10129
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										10129
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										49
									
								
								package.json
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								package.json
									
										
									
									
									
								
							|  | @ -1,24 +1,30 @@ | ||||||
| { | { | ||||||
|   "name": "armcord", |   "name": "armcord", | ||||||
|   "version": "2.0.1", |   "version": "2.2.0", | ||||||
|   "description": "ArmCord is a Discord client made for ARM Linux that allows you to customize your experience.", |   "description": "ArmCord is a Discord client made for ARM Linux that allows you to customize your experience.", | ||||||
|   "main": "main.js", |   "main": "main.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "start": "electron .", |     "start": "electron-forge start", | ||||||
|     "dist": "electron-builder", |     "dist": "electron-builder", | ||||||
|     "test": "echo \"Error: no test specified\" && exit 1" |     "test": "echo \"Error: no test specified\" && exit 1", | ||||||
|  |     "package": "electron-forge package", | ||||||
|  |     "make": "electron-forge make" | ||||||
|   }, |   }, | ||||||
|   "author": "smartfrigde", |   "author": "smartfrigde", | ||||||
|   "license": "MIT", |   "license": "MIT", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "custom-electron-titlebar": "3.2.6", |     "custom-electron-titlebar": "3.2.6", | ||||||
|     "update-electron-app": "^2.0.1", |     "electron-localshortcut": "^3.2.1", | ||||||
|  |     "electron-squirrel-startup": "^1.0.0", | ||||||
|     "v8-compile-cache": "^2.3.0" |     "v8-compile-cache": "^2.3.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "electron": "latest", |     "@electron-forge/cli": "^6.0.0-beta.54", | ||||||
|     "electron-builder": "latest", |     "@electron-forge/maker-deb": "^6.0.0-beta.54", | ||||||
|     "electron-packager": "latest" |     "@electron-forge/maker-rpm": "^6.0.0-beta.54", | ||||||
|  |     "@electron-forge/maker-squirrel": "^6.0.0-beta.54", | ||||||
|  |     "@electron-forge/maker-zip": "^6.0.0-beta.54", | ||||||
|  |     "electron": "latest" | ||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|  | @ -32,5 +38,32 @@ | ||||||
|   "bugs": { |   "bugs": { | ||||||
|     "url": "https://github.com/smartfrigde/armcord/issues" |     "url": "https://github.com/smartfrigde/armcord/issues" | ||||||
|   }, |   }, | ||||||
|   "homepage": "https://github.com/smartfrigde/armcord#readme" |   "homepage": "https://github.com/smartfrigde/armcord#readme", | ||||||
|  |   "config": { | ||||||
|  |     "forge": { | ||||||
|  |       "packagerConfig": {}, | ||||||
|  |       "makers": [ | ||||||
|  |         { | ||||||
|  |           "name": "@electron-forge/maker-squirrel", | ||||||
|  |           "config": { | ||||||
|  |             "name": "armcord" | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "name": "@electron-forge/maker-zip", | ||||||
|  |           "platforms": [ | ||||||
|  |             "darwin" | ||||||
|  |           ] | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "name": "@electron-forge/maker-deb", | ||||||
|  |           "config": {} | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "name": "@electron-forge/maker-rpm", | ||||||
|  |           "config": {} | ||||||
|  |         } | ||||||
|  |       ] | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								preload.js
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								preload.js
									
										
									
									
									
								
							|  | @ -1,4 +1,6 @@ | ||||||
| const customTitlebar = require('custom-electron-titlebar') | const customTitlebar = require('custom-electron-titlebar') | ||||||
|  | const electronLocalshortcut = require("electron-localshortcut"); | ||||||
|  | const { remote } = require("electron"); | ||||||
| 
 | 
 | ||||||
| window.addEventListener('DOMContentLoaded', () => { | window.addEventListener('DOMContentLoaded', () => { | ||||||
|   new customTitlebar.Titlebar({ |   new customTitlebar.Titlebar({ | ||||||
|  | @ -15,6 +17,16 @@ window.addEventListener('DOMContentLoaded', () => { | ||||||
|   document.head.append(style); |   document.head.append(style); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | }) | ||||||
|  | const currentWindow = remote.getCurrentWindow(); | ||||||
|  | electronLocalshortcut.register(currentWindow, "F5", () => { | ||||||
|  |   location.reload(); | ||||||
|  | }); | ||||||
|  | electronLocalshortcut.register(currentWindow, "F12", () => { | ||||||
|  |   currentWindow.webContents.openDevTools(); | ||||||
|  | }); | ||||||
|  | require("./utils/capturer.js") | ||||||
| addStyle(` | addStyle(` | ||||||
| @import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); | @import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); | ||||||
| 
 | 
 | ||||||
|  | @ -60,3 +72,4 @@ div.menubar[role="menubar"] { | ||||||
| } | } | ||||||
| `);
 | `);
 | ||||||
| }) | }) | ||||||
|  | 
 | ||||||
|  |  | ||||||
							
								
								
									
										164
									
								
								utils/capturer.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								utils/capturer.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,164 @@ | ||||||
|  | // This desktop capturer has been taken from https://github.com/SpacingBat3/electron-discord-webapp
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * Thanks, @WesselKroos! | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /*function l10n(origin, locale){ | ||||||
|  |   if(originalString == 'Entire Screen') { | ||||||
|  |     return locale; | ||||||
|  |   } else { | ||||||
|  |     return origin; | ||||||
|  |   } | ||||||
|  | }*/ | ||||||
|  | const { desktopCapturer } = require("electron"); | ||||||
|  | 
 | ||||||
|  | navigator.mediaDevices.getDisplayMedia = () => { | ||||||
|  |   return new Promise(async (resolve, reject) => { | ||||||
|  |     try { | ||||||
|  |       const sources = await desktopCapturer.getSources({ | ||||||
|  |         types: ["screen", "window"], | ||||||
|  |       }); | ||||||
|  |       const selectionElem = document.createElement("div"); | ||||||
|  |       selectionElem.setAttribute("class", "desktop-capturer-selection"); | ||||||
|  |       selectionElem.innerHTML = ` | ||||||
|  |         <style> | ||||||
|  |         .desktop-capturer-selection { | ||||||
|  |           position: fixed; | ||||||
|  |           top: 0; | ||||||
|  |           left: 0; | ||||||
|  |           width: 100%; | ||||||
|  |           height: 100vh; | ||||||
|  |           background: rgba(30,30,30,.75); | ||||||
|  |           color: #fff; | ||||||
|  |           z-index: 10000000; | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           justify-content: center; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-selection__scroller { | ||||||
|  |           width: 100%; | ||||||
|  |           max-height: 100vh; | ||||||
|  |           overflow-y: auto; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-selection__list { | ||||||
|  |           max-width: calc(100% - 100px); | ||||||
|  |           margin: 50px; | ||||||
|  |           padding: 0; | ||||||
|  |           display: flex; | ||||||
|  |           flex-wrap: wrap; | ||||||
|  |           list-style: none; | ||||||
|  |           overflow: hidden; | ||||||
|  |           justify-content: center; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-selection__item { | ||||||
|  |           display: flex; | ||||||
|  |           margin: 4px; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-selection__btn { | ||||||
|  |           display: flex; | ||||||
|  |           flex-direction: column; | ||||||
|  |           align-items: stretch; | ||||||
|  |           width: 145px; | ||||||
|  |           margin: 0; | ||||||
|  |           border: 0; | ||||||
|  |           border-radius: 3px; | ||||||
|  |           padding: 4px; | ||||||
|  |           color: #FFFFFF; | ||||||
|  |           background: #36393F; | ||||||
|  |           text-align: left; | ||||||
|  |           transition: background-color .15s, box-shadow .15s; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-selection__btn:hover, | ||||||
|  |         .desktop-capturer-selection__btn:focus { | ||||||
|  |           background: #7289DA; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-selection__thumbnail { | ||||||
|  |           width: 100%; | ||||||
|  |           height: 81px; | ||||||
|  |           object-fit: cover; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-selection__name { | ||||||
|  |           margin: 6px 0 6px; | ||||||
|  |           white-space: nowrap; | ||||||
|  |           text-overflow: ellipsis; | ||||||
|  |           overflow: hidden; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-close { | ||||||
|  |           background-color: #36393F; | ||||||
|  |           position: fixed; | ||||||
|  |           top: 50%; | ||||||
|  |           transform: translateY(-50%); | ||||||
|  |           right: 15px; | ||||||
|  |           padding-top: 5px; | ||||||
|  |           transition: background-color .15s; | ||||||
|  |         } | ||||||
|  |         .desktop-capturer-close:hover { | ||||||
|  |           background-color: #823A3A; | ||||||
|  |         } | ||||||
|  |         </style> | ||||||
|  |         <div class="desktop-capturer-selection__scroller"> | ||||||
|  |           <ul class="desktop-capturer-selection__list"> | ||||||
|  |             ${sources | ||||||
|  |               .map( | ||||||
|  |                 ({ id, name, thumbnail }) => ` | ||||||
|  |               <li class="desktop-capturer-selection__item"> | ||||||
|  |                 <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}"> | ||||||
|  |                   <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" /> | ||||||
|  |                   <span class="desktop-capturer-selection__name">${name}</span> | ||||||
|  |                 </button> | ||||||
|  |               </li> | ||||||
|  |             ` | ||||||
|  |               ) | ||||||
|  |               .join("")} | ||||||
|  |           </ul> | ||||||
|  |           <button class="desktop-capturer-close"> | ||||||
|  |             <svg viewBox="0 0 10 10" height=20px> | ||||||
|  |               <line x1="0" y1="10" x2="10" y2="0" stroke="white" /> | ||||||
|  |               <line x1="0" y1="0" x2="10" y2="10" stroke="white" /> | ||||||
|  |             </svg> | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       `;
 | ||||||
|  |       document.body.appendChild(selectionElem); | ||||||
|  | 
 | ||||||
|  |       document | ||||||
|  |         .querySelectorAll(".desktop-capturer-selection__btn") | ||||||
|  |         .forEach((button) => { | ||||||
|  |           button.addEventListener("click", async () => { | ||||||
|  |             try { | ||||||
|  |               const id = button.getAttribute("data-id"); | ||||||
|  |               const source = sources.find((source) => source.id === id); | ||||||
|  |               if (!source) { | ||||||
|  |                 throw new Error(`Source with id ${id} does not exist`); | ||||||
|  |               } | ||||||
|  |               const stream = await navigator.mediaDevices.getUserMedia({ | ||||||
|  |                 audio: false, | ||||||
|  |                 video: { | ||||||
|  |                   mandatory: { | ||||||
|  |                     chromeMediaSource: "desktop", | ||||||
|  |                     chromeMediaSourceId: source.id, | ||||||
|  |                   }, | ||||||
|  |                 }, | ||||||
|  |               }); | ||||||
|  |               resolve(stream); | ||||||
|  |               selectionElem.remove(); | ||||||
|  |             } catch (err) { | ||||||
|  |               console.error("Error selecting desktop capture source:", err); | ||||||
|  |               reject(err); | ||||||
|  |             } | ||||||
|  |           }); | ||||||
|  |         }); | ||||||
|  |       document.querySelectorAll(".desktop-capturer-close").forEach((button) => { | ||||||
|  |         button.addEventListener("click", () => { | ||||||
|  |           selectionElem.remove(); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  |     } catch (err) { | ||||||
|  |       console.error("Error displaying desktop capture sources:", err); | ||||||
|  |       reject(err); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | console.log("Desktop capturer has been preloaded 🎉️"); | ||||||
							
								
								
									
										66
									
								
								utils/updater.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								utils/updater.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | const electron = require("electron"); | ||||||
|  | const APP_VERSION = require("../package.json").version; | ||||||
|  | 
 | ||||||
|  | /* IMPORTANT! | ||||||
|  |   This url will need to be modified for yours */ | ||||||
|  | // The url that the application is going to query for new release
 | ||||||
|  | const AUTO_UPDATE_URL = | ||||||
|  |   'https://api.dev.update.rocks/update/github.com/smartfrigde/armcord/stable/' + process.platform + '/' + APP_VERSION | ||||||
|  | 
 | ||||||
|  | function init() { | ||||||
|  |   if (process.platform === "linux") { | ||||||
|  |     /* There is no auto update for linux however you can still | ||||||
|  |        notify the user that a new update has been released | ||||||
|  |        our service will return an answer with the latest version. */ | ||||||
|  |     console.log("Auto updates not available on linux"); | ||||||
|  |   } else { | ||||||
|  |     initDarwinWin32(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function initDarwinWin32() { | ||||||
|  |   electron.autoUpdater.on("error", (err) => | ||||||
|  |     console.error(`Update error: ${err.message}`) | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   electron.autoUpdater.on("checking-for-update", () => | ||||||
|  |     console.log("Checking for update") | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   electron.autoUpdater.on("update-available", () => | ||||||
|  |     console.log("Update available") | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   electron.autoUpdater.on("update-not-available", () => | ||||||
|  |     console.log("No update available") | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   // Ask the user if he wants to update if update is available
 | ||||||
|  |   electron.autoUpdater.on( | ||||||
|  |     "update-downloaded", | ||||||
|  |     (event, releaseNotes, releaseName) => { | ||||||
|  |       dialog.showMessageBox( | ||||||
|  |         window, | ||||||
|  |         { | ||||||
|  |           type: "question", | ||||||
|  |           buttons: ["Update", "Cancel"], | ||||||
|  |           defaultId: 0, | ||||||
|  |           message: `Version ${releaseName} is available, do you want to install it now?`, | ||||||
|  |           title: "Update available", | ||||||
|  |         }, | ||||||
|  |         (response) => { | ||||||
|  |           if (response === 0) { | ||||||
|  |             electron.autoUpdater.quitAndInstall(); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   electron.autoUpdater.setFeedURL(AUTO_UPDATE_URL); | ||||||
|  |   electron.autoUpdater.checkForUpdates(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  |   init, | ||||||
|  | }; | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue